commit 53613e2fe786575a5efa9890ccf39e85005e47f5
parent d442697a1f276471a15012c8eba802e725acfebc
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 2 Jan 2025 10:30:11 +0100
fix FIXMEs in taler-helper-auditor-purses: check deletion/refund status and deletion signature
Diffstat:
7 files changed, 395 insertions(+), 74 deletions(-)
diff --git a/src/auditor/taler-helper-auditor-purses.c b/src/auditor/taler-helper-auditor-purses.c
@@ -49,6 +49,7 @@ static int test_mode;
*/
static TALER_ARL_DEF_PP (purse_account_merge_serial_id);
static TALER_ARL_DEF_PP (purse_decision_serial_id);
+static TALER_ARL_DEF_PP (purse_deletion_serial_id);
static TALER_ARL_DEF_PP (purse_deposits_serial_id);
static TALER_ARL_DEF_PP (purse_merges_serial_id);
static TALER_ARL_DEF_PP (purse_request_serial_id);
@@ -325,15 +326,16 @@ struct PurseSummary
bool had_pi;
/**
- * Was the purse deleted? FIXME: Not yet handled (do we need to? purse
- * might just appear as expired eventually; but in the meantime, exchange
- * may seem to have refunded the coins for no good reason...), also we do
- * not yet check the deletion signature.
+ * Was the purse deleted? Note: as this is set via an UPDATE, it
+ * may be false at the auditor even if the purse was deleted. Thus,
+ * this value is only meaningful for *internal* checks.
*/
bool purse_deleted;
/**
- * Was the purse refunded? FIXME: Not yet handled (do we need to?)
+ * Was the purse refunded? Note: as this is set via an UPDATE, it
+ * may be false at the auditor even if the purse was deleted. Thus,
+ * this value is only meaningful for *internal* checks.
*/
bool purse_refunded;
@@ -401,7 +403,7 @@ struct PurseContext
/**
- * Create a new reserve for @a reserve_pub in @a rc.
+ * Create a new purse for @a purse_pub in @a pc.
*
* @param[in,out] pc context to update
* @param purse_pub key for which to create a purse
@@ -987,6 +989,20 @@ handle_purse_decision (
return GNUNET_SYSERR;
}
}
+ if ( (internal_checks) &&
+ (! ps->purse_refunded) )
+ {
+ qs = report_row_inconsistency (
+ "purse-decision",
+ rowid,
+ "purse not marked as refunded (internal check)");
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ pc->qs = qs;
+ return GNUNET_SYSERR;
+ }
+ }
}
else
{
@@ -1033,6 +1049,67 @@ handle_purse_decision (
/**
+ * Function called on explicitly deleted purses.
+ *
+ * @param cls closure
+ * @param deletion_serial_id row ID with the deletion data
+ * @param purse_pub public key of the purse
+ * @param purse_sig signature affirming deletion of the purse
+ * @return #GNUNET_OK to continue to iterate
+ */
+static enum GNUNET_GenericReturnValue
+handle_purse_deletion (
+ void *cls,
+ uint64_t deletion_serial_id,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_PurseContractSignatureP *purse_sig)
+{
+ struct PurseContext *pc = cls;
+ struct PurseSummary *ps;
+
+ ps = setup_purse (pc,
+ purse_pub);
+ if (GNUNET_OK !=
+ TALER_wallet_purse_delete_verify (purse_pub,
+ purse_sig))
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = report_row_inconsistency (
+ "purse-delete",
+ deletion_serial_id,
+ "purse deletion signature invalid");
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ pc->qs = qs;
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ if ( (internal_checks) &&
+ (! ps->purse_deleted) )
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = report_row_inconsistency (
+ "purse-delete",
+ deletion_serial_id,
+ "purse not marked as deleted (internal check)");
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ pc->qs = qs;
+ return GNUNET_SYSERR;
+ }
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+/**
* Function called on expired purses.
*
* @param cls closure
@@ -1056,7 +1133,6 @@ handle_purse_expired (
.purse_pub = purse_pub->eddsa_pub
};
- (void) pc;
qs = TALER_ARL_adb->insert_purse_not_closed_inconsistencies (
TALER_ARL_adb->cls,
&pnci);
@@ -1203,6 +1279,8 @@ analyze_purses (void *cls)
{
struct PurseContext pc;
enum GNUNET_DB_QueryStatus qs;
+ bool had_pp;
+ bool had_bal;
(void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1211,6 +1289,7 @@ analyze_purses (void *cls)
TALER_ARL_adb->cls,
TALER_ARL_GET_PP (purse_account_merge_serial_id),
TALER_ARL_GET_PP (purse_decision_serial_id),
+ TALER_ARL_GET_PP (purse_deletion_serial_id),
TALER_ARL_GET_PP (purse_deposits_serial_id),
TALER_ARL_GET_PP (purse_merges_serial_id),
TALER_ARL_GET_PP (purse_request_serial_id),
@@ -1221,26 +1300,29 @@ analyze_purses (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 this 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 purse audit at %llu/%llu/%llu/%llu/%llu\n",
+ "Resuming purse audit at %llu/%llu/%llu/%llu/%llu/%llu\n",
(unsigned long long) TALER_ARL_USE_PP (
purse_request_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
purse_decision_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
+ purse_deletion_serial_id),
+ (unsigned long long) TALER_ARL_USE_PP (
purse_merges_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
purse_deposits_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
purse_account_merge_serial_id));
}
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+ "First analysis using this auditor, starting audit from scratch\n");
+ }
pc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
qs = TALER_ARL_adb->get_balance (
TALER_ARL_adb->cls,
@@ -1257,6 +1339,7 @@ analyze_purses (void *cls)
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
+ had_bal = (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
pc.purses = GNUNET_CONTAINER_multihashmap_create (512,
GNUNET_NO);
@@ -1340,6 +1423,22 @@ analyze_purses (void *cls)
return pc.qs;
}
+ qs = TALER_ARL_edb->select_all_purse_deletions_above_serial_id (
+ TALER_ARL_edb->cls,
+ TALER_ARL_USE_PP (purse_deletion_serial_id),
+ &handle_purse_deletion,
+ &pc);
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ return qs;
+ }
+ if (pc.qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == pc.qs);
+ return pc.qs;
+ }
+
qs = TALER_ARL_adb->select_purse_expired (
TALER_ARL_adb->cls,
&handle_purse_expired,
@@ -1369,52 +1468,28 @@ analyze_purses (void *cls)
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == pc.qs);
return pc.qs;
}
-
- qs = TALER_ARL_adb->insert_balance (
- TALER_ARL_adb->cls,
- TALER_ARL_SET_AB (purse_global_balance),
- TALER_ARL_SET_AB (purse_total_balance_insufficient_loss),
- TALER_ARL_SET_AB (purse_total_delayed_decisions),
- TALER_ARL_SET_AB (purse_total_balance_purse_not_closed),
- TALER_ARL_SET_AB (purse_total_arithmetic_delta_plus),
- TALER_ARL_SET_AB (purse_total_arithmetic_delta_minus),
- TALER_ARL_SET_AB (purse_total_bad_sig_loss),
- 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_balance (
- TALER_ARL_adb->cls,
- TALER_ARL_SET_AB (purse_global_balance),
- TALER_ARL_SET_AB (purse_total_balance_insufficient_loss),
- TALER_ARL_SET_AB (purse_total_delayed_decisions),
- TALER_ARL_SET_AB (purse_total_balance_purse_not_closed),
- TALER_ARL_SET_AB (purse_total_arithmetic_delta_plus),
- TALER_ARL_SET_AB (purse_total_arithmetic_delta_minus),
- TALER_ARL_SET_AB (purse_total_bad_sig_loss),
- 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->insert_auditor_progress (
- TALER_ARL_adb->cls,
- TALER_ARL_SET_PP (purse_account_merge_serial_id),
- TALER_ARL_SET_PP (purse_decision_serial_id),
- TALER_ARL_SET_PP (purse_deposits_serial_id),
- TALER_ARL_SET_PP (purse_merges_serial_id),
- TALER_ARL_SET_PP (purse_request_serial_id),
- TALER_ARL_SET_PP (purse_open_counter),
- NULL);
+ if (had_bal)
+ qs = TALER_ARL_adb->update_balance (
+ TALER_ARL_adb->cls,
+ TALER_ARL_SET_AB (purse_global_balance),
+ TALER_ARL_SET_AB (purse_total_balance_insufficient_loss),
+ TALER_ARL_SET_AB (purse_total_delayed_decisions),
+ TALER_ARL_SET_AB (purse_total_balance_purse_not_closed),
+ TALER_ARL_SET_AB (purse_total_arithmetic_delta_plus),
+ TALER_ARL_SET_AB (purse_total_arithmetic_delta_minus),
+ TALER_ARL_SET_AB (purse_total_bad_sig_loss),
+ NULL);
+ else
+ qs = TALER_ARL_adb->insert_balance (
+ TALER_ARL_adb->cls,
+ TALER_ARL_SET_AB (purse_global_balance),
+ TALER_ARL_SET_AB (purse_total_balance_insufficient_loss),
+ TALER_ARL_SET_AB (purse_total_delayed_decisions),
+ TALER_ARL_SET_AB (purse_total_balance_purse_not_closed),
+ TALER_ARL_SET_AB (purse_total_arithmetic_delta_plus),
+ TALER_ARL_SET_AB (purse_total_arithmetic_delta_minus),
+ TALER_ARL_SET_AB (purse_total_bad_sig_loss),
+ NULL);
if (0 > qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1422,16 +1497,28 @@ analyze_purses (void *cls)
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 (purse_account_merge_serial_id),
- TALER_ARL_SET_PP (purse_decision_serial_id),
- TALER_ARL_SET_PP (purse_deposits_serial_id),
- TALER_ARL_SET_PP (purse_merges_serial_id),
- TALER_ARL_SET_PP (purse_request_serial_id),
- TALER_ARL_SET_PP (purse_open_counter),
- NULL);
+ if (had_pp)
+ qs = TALER_ARL_adb->update_auditor_progress (
+ TALER_ARL_adb->cls,
+ TALER_ARL_SET_PP (purse_account_merge_serial_id),
+ TALER_ARL_SET_PP (purse_decision_serial_id),
+ TALER_ARL_SET_PP (purse_deletion_serial_id),
+ TALER_ARL_SET_PP (purse_deposits_serial_id),
+ TALER_ARL_SET_PP (purse_merges_serial_id),
+ TALER_ARL_SET_PP (purse_request_serial_id),
+ TALER_ARL_SET_PP (purse_open_counter),
+ NULL);
+ else
+ qs = TALER_ARL_adb->insert_auditor_progress (
+ TALER_ARL_adb->cls,
+ TALER_ARL_SET_PP (purse_account_merge_serial_id),
+ TALER_ARL_SET_PP (purse_decision_serial_id),
+ TALER_ARL_SET_PP (purse_deletion_serial_id),
+ TALER_ARL_SET_PP (purse_deposits_serial_id),
+ TALER_ARL_SET_PP (purse_merges_serial_id),
+ TALER_ARL_SET_PP (purse_request_serial_id),
+ TALER_ARL_SET_PP (purse_open_counter),
+ NULL);
if (0 > qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1440,12 +1527,14 @@ analyze_purses (void *cls)
return qs;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Concluded purse audit step at %llu/%llu/%llu/%llu/%llu\n",
+ "Concluded purse audit step at %llu/%llu/%llu/%llu/%llu/%llu\n",
(unsigned long long) TALER_ARL_USE_PP (
purse_request_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
purse_decision_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
+ purse_deletion_serial_id),
+ (unsigned long long) TALER_ARL_USE_PP (
purse_merges_serial_id),
(unsigned long long) TALER_ARL_USE_PP (
purse_deposits_serial_id),
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
@@ -271,6 +271,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_select_aggregation_transient.h pg_select_aggregation_transient.c \
pg_select_aggregations_above_serial.h pg_select_aggregations_above_serial.c \
pg_select_all_purse_decisions_above_serial_id.h pg_select_all_purse_decisions_above_serial_id.c \
+ pg_select_all_purse_deletions_above_serial_id.h pg_select_all_purse_deletions_above_serial_id.c \
pg_select_aml_attributes.h pg_select_aml_attributes.c \
pg_select_aml_decisions.h pg_select_aml_decisions.c \
pg_select_aml_measures.h pg_select_aml_measures.c \
diff --git a/src/exchangedb/pg_select_all_purse_decisions_above_serial_id.c b/src/exchangedb/pg_select_all_purse_decisions_above_serial_id.c
@@ -126,7 +126,7 @@ TEH_PG_select_all_purse_decisions_above_serial_id (
enum GNUNET_DB_QueryStatus qs;
PREPARE (pg,
- "audit_get_all_purse_decision_incr",
+ "audit_select_all_purse_decisions_above_serial_id",
"SELECT"
" purse_pub"
",refunded"
@@ -136,7 +136,7 @@ TEH_PG_select_all_purse_decisions_above_serial_id (
" ORDER BY purse_decision_serial_id ASC;");
qs = GNUNET_PQ_eval_prepared_multi_select (
pg->conn,
- "audit_get_all_purse_decision_incr",
+ "audit_select_all_purse_decisions_above_serial_id",
params,
&all_purse_decision_serial_helper_cb,
&dsc);
diff --git a/src/exchangedb/pg_select_all_purse_deletions_above_serial_id.c b/src/exchangedb/pg_select_all_purse_deletions_above_serial_id.c
@@ -0,0 +1,146 @@
+/*
+ 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 exchangedb/pg_select_all_purse_deletions_above_serial_id.c
+ * @brief Implementation of the select_all_purse_deletions_above_serial_id 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_select_all_purse_deletions_above_serial_id.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #all_purse_deletion_serial_helper_cb().
+ */
+struct AllPurseDeletionSerialContext
+{
+
+ /**
+ * Callback to call.
+ */
+ TALER_EXCHANGEDB_AllPurseDeletionsCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Status code, set to #GNUNET_SYSERR on hard errors.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Helper function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct PurseRefundSerialContext`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+all_purse_deletion_serial_helper_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct AllPurseDeletionSerialContext *dsc = cls;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct TALER_PurseContractPublicKeyP purse_pub;
+ struct TALER_PurseContractSignatureP purse_sig;
+ uint64_t rowid;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
+ &purse_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("purse_sig",
+ &purse_sig),
+ GNUNET_PQ_result_spec_uint64 ("purse_deletion_serial_id",
+ &rowid),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_GenericReturnValue ret;
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ dsc->status = GNUNET_SYSERR;
+ return;
+ }
+ ret = dsc->cb (dsc->cb_cls,
+ rowid,
+ &purse_pub,
+ &purse_sig);
+ GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_all_purse_deletions_above_serial_id (
+ void *cls,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_AllPurseDeletionsCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct AllPurseDeletionSerialContext dsc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .status = GNUNET_OK
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "audit_select_all_purse_deletions_above_serial_id",
+ "SELECT"
+ " purse_pub"
+ ",purse_sig"
+ ",purse_deletion_serial_id"
+ " FROM purse_deletion"
+ " WHERE purse_deletion_serial_id>=$1"
+ " ORDER BY purse_deletion_serial_id ASC;");
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "audit_select_all_purse_deletions_above_serial_id",
+ params,
+ &all_purse_deletion_serial_helper_cb,
+ &dsc);
+ if (GNUNET_OK != dsc.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_all_purse_deletions_above_serial_id.h b/src/exchangedb/pg_select_all_purse_deletions_above_serial_id.h
@@ -0,0 +1,46 @@
+/*
+ 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 exchangedb/pg_select_all_purse_deletions_above_serial_id.h
+ * @brief implementation of the select_all_purse_deletions_above_serial_id function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_ALL_PURSE_DELETIONS_ABOVE_SERIAL_ID_H
+#define PG_SELECT_ALL_PURSE_DELETIONS_ABOVE_SERIAL_ID_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Select all purse deletions above @a serial_id in monotonically increasing
+ * order.
+ *
+ * @param cls closure
+ * @param serial_id highest serial ID to exclude (select strictly larger)
+ * @param cb function to call on each result
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_all_purse_deletions_above_serial_id (
+ void *cls,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_AllPurseDeletionsCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -175,6 +175,7 @@
#include "pg_select_aggregation_transient.h"
#include "pg_select_aggregations_above_serial.h"
#include "pg_select_all_purse_decisions_above_serial_id.h"
+#include "pg_select_all_purse_deletions_above_serial_id.h"
#include "pg_select_aml_attributes.h"
#include "pg_select_aml_decisions.h"
#include "pg_select_aml_measures.h"
@@ -414,6 +415,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_account_merges_above_serial_id;
plugin->select_all_purse_decisions_above_serial_id
= &TEH_PG_select_all_purse_decisions_above_serial_id;
+ plugin->select_all_purse_deletions_above_serial_id
+ = &TEH_PG_select_all_purse_deletions_above_serial_id;
plugin->select_purse
= &TEH_PG_select_purse;
plugin->select_purse_deposits_above_serial_id
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
@@ -2829,6 +2829,24 @@ typedef enum GNUNET_GenericReturnValue
/**
+ * Function called with details about purse deletions that have been made, with
+ * the goal of auditing the purse's execution.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the deposit in our DB
+ * @param purse_pub public key of the purse
+ * @param purse_sig signature affirming deletion of the purse
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+typedef enum GNUNET_GenericReturnValue
+(*TALER_EXCHANGEDB_AllPurseDeletionsCallback)(
+ void *cls,
+ uint64_t rowid,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_PurseContractSignatureP *purse_sig);
+
+
+/**
* Function called with details about purse refunds that have been made, with
* the goal of auditing the purse refund's execution.
*
@@ -5504,7 +5522,7 @@ struct TALER_EXCHANGEDB_Plugin
/**
- * Select all purse refunds above @a serial_id in monotonically increasing
+ * Select all purse decisions above @a serial_id in monotonically increasing
* order.
*
* @param cls closure
@@ -5522,6 +5540,24 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * Select all purse deletions above @a serial_id in monotonically increasing
+ * order.
+ *
+ * @param cls closure
+ * @param serial_id highest serial ID to exclude (select strictly larger)
+ * @param cb function to call on each result
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_all_purse_deletions_above_serial_id)(
+ void *cls,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_AllPurseDeletionsCallback cb,
+ void *cb_cls);
+
+
+ /**
* Select coins deposited into a purse.
*
* @param cls closure