donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 208d112a6ec33adebc7ab6b08a0b400fb5314bc8
parent 0da2155fc1017a211eb4d33cc5a0bc550c41d8b4
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri,  7 Aug 2026 00:23:30 +0200

fix theoretical issue with duplicate receipt_id

Diffstat:
Msrc/donau/donau-httpd_post-batch-issue-CHARITY_ID.c | 20+++++++++++++++++++-
Asrc/donaudb/donau-0004.sql | 32++++++++++++++++++++++++++++++++
Msrc/donaudb/meson.build | 1+
3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/src/donau/donau-httpd_post-batch-issue-CHARITY_ID.c b/src/donau/donau-httpd_post-batch-issue-CHARITY_ID.c @@ -530,7 +530,25 @@ start: TALER_EC_GENERIC_DB_FETCH_FAILED, NULL); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_assert (! second_time); + /* Some unique violation: normally the receipt_hash, i.e. a concurrent + idempotent request whose result we serve from the database below. + It can also be a database-state anomaly (e.g. a desynchronised + receipts_issued identity sequence), in which case the re-read finds + nothing and we end up here a second time. That is a 500, not a + reason to abort() the whole daemon. */ + if (second_time) + { + GNUNET_break (0); + free_bkps (num_bkps, + bkps); + json_decref (blind_signatures); + for (unsigned int i = 0; i<num_bkps; i++) + GNUNET_CRYPTO_blinded_sig_decref (du_sigs[i].blinded_sig); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "receipts_issued"); + } second_time = true; for (unsigned int i = 0; i<num_bkps; i++) GNUNET_CRYPTO_blinded_sig_decref (du_sigs[i].blinded_sig); diff --git a/src/donaudb/donau-0004.sql b/src/donaudb/donau-0004.sql @@ -0,0 +1,32 @@ +-- +-- 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('donau-0004', NULL, NULL); +SET search_path TO donau; + +-- receipts_issued.receipt_id was GENERATED BY DEFAULT AS IDENTITY, which +-- permits explicit inserts (bulk load, partial restore, ad-hoc migration) +-- and thus permits leaving the identity sequence behind the largest stored +-- value. Every subsequent insert then fails with a unique violation on +-- receipts_issued_receipt_id_key -- which donau-httpd cannot distinguish +-- from "this receipt_hash already exists". The value is never supplied by +-- the daemon, so make it unforgeable from the outside. +ALTER TABLE receipts_issued + ALTER COLUMN receipt_id SET GENERATED ALWAYS; + +COMMIT; diff --git a/src/donaudb/meson.build b/src/donaudb/meson.build @@ -32,6 +32,7 @@ generated_sql = [ ['donau-0001.sql', ['donau-0001.sql']], ['donau-0002.sql', donau_0002], ['donau-0003.sql', ['donau-0003.sql']], + ['donau-0004.sql', ['donau-0004.sql']], ]