exchange

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

commit e9837976d0c89c2fa7a50b61854d1cf6da5e8705
parent aa97d3af2443e20190dc163959816cc49d9c837b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon, 12 Oct 2026 22:52:44 +0200

fix overlooked PRIMARY KEY on kyc_alerts, only the existing UNIQUE should apply

Diffstat:
Asrc/exchangedb/sql-schema/exchange-0019.sql | 44++++++++++++++++++++++++++++++++++++++++++++
Msrc/exchangedb/sql-schema/meson.build | 1+
Msrc/exchangedb/test_kyc_alerts.c | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/src/exchangedb/sql-schema/exchange-0019.sql b/src/exchangedb/sql-schema/exchange-0019.sql @@ -0,0 +1,44 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2026 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/> +-- + +BEGIN; + +SELECT _v.register_patch('exchange-0019', NULL, NULL); + +SET search_path TO exchange; + + +-- Allow one pending alert per account *and* receiver. +-- +-- kyc_alerts was keyed by h_payto alone, so an account could only have a +-- single pending alert, whatever its trigger_type: the alert for a second +-- receiver was dropped by the producers' ON CONFLICT DO NOTHING, and the +-- first receiver to drain the row deleted it for everybody. Key the table +-- by (trigger_type, h_payto) instead, which also makes the old +-- UNIQUE (trigger_type, h_payto) redundant. Existing rows satisfy both +-- keys, so they are kept as they are. + +ALTER TABLE kyc_alerts + DROP CONSTRAINT kyc_alerts_pkey, + DROP CONSTRAINT kyc_alerts_trigger_type_h_payto_key; + +ALTER TABLE kyc_alerts + ADD PRIMARY KEY (trigger_type, h_payto); + +COMMENT ON TABLE kyc_alerts + IS 'alerts about completed KYC events reliably notifying other components (even if they are not running); at most one pending alert per account and receiver'; + +COMMIT; diff --git a/src/exchangedb/sql-schema/meson.build b/src/exchangedb/sql-schema/meson.build @@ -195,6 +195,7 @@ generated_sql = [ ['exchange-0016.sql', ['exchange-0016.sql']], ['exchange-0017.sql', ['exchange-0017.sql']], ['exchange-0018.sql', ['exchange-0018.sql']], + ['exchange-0019.sql', ['exchange-0019.sql']], ['tops-0001.sql', ['tops-0001.sql']], ] diff --git a/src/exchangedb/test_kyc_alerts.c b/src/exchangedb/test_kyc_alerts.c @@ -19,7 +19,8 @@ * `kyc_alerts` * @author Christian Grothoff * - * Covers #TALER_EXCHANGEDB_do_drain_kyc_alert(). + * Covers #TALER_EXCHANGEDB_do_drain_kyc_alert(), and that the table keeps + * one alert per account and trigger type. * * `kyc_alerts` is a work queue: the stored procedures that change the KYC * state of an account append a row, and taler-exchange-aggregator drains @@ -39,6 +40,11 @@ */ #define AGGREGATOR_TRIGGER 1 +/** + * Trigger type of a (hypothetical) second receiver of alerts. + */ +#define OTHER_TRIGGER 2 + /** * The two accounts we raise alerts for. @@ -200,6 +206,69 @@ check_requeue (struct TALER_EXCHANGEDB_PostgresContext *pg) /** + * Each receiver has its own queue: an account can be queued for two + * receivers at once, and draining it for one leaves it queued for the + * other. + * + * @param pg the database context + * @return 0 on success + */ +static int +check_per_trigger (struct TALER_EXCHANGEDB_PostgresContext *pg) +{ + struct TALER_NormalizedPaytoHashP h_payto; + char *hex; + + /* no producer writes another trigger type yet, so do it by hand */ + hex = TDB_hex (&account[0].h_normalized, + sizeof (account[0].h_normalized)); + FAILIF_C (GNUNET_OK != + TDB_exec (pg, + "INSERT INTO kyc_alerts" + " (h_payto,trigger_type)" + " VALUES (decode('%s','hex'),%d);", + hex, + OTHER_TRIGGER), + GNUNET_free (hex)); + GNUNET_free (hex); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + TALER_EXCHANGEDB_insert_aml_program_failure ( + pg, + 0, + &account[0].h_normalized, + "for the aggregator", + TALER_EC_EXCHANGE_GENERIC_KYC_FAILED)); + /* both alerts for the same account are queued */ + FAILIF (2 != TDB_count (pg, + "FROM kyc_alerts")); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + TALER_EXCHANGEDB_do_drain_kyc_alert (pg, + AGGREGATOR_TRIGGER, + &h_payto)); + FAILIF (0 != GNUNET_memcmp (&h_payto, + &account[0].h_normalized)); + /* draining it for the aggregator leaves the other receiver's alert */ + FAILIF (1 != TDB_count (pg, + "FROM kyc_alerts" + " WHERE trigger_type=%d", + OTHER_TRIGGER)); + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + TALER_EXCHANGEDB_do_drain_kyc_alert (pg, + AGGREGATOR_TRIGGER, + &h_payto)); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + TALER_EXCHANGEDB_do_drain_kyc_alert (pg, + OTHER_TRIGGER, + &h_payto)); + FAILIF (0 != GNUNET_memcmp (&h_payto, + &account[0].h_normalized)); + FAILIF (0 != TDB_count (pg, + "FROM kyc_alerts")); + return 0; +} + + +/** * The checks to run, in order. */ static const struct TDB_Test tests[] = { @@ -211,6 +280,8 @@ static const struct TDB_Test tests[] = { &check_drain }, { "kyc-alerts-requeue", &check_requeue }, + { "kyc-alerts-per-trigger", + &check_per_trigger }, { NULL, NULL } };