donau

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

commit 1d9fa76053c5523de38c1cf58f3887ed33fae4dc
parent 736e6a16715b4e43fcb79596a65cfebabda35c59
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri,  7 Aug 2026 00:15:20 +0200

handle soft error with retries

Diffstat:
Msrc/donau/donau-httpd_post-batch-issue-CHARITY_ID.c | 42+++++++++++++++++++++++++++++++-----------
Msrc/donau/donau-httpd_post-batch-submit.c | 25++++++++++++++++++++-----
2 files changed, 51 insertions(+), 16 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 @@ -485,20 +485,40 @@ start: "made blind signatures!\n"); /* save new receipts to date and save receipts Request (blinded signatures, - * charity id, amount, hash over bkps) to make it idempotent*/ - qs_insert_ir - = DONAUDB_do_insert_receipt_issued (DH_context, - year, - num_bkps, - du_sigs, - (uint64_t) charity_id, - &h_receipts, - &receipts_sum, - &smaller_than_max_per_year); + * charity id, amount, hash over bkps) to make it idempotent. + * Two concurrent requests for the same charity update the same + * `charities' row and thus serialize against each other; the database + * reports that as a soft error, which means "retry me". */ + for (unsigned int retries = 0; + retries < MAX_TRANSACTION_COMMIT_RETRIES; + retries++) + { + qs_insert_ir + = DONAUDB_do_insert_receipt_issued (DH_context, + year, + num_bkps, + du_sigs, + (uint64_t) charity_id, + &h_receipts, + &receipts_sum, + &smaller_than_max_per_year); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs_insert_ir) + break; + } switch (qs_insert_ir) { - case GNUNET_DB_STATUS_HARD_ERROR: case GNUNET_DB_STATUS_SOFT_ERROR: + /* still failing after MAX_TRANSACTION_COMMIT_RETRIES attempts */ + 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_SOFT_FAILURE, + NULL); + case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); free_bkps (num_bkps, bkps); diff --git a/src/donau/donau-httpd_post-batch-submit.c b/src/donau/donau-httpd_post-batch-submit.c @@ -27,6 +27,7 @@ #include "taler/taler_mhd_lib.h" #include "taler/taler_signatures.h" #include "donau-httpd_post-batch-submit.h" +#include "donau-httpd_db.h" #include "donau-httpd_get-keys.h" #include "donau-database/insert_receipts_submitted.h" @@ -246,12 +247,26 @@ DH_handler_post_batch_submit (struct DH_RequestContext *rc, { enum GNUNET_DB_QueryStatus qs; - qs = DONAUDB_insert_receipts_submitted (DH_context, - &irc.h_donor_tax_id, - num_dr, - irc.donation_receipts, - irc.donation_year); + /* Concurrent submissions can serialize against each other; the + database reports that as a soft error, which means "retry me". */ + for (unsigned int retries = 0; + retries < MAX_TRANSACTION_COMMIT_RETRIES; + retries++) + { + qs = DONAUDB_insert_receipts_submitted (DH_context, + &irc.h_donor_tax_id, + num_dr, + irc.donation_receipts, + irc.donation_year); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } free_irc (&irc); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + "insert_receipts_submitted"); if (qs < 0) { GNUNET_break (0);