exchange

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

commit f34d9ad1be4cc8d47b7c8055e59b072c4129afc9
parent 0da81c2a5dcccb1d6069729d620f998740f5ac7b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  2 Jan 2025 00:01:33 +0100

partial fix for FIXME in taler-helper-auditor-transfer

Diffstat:
Msrc/auditor/taler-helper-auditor-transfer.c | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/auditor/taler-helper-auditor-wire-credit.c | 57+++++++++++++++++++++++++++++++++++++++++----------------
Asrc/auditordb/0002-auditor_early_aggregation.sql | 26++++++++++++++++++++++++++
Msrc/auditordb/Makefile.am | 2++
Msrc/auditordb/auditor-0002.sql.in | 3++-
Asrc/auditordb/pg_delete_early_aggregation.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/auditordb/pg_delete_early_aggregation.h | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/auditordb/pg_insert_early_aggregation.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/auditordb/pg_insert_early_aggregation.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/auditordb/pg_template.c | 2+-
Msrc/auditordb/pg_template.h | 2+-
Msrc/auditordb/plugin_auditordb_postgres.c | 7+++++++
Msrc/exchangedb/pg_template.c | 2+-
Msrc/exchangedb/pg_template.h | 2+-
Msrc/include/taler_auditordb_plugin.h | 35+++++++++++++++++++++++++++++++++++
15 files changed, 386 insertions(+), 43 deletions(-)

