diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-06-19 00:00:21 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-06-19 00:17:16 +0200 |
commit | dea0f7c411d6ae5c5410d30f6072478e905cabb4 (patch) | |
tree | 63fd5490d62d991f47148c5147c51d249d9d61b8 | |
parent | 4cb035cd298139f606562ed88f60ba89dff0febc (diff) |
fixing #5010 for /reserve/withdraw
-rw-r--r-- | src/exchange-lib/test_exchange_api.c | 2 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_db.c | 344 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_db.h | 23 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserve_status.c | 36 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserve_withdraw.c | 454 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 91 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.h | 51 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb_interpreter.c | 18 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 117 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 4 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 12 |
11 files changed, 510 insertions, 642 deletions
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c index e435ed77c..24b8f7e20 100644 --- a/src/exchange-lib/test_exchange_api.c +++ b/src/exchange-lib/test_exchange_api.c @@ -3576,7 +3576,7 @@ run (void *cls) GNUNET_assert (NULL != exchange); timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 150), + (GNUNET_TIME_UNIT_SECONDS, 300), &do_timeout, NULL); GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is); } diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index 4131e1230..ebe19a9b5 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -553,350 +553,6 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, /** - * Try to execute /reserve/withdraw transaction. - * - * @param connection request we are handling - * @param session database session we are using - * @param key_state key state to lookup denomination pubs - * @param reserve reserve to withdraw from - * @param denomination_pub public key of the denomination requested - * @param dki denomination to withdraw - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param h_blind hash of @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @param[out] denom_sig where to write the resulting signature - * (used to release memory in case of transaction failure - * @return MHD result code - */ -static int -execute_reserve_withdraw_transaction (struct MHD_Connection *connection, - struct TALER_EXCHANGEDB_Session *session, - struct TEH_KS_StateHandle *key_state, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, - const char *blinded_msg, - size_t blinded_msg_len, - const struct GNUNET_HashCode *h_blind, - const struct TALER_ReserveSignatureP *signature, - struct TALER_DenominationSignature *denom_sig) -{ - struct TALER_EXCHANGEDB_ReserveHistory *rh; - const struct TALER_EXCHANGEDB_ReserveHistory *pos; - struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *tdki; - struct TALER_EXCHANGEDB_CollectableBlindcoin collectable; - struct TALER_Amount amount_required; - struct TALER_Amount deposit_total; - struct TALER_Amount withdraw_total; - struct TALER_Amount balance; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - int res; - int ret; - enum GNUNET_DB_QueryStatus qs; - - /* Check if balance is sufficient */ - START_TRANSACTION (session, connection); - qs = TEH_plugin->get_reserve_history (TEH_plugin->cls, - session, - reserve, - &rh); - (void) qs; - /* qs: #5010! */ - if (NULL == rh) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_arg_unknown (connection, - TALER_EC_WITHDRAW_RESERVE_UNKNOWN, - "reserve_pub"); - } - - /* calculate amount required including fees */ - TALER_amount_ntoh (&value, - &dki->issue.properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->issue.properties.fee_withdraw); - - if (GNUNET_OK != - TALER_amount_add (&amount_required, - &value, - &fee_withdraw)) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW); - } - - /* calculate balance of the reserve */ - res = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: - if (0 == (res & 1)) - deposit_total = pos->details.bank->amount; - else - if (GNUNET_OK != - TALER_amount_add (&deposit_total, - &deposit_total, - &pos->details.bank->amount)) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW); - } - res |= 1; - break; - case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: - tdki = TEH_KS_denomination_key_lookup (key_state, - &pos->details.withdraw->denom_pub, - TEH_KS_DKU_WITHDRAW); - if (NULL == tdki) - { - GNUNET_break (0); - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND); - } - TALER_amount_ntoh (&value, - &tdki->issue.properties.value); - if (0 == (res & 2)) - withdraw_total = value; - else - if (GNUNET_OK != - TALER_amount_add (&withdraw_total, - &withdraw_total, - &value)) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW); - } - res |= 2; - break; - - case TALER_EXCHANGEDB_RO_PAYBACK_COIN: - if (0 == (res & 1)) - deposit_total = pos->details.payback->value; - else - if (GNUNET_OK != - TALER_amount_add (&deposit_total, - &deposit_total, - &pos->details.payback->value)) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW); - } - res |= 1; - break; - - case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK: - if (0 == (res & 2)) - withdraw_total = pos->details.bank->amount; - else - if (GNUNET_OK != - TALER_amount_add (&withdraw_total, - &withdraw_total, - &pos->details.bank->amount)) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW); - } - res |= 2; - break; - } - } - if (0 == (res & 1)) - { - /* did not encounter any wire transfer operations, how can we have a reserve? */ - GNUNET_break (0); - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER); - } - if (0 == (res & 2)) - { - /* did not encounter any withdraw operations, set to zero */ - TALER_amount_get_zero (deposit_total.currency, - &withdraw_total); - } - /* All reserve balances should be non-negative */ - if (GNUNET_SYSERR == - TALER_amount_subtract (&balance, - &deposit_total, - &withdraw_total)) - { - GNUNET_break (0); /* database inconsistent */ - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_RESERVE_HISTORY_IMPOSSIBLE); - } - if (0 < TALER_amount_cmp (&amount_required, - &balance)) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - res = TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (connection, - rh); - TEH_plugin->free_reserve_history (TEH_plugin->cls, - rh); - return res; - } - TEH_plugin->free_reserve_history (TEH_plugin->cls, - rh); - - /* Balance is good, sign the coin! */ - denom_sig->rsa_signature - = GNUNET_CRYPTO_rsa_sign_blinded (dki->denom_priv.rsa_private_key, - blinded_msg, - blinded_msg_len); - if (NULL == denom_sig->rsa_signature) - { - GNUNET_break (0); - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_WITHDRAW_SIGNATURE_FAILED, - "Internal error"); - } - collectable.sig = *denom_sig; - collectable.denom_pub = *denomination_pub; - collectable.amount_with_fee = amount_required; - collectable.withdraw_fee = fee_withdraw; - collectable.reserve_pub = *reserve; - collectable.h_coin_envelope = *h_blind; - collectable.reserve_sig = *signature; - ret = TEH_plugin->insert_withdraw_info (TEH_plugin->cls, - session, - &collectable); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); - TEH_plugin->rollback (TEH_plugin->cls, - session); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_DB_STORE_ERROR); - } - if (GNUNET_NO == ret) - RETRY_TRANSACTION(session, connection); - COMMIT_TRANSACTION (session, connection); - - return TEH_RESPONSE_reply_reserve_withdraw_success (connection, - &collectable); -} - - - -/** - * Execute a "/reserve/withdraw". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. - * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve - * @param denomination_pub public key of the denomination requested - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @return MHD result code - */ -int -TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const char *blinded_msg, - size_t blinded_msg_len, - const struct TALER_ReserveSignatureP *signature) -{ - struct TALER_EXCHANGEDB_Session *session; - struct TEH_KS_StateHandle *key_state; - struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - struct TALER_EXCHANGEDB_CollectableBlindcoin collectable; - struct TALER_DenominationSignature denom_sig; - struct GNUNET_HashCode h_blind; - int res; - - GNUNET_CRYPTO_hash (blinded_msg, - blinded_msg_len, - &h_blind); - if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) - { - GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_SETUP_FAILED); - } - res = TEH_plugin->get_withdraw_info (TEH_plugin->cls, - session, - &h_blind, - &collectable); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_DB_FETCH_ERROR); - } - - /* Don't sign again if we have already signed the coin */ - if (GNUNET_YES == res) - { - res = TEH_RESPONSE_reply_reserve_withdraw_success (connection, - &collectable); - GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key); - return res; - } - GNUNET_assert (GNUNET_NO == res); - - /* FIXME: do we have to do this a second time here? */ - key_state = TEH_KS_acquire (); - dki = TEH_KS_denomination_key_lookup (key_state, - denomination_pub, - TEH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - TEH_KS_release (key_state); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:I}", - "error", - "Denomination not found", - "code", - (json_int_t) TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND); - } - denom_sig.rsa_signature = NULL; - res = execute_reserve_withdraw_transaction (connection, - session, - key_state, - reserve, - denomination_pub, - dki, - blinded_msg, - blinded_msg_len, - &h_blind, - signature, - &denom_sig); - if (NULL != denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature); - TEH_KS_release (key_state); - return res; -} - - -/** * Parse coin melt requests from a JSON object and write them to * the database. * diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h index 0834db56c..e3717bdb4 100644 --- a/src/exchange/taler-exchange-httpd_db.h +++ b/src/exchange/taler-exchange-httpd_db.h @@ -98,29 +98,6 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, /** - * Execute a "/reserve/withdraw". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. - * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve - * @param denomination_pub public key of the denomination requested - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @return MHD result code - */ -int -TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const char *blinded_msg, - size_t blinded_msg_len, - const struct TALER_ReserveSignatureP *signature); - - -/** * @brief Details about a melt operation of an individual coin. */ struct TEH_DB_MeltDetails diff --git a/src/exchange/taler-exchange-httpd_reserve_status.c b/src/exchange/taler-exchange-httpd_reserve_status.c index e13b8f393..f87afa5ae 100644 --- a/src/exchange/taler-exchange-httpd_reserve_status.c +++ b/src/exchange/taler-exchange-httpd_reserve_status.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014-2017 GNUnet e.V. 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 @@ -30,6 +30,36 @@ /** + * Send reserve status information to client. + * + * @param connection connection to the client + * @param rh reserve history to return + * @return MHD result code + */ +static int +reply_reserve_status_success (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_ReserveHistory *rh) +{ + json_t *json_balance; + json_t *json_history; + struct TALER_Amount balance; + + json_history = TEH_RESPONSE_compile_reserve_history (rh, + &balance); + if (NULL == json_history) + return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_RESERVE_STATUS_DB_ERROR, + "balance calculation failure"); + json_balance = TALER_JSON_from_amount (&balance); + return TEH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o}", + "balance", json_balance, + "history", json_history); +} + + +/** * Closure for #reserve_status_transaction. */ struct ReserveStatusContext @@ -126,8 +156,8 @@ TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh, "{s:s, s:s}", "error", "Reserve not found", "parameter", "withdraw_pub"); - mhd_ret = TEH_RESPONSE_reply_reserve_status_success (connection, - rsc.rh); + mhd_ret = reply_reserve_status_success (connection, + rsc.rh); TEH_plugin->free_reserve_history (TEH_plugin->cls, rsc.rh); return mhd_ret; diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c b/src/exchange/taler-exchange-httpd_reserve_withdraw.c index 6f6e66a6a..2bc268d5b 100644 --- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c +++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014-2017 GNUnet e.V. 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 @@ -30,6 +30,348 @@ /** + * Send reserve status information to client with the + * message that we have insufficient funds for the + * requested /reserve/withdraw operation. + * + * @param connection connection to the client + * @param rh reserve history to return + * @return MHD result code + */ +static int +reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_ReserveHistory *rh) +{ + json_t *json_balance; + json_t *json_history; + struct TALER_Amount balance; + + json_history = TEH_RESPONSE_compile_reserve_history (rh, + &balance); + if (NULL == json_history) + return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, + "balance calculation failure"); + json_balance = TALER_JSON_from_amount (&balance); + return TEH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s, s:I, s:o, s:o}", + "error", "Insufficient funds", + "code", (json_int_t) TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS, + "balance", json_balance, + "history", json_history); +} + + +/** + * Send blinded coin information to client. + * + * @param connection connection to the client + * @param collectable blinded coin to return + * @return MHD result code + */ +static int +reply_reserve_withdraw_success (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) +{ + json_t *sig_json; + + sig_json = GNUNET_JSON_from_rsa_signature (collectable->sig.rsa_signature); + return TEH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "ev_sig", sig_json); +} + + +/** + * Context for #withdraw_transaction. + */ +struct WithdrawContext +{ + /** + * Details about the withdrawal request. + */ + struct TALER_WithdrawRequestPS wsrd; + + /** + * Value of the coin plus withdraw fee. + */ + struct TALER_Amount amount_required; + + /** + * Denomination public key. + */ + struct TALER_DenominationPublicKey denomination_pub; + + /** + * Signature over the request. + */ + struct TALER_ReserveSignatureP signature; + + /** + * Blinded planchet. + */ + char *blinded_msg; + + /** + * Key state to use to inspect previous withdrawal values. + */ + struct TEH_KS_StateHandle *key_state; + + /** + * Number of bytes in @e blinded_msg. + */ + size_t blinded_msg_len; + + /** + * Details about denomination we are about to withdraw. + */ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + + /** + * Set to the resulting signed coin data to be returned to the client. + */ + struct TALER_EXCHANGEDB_CollectableBlindcoin collectable; + +}; + + +/** + * Function implementing /reserve/withdraw transaction. Runs the + * transaction logic; IF it returns a non-error code, the transaction + * logic MUST NOT queue a MHD response. IF it returns an hard error, + * the transaction logic MUST queue a MHD response and set @a mhd_ret. + * IF it returns the soft error code, the function MAY be called again + * to retry and MUST not queue a MHD response. + * + * @param cls a `struct WithdrawContext *` + * @param connection MHD request which triggered the transaction + * @param session database session to use + * @param[out] mhd_ret set to MHD response status for @a connection, + * if transaction failed (!) + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +withdraw_transaction (void *cls, + struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + int *mhd_ret) +{ + struct WithdrawContext *wc = cls; + struct TALER_EXCHANGEDB_ReserveHistory *rh; + struct TALER_Amount deposit_total; + struct TALER_Amount withdraw_total; + struct TALER_Amount balance; + struct TALER_Amount value; + struct TALER_Amount fee_withdraw; + int res; + enum GNUNET_DB_QueryStatus qs; + struct TALER_DenominationSignature denom_sig; + struct GNUNET_HashCode h_blind; + + GNUNET_CRYPTO_hash (wc->blinded_msg, + wc->blinded_msg_len, + &h_blind); + qs = TEH_plugin->get_withdraw_info (TEH_plugin->cls, + session, + &h_blind, + &wc->collectable); + if (0 > qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_DB_FETCH_ERROR); + return qs; + } + + /* Don't sign again if we have already signed the coin */ + if (1 == qs) + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + GNUNET_assert (0 == qs); + + /* Check if balance is sufficient */ + qs = TEH_plugin->get_reserve_history (TEH_plugin->cls, + session, + &wc->wsrd.reserve_pub, + &rh); + if (0 > qs) + { + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_DB_FETCH_ERROR); + return qs; + } + if (NULL == rh) + { + *mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_WITHDRAW_RESERVE_UNKNOWN, + "reserve_pub"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + /* calculate balance of the reserve */ + res = 0; + for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh; + NULL != pos; + pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + if (0 == (res & 1)) + deposit_total = pos->details.bank->amount; + else + if (GNUNET_OK != + TALER_amount_add (&deposit_total, + &deposit_total, + &pos->details.bank->amount)) + { + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW); + return GNUNET_DB_STATUS_HARD_ERROR; + } + res |= 1; + break; + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + { + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *tdki; + + tdki = TEH_KS_denomination_key_lookup (wc->key_state, + &pos->details.withdraw->denom_pub, + TEH_KS_DKU_WITHDRAW); + if (NULL == tdki) + { + GNUNET_break (0); + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND); + return GNUNET_DB_STATUS_HARD_ERROR; + } + TALER_amount_ntoh (&value, + &tdki->issue.properties.value); + if (0 == (res & 2)) + withdraw_total = value; + else + if (GNUNET_OK != + TALER_amount_add (&withdraw_total, + &withdraw_total, + &value)) + { + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW); + return GNUNET_DB_STATUS_HARD_ERROR; + } + res |= 2; + break; + } + case TALER_EXCHANGEDB_RO_PAYBACK_COIN: + if (0 == (res & 1)) + deposit_total = pos->details.payback->value; + else + if (GNUNET_OK != + TALER_amount_add (&deposit_total, + &deposit_total, + &pos->details.payback->value)) + { + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW); + return GNUNET_DB_STATUS_HARD_ERROR; + } + res |= 1; + break; + + case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK: + if (0 == (res & 2)) + withdraw_total = pos->details.bank->amount; + else + if (GNUNET_OK != + TALER_amount_add (&withdraw_total, + &withdraw_total, + &pos->details.bank->amount)) + { + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW); + return GNUNET_DB_STATUS_HARD_ERROR; + } + res |= 2; + break; + } + } + if (0 == (res & 1)) + { + /* did not encounter any wire transfer operations, how can we have a reserve? */ + GNUNET_break (0); + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (0 == (res & 2)) + { + /* did not encounter any withdraw operations, set to zero */ + TALER_amount_get_zero (deposit_total.currency, + &withdraw_total); + } + /* All reserve balances should be non-negative */ + if (GNUNET_SYSERR == + TALER_amount_subtract (&balance, + &deposit_total, + &withdraw_total)) + { + GNUNET_break (0); /* database inconsistent */ + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_RESERVE_HISTORY_IMPOSSIBLE); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (0 < TALER_amount_cmp (&wc->amount_required, + &balance)) + { + *mhd_ret = reply_reserve_withdraw_insufficient_funds (connection, + rh); + TEH_plugin->free_reserve_history (TEH_plugin->cls, + rh); + return GNUNET_DB_STATUS_HARD_ERROR; + } + TEH_plugin->free_reserve_history (TEH_plugin->cls, + rh); + + /* Balance is good, sign the coin! */ + denom_sig.rsa_signature + = GNUNET_CRYPTO_rsa_sign_blinded (wc->dki->denom_priv.rsa_private_key, + wc->blinded_msg, + wc->blinded_msg_len); + if (NULL == denom_sig.rsa_signature) + { + GNUNET_break (0); + *mhd_ret = TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_WITHDRAW_SIGNATURE_FAILED, + "Internal error"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + wc->collectable.sig = denom_sig; + wc->collectable.denom_pub = wc->denomination_pub; + wc->collectable.amount_with_fee = wc->amount_required; + wc->collectable.withdraw_fee = fee_withdraw; + wc->collectable.reserve_pub = wc->wsrd.reserve_pub; + wc->collectable.h_coin_envelope = h_blind; + wc->collectable.reserve_sig = wc->signature; + qs = TEH_plugin->insert_withdraw_info (TEH_plugin->cls, + session, + &wc->collectable); + if (0 > qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_DB_STORE_ERROR); + return qs; + } + return qs; +} + + +/** * Handle a "/reserve/withdraw" request. Parses the "reserve_pub" * EdDSA key of the reserve and the requested "denom_pub" which * specifies the key/value of the coin to be withdrawn, and checks @@ -52,29 +394,22 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { + struct WithdrawContext wc; json_t *root; - struct TALER_WithdrawRequestPS wsrd; int res; - struct TALER_DenominationPublicKey denomination_pub; - char *blinded_msg; - size_t blinded_msg_len; + int mhd_ret; struct TALER_Amount amount; - struct TALER_Amount amount_with_fee; struct TALER_Amount fee_withdraw; - struct TALER_ReserveSignatureP signature; - struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - struct TEH_KS_StateHandle *ks; - struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_varsize ("coin_ev", - (void **) &blinded_msg, - &blinded_msg_len), + (void **) &wc.blinded_msg, + &wc.blinded_msg_len), GNUNET_JSON_spec_fixed_auto ("reserve_pub", - &wsrd.reserve_pub), + &wc.wsrd.reserve_pub), GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &signature), + &wc.signature), TALER_JSON_spec_denomination_public_key ("denom_pub", - &denomination_pub), + &wc.denomination_pub), GNUNET_JSON_spec_end () }; @@ -93,60 +428,79 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, json_decref (root); if (GNUNET_OK != res) return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - ks = TEH_KS_acquire (); - dki = TEH_KS_denomination_key_lookup (ks, - &denomination_pub, - TEH_KS_DKU_WITHDRAW); - if (NULL == dki) + wc.key_state = TEH_KS_acquire (); + wc.dki = TEH_KS_denomination_key_lookup (wc.key_state, + &wc.denomination_pub, + TEH_KS_DKU_WITHDRAW); + if (NULL == wc.dki) { GNUNET_JSON_parse_free (spec); - TEH_KS_release (ks); + TEH_KS_release (wc.key_state); return TEH_RESPONSE_reply_arg_unknown (connection, TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND, "denom_pub"); } TALER_amount_ntoh (&amount, - &dki->issue.properties.value); + &wc.dki->issue.properties.value); TALER_amount_ntoh (&fee_withdraw, - &dki->issue.properties.fee_withdraw); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&amount_with_fee, - &amount, - &fee_withdraw)); - TALER_amount_hton (&wsrd.amount_with_fee, - &amount_with_fee); - TALER_amount_hton (&wsrd.withdraw_fee, + &wc.dki->issue.properties.fee_withdraw); + if (GNUNET_OK != + TALER_amount_add (&wc.amount_required, + &amount, + &fee_withdraw)) + { + GNUNET_JSON_parse_free (spec); + TEH_KS_release (wc.key_state); + return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW, + "amount overflow for value plus withdraw fee"); + } + TALER_amount_hton (&wc.wsrd.amount_with_fee, + &wc.amount_required); + TALER_amount_hton (&wc.wsrd.withdraw_fee, &fee_withdraw); - TEH_KS_release (ks); /* verify signature! */ - wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); - wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); - - GNUNET_CRYPTO_rsa_public_key_hash (denomination_pub.rsa_public_key, - &wsrd.h_denomination_pub); - GNUNET_CRYPTO_hash (blinded_msg, - blinded_msg_len, - &wsrd.h_coin_envelope); + wc.wsrd.purpose.size + = htonl (sizeof (struct TALER_WithdrawRequestPS)); + wc.wsrd.purpose.purpose + = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); + GNUNET_CRYPTO_rsa_public_key_hash (wc.denomination_pub.rsa_public_key, + &wc.wsrd.h_denomination_pub); + GNUNET_CRYPTO_hash (wc.blinded_msg, + wc.blinded_msg_len, + &wc.wsrd.h_coin_envelope); if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, - &wsrd.purpose, - &signature.eddsa_signature, - &wsrd.reserve_pub.eddsa_pub)) + &wc.wsrd.purpose, + &wc.signature.eddsa_signature, + &wc.wsrd.reserve_pub.eddsa_pub)) { TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n"); GNUNET_JSON_parse_free (spec); + TEH_KS_release (wc.key_state); return TEH_RESPONSE_reply_signature_invalid (connection, TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID, "reserve_sig"); } - res = TEH_DB_execute_reserve_withdraw (connection, - &wsrd.reserve_pub, - &denomination_pub, - blinded_msg, - blinded_msg_len, - &signature); + + if (GNUNET_OK != + TEH_DB_run_transaction (connection, + &mhd_ret, + &withdraw_transaction, + &wc)) + { + TEH_KS_release (wc.key_state); + GNUNET_JSON_parse_free (spec); + return mhd_ret; + } + TEH_KS_release (wc.key_state); GNUNET_JSON_parse_free (spec); - return res; + + mhd_ret = reply_reserve_withdraw_success (connection, + &wc.collectable); + GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature); + return mhd_ret; } -/* end of taler-exchange-httpd_reserve.c */ + +/* end of taler-exchange-httpd_reserve_withdraw.c */ diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 771b8adfe..48df955f7 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -685,9 +685,9 @@ TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, * @param[out] balance set to current reserve balance * @return json representation of the @a rh, NULL on error */ -static json_t * -compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh, - struct TALER_Amount *balance) +json_t * +TEH_RESPONSE_compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh, + struct TALER_Amount *balance) { struct TALER_Amount deposit_total; struct TALER_Amount withdraw_total; @@ -959,91 +959,6 @@ TEH_RESPONSE_reply_refund_success (struct MHD_Connection *connection, /** - * Send reserve status information to client. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TEH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_ReserveHistory *rh) -{ - json_t *json_balance; - json_t *json_history; - struct TALER_Amount balance; - - json_history = compile_reserve_history (rh, - &balance); - if (NULL == json_history) - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_RESERVE_STATUS_DB_ERROR, - "balance calculation failure"); - json_balance = TALER_JSON_from_amount (&balance); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o}", - "balance", json_balance, - "history", json_history); -} - - -/** - * Send reserve status information to client with the - * message that we have insufficient funds for the - * requested /reserve/withdraw operation. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_ReserveHistory *rh) -{ - json_t *json_balance; - json_t *json_history; - struct TALER_Amount balance; - - json_history = compile_reserve_history (rh, - &balance); - if (NULL == json_history) - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, - "balance calculation failure"); - json_balance = TALER_JSON_from_amount (&balance); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:I, s:o, s:o}", - "error", "Insufficient funds", - "code", (json_int_t) TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS, - "balance", json_balance, - "history", json_history); -} - - -/** - * Send blinded coin information to client. - * - * @param connection connection to the client - * @param collectable blinded coin to return - * @return MHD result code - */ -int -TEH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) -{ - json_t *sig_json; - - sig_json = GNUNET_JSON_from_rsa_signature (collectable->sig.rsa_signature); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "ev_sig", sig_json); -} - - -/** * Send a response for a failed "/refresh/melt" request. The * transaction history of the given coin demonstrates that the * @a residual value of the coin is below the @a requested diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index 047bb4f37..aef5bf94d 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -244,6 +244,19 @@ TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connectionx); /** + * Compile the history of a reserve into a JSON object + * and calculate the total balance. + * + * @param rh reserve history to JSON-ify + * @param[out] balance set to current reserve balance + * @return json representation of the @a rh, NULL on error + */ +json_t * +TEH_RESPONSE_compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh, + struct TALER_Amount *balance); + + +/** * Send proof that a request is invalid to client because of * insufficient funds. This function will create a message with all * of the operations affecting the coin that demonstrate that the coin @@ -412,44 +425,6 @@ TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection, /** - * Send reserve status information to client. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TEH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_ReserveHistory *rh); - - -/** - * Send reserve status information to client with the - * message that we have insufficient funds for the - * requested /reserve/withdraw operation. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_ReserveHistory *rh); - - -/** - * Send blinded coin information to client. - * - * @param connection connection to the client - * @param collectable blinded coin to return - * @return MHD result code - */ -int -TEH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable); - - -/** * Send a confirmation response to a "/refresh/melt" request. * * @param connection the connection to send the response to diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c index b5845411e..5e5c6a399 100644 --- a/src/exchangedb/perf_taler_exchangedb_interpreter.c +++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c @@ -1496,31 +1496,31 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) case PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW: { unsigned int coin_index; - int ret; + enum GNUNET_DB_QueryStatus qs; struct PERF_TALER_EXCHANGEDB_Coin *coin; coin_index = state->cmd[state->i].details.insert_withdraw.index_coin; coin = state->cmd[coin_index].exposed.data.coin; - ret = state->plugin->insert_withdraw_info (state->plugin->cls, + qs = state->plugin->insert_withdraw_info (state->plugin->cls, state->session, &coin->blind); - GNUNET_assert (GNUNET_SYSERR != ret); + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); } break; case PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW: { unsigned int source_index; - int ret; + enum GNUNET_DB_QueryStatus qs; struct PERF_TALER_EXCHANGEDB_Data *data; source_index = state->cmd[state->i].details.get_denomination.index_denom; data = &state->cmd[source_index].exposed; - ret = state->plugin->get_withdraw_info (state->plugin->cls, - state->session, - &data->data.coin->blind.h_coin_envelope, - &data->data.coin->blind); - GNUNET_assert (GNUNET_SYSERR != ret); + qs = state->plugin->get_withdraw_info (state->plugin->cls, + state->session, + &data->data.coin->blind.h_coin_envelope, + &data->data.coin->blind); + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); } break; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 0f18ef587..41b5f720d 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -2242,70 +2242,39 @@ postgres_get_latest_reserve_in_reference (void *cls, * `h_coin_envelope` in the @a collectable to be returned) * @param collectable corresponding collectable coin (blind signature) * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success + * @return statement execution status */ -static int +static enum GNUNET_DB_QueryStatus postgres_get_withdraw_info (void *cls, struct TALER_EXCHANGEDB_Session *session, const struct GNUNET_HashCode *h_blind, struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) { - PGresult *result; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (h_blind), GNUNET_PQ_query_param_end }; - int ret; - - ret = GNUNET_SYSERR; - result = GNUNET_PQ_exec_prepared (session->conn, - "get_withdraw_info", - params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result, session->conn); - goto cleanup; - } - if (0 == PQntuples (result)) - { - ret = GNUNET_NO; - goto cleanup; - } - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &collectable->denom_pub.rsa_public_key), - GNUNET_PQ_result_spec_rsa_signature ("denom_sig", - &collectable->sig.rsa_signature), - GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", - &collectable->reserve_sig), - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - &collectable->reserve_pub), - TALER_PQ_result_spec_amount ("amount_with_fee", - &collectable->amount_with_fee), - TALER_PQ_result_spec_amount ("fee_withdraw", - &collectable->withdraw_fee), - GNUNET_PQ_result_spec_end - }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &collectable->denom_pub.rsa_public_key), + GNUNET_PQ_result_spec_rsa_signature ("denom_sig", + &collectable->sig.rsa_signature), + GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", + &collectable->reserve_sig), + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + &collectable->reserve_pub), + TALER_PQ_result_spec_amount ("amount_with_fee", + &collectable->amount_with_fee), + TALER_PQ_result_spec_amount ("fee_withdraw", + &collectable->withdraw_fee), + GNUNET_PQ_result_spec_end + }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - 0)) - { - GNUNET_break (0); - goto cleanup; - } - } collectable->h_coin_envelope = *h_blind; - ret = GNUNET_YES; - - cleanup: - PQclear (result); - return ret; + return GNUNET_PQ_eval_prepared_singleton_select (session->conn, + "get_withdraw_info", + params, + rs); } @@ -2317,17 +2286,14 @@ postgres_get_withdraw_info (void *cls, * @param session database connection to use * @param collectable corresponding collectable coin (blind signature) * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if we failed but should retry the transaction - * #GNUNET_YES on success + * @return query execution status */ -static int +static enum GNUNET_DB_QueryStatus postgres_insert_withdraw_info (void *cls, struct TALER_EXCHANGEDB_Session *session, const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) { struct PostgresClosure *pg = cls; - PGresult *result; struct TALER_EXCHANGEDB_Reserve reserve; struct GNUNET_HashCode denom_pub_hash; struct GNUNET_TIME_Absolute now; @@ -2347,28 +2313,27 @@ postgres_insert_withdraw_info (void *cls, now = GNUNET_TIME_absolute_get (); GNUNET_CRYPTO_rsa_public_key_hash (collectable->denom_pub.rsa_public_key, &denom_pub_hash); - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_withdraw_info", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) + qs = GNUNET_PQ_eval_prepared_non_select (session->conn, + "insert_withdraw_info", + params); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { - QUERY_ERR (result, session->conn); - PQclear (result); - return GNUNET_SYSERR; + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; } - PQclear (result); /* update reserve balance */ reserve.pub = collectable->reserve_pub; if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - postgres_reserve_get (cls, - session, - &reserve)) + (qs = postgres_reserve_get (cls, + session, + &reserve))) { - /* FIXME: #5010 */ /* Should have been checked before we got here... */ - GNUNET_break (0); - return GNUNET_SYSERR; + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + qs = GNUNET_DB_STATUS_HARD_ERROR; + return qs; } if (GNUNET_SYSERR == TALER_amount_subtract (&reserve.balance, @@ -2381,7 +2346,7 @@ postgres_insert_withdraw_info (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Withdrawal from reserve `%s' refused due to balance missmatch. Retrying.\n", TALER_B2S (&collectable->reserve_pub)); - return GNUNET_NO; + return GNUNET_DB_STATUS_SOFT_ERROR; } expiry = GNUNET_TIME_absolute_add (now, pg->idle_reserve_expiration_time); @@ -2390,13 +2355,13 @@ postgres_insert_withdraw_info (void *cls, qs = reserves_update (cls, session, &reserve); - if (0 >= qs) + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { GNUNET_break (0); - - return GNUNET_SYSERR; + qs = GNUNET_DB_STATUS_HARD_ERROR; } - return GNUNET_OK; + return qs; } diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 8c7e4b9c8..ac1301d44 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1584,7 +1584,7 @@ run (void *cls) cbc.amount_with_fee = value; GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee)); - FAILIF (GNUNET_OK != + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->insert_withdraw_info (plugin->cls, session, &cbc)); @@ -1604,7 +1604,7 @@ run (void *cls) &reserve_pub2, sizeof (reserve_pub))); - FAILIF (GNUNET_YES != + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->get_withdraw_info (plugin->cls, session, &cbc.h_coin_envelope, diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 843c62720..af6b5547d 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1232,11 +1232,9 @@ struct TALER_EXCHANGEDB_Plugin * `h_coin_envelope` in the @a collectable to be returned) * @param collectable corresponding collectable coin (blind signature) * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success + * @return statement execution status */ - int + enum GNUNET_DB_QueryStatus (*get_withdraw_info) (void *cls, struct TALER_EXCHANGEDB_Session *session, const struct GNUNET_HashCode *h_blind, @@ -1251,11 +1249,9 @@ struct TALER_EXCHANGEDB_Plugin * @param session database connection to use * @param collectable corresponding collectable coin (blind signature) * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success + * @return statement execution status */ - int + enum GNUNET_DB_QueryStatus (*insert_withdraw_info) (void *cls, struct TALER_EXCHANGEDB_Session *session, const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable); |