exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit d442697a1f276471a15012c8eba802e725acfebc
parent f34d9ad1be4cc8d47b7c8055e59b072c4129afc9
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  2 Jan 2025 09:48:29 +0100

add logic to properly decrement balance if missing deposit confirmations appear

Diffstat:
Msrc/auditor/taler-helper-auditor-deposits.c | 181++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/include/taler_auditordb_plugin.h | 2--
2 files changed, 143 insertions(+), 40 deletions(-)

diff --git a/src/auditor/taler-helper-auditor-deposits.c b/src/auditor/taler-helper-auditor-deposits.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2016-2024 Taler Systems SA + Copyright (C) 2016-2025 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero Public License as published by the Free Software @@ -59,6 +59,12 @@ */ static int global_ret; +/** + * Row ID until which we have added up missing deposit confirmations + * in the total_missed_deposit_confirmations amount. Missing deposit + * confirmations above this value need to be added, and if any appear + * below this value we should subtract them from the reported amount. + */ static TALER_ARL_DEF_PP (deposit_confirmation_serial_id); /** @@ -74,9 +80,13 @@ static TALER_ARL_DEF_AB (total_missed_deposit_confirmations); /** * Should we run checks that only work for exchange-internal audits? + * Does nothing for this helper (present only for uniformity). */ static int internal_checks; +/** + * Handler to wake us up on new deposit confirmations. + */ static struct GNUNET_DB_EventHandler *eh; /** @@ -86,7 +96,7 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Success or failure of (exchange) database operations within - * #test_dc. + * #test_dc and #recheck_dc. */ static enum GNUNET_DB_QueryStatus eqs; @@ -95,7 +105,7 @@ static enum GNUNET_DB_QueryStatus eqs; * Given a deposit confirmation from #TALER_ARL_adb, check that it is also * in #TALER_ARL_edb. Update the deposit confirmation context accordingly. * - * @param cls our `struct DepositConfirmationContext` + * @param cls NULL * @param dc the deposit confirmation we know * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop iterating */ @@ -154,7 +164,6 @@ test_dc (void *cls, GNUNET_h2s (&dc->h_contract_terms.hash)); return GNUNET_OK; /* all coins found, all good */ } - // FIXME: where do we *decrease* this amount if we get a DC later? TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_missed_deposit_confirmations), &TALER_ARL_USE_AB (total_missed_deposit_confirmations), &dc->total_without_fee); @@ -163,6 +172,80 @@ test_dc (void *cls, /** + * Given a previously missing deposit confirmation from #TALER_ARL_adb, check + * *again* whether it is now in #TALER_ARL_edb. Update the deposit + * confirmation context accordingly. + * + * @param cls NULL + * @param dc the deposit confirmation we know + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop iterating + */ +static enum GNUNET_GenericReturnValue +recheck_dc (void *cls, + const struct TALER_AUDITORDB_DepositConfirmation *dc) +{ + bool missing = false; + enum GNUNET_DB_QueryStatus qs; + + (void) cls; + for (unsigned int i = 0; i < dc->num_coins; i++) + { + struct GNUNET_TIME_Timestamp exchange_timestamp; + struct TALER_Amount deposit_fee; + + qs = TALER_ARL_edb->have_deposit2 (TALER_ARL_edb->cls, + &dc->h_contract_terms, + &dc->h_wire, + &dc->coin_pubs[i], + &dc->merchant, + dc->refund_deadline, + &deposit_fee, + &exchange_timestamp); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Status for deposit confirmation %llu-%u is %d on re-check\n", + (unsigned long long) dc->row_id, + i, + qs); + missing |= (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs); + if (qs < 0) + { + GNUNET_break (0); /* DB error, complain */ + eqs = qs; + return GNUNET_SYSERR; + } + } + if (! missing) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Deleting matching deposit confirmation %llu\n", + (unsigned long long) dc->row_id); + qs = TALER_ARL_adb->delete_generic ( + TALER_ARL_adb->cls, + TALER_AUDITORDB_DEPOSIT_CONFIRMATION, + dc->row_id); + if (qs < 0) + { + GNUNET_break (0); /* DB error, complain */ + eqs = qs; + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Previously missing deposit %s appeared in exchange database\n", + GNUNET_h2s (&dc->h_contract_terms.hash)); + /* It appeared, so *reduce* total missing balance */ + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB ( + total_missed_deposit_confirmations), + &TALER_ARL_USE_AB ( + total_missed_deposit_confirmations), + &dc->total_without_fee); + return GNUNET_OK; /* all coins found, all good */ + } + /* still missing, no change to totalmissing balance */ + return GNUNET_OK; +} + + +/** * Check that the deposit-confirmations that were reported to * us by merchants are also in the exchange's database. * @@ -173,6 +256,10 @@ static enum GNUNET_DB_QueryStatus analyze_deposit_confirmations (void *cls) { enum GNUNET_DB_QueryStatus qs; + bool had_pp; + bool had_bal; + bool had_missing; + uint64_t pp; (void) cls; qs = TALER_ARL_adb->get_auditor_progress ( @@ -184,17 +271,19 @@ analyze_deposit_confirmations (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "First analysis using deposit auditor, starting audit from scratch\n"); - } - else + had_pp = (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); + if (had_pp) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resuming deposit confirmation audit at %llu\n", (unsigned long long) TALER_ARL_USE_PP ( deposit_confirmation_serial_id)); + pp = TALER_ARL_USE_PP (deposit_confirmation_serial_id); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "First analysis using deposit auditor, starting audit from scratch\n"); } qs = TALER_ARL_adb->get_balance ( TALER_ARL_adb->cls, @@ -205,10 +294,13 @@ analyze_deposit_confirmations (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } + had_bal = (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); + had_missing = ! TALER_amount_is_zero ( + &TALER_ARL_USE_AB (total_missed_deposit_confirmations)); qs = TALER_ARL_adb->get_deposit_confirmations ( TALER_ARL_adb->cls, INT64_MAX, - 0, + TALER_ARL_USE_PP (deposit_confirmation_serial_id), true, /* return suppressed */ &test_dc, NULL); @@ -225,21 +317,16 @@ analyze_deposit_confirmations (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Analyzed %d deposit confirmations\n", (int) qs); - qs = TALER_ARL_adb->insert_auditor_progress ( - TALER_ARL_adb->cls, - TALER_ARL_SET_PP (deposit_confirmation_serial_id), - NULL); - if (0 > qs) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to update auditor DB, not recording progress\n"); - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; - } - qs = TALER_ARL_adb->update_auditor_progress ( - TALER_ARL_adb->cls, - TALER_ARL_SET_PP (deposit_confirmation_serial_id), - NULL); + if (had_pp) + qs = TALER_ARL_adb->update_auditor_progress ( + TALER_ARL_adb->cls, + TALER_ARL_SET_PP (deposit_confirmation_serial_id), + NULL); + else + qs = TALER_ARL_adb->insert_auditor_progress ( + TALER_ARL_adb->cls, + TALER_ARL_SET_PP (deposit_confirmation_serial_id), + NULL); if (0 > qs) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -247,21 +334,39 @@ analyze_deposit_confirmations (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - qs = TALER_ARL_adb->insert_balance ( - TALER_ARL_adb->cls, - TALER_ARL_SET_AB (total_missed_deposit_confirmations), - NULL); - if (0 > qs) + if (had_bal && had_pp && had_missing) { + qs = TALER_ARL_adb->get_deposit_confirmations ( + TALER_ARL_adb->cls, + -INT64_MAX, + pp + 1, /* previous iteration went up to 'pp', try missing again */ + true, /* return suppressed */ + &recheck_dc, + NULL); + if (0 > qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; + } + if (0 > eqs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == eqs); + return eqs; + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to update auditor DB, not recording progress\n"); - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; + "Re-analyzed %d deposit confirmations\n", + (int) qs); } - qs = TALER_ARL_adb->update_balance ( - TALER_ARL_adb->cls, - TALER_ARL_SET_AB (total_missed_deposit_confirmations), - NULL); + if (had_bal) + qs = TALER_ARL_adb->update_balance ( + TALER_ARL_adb->cls, + TALER_ARL_SET_AB (total_missed_deposit_confirmations), + NULL); + else + qs = TALER_ARL_adb->insert_balance ( + TALER_ARL_adb->cls, + TALER_ARL_SET_AB (total_missed_deposit_confirmations), + NULL); if (0 > qs) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h @@ -1263,8 +1263,6 @@ struct TALER_AUDITORDB_Plugin void *cb_cls); - // MARK: CRUD - /** * Get information about arithmetic inconsistencies from the database. *