clean up /withdraw/sign logic
This commit is contained in:
parent
8adde040ab
commit
758ce80519
@ -22,11 +22,6 @@
|
|||||||
* - actually abstract DB implementation (i.e. via plugin logic)
|
* - actually abstract DB implementation (i.e. via plugin logic)
|
||||||
* (this file should remain largely unchanged with the exception
|
* (this file should remain largely unchanged with the exception
|
||||||
* of the PQ-specific DB handle types)
|
* of the PQ-specific DB handle types)
|
||||||
* - /withdraw/sign: all
|
|
||||||
* + properly check all conditions and handle errors
|
|
||||||
* + properly check transaction logic
|
|
||||||
* + check for leaks
|
|
||||||
* + check low-level API
|
|
||||||
* - /refresh/melt: all
|
* - /refresh/melt: all
|
||||||
* + properly check all conditions and handle errors
|
* + properly check all conditions and handle errors
|
||||||
* + properly check transaction logic
|
* + properly check transaction logic
|
||||||
@ -264,11 +259,17 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
|||||||
{
|
{
|
||||||
PGconn *db_conn;
|
PGconn *db_conn;
|
||||||
struct ReserveHistory *rh;
|
struct ReserveHistory *rh;
|
||||||
|
const struct ReserveHistory *pos;
|
||||||
struct MintKeyState *key_state;
|
struct MintKeyState *key_state;
|
||||||
struct CollectableBlindcoin collectable;
|
struct CollectableBlindcoin collectable;
|
||||||
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
||||||
|
struct TALER_MINT_DenomKeyIssuePriv *tdki;
|
||||||
struct GNUNET_CRYPTO_rsa_Signature *sig;
|
struct GNUNET_CRYPTO_rsa_Signature *sig;
|
||||||
struct TALER_Amount amount_required;
|
struct TALER_Amount amount_required;
|
||||||
|
struct TALER_Amount deposit_total;
|
||||||
|
struct TALER_Amount withdraw_total;
|
||||||
|
struct TALER_Amount balance;
|
||||||
|
struct TALER_Amount value;
|
||||||
struct GNUNET_HashCode h_blind;
|
struct GNUNET_HashCode h_blind;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
@ -299,63 +300,102 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
GNUNET_assert (GNUNET_NO == res);
|
GNUNET_assert (GNUNET_NO == res);
|
||||||
rh = TALER_MINT_DB_get_reserve_history (db_conn,
|
|
||||||
reserve);
|
|
||||||
if (NULL == rh)
|
|
||||||
return TALER_MINT_reply_json_pack (connection,
|
|
||||||
MHD_HTTP_NOT_FOUND,
|
|
||||||
"{s:s}",
|
|
||||||
"error",
|
|
||||||
"Reserve not found");
|
|
||||||
|
|
||||||
|
/* Check if balance is sufficient */
|
||||||
key_state = TALER_MINT_key_state_acquire ();
|
key_state = TALER_MINT_key_state_acquire ();
|
||||||
dki = TALER_MINT_get_denom_key (key_state,
|
dki = TALER_MINT_get_denom_key (key_state,
|
||||||
denomination_pub);
|
denomination_pub);
|
||||||
TALER_MINT_key_state_release (key_state);
|
|
||||||
if (NULL == dki)
|
if (NULL == dki)
|
||||||
|
{
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
return TALER_MINT_reply_json_pack (connection,
|
return TALER_MINT_reply_json_pack (connection,
|
||||||
MHD_HTTP_NOT_FOUND,
|
MHD_HTTP_NOT_FOUND,
|
||||||
"{s:s}",
|
"{s:s}",
|
||||||
"error",
|
"error",
|
||||||
"Denomination not found");
|
"Denomination not found");
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_transaction (db_conn))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
|
|
||||||
amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value),
|
rh = TALER_MINT_DB_get_reserve_history (db_conn,
|
||||||
TALER_amount_ntoh (dki->issue.fee_withdraw));
|
reserve);
|
||||||
// FIX LOGIC!
|
if (NULL == rh)
|
||||||
#if 0
|
{
|
||||||
if (0 < TALER_amount_cmp (amount_required,
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
TALER_amount_ntoh (db_reserve.balance)))
|
TALER_MINT_key_state_release (key_state);
|
||||||
return TALER_MINT_reply_json_pack (connection,
|
return TALER_MINT_reply_json_pack (connection,
|
||||||
MHD_HTTP_PAYMENT_REQUIRED,
|
MHD_HTTP_NOT_FOUND,
|
||||||
"{s:s}",
|
"{s:s}",
|
||||||
"error",
|
"error",
|
||||||
"Insufficient funds");
|
"Reserve not found");
|
||||||
|
}
|
||||||
|
|
||||||
db_reserve.balance = TALER_amount_hton
|
/* calculate amount required including fees */
|
||||||
(TALER_amount_subtract (TALER_amount_ntoh (db_reserve.balance),
|
amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value),
|
||||||
amount_required));
|
TALER_amount_ntoh (dki->issue.fee_withdraw));
|
||||||
|
|
||||||
|
/* calculate balance of the reserve */
|
||||||
|
res = 0;
|
||||||
|
for (pos = rh; NULL != pos; pos = pos->next)
|
||||||
|
{
|
||||||
|
switch (pos->type)
|
||||||
|
{
|
||||||
|
case TALER_MINT_DB_RO_BANK_TO_MINT:
|
||||||
|
if (0 == (res & 1))
|
||||||
|
deposit_total = pos->details.bank->amount;
|
||||||
|
else
|
||||||
|
deposit_total = TALER_amount_add (deposit_total,
|
||||||
|
pos->details.bank->amount);
|
||||||
|
res |= 1;
|
||||||
|
break;
|
||||||
|
case TALER_MINT_DB_RO_WITHDRAW_COIN:
|
||||||
|
tdki = TALER_MINT_get_denom_key (key_state,
|
||||||
|
pos->details.withdraw->denom_pub);
|
||||||
|
value = TALER_amount_ntoh (tdki->issue.value);
|
||||||
|
if (0 == (res & 2))
|
||||||
|
withdraw_total = value;
|
||||||
|
else
|
||||||
|
withdraw_total = TALER_amount_add (withdraw_total,
|
||||||
|
value);
|
||||||
|
res |= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: good place to assert deposit_total > withdraw_total... */
|
||||||
|
balance = TALER_amount_subtract (deposit_total,
|
||||||
|
withdraw_total);
|
||||||
|
if (0 < TALER_amount_cmp (amount_required,
|
||||||
|
balance))
|
||||||
|
{
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
|
res = TALER_MINT_reply_withdraw_sign_insufficient_funds (connection,
|
||||||
|
rh);
|
||||||
|
TALER_MINT_DB_free_reserve_history (rh);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
TALER_MINT_DB_free_reserve_history (rh);
|
||||||
|
|
||||||
|
/* Balance is good, sign the coin! */
|
||||||
sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv,
|
sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv,
|
||||||
blinded_msg,
|
blinded_msg,
|
||||||
blinded_msg_len);
|
blinded_msg_len);
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
if (NULL == sig)
|
if (NULL == sig)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
return TALER_MINT_reply_internal_error (connection,
|
return TALER_MINT_reply_internal_error (connection,
|
||||||
"Internal error");
|
"Internal error");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* transaction start */
|
// FIXME: can we avoid the cast?
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_MINT_DB_update_reserve (db_conn,
|
|
||||||
&db_reserve,
|
|
||||||
GNUNET_YES))
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return TALER_MINT_reply_internal_db_error (connection);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;
|
collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;
|
||||||
collectable.sig = sig;
|
collectable.sig = sig;
|
||||||
collectable.reserve_pub = *reserve;
|
collectable.reserve_pub = *reserve;
|
||||||
@ -367,17 +407,27 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
|||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
GNUNET_CRYPTO_rsa_signature_free (sig);
|
GNUNET_CRYPTO_rsa_signature_free (sig);
|
||||||
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
return TALER_MINT_reply_internal_db_error (connection);
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
}
|
}
|
||||||
/* transaction end */
|
if (GNUNET_OK !=
|
||||||
GNUNET_CRYPTO_rsa_signature_free (sig);
|
TALER_MINT_DB_commit (db_conn))
|
||||||
return TALER_MINT_reply_withdraw_sign_success (connection,
|
{
|
||||||
|
LOG_WARNING ("/withdraw/sign transaction commit failed\n");
|
||||||
|
return TALER_MINT_reply_commit_error (connection);
|
||||||
|
}
|
||||||
|
res = TALER_MINT_reply_withdraw_sign_success (connection,
|
||||||
&collectable);
|
&collectable);
|
||||||
|
GNUNET_CRYPTO_rsa_signature_free (sig);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert all requested denominations into the db, and compute the
|
* Insert all requested denominations into the DB, and compute the
|
||||||
* required cost of the denominations, including fees.
|
* required cost of the denominations, including fees.
|
||||||
*
|
*
|
||||||
* @param connection the connection to send an error response to
|
* @param connection the connection to send an error response to
|
||||||
@ -615,11 +665,11 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_transaction (db_conn))
|
||||||
{
|
{
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return MHD_NO;
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_create_refresh_session (db_conn,
|
if (GNUNET_OK != TALER_MINT_DB_create_refresh_session (db_conn,
|
||||||
@ -678,10 +728,11 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
|
|||||||
"not enough coins melted");
|
"not enough coins melted");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_commit (db_conn))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
LOG_WARNING ("/refresh/melt transaction commit failed\n");
|
||||||
return MHD_NO;
|
return TALER_MINT_reply_commit_error (connection);
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
(res = TALER_MINT_DB_get_refresh_session (db_conn,
|
(res = TALER_MINT_DB_get_refresh_session (db_conn,
|
||||||
@ -795,11 +846,11 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_transaction (db_conn))
|
||||||
{
|
{
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return MHD_NO;
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-fetch the session information from the database,
|
/* Re-fetch the session information from the database,
|
||||||
@ -816,11 +867,11 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_commit (db_conn))
|
||||||
{
|
{
|
||||||
// FIXME: return 'internal error'?
|
LOG_WARNING ("/refresh/commit transaction commit failed\n");
|
||||||
GNUNET_break (0);
|
return TALER_MINT_reply_commit_error (connection);
|
||||||
return MHD_NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session);
|
return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session);
|
||||||
@ -1095,11 +1146,11 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_transaction (db_conn))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
// FIXME: return error code!
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
return MHD_NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < refresh_session.num_newcoins; j++)
|
for (j = 0; j < refresh_session.num_newcoins; j++)
|
||||||
@ -1169,10 +1220,11 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
if (GNUNET_OK !=
|
||||||
|
TALER_MINT_DB_commit (db_conn))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
LOG_WARNING ("/refresh/reveal transaction commit failed\n");
|
||||||
return MHD_NO;
|
return TALER_MINT_reply_commit_error (connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
return helper_refresh_reveal_send_response (connection,
|
return helper_refresh_reveal_send_response (connection,
|
||||||
|
@ -351,26 +351,25 @@ TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send reserve status information to client.
|
* Compile the history of a reserve into a JSON object
|
||||||
|
* and calculate the total balance.
|
||||||
*
|
*
|
||||||
* @param connection connection to the client
|
* @param rh reserve history to JSON-ify
|
||||||
* @param rh reserve history to return
|
* @param balance[OUT] set to current reserve balance
|
||||||
* @return MHD result code
|
* @return json representation of the @a rh
|
||||||
*/
|
*/
|
||||||
int
|
static json_t *
|
||||||
TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
|
compile_reserve_history (const struct ReserveHistory *rh,
|
||||||
const struct ReserveHistory *rh)
|
struct TALER_Amount *balance)
|
||||||
{
|
{
|
||||||
struct TALER_Amount deposit_total;
|
struct TALER_Amount deposit_total;
|
||||||
struct TALER_Amount withdraw_total;
|
struct TALER_Amount withdraw_total;
|
||||||
struct TALER_Amount balance;
|
|
||||||
struct TALER_Amount value;
|
struct TALER_Amount value;
|
||||||
json_t *json_balance;
|
|
||||||
json_t *json_history;
|
json_t *json_history;
|
||||||
int ret;
|
int ret;
|
||||||
struct MintKeyState *key_state;
|
|
||||||
const struct ReserveHistory *pos;
|
const struct ReserveHistory *pos;
|
||||||
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
||||||
|
struct MintKeyState *key_state;
|
||||||
|
|
||||||
json_history = json_array ();
|
json_history = json_array ();
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -425,8 +424,30 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
TALER_MINT_key_state_release (key_state);
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
|
||||||
balance = TALER_amount_subtract (deposit_total,
|
*balance = TALER_amount_subtract (deposit_total,
|
||||||
withdraw_total);
|
withdraw_total);
|
||||||
|
return json_history;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send reserve status information to client.
|
||||||
|
*
|
||||||
|
* @param connection connection to the client
|
||||||
|
* @param rh reserve history to return
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
|
||||||
|
const struct ReserveHistory *rh)
|
||||||
|
{
|
||||||
|
json_t *json_balance;
|
||||||
|
json_t *json_history;
|
||||||
|
struct TALER_Amount balance;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
json_history = compile_reserve_history (rh,
|
||||||
|
&balance);
|
||||||
json_balance = TALER_JSON_from_amount (balance);
|
json_balance = TALER_JSON_from_amount (balance);
|
||||||
ret = TALER_MINT_reply_json_pack (connection,
|
ret = TALER_MINT_reply_json_pack (connection,
|
||||||
MHD_HTTP_OK,
|
MHD_HTTP_OK,
|
||||||
@ -439,6 +460,39 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send reserve status information to client with the
|
||||||
|
* message that we have insufficient funds for the
|
||||||
|
* requested /withdraw/sign operation.
|
||||||
|
*
|
||||||
|
* @param connection connection to the client
|
||||||
|
* @param rh reserve history to return
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connection,
|
||||||
|
const struct ReserveHistory *rh)
|
||||||
|
{
|
||||||
|
json_t *json_balance;
|
||||||
|
json_t *json_history;
|
||||||
|
struct TALER_Amount balance;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
json_history = compile_reserve_history (rh,
|
||||||
|
&balance);
|
||||||
|
json_balance = TALER_JSON_from_amount (balance);
|
||||||
|
ret = TALER_MINT_reply_json_pack (connection,
|
||||||
|
MHD_HTTP_PAYMENT_REQUIRED,
|
||||||
|
"{s:s, s:o, s:o}",
|
||||||
|
"error", "Insufficient funds"
|
||||||
|
"balance", json_balance,
|
||||||
|
"history", json_history);
|
||||||
|
json_decref (json_history);
|
||||||
|
json_decref (json_balance);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send blinded coin information to client.
|
* Send blinded coin information to client.
|
||||||
*
|
*
|
||||||
|
@ -208,6 +208,20 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
|
|||||||
const struct ReserveHistory *rh);
|
const struct ReserveHistory *rh);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send reserve status information to client with the
|
||||||
|
* message that we have insufficient funds for the
|
||||||
|
* requested /withdraw/sign operation.
|
||||||
|
*
|
||||||
|
* @param connection connection to the client
|
||||||
|
* @param rh reserve history to return
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connection,
|
||||||
|
const struct ReserveHistory *rh);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send blinded coin information to client.
|
* Send blinded coin information to client.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user