From d292b8edca01c5152d3ccc8ac7ace9e8d27d3659 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 14 Mar 2020 20:18:47 +0100 Subject: code cleanup and additional error checking logic for #6124, but no actual semantic change --- src/exchange/taler-exchange-httpd_responses.c | 42 ++++++++++++++++++--------- src/exchange/taler-exchange-httpd_withdraw.c | 31 +++++++++++++------- src/include/taler_error_codes.h | 7 +++++ 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 0e7704e47..e2a20243d 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -433,10 +433,13 @@ TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, history = TEH_RESPONSE_compile_transaction_history (coin_pub, tl); if (NULL == history) + { + GNUNET_break (0); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_COIN_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, "failed to convert transaction history to JSON"); + } return TALER_MHD_reply_json_pack (connection, MHD_HTTP_CONFLICT, "{s:s, s:I, s:o}", @@ -462,10 +465,17 @@ TEH_RESPONSE_compile_reserve_history (const struct struct TALER_Amount deposit_total; struct TALER_Amount withdraw_total; json_t *json_history; - int ret; + enum InitAmounts + { + /** Nothing initialized */ + IA_NONE = 0, + /** deposit_total initialized */ + IA_DEPOSIT = 1, + /** withdraw_total initialized */ + IA_WITHDRAW = 2 + } init = IA_NONE; json_history = json_array (); - ret = 0; for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh; NULL != pos; pos = pos->next) @@ -473,8 +483,11 @@ TEH_RESPONSE_compile_reserve_history (const struct switch (pos->type) { case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: - if (0 == (1 & ret)) + if (0 == (IA_DEPOSIT & init)) + { deposit_total = pos->details.bank->amount; + init |= IA_DEPOSIT; + } else if (GNUNET_OK != TALER_amount_add (&deposit_total, &deposit_total, @@ -484,7 +497,6 @@ TEH_RESPONSE_compile_reserve_history (const struct json_decref (json_history); return NULL; } - ret |= 1; if (0 != json_array_append_new (json_history, json_pack ("{s:s, s:o, s:s, s:o, s:o}", @@ -514,9 +526,10 @@ TEH_RESPONSE_compile_reserve_history (const struct struct TALER_Amount value; value = pos->details.withdraw->amount_with_fee; - if (0 == (2 & ret)) + if (0 == (IA_WITHDRAW & init)) { withdraw_total = value; + init |= IA_WITHDRAW; } else { @@ -530,7 +543,6 @@ TEH_RESPONSE_compile_reserve_history (const struct return NULL; } } - ret |= 2; if (0 != json_array_append_new (json_history, json_pack ("{s:s, s:o, s:o, s:o, s:o, s:o}", @@ -568,8 +580,11 @@ TEH_RESPONSE_compile_reserve_history (const struct struct TALER_ExchangeSignatureP sig; recoup = pos->details.recoup; - if (0 == (1 & ret)) + if (0 == (IA_DEPOSIT & init)) + { deposit_total = recoup->value; + init |= IA_DEPOSIT; + } else if (GNUNET_OK != TALER_amount_add (&deposit_total, &deposit_total, @@ -579,7 +594,6 @@ TEH_RESPONSE_compile_reserve_history (const struct json_decref (json_history); return NULL; } - ret |= 1; pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP); pc.purpose.size = htonl (sizeof (struct TALER_RecoupConfirmationPS)); pc.timestamp = GNUNET_TIME_absolute_hton (recoup->timestamp); @@ -628,9 +642,10 @@ TEH_RESPONSE_compile_reserve_history (const struct struct TALER_Amount value; value = pos->details.closing->amount; - if (0 == (2 & ret)) + if (0 == (IA_WITHDRAW & init)) { withdraw_total = value; + init |= IA_WITHDRAW; } else { @@ -644,7 +659,6 @@ TEH_RESPONSE_compile_reserve_history (const struct return NULL; } } - ret |= 2; rcc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED); rcc.purpose.size = htonl (sizeof (struct TALER_ReserveCloseConfirmationPS)); @@ -703,15 +717,17 @@ TEH_RESPONSE_compile_reserve_history (const struct } } - if (0 == (1 & ret)) + if (0 == (IA_DEPOSIT & init)) { + /* We should not have gotten here, without deposits no reserve + should exist! */ GNUNET_break (0); json_decref (json_history); return NULL; } - if (0 == (2 & ret)) + if (0 == (IA_WITHDRAW & init)) { - /* did not encounter any withdraw operations, set to zero */ + /* did not encounter any withdraw operations, set withdraw_total to zero */ GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (deposit_total.currency, &withdraw_total)); diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c index ddb543c84..1abf1932c 100644 --- a/src/exchange/taler-exchange-httpd_withdraw.c +++ b/src/exchange/taler-exchange-httpd_withdraw.c @@ -44,33 +44,40 @@ /** * Send reserve status information to client with the * message that we have insufficient funds for the - * requested /reserve/withdraw operation. + * requested withdraw operation. * * @param connection connection to the client + * @param ebalance expected balance based on our database * @param rh reserve history to return * @return MHD result code */ static int reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_Amount *ebalance, 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) - /* Address the case where the ptr is not null, but - * it fails "internally" to dump as string (= corrupted). */ - || (0 == json_dumpb (json_history, NULL, 0, 0))) + if (NULL == json_history) return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, "balance calculation failure"); - json_balance = TALER_JSON_from_amount (&balance); - + if (0 != + TALER_amount_cmp (&balance, + ebalance)) + { + GNUNET_break (0); + json_decref (json_history); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_HISTORY_RESERVE_BALANCE_CORRUPT, + "internal balance inconsistency error"); + } return TALER_MHD_reply_json_pack (connection, MHD_HTTP_CONFLICT, "{s:s, s:I, s:o, s:o}", @@ -78,7 +85,8 @@ reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, "code", (json_int_t) TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS, - "balance", json_balance, + "balance", TALER_JSON_from_amount ( + &balance), "history", json_history); } @@ -285,6 +293,7 @@ withdraw_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } *mhd_ret = reply_reserve_withdraw_insufficient_funds (connection, + &r.balance, rh); TEH_plugin->free_reserve_history (TEH_plugin->cls, rh); @@ -455,7 +464,7 @@ TEH_RESERVE_handler_reserve_withdraw (const struct TEH_RequestHandler *rh, &wc.wsrd.reserve_pub.eddsa_pub)) { TALER_LOG_WARNING ( - "Client supplied invalid signature for /reserve/withdraw request\n"); + "Client supplied invalid signature for withdraw request\n"); GNUNET_JSON_parse_free (spec); TEH_KS_release (wc.key_state); return TALER_MHD_reply_with_error (connection, @@ -484,7 +493,7 @@ TEH_RESERVE_handler_reserve_withdraw (const struct TEH_RequestHandler *rh, if (GNUNET_OK != TEH_DB_run_transaction (connection, - "run reserve withdraw", + "run withdraw", &mhd_ret, &withdraw_transaction, &wc)) diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index f485f2da7..e6bd73647 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -381,6 +381,13 @@ enum TALER_ErrorCode */ TALER_EC_DENOMINATION_KEY_LOST = 1116, + /** + * The exchange's database entry with the reserve balance summary + * is inconsistent with its own history of the reserve. + * Returned with an HTTP status of #MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_WITHDRAW_HISTORY_RESERVE_BALANCE_CORRUPT = 1117, + /** * The exchange failed to obtain the transaction history of the given * reserve from the database. This response is provided with HTTP -- cgit v1.2.3