diff options
Diffstat (limited to 'src/auditor/taler-helper-auditor-deposits.c')
-rw-r--r-- | src/auditor/taler-helper-auditor-deposits.c | 237 |
1 files changed, 195 insertions, 42 deletions
diff --git a/src/auditor/taler-helper-auditor-deposits.c b/src/auditor/taler-helper-auditor-deposits.c index c08727d37..3dbce0183 100644 --- 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-2021 Taler Systems SA + Copyright (C) 2016-2023 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 @@ -17,6 +17,7 @@ * @file auditor/taler-helper-auditor-deposits.c * @brief audits an exchange database for deposit confirmation consistency * @author Christian Grothoff + * @author Nic Eigel * * We simply check that all of the deposit confirmations reported to us * by merchants were also reported to us by the exchange. @@ -29,7 +30,29 @@ #include "taler_bank_service.h" #include "taler_signatures.h" #include "report-lib.h" +#include "taler_dbevents.h" +#include <jansson.h> +/* +-- +-- SELECT serial_id,h_contract_terms,h_wire,merchant_pub ... +-- FROM auditor.auditor_deposit_confirmations +-- WHERE NOT ancient +-- ORDER BY exchange_timestamp ASC; +-- SELECT 1 +- FROM exchange.deposits dep + WHERE ($RESULT.contract_terms = dep.h_contract_terms) AND ($RESULT.h_wire = dep.h_wire) AND ...); +-- IF FOUND +-- DELETE FROM auditor.auditor_deposit_confirmations +-- WHERE serial_id = $RESULT.serial_id; +-- SELECT exchange_timestamp AS latest +-- FROM exchange.deposits ORDER BY exchange_timestamp DESC; +-- latest -= 1 hour; // time is not exactly monotonic... +-- UPDATE auditor.deposit_confirmations +-- SET ancient=TRUE +-- WHERE exchange_timestamp < latest +-- AND NOT ancient; +*/ /** * Return value from main(). @@ -37,6 +60,14 @@ static int global_ret; /** + * Run in test mode. Exit when idle instead of + * going to sleep and waiting for more work. + * + * FIXME: not yet implemented! + */ +static int test_mode; + +/** * Array of reports about missing deposit confirmations. */ static json_t *report_deposit_confirmation_inconsistencies; @@ -56,6 +87,18 @@ static struct TALER_Amount total_missed_deposit_confirmations; */ static int internal_checks; +static struct GNUNET_DB_EventHandler *eh; + +/** + * Our database plugin. + */ +static struct TALER_AUDITORDB_Plugin *db_plugin; + +/** + * The auditors's configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + /** * Closure for #test_dc. */ @@ -92,7 +135,6 @@ struct DepositConfirmationContext }; - /** * Given a deposit confirmation from #TALER_ARL_adb, check that it is also * in #TALER_ARL_edb. Update the deposit confirmation context accordingly. @@ -108,8 +150,10 @@ test_dc (void *cls, const struct TALER_AUDITORDB_DepositConfirmation *dc) { struct DepositConfirmationContext *dcc = cls; + bool missing = false; dcc->last_seen_coin_serial = serial_id; + for (unsigned int i = 0; i < dc->num_coins; i++) { enum GNUNET_DB_QueryStatus qs; struct GNUNET_TIME_Timestamp exchange_timestamp; @@ -118,20 +162,12 @@ test_dc (void *cls, qs = TALER_ARL_edb->have_deposit2 (TALER_ARL_edb->cls, &dc->h_contract_terms, &dc->h_wire, - &dc->coin_pub, + &dc->coin_pubs[i], &dc->merchant, dc->refund_deadline, &deposit_fee, &exchange_timestamp); - if (qs > 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found deposit %s in exchange database\n", - GNUNET_h2s (&dc->h_contract_terms.hash)); - if (TALER_ARL_do_abort ()) - return GNUNET_SYSERR; - return GNUNET_OK; /* found, all good */ - } + missing |= (0 == qs); if (qs < 0) { GNUNET_break (0); /* DB error, complain */ @@ -139,6 +175,15 @@ test_dc (void *cls, return GNUNET_SYSERR; } } + if (! missing) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found deposit %s in exchange database\n", + GNUNET_h2s (&dc->h_contract_terms.hash)); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; /* all coins found, all good */ + } /* deposit confirmation missing! report! */ TALER_ARL_report ( report_deposit_confirmation_inconsistencies, @@ -146,7 +191,7 @@ test_dc (void *cls, TALER_JSON_pack_time_abs_human ("timestamp", dc->exchange_timestamp.abs_time), TALER_JSON_pack_amount ("amount", - &dc->amount_without_fee), + &dc->total_without_fee), GNUNET_JSON_pack_uint64 ("rowid", serial_id), GNUNET_JSON_pack_data_auto ("account", @@ -156,7 +201,7 @@ test_dc (void *cls, dcc->missed_count++; TALER_ARL_amount_add (&dcc->missed_amount, &dcc->missed_amount, - &dc->amount_without_fee); + &dc->total_without_fee); if (TALER_ARL_do_abort ()) return GNUNET_SYSERR; return GNUNET_OK; @@ -173,20 +218,18 @@ test_dc (void *cls, static enum GNUNET_DB_QueryStatus analyze_deposit_confirmations (void *cls) { - struct TALER_AUDITORDB_ProgressPointDepositConfirmation ppdc; + TALER_ARL_DEF_PP (deposit_confirmation_serial_id); struct DepositConfirmationContext dcc; enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qsx; enum GNUNET_DB_QueryStatus qsp; - (void) cls; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Analyzing deposit confirmations\n"); - ppdc.last_deposit_confirmation_serial_id = 0; - qsp = TALER_ARL_adb->get_auditor_progress_deposit_confirmation ( + + qsp = TALER_ARL_adb->get_auditor_progress ( TALER_ARL_adb->cls, - &TALER_ARL_master_pub, - &ppdc); + TALER_ARL_GET_PP (deposit_confirmation_serial_id), + NULL); + if (0 > qsp) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsp); @@ -201,7 +244,8 @@ analyze_deposit_confirmations (void *cls) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resuming deposit confirmation audit at %llu\n", - (unsigned long long) ppdc.last_deposit_confirmation_serial_id); + (unsigned long long) TALER_ARL_USE_PP ( + deposit_confirmation_serial_id)); } /* setup 'cc' */ @@ -211,10 +255,13 @@ analyze_deposit_confirmations (void *cls) dcc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; dcc.missed_count = 0LLU; dcc.first_missed_coin_serial = UINT64_MAX; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "lastdepconfserialid %lu\n", + TALER_ARL_USE_PP (deposit_confirmation_serial_id)); qsx = TALER_ARL_adb->get_deposit_confirmations ( TALER_ARL_adb->cls, - &TALER_ARL_master_pub, - ppdc.last_deposit_confirmation_serial_id, + TALER_ARL_USE_PP (deposit_confirmation_serial_id), + true, /* return suppressed */ &test_dc, &dcc); if (0 > qsx) @@ -225,28 +272,30 @@ analyze_deposit_confirmations (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Analyzed %d deposit confirmations (above serial ID %llu)\n", (int) qsx, - (unsigned long long) ppdc.last_deposit_confirmation_serial_id); + (unsigned long long) TALER_ARL_USE_PP ( + deposit_confirmation_serial_id)); if (0 > dcc.qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == dcc.qs); return dcc.qs; } - if (UINT64_MAX == dcc.first_missed_coin_serial) - ppdc.last_deposit_confirmation_serial_id = dcc.last_seen_coin_serial; - else - ppdc.last_deposit_confirmation_serial_id = dcc.first_missed_coin_serial - 1; + /* if (UINT64_MAX == dcc.first_missed_coin_serial) + ppdc.last_deposit_confirmation_serial_id = dcc.last_seen_coin_serial; + else + ppdc.last_deposit_confirmation_serial_id = dcc.first_missed_coin_serial - 1; + */ /* sync 'cc' back to disk */ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsp) - qs = TALER_ARL_adb->update_auditor_progress_deposit_confirmation ( + qs = TALER_ARL_adb->update_auditor_progress ( TALER_ARL_adb->cls, - &TALER_ARL_master_pub, - &ppdc); + TALER_ARL_SET_PP (deposit_confirmation_serial_id), + NULL); else - qs = TALER_ARL_adb->insert_auditor_progress_deposit_confirmation ( + qs = TALER_ARL_adb->insert_auditor_progress ( TALER_ARL_adb->cls, - &TALER_ARL_master_pub, - &ppdc); + TALER_ARL_SET_PP (deposit_confirmation_serial_id), + NULL); if (0 >= qs) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -254,17 +303,90 @@ analyze_deposit_confirmations (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } + number_missed_deposit_confirmations = (json_int_t) dcc.missed_count; total_missed_deposit_confirmations = dcc.missed_amount; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Concluded deposit confirmation audit step at %llu\n", - (unsigned long long) ppdc.last_deposit_confirmation_serial_id); + (unsigned long long) TALER_ARL_USE_PP ( + deposit_confirmation_serial_id)); return qs; } /** + * Function called on events received from Postgres. + * + * @param cls closure, NULL + * @param extra additional event data provided + * @param extra_size number of bytes in @a extra + */ +static void +db_notify (void *cls, + const void *extra, + size_t extra_size) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received notification for new deposit_confirmation\n"); + + (void) cls; + (void) extra; + (void) extra_size; + + if (NULL == + (db_plugin = TALER_AUDITORDB_plugin_load (cfg))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to initialize DB subsystem\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_assert (NULL != + (report_deposit_confirmation_inconsistencies = json_array ())); + + if (GNUNET_OK != + TALER_ARL_setup_sessions_and_run (&analyze_deposit_confirmations, + NULL)) + { + global_ret = EXIT_FAILURE; + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deposit audit complete\n"); + TALER_ARL_done ( + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_array_steal ("deposit_confirmation_inconsistencies", + report_deposit_confirmation_inconsistencies), + GNUNET_JSON_pack_uint64 ("missing_deposit_confirmation_count", + number_missed_deposit_confirmations), + TALER_JSON_pack_amount ("missing_deposit_confirmation_total", + &total_missed_deposit_confirmations), + TALER_JSON_pack_time_abs_human ("auditor_start_time", + start_time), + TALER_JSON_pack_time_abs_human ("auditor_end_time", + GNUNET_TIME_absolute_get ()))); +} + + +/** + * Function called on shutdown. + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + + db_plugin->event_listen_cancel (eh); + eh = NULL; + TALER_AUDITORDB_plugin_unload (db_plugin); + db_plugin = NULL; + TALER_ARL_done (NULL); +} + + +/** * Main function that will be run. * * @param cls closure @@ -281,6 +403,10 @@ run (void *cls, (void) cls; (void) args; (void) cfgfile; + cfg = c; + + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching deposit auditor\n"); if (GNUNET_OK != @@ -289,6 +415,34 @@ run (void *cls, global_ret = EXIT_FAILURE; return; } + + if (NULL == + (db_plugin = TALER_AUDITORDB_plugin_load (cfg))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to initialize DB subsystem\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != + db_plugin->preflight (db_plugin->cls)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to database\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + struct GNUNET_DB_EventHeaderP es = { + .size = htons (sizeof (es)), + .type = htons (TALER_DBEVENT_EXCHANGE_AUDITOR_NEW_DEPOSIT_CONFIRMATION) + }; + eh = db_plugin->event_listen (db_plugin->cls, + &es, + GNUNET_TIME_UNIT_FOREVER_REL, + &db_notify, + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting deposit audit\n"); GNUNET_assert (NULL != @@ -333,11 +487,10 @@ main (int argc, "internal", "perform checks only applicable for exchange-internal audits", &internal_checks), - GNUNET_GETOPT_option_base32_auto ('m', - "exchange-key", - "KEY", - "public key of the exchange (Crockford base32 encoded)", - &TALER_ARL_master_pub), + GNUNET_GETOPT_option_flag ('t', + "test", + "run in test mode and exit when idle", + &test_mode), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_OPTION_END |