incomplete work on fixing #5010 for /refresh/melt
This commit is contained in:
parent
053096475f
commit
87e16541af
@ -31,94 +31,6 @@
|
|||||||
#include "taler-exchange-httpd_keystate.h"
|
#include "taler-exchange-httpd_keystate.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How often should we retry a transaction before giving up
|
|
||||||
* (for transactions resulting in serialization/dead locks only).
|
|
||||||
*/
|
|
||||||
#define MAX_TRANSACTION_COMMIT_RETRIES 3
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Code to begin a transaction, must be inline as we define a block
|
|
||||||
* that ends with #COMMIT_TRANSACTION() within which we perform a number
|
|
||||||
* of retries. Note that this code may call "return" internally, so
|
|
||||||
* it must be called within a function where any cleanup will be done
|
|
||||||
* by the caller. Furthermore, the function's return value must
|
|
||||||
* match that of a #TEH_RESPONSE_reply_internal_db_error() status code.
|
|
||||||
*
|
|
||||||
* @param session session handle
|
|
||||||
* @param connection connection handle
|
|
||||||
*/
|
|
||||||
#define START_TRANSACTION(session,connection) \
|
|
||||||
{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\
|
|
||||||
unsigned int transaction_retries = 0; \
|
|
||||||
enum GNUNET_DB_QueryStatus transaction_commit_result; \
|
|
||||||
transaction_start_label: /* we will use goto for retries */ \
|
|
||||||
if (GNUNET_OK != \
|
|
||||||
TEH_plugin->start (TEH_plugin->cls, \
|
|
||||||
session)) \
|
|
||||||
{ \
|
|
||||||
GNUNET_break (0); \
|
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection, \
|
|
||||||
TALER_EC_DB_START_FAILED); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Code to conclude a transaction, dual to #START_TRANSACTION(). Note
|
|
||||||
* that this code may call "return" internally, so it must be called
|
|
||||||
* within a function where any cleanup will be done by the caller.
|
|
||||||
* Furthermore, the function's return value must match that of a
|
|
||||||
* #TEH_RESPONSE_reply_internal_db_error() status code.
|
|
||||||
*
|
|
||||||
* @param session session handle
|
|
||||||
* @param connection connection handle
|
|
||||||
*/
|
|
||||||
#define COMMIT_TRANSACTION(session,connection) \
|
|
||||||
transaction_commit_result = \
|
|
||||||
TEH_plugin->commit (TEH_plugin->cls, \
|
|
||||||
session); \
|
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == transaction_commit_result) \
|
|
||||||
{ \
|
|
||||||
TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
|
|
||||||
return TEH_RESPONSE_reply_commit_error (connection, \
|
|
||||||
TALER_EC_DB_COMMIT_FAILED_HARD); \
|
|
||||||
} \
|
|
||||||
if (GNUNET_DB_STATUS_SOFT_ERROR == transaction_commit_result) \
|
|
||||||
{ \
|
|
||||||
TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
|
|
||||||
if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \
|
|
||||||
goto transaction_start_label; \
|
|
||||||
TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \
|
|
||||||
transaction_retries, \
|
|
||||||
__FUNCTION__); \
|
|
||||||
return TEH_RESPONSE_reply_commit_error (connection, \
|
|
||||||
TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \
|
|
||||||
} \
|
|
||||||
} /* end of scope opened by BEGIN_TRANSACTION */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Code to include to retry a transaction, must only be used in between
|
|
||||||
* #START_TRANSACTION and #COMMIT_TRANSACTION.
|
|
||||||
*
|
|
||||||
* @param session session handle
|
|
||||||
* @param connection connection handle
|
|
||||||
*/
|
|
||||||
#define RETRY_TRANSACTION(session,connection) \
|
|
||||||
do { \
|
|
||||||
TEH_plugin->rollback (TEH_plugin->cls, \
|
|
||||||
session); \
|
|
||||||
if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \
|
|
||||||
goto transaction_start_label; \
|
|
||||||
TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \
|
|
||||||
transaction_retries, \
|
|
||||||
__FUNCTION__); \
|
|
||||||
return TEH_RESPONSE_reply_commit_error (connection, \
|
|
||||||
TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Details about a melt operation of an individual coin.
|
* @brief Details about a melt operation of an individual coin.
|
||||||
*/
|
*/
|
||||||
@ -237,6 +149,56 @@ reply_refresh_melt_success (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context for the /refresh/melt operation.
|
||||||
|
*/
|
||||||
|
struct RefreshMeltContext
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of denominations of the fresh coins.
|
||||||
|
*/
|
||||||
|
struct TALER_DenominationPublicKey *denom_pubs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of new coins to be generated in the melt.
|
||||||
|
* Size of the @e denom_pubs array.
|
||||||
|
*/
|
||||||
|
unsigned int num_newcoins;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details about the coin to be melted.
|
||||||
|
*/
|
||||||
|
struct TEH_DB_MeltDetails coin_melt_details;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to the session hash once the @e hash_context has finished.
|
||||||
|
*/
|
||||||
|
struct GNUNET_HashCode session_hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash operation used to calculate the session hash.
|
||||||
|
*/
|
||||||
|
struct GNUNET_HashContext *hash_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Committments to the blinded envelopes for the fresh coins.
|
||||||
|
*/
|
||||||
|
struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commmittments to the transfer public keys.
|
||||||
|
*/
|
||||||
|
struct TALER_TransferPublicKeyP transfer_pub[TALER_CNC_KAPPA];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialized during #refresh_melt_transaction().
|
||||||
|
*/
|
||||||
|
struct TALER_EXCHANGEDB_RefreshSession refresh_session;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse coin melt requests from a JSON object and write them to
|
* Parse coin melt requests from a JSON object and write them to
|
||||||
* the database.
|
* the database.
|
||||||
@ -341,136 +303,102 @@ refresh_check_melt (struct MHD_Connection *connection,
|
|||||||
* required value left and if so, store that they have been
|
* required value left and if so, store that they have been
|
||||||
* melted and confirm the melting operation to the client.
|
* melted and confirm the melting operation to the client.
|
||||||
*
|
*
|
||||||
* @param connection the MHD connection to handle
|
* If it returns a non-error code, the transaction logic MUST
|
||||||
* @param session_hash hash code of the session the coins are melted into
|
* NOT queue a MHD response. IF it returns an hard error, the
|
||||||
* @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array
|
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF
|
||||||
* @param denom_pubs public keys of the coins we want to withdraw in the end
|
* it returns the soft error code, the function MAY be called again to
|
||||||
* @param coin_melt_detail signature and (residual) value of the respective coin should be melted
|
* retry and MUST not queue a MHD response.
|
||||||
* @param commit_coin 2d array of coin commitments (what the exchange is to sign
|
*
|
||||||
* once the "/refres/reveal" of cut and choose is done),
|
* @param cls our `struct RefreshMeltContext`
|
||||||
* x-dimension must be #TALER_CNC_KAPPA
|
* @param connection MHD request which triggered the transaction
|
||||||
* @param transfer_pubs array of transfer public keys (what the exchange is
|
* @param session database session to use
|
||||||
* to return via "/refresh/link" to enable linkage in the
|
* @param[out] mhd_ret set to MHD response status for @a connection,
|
||||||
* future) of length #TALER_CNC_KAPPA
|
* if transaction failed (!)
|
||||||
* @return MHD result code
|
* @return transaction status
|
||||||
*/
|
*/
|
||||||
static int
|
static enum GNUNET_DB_QueryStatus
|
||||||
execute_refresh_melt (struct MHD_Connection *connection,
|
refresh_melt_transaction (void *cls,
|
||||||
const struct GNUNET_HashCode *session_hash,
|
struct MHD_Connection *connection,
|
||||||
unsigned int num_new_denoms,
|
struct TALER_EXCHANGEDB_Session *session,
|
||||||
const struct TALER_DenominationPublicKey *denom_pubs,
|
int *mhd_ret)
|
||||||
const struct TEH_DB_MeltDetails *coin_melt_detail,
|
|
||||||
struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin,
|
|
||||||
const struct TALER_TransferPublicKeyP *transfer_pubs)
|
|
||||||
{
|
{
|
||||||
|
struct RefreshMeltContext *rmc = cls;
|
||||||
struct TEH_KS_StateHandle *key_state;
|
struct TEH_KS_StateHandle *key_state;
|
||||||
struct TALER_EXCHANGEDB_RefreshSession refresh_session;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
struct TALER_EXCHANGEDB_Session *session;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
|
qs = TEH_plugin->get_refresh_session (TEH_plugin->cls,
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection,
|
|
||||||
TALER_EC_DB_SETUP_FAILED);
|
|
||||||
}
|
|
||||||
START_TRANSACTION (session, connection);
|
|
||||||
res = TEH_plugin->get_refresh_session (TEH_plugin->cls,
|
|
||||||
session,
|
session,
|
||||||
session_hash,
|
&rmc->session_hash,
|
||||||
&refresh_session);
|
&rmc->refresh_session);
|
||||||
if (GNUNET_YES == res)
|
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
|
||||||
{
|
{
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
*mhd_ret = reply_refresh_melt_success (connection,
|
||||||
session);
|
&rmc->session_hash,
|
||||||
res = reply_refresh_melt_success (connection,
|
rmc->refresh_session.noreveal_index);
|
||||||
session_hash,
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
refresh_session.noreveal_index);
|
|
||||||
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
|
||||||
}
|
}
|
||||||
if (GNUNET_SYSERR == res)
|
if (0 > qs)
|
||||||
{
|
{
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||||
session);
|
*mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection,
|
|
||||||
TALER_EC_REFRESH_MELT_DB_FETCH_ERROR);
|
TALER_EC_REFRESH_MELT_DB_FETCH_ERROR);
|
||||||
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store 'global' session data */
|
/* store 'global' session data */
|
||||||
refresh_session.num_newcoins = num_new_denoms;
|
rmc->refresh_session.num_newcoins = rmc->num_newcoins;
|
||||||
refresh_session.noreveal_index
|
rmc->refresh_session.noreveal_index
|
||||||
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
|
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
|
||||||
TALER_CNC_KAPPA);
|
TALER_CNC_KAPPA);
|
||||||
|
|
||||||
key_state = TEH_KS_acquire ();
|
key_state = TEH_KS_acquire ();
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
(res = refresh_check_melt (connection,
|
(res = refresh_check_melt (connection,
|
||||||
session,
|
session,
|
||||||
key_state,
|
key_state,
|
||||||
session_hash,
|
&rmc->session_hash,
|
||||||
coin_melt_detail,
|
&rmc->coin_melt_details,
|
||||||
&refresh_session.melt)))
|
&rmc->refresh_session.melt)))
|
||||||
{
|
{
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
*mhd_ret = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||||
session);
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
|
||||||
}
|
}
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if ( (0 >=
|
||||||
(res = TEH_plugin->create_refresh_session (TEH_plugin->cls,
|
(qs = TEH_plugin->create_refresh_session (TEH_plugin->cls,
|
||||||
session,
|
session,
|
||||||
session_hash,
|
&rmc->session_hash,
|
||||||
&refresh_session)))
|
&rmc->refresh_session))) ||
|
||||||
|
(0 >=
|
||||||
|
(qs = TEH_plugin->insert_refresh_order (TEH_plugin->cls,
|
||||||
|
session,
|
||||||
|
&rmc->session_hash,
|
||||||
|
rmc->num_newcoins,
|
||||||
|
rmc->denom_pubs))) ||
|
||||||
|
(0 >=
|
||||||
|
(qs = TEH_plugin->insert_refresh_commit_coins (TEH_plugin->cls,
|
||||||
|
session,
|
||||||
|
&rmc->session_hash,
|
||||||
|
rmc->num_newcoins,
|
||||||
|
rmc->commit_coin[rmc->refresh_session.noreveal_index]))) ||
|
||||||
|
(0 >=
|
||||||
|
(qs = TEH_plugin->insert_refresh_transfer_public_key (TEH_plugin->cls,
|
||||||
|
session,
|
||||||
|
&rmc->session_hash,
|
||||||
|
&rmc->transfer_pub[rmc->refresh_session.noreveal_index]))) )
|
||||||
{
|
{
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
|
||||||
session);
|
{
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection,
|
*mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR);
|
TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR);
|
||||||
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
return qs;
|
||||||
/* store requested new denominations */
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TEH_plugin->insert_refresh_order (TEH_plugin->cls,
|
|
||||||
session,
|
|
||||||
session_hash,
|
|
||||||
num_new_denoms,
|
|
||||||
denom_pubs))
|
|
||||||
{
|
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
|
||||||
session);
|
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection,
|
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR);
|
|
||||||
}
|
}
|
||||||
|
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||||
if (GNUNET_OK !=
|
|
||||||
TEH_plugin->insert_refresh_commit_coins (TEH_plugin->cls,
|
|
||||||
session,
|
|
||||||
session_hash,
|
|
||||||
num_new_denoms,
|
|
||||||
commit_coin[refresh_session.noreveal_index]))
|
|
||||||
{
|
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
|
||||||
session);
|
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection,
|
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR);
|
|
||||||
}
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TEH_plugin->insert_refresh_transfer_public_key (TEH_plugin->cls,
|
|
||||||
session,
|
|
||||||
session_hash,
|
|
||||||
&transfer_pubs[refresh_session.noreveal_index]))
|
|
||||||
{
|
|
||||||
TEH_plugin->rollback (TEH_plugin->cls,
|
|
||||||
session);
|
|
||||||
return TEH_RESPONSE_reply_internal_db_error (connection,
|
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMIT_TRANSACTION (session, connection);
|
|
||||||
return reply_refresh_melt_success (connection,
|
|
||||||
session_hash,
|
|
||||||
refresh_session.noreveal_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -480,25 +408,14 @@ execute_refresh_melt (struct MHD_Connection *connection,
|
|||||||
* and then hand things of to execute the melt operation.
|
* and then hand things of to execute the melt operation.
|
||||||
*
|
*
|
||||||
* @param connection the MHD connection to handle
|
* @param connection the MHD connection to handle
|
||||||
* @param num_new_denoms number of coins to be created, size of y-dimension of @a commit_link array
|
* @param[out] mhd_ret set on failure to return value for MHD
|
||||||
* @param denom_pubs array of @a num_new_denoms keys
|
* @param rmc information about the melt to process
|
||||||
* @param coin_melt_details melting details
|
|
||||||
* @param session_hash hash over the data that the client commits to
|
|
||||||
* @param commit_coin 2d array of coin commitments (what the exchange is to sign
|
|
||||||
* once the "/refres/reveal" of cut and choose is done)
|
|
||||||
* @param transfer_pubs array of transfer public keys (which the exchange is
|
|
||||||
* to return via "/refresh/link" to enable linkage in the
|
|
||||||
* future) of length #TALER_CNC_KAPPA
|
|
||||||
* @return MHD result code
|
* @return MHD result code
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
handle_refresh_melt_binary (struct MHD_Connection *connection,
|
refresh_melt_prepare (struct MHD_Connection *connection,
|
||||||
unsigned int num_new_denoms,
|
int *mhd_ret,
|
||||||
const struct TALER_DenominationPublicKey *denom_pubs,
|
struct RefreshMeltContext *rmc)
|
||||||
const struct TEH_DB_MeltDetails *coin_melt_details,
|
|
||||||
const struct GNUNET_HashCode *session_hash,
|
|
||||||
struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin,
|
|
||||||
const struct TALER_TransferPublicKeyP *transfer_pubs)
|
|
||||||
{
|
{
|
||||||
struct TEH_KS_StateHandle *key_state;
|
struct TEH_KS_StateHandle *key_state;
|
||||||
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk;
|
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk;
|
||||||
@ -512,24 +429,25 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
"/refresh/melt request for session %s\n",
|
"/refresh/melt request for session %s\n",
|
||||||
GNUNET_h2s (session_hash));
|
GNUNET_h2s (&rmc->session_hash));
|
||||||
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_amount_get_zero (TEH_exchange_currency_string,
|
TALER_amount_get_zero (TEH_exchange_currency_string,
|
||||||
&total_cost));
|
&total_cost));
|
||||||
key_state = TEH_KS_acquire ();
|
key_state = TEH_KS_acquire ();
|
||||||
for (unsigned int i=0;i<num_new_denoms;i++)
|
for (unsigned int i=0;i<rmc->num_newcoins;i++)
|
||||||
{
|
{
|
||||||
dk = TEH_KS_denomination_key_lookup (key_state,
|
dk = TEH_KS_denomination_key_lookup (key_state,
|
||||||
&denom_pubs[i],
|
&rmc->denom_pubs[i],
|
||||||
TEH_KS_DKU_WITHDRAW);
|
TEH_KS_DKU_WITHDRAW);
|
||||||
if (NULL == dk)
|
if (NULL == dk)
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
return TEH_RESPONSE_reply_arg_invalid (connection,
|
*mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection,
|
||||||
TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND,
|
TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND,
|
||||||
"new_denoms");
|
"new_denoms");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
dki = &dk->issue;
|
dki = &dk->issue;
|
||||||
TALER_amount_ntoh (&value,
|
TALER_amount_ntoh (&value,
|
||||||
@ -547,35 +465,38 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
return TEH_RESPONSE_reply_internal_error (connection,
|
*mhd_ret = TEH_RESPONSE_reply_internal_error (connection,
|
||||||
TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW,
|
TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW,
|
||||||
"cost calculation failure");
|
"cost calculation failure");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dk = TEH_KS_denomination_key_lookup (key_state,
|
dk = TEH_KS_denomination_key_lookup (key_state,
|
||||||
&coin_melt_details->coin_info.denom_pub,
|
&rmc->coin_melt_details.coin_info.denom_pub,
|
||||||
TEH_KS_DKU_DEPOSIT);
|
TEH_KS_DKU_DEPOSIT);
|
||||||
if (NULL == dk)
|
if (NULL == dk)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return TEH_RESPONSE_reply_arg_unknown (connection,
|
*mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection,
|
||||||
TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
|
TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
|
||||||
"denom_pub");
|
"denom_pub");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
dki = &dk->issue;
|
dki = &dk->issue;
|
||||||
TALER_amount_ntoh (&fee_melt,
|
TALER_amount_ntoh (&fee_melt,
|
||||||
&dki->properties.fee_refresh);
|
&dki->properties.fee_refresh);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_subtract (&total_melt,
|
TALER_amount_subtract (&total_melt,
|
||||||
&coin_melt_details->melt_amount_with_fee,
|
&rmc->coin_melt_details.melt_amount_with_fee,
|
||||||
&fee_melt))
|
&fee_melt))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
return TEH_RESPONSE_reply_external_error (connection,
|
*mhd_ret = TEH_RESPONSE_reply_external_error (connection,
|
||||||
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION,
|
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION,
|
||||||
"Melt contribution below melting fee");
|
"Melt contribution below melting fee");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
if (0 !=
|
if (0 !=
|
||||||
@ -585,19 +506,17 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
/* We require total value of coins being melted and
|
/* We require total value of coins being melted and
|
||||||
total value of coins being generated to match! */
|
total value of coins being generated to match! */
|
||||||
return TEH_RESPONSE_reply_json_pack (connection,
|
*mhd_ret = TEH_RESPONSE_reply_json_pack (connection,
|
||||||
MHD_HTTP_BAD_REQUEST,
|
MHD_HTTP_BAD_REQUEST,
|
||||||
"{s:s, s:I}",
|
"{s:s, s:I}",
|
||||||
"error", "value mismatch",
|
"error", "value mismatch",
|
||||||
"code", (json_int_t) TALER_EC_REFRESH_MELT_FEES_MISSMATCH);
|
"code", (json_int_t) TALER_EC_REFRESH_MELT_FEES_MISSMATCH);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
return execute_refresh_melt (connection,
|
return TEH_DB_run_transaction (connection,
|
||||||
session_hash,
|
mhd_ret,
|
||||||
num_new_denoms,
|
&refresh_melt_transaction,
|
||||||
denom_pubs,
|
rmc);
|
||||||
coin_melt_details,
|
|
||||||
commit_coin,
|
|
||||||
transfer_pubs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -764,6 +683,33 @@ free_commit_coins (struct TALER_EXCHANGEDB_RefreshCommitCoin **commit_coin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup state kept in the @a rmc.
|
||||||
|
*
|
||||||
|
* @param rmc state to clean up; does not free @a rmc itself
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cleanup_rmc (struct RefreshMeltContext *rmc)
|
||||||
|
{
|
||||||
|
free_commit_coins (rmc->commit_coin,
|
||||||
|
TALER_CNC_KAPPA,
|
||||||
|
rmc->num_newcoins);
|
||||||
|
if (NULL != rmc->coin_melt_details.coin_info.denom_pub.rsa_public_key)
|
||||||
|
GNUNET_CRYPTO_rsa_public_key_free (rmc->coin_melt_details.coin_info.denom_pub.rsa_public_key);
|
||||||
|
if (NULL != rmc->coin_melt_details.coin_info.denom_sig.rsa_signature)
|
||||||
|
GNUNET_CRYPTO_rsa_signature_free (rmc->coin_melt_details.coin_info.denom_sig.rsa_signature);
|
||||||
|
if (NULL != rmc->denom_pubs)
|
||||||
|
{
|
||||||
|
for (unsigned int j=0;j<rmc->num_newcoins;j++)
|
||||||
|
if (NULL != rmc->denom_pubs[j].rsa_public_key)
|
||||||
|
GNUNET_CRYPTO_rsa_public_key_free (rmc->denom_pubs[j].rsa_public_key);
|
||||||
|
GNUNET_free (rmc->denom_pubs);
|
||||||
|
}
|
||||||
|
if (NULL != rmc->hash_context)
|
||||||
|
GNUNET_CRYPTO_hash_context_abort (rmc->hash_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a "/refresh/melt" request after the first parsing has happened.
|
* Handle a "/refresh/melt" request after the first parsing has happened.
|
||||||
* We now need to validate the coins being melted and the session signature
|
* We now need to validate the coins being melted and the session signature
|
||||||
@ -786,22 +732,20 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
|||||||
const json_t *coin_evs)
|
const json_t *coin_evs)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct TALER_DenominationPublicKey *denom_pubs;
|
int mhd_ret;
|
||||||
unsigned int num_newcoins;
|
struct RefreshMeltContext rmc;
|
||||||
struct TEH_DB_MeltDetails coin_melt_details;
|
|
||||||
struct GNUNET_HashCode session_hash;
|
|
||||||
struct GNUNET_HashContext *hash_context;
|
|
||||||
struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA];
|
|
||||||
struct TALER_TransferPublicKeyP transfer_pub[TALER_CNC_KAPPA];
|
|
||||||
|
|
||||||
|
memset (&rmc,
|
||||||
|
0,
|
||||||
|
sizeof (rmc));
|
||||||
/* For the signature check, we hash most of the inputs together
|
/* For the signature check, we hash most of the inputs together
|
||||||
(except for the signatures on the coins). */
|
(except for the signatures on the coins). */
|
||||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
rmc.hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
|
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
|
||||||
{
|
{
|
||||||
struct GNUNET_JSON_Specification trans_spec[] = {
|
struct GNUNET_JSON_Specification trans_spec[] = {
|
||||||
GNUNET_JSON_spec_fixed_auto (NULL, &transfer_pub[i]),
|
GNUNET_JSON_spec_fixed_auto (NULL, &rmc.transfer_pub[i]),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -812,40 +756,43 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
|||||||
if (GNUNET_OK != res)
|
if (GNUNET_OK != res)
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
mhd_ret = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||||
goto cleanup_hc;
|
cleanup_rmc (&rmc);
|
||||||
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
|
||||||
&transfer_pub[i],
|
&rmc.transfer_pub[i],
|
||||||
sizeof (struct TALER_TransferPublicKeyP));
|
sizeof (struct TALER_TransferPublicKeyP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
num_newcoins = json_array_size (new_denoms);
|
rmc.num_newcoins = json_array_size (new_denoms);
|
||||||
denom_pubs = GNUNET_new_array (num_newcoins,
|
rmc.denom_pubs = GNUNET_new_array (rmc.num_newcoins,
|
||||||
struct TALER_DenominationPublicKey);
|
struct TALER_DenominationPublicKey);
|
||||||
for (unsigned int i=0;i<num_newcoins;i++)
|
for (unsigned int i=0;i<rmc.num_newcoins;i++)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
TALER_JSON_spec_denomination_public_key (NULL,
|
TALER_JSON_spec_denomination_public_key (NULL,
|
||||||
&denom_pubs[i]),
|
&rmc.denom_pubs[i]),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
|
|
||||||
res = TEH_PARSE_json_array (connection,
|
res = TEH_PARSE_json_array (connection,
|
||||||
new_denoms,
|
new_denoms,
|
||||||
spec,
|
spec,
|
||||||
i, -1);
|
i,
|
||||||
|
-1);
|
||||||
if (GNUNET_OK != res)
|
if (GNUNET_OK != res)
|
||||||
{
|
{
|
||||||
res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
||||||
goto cleanup_denoms;
|
cleanup_rmc (&rmc);
|
||||||
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key,
|
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rmc.denom_pubs[i].rsa_public_key,
|
||||||
&buf);
|
&buf);
|
||||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
|
||||||
buf,
|
buf,
|
||||||
buf_size);
|
buf_size);
|
||||||
GNUNET_free (buf);
|
GNUNET_free (buf);
|
||||||
@ -857,35 +804,33 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
|||||||
|
|
||||||
res = get_coin_public_info (connection,
|
res = get_coin_public_info (connection,
|
||||||
melt_coin,
|
melt_coin,
|
||||||
&coin_melt_details);
|
&rmc.coin_melt_details);
|
||||||
if (GNUNET_OK != res)
|
if (GNUNET_OK != res)
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
||||||
goto cleanup_melt_details;
|
cleanup_rmc (&rmc);
|
||||||
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
TALER_amount_hton (&melt_amount,
|
TALER_amount_hton (&melt_amount,
|
||||||
&coin_melt_details.melt_amount_with_fee);
|
&rmc.coin_melt_details.melt_amount_with_fee);
|
||||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
|
||||||
&coin_melt_details.coin_info.coin_pub,
|
&rmc.coin_melt_details.coin_info.coin_pub,
|
||||||
sizeof (struct TALER_CoinSpendPublicKeyP));
|
sizeof (struct TALER_CoinSpendPublicKeyP));
|
||||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
|
||||||
&melt_amount,
|
&melt_amount,
|
||||||
sizeof (struct TALER_AmountNBO));
|
sizeof (struct TALER_AmountNBO));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse JSON arrays into binary arrays and hash everything
|
/* parse JSON arrays into binary arrays and hash everything
|
||||||
together for the signature check */
|
together for the signature check */
|
||||||
memset (commit_coin,
|
|
||||||
0,
|
|
||||||
sizeof (commit_coin));
|
|
||||||
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
|
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
|
||||||
{
|
{
|
||||||
commit_coin[i] = GNUNET_new_array (num_newcoins,
|
rmc.commit_coin[i] = GNUNET_new_array (rmc.num_newcoins,
|
||||||
struct TALER_EXCHANGEDB_RefreshCommitCoin);
|
struct TALER_EXCHANGEDB_RefreshCommitCoin);
|
||||||
for (unsigned int j = 0; j < num_newcoins; j++)
|
for (unsigned int j = 0; j < rmc.num_newcoins; j++)
|
||||||
{
|
{
|
||||||
struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &commit_coin[i][j];
|
struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &rmc.commit_coin[i][j];
|
||||||
struct GNUNET_JSON_Specification coin_spec[] = {
|
struct GNUNET_JSON_Specification coin_spec[] = {
|
||||||
GNUNET_JSON_spec_varsize (NULL,
|
GNUNET_JSON_spec_varsize (NULL,
|
||||||
(void **) &rcc->coin_ev,
|
(void **) &rcc->coin_ev,
|
||||||
@ -896,63 +841,52 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
|||||||
res = TEH_PARSE_json_array (connection,
|
res = TEH_PARSE_json_array (connection,
|
||||||
coin_evs,
|
coin_evs,
|
||||||
coin_spec,
|
coin_spec,
|
||||||
i, j, -1);
|
i,
|
||||||
|
j,
|
||||||
|
-1);
|
||||||
if (GNUNET_OK != res)
|
if (GNUNET_OK != res)
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
mhd_ret = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||||
goto cleanup;
|
cleanup_rmc (&rmc);
|
||||||
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
GNUNET_CRYPTO_hash_context_read (rmc.hash_context,
|
||||||
rcc->coin_ev,
|
rcc->coin_ev,
|
||||||
rcc->coin_ev_size);
|
rcc->coin_ev_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
GNUNET_CRYPTO_hash_context_finish (rmc.hash_context,
|
||||||
&session_hash);
|
&rmc.session_hash);
|
||||||
hash_context = NULL;
|
rmc.hash_context = NULL;
|
||||||
/* verify signature on coins to melt */
|
/* verify signature on coins to melt */
|
||||||
res = verify_coin_public_info (connection,
|
res = verify_coin_public_info (connection,
|
||||||
&session_hash,
|
&rmc.session_hash,
|
||||||
&coin_melt_details);
|
&rmc.coin_melt_details);
|
||||||
if (GNUNET_OK != res)
|
if (GNUNET_OK != res)
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
||||||
goto cleanup;
|
cleanup_rmc (&rmc);
|
||||||
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* execute commit */
|
/* prepare commit */
|
||||||
res = handle_refresh_melt_binary (connection,
|
if (GNUNET_OK !=
|
||||||
num_newcoins,
|
refresh_melt_prepare (connection,
|
||||||
denom_pubs,
|
&mhd_ret,
|
||||||
&coin_melt_details,
|
&rmc))
|
||||||
&session_hash,
|
|
||||||
commit_coin,
|
|
||||||
transfer_pub);
|
|
||||||
cleanup:
|
|
||||||
free_commit_coins (commit_coin,
|
|
||||||
TALER_CNC_KAPPA,
|
|
||||||
num_newcoins);
|
|
||||||
cleanup_melt_details:
|
|
||||||
if (NULL != coin_melt_details.coin_info.denom_pub.rsa_public_key)
|
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details.coin_info.denom_pub.rsa_public_key);
|
|
||||||
if (NULL != coin_melt_details.coin_info.denom_sig.rsa_signature)
|
|
||||||
GNUNET_CRYPTO_rsa_signature_free (coin_melt_details.coin_info.denom_sig.rsa_signature);
|
|
||||||
cleanup_denoms:
|
|
||||||
if (NULL != denom_pubs)
|
|
||||||
{
|
{
|
||||||
for (unsigned int j=0;j<num_newcoins;j++)
|
cleanup_rmc (&rmc);
|
||||||
if (NULL != denom_pubs[j].rsa_public_key)
|
return mhd_ret;
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
|
|
||||||
GNUNET_free (denom_pubs);
|
|
||||||
}
|
}
|
||||||
cleanup_hc:
|
mhd_ret = reply_refresh_melt_success (connection,
|
||||||
if (NULL != hash_context)
|
&rmc.session_hash,
|
||||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
rmc.refresh_session.noreveal_index);
|
||||||
return res;
|
cleanup_rmc (&rmc);
|
||||||
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -997,7 +931,8 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
|
|||||||
&root);
|
&root);
|
||||||
if (GNUNET_SYSERR == res)
|
if (GNUNET_SYSERR == res)
|
||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
if ( (GNUNET_NO == res) || (NULL == root) )
|
if ( (GNUNET_NO == res) ||
|
||||||
|
(NULL == root) )
|
||||||
return MHD_YES;
|
return MHD_YES;
|
||||||
|
|
||||||
res = TEH_PARSE_json_data (connection,
|
res = TEH_PARSE_json_data (connection,
|
||||||
|
@ -440,14 +440,6 @@ enum TALER_ErrorCode
|
|||||||
*/
|
*/
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304,
|
TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304,
|
||||||
|
|
||||||
/**
|
|
||||||
* The exchange failed to store refresh order data in the
|
|
||||||
* database.
|
|
||||||
* This response is provided with HTTP status code
|
|
||||||
* MHD_HTTP_INTERNAL_ERROR.
|
|
||||||
*/
|
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR = 1305,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The exchange failed to store commit data in the
|
* The exchange failed to store commit data in the
|
||||||
* database.
|
* database.
|
||||||
@ -456,14 +448,6 @@ enum TALER_ErrorCode
|
|||||||
*/
|
*/
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306,
|
TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306,
|
||||||
|
|
||||||
/**
|
|
||||||
* The exchange failed to store transfer keys in the
|
|
||||||
* database.
|
|
||||||
* This response is provided with HTTP status code
|
|
||||||
* MHD_HTTP_INTERNAL_ERROR.
|
|
||||||
*/
|
|
||||||
TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR = 1307,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The exchange is unaware of the denomination key that was
|
* The exchange is unaware of the denomination key that was
|
||||||
* requested for one of the fresh coins. This response is provided
|
* requested for one of the fresh coins. This response is provided
|
||||||
|
Loading…
Reference in New Issue
Block a user