diff --git a/src/auditor/taler-helper-auditor-transfer.c b/src/auditor/taler-helper-auditor-transfer.c @@ -49,11 +49,16 @@ static TALER_ARL_DEF_PP (wire_batch_deposit_id); static TALER_ARL_DEF_PP (wire_aggregation_id); /** - * Total amount which the exchange did not transfer in time. + * Total amount which the exchange did not aggregate/transfer in time. */ static TALER_ARL_DEF_AB (total_amount_lag); /** + * Total amount which the exchange did aggregate/transfer too early. + */ +static TALER_ARL_DEF_AB (total_early_aggregation); + +/** * Should we run checks that only work for exchange-internal audits? */ static int internal_checks; @@ -131,20 +136,43 @@ import_wire_missing_cb ( return; /* already failed */ GNUNET_assert (batch_deposit_serial_id >= wc->max_batch_deposit_uuid); wc->max_batch_deposit_uuid = batch_deposit_serial_id + 1; - qs = TALER_ARL_adb->insert_pending_deposit ( + qs = TALER_ARL_adb->delete_early_aggregation ( TALER_ARL_adb->cls, - batch_deposit_serial_id, - wire_target_h_payto, - total_amount, - deadline); - if (qs < 0) + batch_deposit_serial_id); + switch (qs) { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + wc->err = qs; + return; + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); wc->err = qs; + return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + qs = TALER_ARL_adb->insert_pending_deposit ( + TALER_ARL_adb->cls, + batch_deposit_serial_id, + wire_target_h_payto, + total_amount, + deadline); + if (0 < qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + wc->err = qs; + } + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_amount_lag), + &TALER_ARL_USE_AB (total_amount_lag), + total_amount); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (total_early_aggregation), + &TALER_ARL_USE_AB (total_early_aggregation), + total_amount); + break; + default: + GNUNET_assert (0); } - TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_amount_lag), - &TALER_ARL_USE_AB (total_amount_lag), - total_amount); } @@ -225,22 +253,40 @@ clear_finished_transfer_cb ( qs = TALER_ARL_adb->delete_pending_deposit ( TALER_ARL_adb->cls, batch_deposit_serial_id); - if (0 == qs) + switch (qs) { - /* Aggregated something twice or other error, report! */ + case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (0); - // FIXME: report more nicely! + ac->err = qs; return; - } - if (0 > qs) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); ac->err = qs; return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + qs = TALER_ARL_adb->insert_early_aggregation ( + TALER_ARL_adb->cls, + batch_deposit_serial_id, + tracking_serial_id, + amount); + if (0 > qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + ac->err = qs; + return; + } + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_early_aggregation), + &TALER_ARL_USE_AB (total_early_aggregation), + amount); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (total_amount_lag), + &TALER_ARL_USE_AB (total_amount_lag), + amount); + break; + default: + GNUNET_assert (0); } - TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (total_amount_lag), - &TALER_ARL_USE_AB (total_amount_lag), - amount); } @@ -328,6 +374,7 @@ begin_transaction (void) qs = TALER_ARL_adb->get_balance ( TALER_ARL_adb->cls, TALER_ARL_GET_AB (total_amount_lag), + TALER_ARL_GET_AB (total_early_aggregation), NULL); if (0 > qs) goto handle_db_error; @@ -368,12 +415,14 @@ begin_transaction (void) qs = TALER_ARL_adb->update_balance ( TALER_ARL_adb->cls, TALER_ARL_SET_AB (total_amount_lag), + TALER_ARL_SET_AB (total_early_aggregation), NULL); if (0 > qs) goto handle_db_error; qs = TALER_ARL_adb->insert_balance ( TALER_ARL_adb->cls, TALER_ARL_SET_AB (total_amount_lag), + TALER_ARL_SET_AB (total_early_aggregation), NULL); if (0 > qs) goto handle_db_error; @@ -538,7 +587,7 @@ main (int argc, argv, "taler-helper-auditor-transfer", gettext_noop ( - "Audit exchange database for consistency of transfers with respect to deposit deadlines"), + "Audit exchange database for consistency of aggregations/transfers with respect to deposit deadlines"), options, &run, NULL); diff --git a/src/auditor/taler-helper-auditor-wire-credit.c b/src/auditor/taler-helper-auditor-wire-credit.c @@ -327,6 +327,35 @@ begin_transaction (void); /** + * Rollback the current transaction, reset our state and try + * again (we had a serialization error). + */ +static void +rollback_and_reset (void) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Serialization issue, trying again\n"); + TALER_ARL_adb->rollback (TALER_ARL_adb->cls); + GNUNET_CONTAINER_multihashmap_iterate (in_map, + &free_rii, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (in_map); + in_map = NULL; + for (unsigned int max_retries = 3; max_retries>0; max_retries--) + { + enum GNUNET_DB_QueryStatus qs; + + qs = begin_transaction (); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + break; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Hard database error, terminating\n"); + GNUNET_SCHEDULER_shutdown (); +} + + +/** * Commit the transaction, checkpointing our progress in the auditor DB. * * @param qs transaction status so far @@ -400,18 +429,7 @@ commit (enum GNUNET_DB_QueryStatus qs) GNUNET_SCHEDULER_shutdown (); return; handle_db_error: - TALER_ARL_adb->rollback (TALER_ARL_adb->cls); - for (unsigned int max_retries = 3; max_retries>0; max_retries--) - { - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - break; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Serialization issue, trying again\n"); - qs = begin_transaction (); - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Hard database error, terminating\n"); - GNUNET_SCHEDULER_shutdown (); + rollback_and_reset (); } @@ -955,13 +973,20 @@ history_credit_cb (void *cls, if (! analyze_credit (wa, cd)) { - if (global_qs < 0) + switch (global_qs) { - /* FIXME: this error handling sucks, - doesn't retry on SOFT errors, doesn't - set global_ret, etc. */ + case GNUNET_DB_STATUS_SOFT_ERROR: + rollback_and_reset (); + return; + case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_SCHEDULER_shutdown (); return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* perfectly fine */ + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* perfectly fine */ + break; } break; } diff --git a/src/auditordb/0002-auditor_early_aggregation.sql b/src/auditordb/0002-auditor_early_aggregation.sql @@ -0,0 +1,26 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2024 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +CREATE TABLE IF NOT EXISTS auditor_early_aggregations +( + row_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY, + batch_deposit_serial_id BIGINT UNIQUE NOT NULL, + tracking_serial_id BIGINT UNIQUE NOT NULL, + amount taler_amount NOT NULL, + suppressed BOOLEAN NOT NULL DEFAULT FALSE +); +COMMENT ON TABLE auditor_early_aggregation + IS 'Reports when aggregations/transfers are encountered before their justifications (can be harmless, if the justifications appear shortly afterwards).'; diff --git a/src/auditordb/Makefile.am b/src/auditordb/Makefile.am @@ -59,6 +59,7 @@ endif libtaler_plugin_auditordb_postgres_la_SOURCES = \ pg_del_denomination_balance.h pg_del_denomination_balance.c \ pg_del_reserve_info.c pg_del_reserve_info.h \ + pg_delete_early_aggregation.h pg_delete_early_aggregation.c \ pg_delete_generic.c pg_delete_generic.h \ pg_delete_pending_deposit.c pg_delete_pending_deposit.h \ pg_delete_purse_info.c pg_delete_purse_info.h \ @@ -109,6 +110,7 @@ libtaler_plugin_auditordb_postgres_la_SOURCES = \ pg_insert_denomination_pending.c pg_insert_denomination_pending.h \ pg_insert_denominations_without_sigs.c pg_insert_denominations_without_sigs.h \ pg_insert_deposit_confirmation.c pg_insert_deposit_confirmation.h \ + pg_insert_early_aggregation.h pg_insert_early_aggregation.c \ pg_insert_emergency.c pg_insert_emergency.h \ pg_insert_emergency_by_count.c pg_insert_emergency_by_count.h \ pg_insert_exchange_signkey.c pg_insert_exchange_signkey.h \ diff --git a/src/auditordb/auditor-0002.sql.in b/src/auditordb/auditor-0002.sql.in @@ -1,6 +1,6 @@ -- -- This file is part of TALER --- Copyright (C) 2014--2023 Taler Systems SA +-- Copyright (C) 2014--2025 Taler Systems SA -- -- TALER is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software @@ -62,5 +62,6 @@ END $$; #include "0002-auditor_wire_format_inconsistency.sql" #include "0002-auditor_wire_out_inconsistency.sql" #include "0002-auditor_pending_deposits.sql" +#include "0002-auditor_early_aggregation.sql" COMMIT; diff --git a/src/auditordb/pg_delete_early_aggregation.c b/src/auditordb/pg_delete_early_aggregation.c @@ -0,0 +1,50 @@ +/* + This file is part of TALER + Copyright (C) 2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file auditordb/pg_delete_early_aggregation.c + * @brief Implementation of the delete_early_aggregation function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_delete_early_aggregation.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TAH_PG_delete_early_aggregation ( + void *cls, + uint64_t batch_deposit_serial_id) +{ + + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&batch_deposit_serial_id), + GNUNET_PQ_query_param_end + }; + + PREPARE (pg, + "auditor_delete_early_aggregation", + "DELETE" + " FROM auditor_early_aggregations" + " WHERE batch_deposit_serial_id=$1;"); + return GNUNET_PQ_eval_prepared_non_select ( + pg->conn, + "auditor_delete_early_aggregation", + params); +} diff --git a/src/auditordb/pg_delete_early_aggregation.h b/src/auditordb/pg_delete_early_aggregation.h @@ -0,0 +1,44 @@ +/* + This file is part of TALER + Copyright (C) 2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file auditordb/pg_delete_early_aggregation.h + * @brief implementation of the delete_early_aggregation function for Postgres + * @author Christian Grothoff + */ +#ifndef PG_DELETE_EARLY_AGGREGATION_H +#define PG_DELETE_EARLY_AGGREGATION_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_auditordb_plugin.h" + + +/** + * Delete a row from the early aggregation table. + * Usually done when the expected aggregation + * was finally detected. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param batch_deposit_serial_id which entry to delete + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TAH_PG_delete_early_aggregation ( + void *cls, + uint64_t batch_deposit_serial_id); + + +#endif diff --git a/src/auditordb/pg_insert_early_aggregation.c b/src/auditordb/pg_insert_early_aggregation.c @@ -0,0 +1,56 @@ +/* + This file is part of TALER + Copyright (C) 2025 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file auditordb/pg_insert_early_aggregation.c + * @brief Implementation of the insert_early_aggregation function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_insert_early_aggregation.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TAH_PG_insert_early_aggregation ( + void *cls, + uint64_t batch_deposit_serial_id, + uint64_t tracking_serial_id, + const struct TALER_Amount *total_amount) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&batch_deposit_serial_id), + GNUNET_PQ_query_param_uint64 (&tracking_serial_id), + TALER_PQ_query_param_amount (pg->conn, + total_amount), + GNUNET_PQ_query_param_end + }; + + PREPARE (pg, + "auditor_insert_early_aggregation", + "INSERT INTO auditor_pending_deposits " + "(batch_deposit_serial_id" + ",tracking_serial_id" + ",amount" + ") VALUES ($1,$2,$3);"); + return GNUNET_PQ_eval_prepared_non_select ( + pg->conn, + "auditor_insert_early_aggregation", + params); +} diff --git a/src/auditordb/pg_insert_early_aggregation.h b/src/auditordb/pg_insert_early_aggregation.h @@ -0,0 +1,48 @@ +/* + This file is part of TALER + Copyright (C) 2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file auditordb/pg_insert_early_aggregation.h + * @brief implementation of the insert_early_aggregation function for Postgres + * @author Christian Grothoff + */ +#ifndef PG_INSERT_EARLY_AGGREGATION_H +#define PG_INSERT_EARLY_AGGREGATION_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_auditordb_plugin.h" + + +/** + * Insert new row into the early aggregation table. This can happen simply + * because of when the taler-helper-auditor-transfer looks at which of the + * two tables. If it is cleared in the next iteration, this is perfectly + * expected. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param batch_deposit_serial_id where in the batch deposit table are we + * @param tracking_serial_id where in the tracking table are we + * @param total_amount value of all missing deposits, including fees + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TAH_PG_insert_early_aggregation ( + void *cls, + uint64_t batch_deposit_serial_id, + uint64_t tracking_serial_id, + const struct TALER_Amount *total_amount); + +#endif diff --git a/src/auditordb/pg_template.c b/src/auditordb/pg_template.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2024 Taler Systems SA + Copyright (C) 2025 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/src/auditordb/pg_template.h b/src/auditordb/pg_template.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2024 Taler Systems SA + Copyright (C) 2025 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c @@ -23,6 +23,7 @@ #include "taler_pq_lib.h" #include <pthread.h> #include <libpq-fe.h> +#include "pg_delete_early_aggregation.h" #include "pg_delete_generic.h" #include "pg_delete_pending_deposit.h" #include "pg_delete_purse_info.h" @@ -42,6 +43,7 @@ #include "pg_insert_balance.h" #include "pg_insert_denomination_balance.h" #include "pg_insert_deposit_confirmation.h" +#include "pg_insert_early_aggregation.h" #include "pg_insert_exchange_signkey.h" #include "pg_insert_historic_denom_revenue.h" #include "pg_insert_historic_reserve_revenue.h" @@ -695,6 +697,11 @@ libtaler_plugin_auditordb_postgres_init (void *cls) &TAH_PG_insert_wire_format_inconsistency; plugin->get_wire_format_inconsistency = &TAH_PG_get_wire_format_inconsistency; + plugin->insert_early_aggregation + = &TAH_PG_insert_early_aggregation; + plugin->delete_early_aggregation + = &TAH_PG_delete_early_aggregation; + plugin->insert_wire_out_inconsistency = &TAH_PG_insert_wire_out_inconsistency; plugin->get_wire_out_inconsistency diff --git a/src/exchangedb/pg_template.c b/src/exchangedb/pg_template.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2024 Taler Systems SA + Copyright (C) 2025 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/src/exchangedb/pg_template.h b/src/exchangedb/pg_template.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2024 Taler Systems SA + Copyright (C) 2025 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h @@ -1873,6 +1873,41 @@ struct TALER_AUDITORDB_Plugin /** + * Insert new row into the early aggregation table. This can happen simply + * because of when the taler-helper-auditor-transfer looks at which of the + * two tables. If it is cleared in the next iteration, this is perfectly + * expected. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param batch_deposit_serial_id where in the batch deposit table are we + * @param tracking_serial_id where in the tracking table are we + * @param total_amount value of all missing deposits, including fees + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*insert_early_aggregation)( + void *cls, + uint64_t batch_deposit_serial_id, + uint64_t tracking_serial_id, + const struct TALER_Amount *total_amount); + + + /** + * Delete a row from the early aggregation table. + * Usually done when the expected aggregation + * was finally detected. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param batch_deposit_serial_id which entry to delete + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*delete_early_aggregation)( + void *cls, + uint64_t batch_deposit_serial_id); + + + /** * Insert new row into the pending deposits table. * * @param cls the @e cls of this struct with the plugin-specific state