commit ed9e169024d696e4a9c96ec800359ec47232f66f
parent 74388fd3718dc67a7fbf712f6983d71443685b7f
Author: Christian Grothoff <christian@grothoff.org>
Date: Fri, 7 Aug 2026 00:34:17 +0200
distinguish better with unknown charity on inserting receipt
Diffstat:
5 files changed, 48 insertions(+), 6 deletions(-)
diff --git a/src/donau/donau-httpd_post-batch-issue-CHARITY_ID.c b/src/donau/donau-httpd_post-batch-issue-CHARITY_ID.c
@@ -462,6 +462,7 @@ start:
enum TALER_ErrorCode batch_sign_ec;
enum GNUNET_DB_QueryStatus qs_insert_ir;
bool smaller_than_max_per_year = false;
+ bool charity_unknown = false;
for (size_t i = 0; i < num_bkps; i++)
{
@@ -501,7 +502,8 @@ start:
(uint64_t) charity_id,
&h_receipts,
&receipts_sum,
- &smaller_than_max_per_year);
+ &smaller_than_max_per_year,
+ &charity_unknown);
if (GNUNET_DB_STATUS_SOFT_ERROR != qs_insert_ir)
break;
}
@@ -554,6 +556,20 @@ start:
GNUNET_CRYPTO_blinded_sig_decref (du_sigs[i].blinded_sig);
goto start;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ if (charity_unknown)
+ {
+ /* The charity was there when we checked at the top of this handler;
+ a concurrent DELETE /charities/$ID removed it since. */
+ 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_NOT_FOUND,
+ TALER_EC_DONAU_CHARITY_NOT_FOUND,
+ NULL);
+ }
if (! smaller_than_max_per_year)
{
GNUNET_break_op (0);
diff --git a/src/donaudb/do_insert_receipt_issued.c b/src/donaudb/do_insert_receipt_issued.c
@@ -38,7 +38,8 @@ DONAUDB_do_insert_receipt_issued (
uint64_t charity_id,
const struct DONAU_DonationReceiptHashP *h_receipt,
const struct TALER_Amount *amount_receipts_request,
- bool *smaller_than_max_per_year)
+ bool *smaller_than_max_per_year,
+ bool *charity_unknown)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&charity_id),
@@ -54,6 +55,8 @@ DONAUDB_do_insert_receipt_issued (
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("smaller_than_max_per_year",
smaller_than_max_per_year),
+ GNUNET_PQ_result_spec_bool ("charity_unknown",
+ charity_unknown),
GNUNET_PQ_result_spec_end
};
@@ -62,6 +65,7 @@ DONAUDB_do_insert_receipt_issued (
"do_insert_receipt_issued",
"SELECT "
" out_smaller_than_max_per_year AS smaller_than_max_per_year"
+ ",out_charity_unknown AS charity_unknown"
" FROM do_insert_issued_receipts"
"($1,$2,$3,$4,$5);");
diff --git a/src/donaudb/do_insert_receipt_issued.sql b/src/donaudb/do_insert_receipt_issued.sql
@@ -22,6 +22,7 @@ CREATE FUNCTION do_insert_issued_receipts (
,IN in_amount taler_amount -- total amount of the requested receipts
,IN in_year INT4
,OUT out_smaller_than_max_per_year BOOLEAN
+ ,OUT out_charity_unknown BOOLEAN
)
LANGUAGE plpgsql
AS $$
@@ -33,6 +34,9 @@ DECLARE
my_year INT4;
rolled_over BOOLEAN DEFAULT FALSE;
BEGIN
+ out_charity_unknown = FALSE;
+ out_smaller_than_max_per_year = FALSE;
+
-- Get charity values
SELECT
(chari.receipts_to_date).val
@@ -54,6 +58,16 @@ BEGIN
-- installed best-effort and DONAUDB_start_read_committed() exists).
FOR UPDATE OF chari;
+ IF NOT FOUND
+ THEN
+ -- Without this arm every local stays NULL, every comparison below is
+ -- NULL (i.e. false), and the function falls through to the final ELSE
+ -- and answers FALSE -- which the handler reports as "annual limit
+ -- exceeded" for a charity that does not exist.
+ out_charity_unknown = TRUE;
+ RETURN;
+ END IF;
+
IF (my_year > in_year)
THEN
-- server travelled back in time? wild, but
diff --git a/src/donaudb/test_donaudb.c b/src/donaudb/test_donaudb.c
@@ -191,6 +191,7 @@ issue_receipt (uint64_t charity_id,
struct DONAU_BlindedDonationUnitSignature du_sigs[1];
struct DONAU_DonationReceiptHashP h_receipt;
struct TALER_Amount amt;
+ bool charity_unknown;
enum GNUNET_DB_QueryStatus qs;
RND_BLK (&h_receipt);
@@ -205,7 +206,8 @@ issue_receipt (uint64_t charity_id,
charity_id,
&h_receipt,
&amt,
- under_limit);
+ under_limit,
+ &charity_unknown);
GNUNET_CRYPTO_blinded_sig_decref (du_sigs[0].blinded_sig);
return qs;
}
@@ -442,6 +444,7 @@ run (void *cls)
struct DONAU_DonationReceiptHashP h_receipt;
struct TALER_Amount amount_receipts;
bool smaller_than_max_per_year;
+ bool charity_unknown;
struct TALER_DenominationPrivateKey denom_priv;
struct TALER_DenominationPublicKey denom_pub;
struct DONAU_DonationUnitPublicKey du_pub;
@@ -646,7 +649,8 @@ run (void *cls)
charity_id,
&h_receipt,
&amount_receipts,
- &smaller_than_max_per_year));
+ &smaller_than_max_per_year,
+ &charity_unknown));
// FIXME
// FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
diff --git a/src/include/donau-database/do_insert_receipt_issued.h b/src/include/donau-database/do_insert_receipt_issued.h
@@ -34,7 +34,10 @@
* @param charity_id identifier of the charity
* @param h_receipt hash of the donation receipt
* @param amount_receipts_request donation amount
- * @param smaller_than_max_per_year new receipts to day smaller than the max?
+ * @param[out] smaller_than_max_per_year new receipts to day smaller than the max?
+ * @param[out] charity_unknown set to true if there is no charity with
+ * @a charity_id; in that case nothing was written and
+ * @a smaller_than_max_per_year is meaningless
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@@ -46,6 +49,7 @@ DONAUDB_do_insert_receipt_issued (
uint64_t charity_id,
const struct DONAU_DonationReceiptHashP *h_receipt,
const struct TALER_Amount *amount_receipts_request,
- bool *smaller_than_max_per_year);
+ bool *smaller_than_max_per_year,
+ bool *charity_unknown);
#endif