commit cb9b9098d63dfbbe908cdbdef5f2e0c31856f158
parent ca30b4e11c847d6082555ae69628e5e169999be9
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 9 Mar 2026 17:15:55 +0100
need to return accumulated_total_without_fee in /batch-deposit
Diffstat:
5 files changed, 85 insertions(+), 94 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_post-orders-ORDER_ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ORDER_ID-pay.c
@@ -1036,35 +1036,9 @@ batch_deposit_transaction (
{
const struct PayContext *pc = eg->pc;
enum GNUNET_DB_QueryStatus qs;
- struct TALER_Amount total_without_fees;
uint64_t b_dep_serial;
uint32_t off = 0;
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
- &total_without_fees));
- for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
- {
- struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
- struct TALER_Amount amount_without_fees;
-
- /* might want to group deposits by batch more explicitly ... */
- if (0 != strcmp (eg->exchange_url,
- dc->exchange_url))
- continue;
- if (dc->found_in_db)
- continue;
- if (! dc->in_batch)
- continue;
- GNUNET_assert (0 <=
- TALER_amount_subtract (&amount_without_fees,
- &dc->cdd.amount,
- &dc->deposit_fee));
- GNUNET_assert (0 <=
- TALER_amount_add (&total_without_fees,
- &total_without_fees,
- &amount_without_fees));
- }
qs = TMH_db->insert_deposit_confirmation (
TMH_db->cls,
pc->hc->instance->settings.id,
@@ -1072,7 +1046,7 @@ batch_deposit_transaction (
&pc->check_contract.h_contract_terms,
eg->exchange_url,
pc->check_contract.contract_terms->wire_deadline,
- &total_without_fees,
+ &dr->details.ok.accumulated_total_without_fee,
&eg->wire_fee,
&pc->check_contract.wm->h_wire,
dr->details.ok.exchange_sig,
diff --git a/src/backenddb/pg_insert_deposit.c b/src/backenddb/pg_insert_deposit.c
@@ -72,7 +72,8 @@ TMH_PG_insert_deposit (
",deposit_fee"
",refund_fee"
",settlement_retry_time"
- ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8)");
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8)"
+ " ON CONFLICT DO NOTHING;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_deposit",
params);
diff --git a/src/backenddb/pg_insert_deposit_confirmation.c b/src/backenddb/pg_insert_deposit_confirmation.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022, 2023, 2024 Taler Systems SA
+ Copyright (C) 2022, 2023, 2024, 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
@@ -41,11 +41,12 @@ TMH_PG_insert_deposit_confirmation (
const struct TALER_ExchangePublicKeyP *exchange_pub,
uint64_t *deposit_confirmation_serial_id)
{
- struct GNUNET_DB_EventHeaderP es = {
- .size = htons (sizeof (es)),
- .type = htons (TALER_DBEVENT_MERCHANT_NEW_WIRE_DEADLINE)
- };
struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_AbsoluteNBO nbo
+ = GNUNET_TIME_absolute_hton (wire_transfer_deadline.abs_time);
+ char *nbo_str
+ = GNUNET_STRINGS_data_to_string_alloc (&nbo,
+ sizeof (nbo));
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
@@ -59,9 +60,25 @@ TMH_PG_insert_deposit_confirmation (
GNUNET_PQ_query_param_auto_from_type (exchange_sig),
GNUNET_PQ_query_param_auto_from_type (exchange_pub),
GNUNET_PQ_query_param_timestamp (&wire_transfer_deadline),
+ GNUNET_PQ_query_param_string (nbo_str),
GNUNET_PQ_query_param_end
};
+ bool no_instance;
+ bool no_order;
+ bool no_account;
+ bool no_signkey;
+ bool conflict;
struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("no_instance",
+ &no_instance),
+ GNUNET_PQ_result_spec_bool ("no_order",
+ &no_order),
+ GNUNET_PQ_result_spec_bool ("no_account",
+ &no_account),
+ GNUNET_PQ_result_spec_bool ("no_signkey",
+ &no_signkey),
+ GNUNET_PQ_result_spec_bool ("conflict",
+ &conflict),
GNUNET_PQ_result_spec_uint64 ("deposit_confirmation_serial",
deposit_confirmation_serial_id),
GNUNET_PQ_result_spec_end
@@ -81,54 +98,49 @@ TMH_PG_insert_deposit_confirmation (
check_connection (pg);
PREPARE (pg,
"insert_deposit_confirmation",
- "WITH md AS"
- " (SELECT account_serial, merchant_serial"
- " FROM merchant_accounts"
- " WHERE h_wire=$7"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"
- ", ed AS"
- " (SELECT signkey_serial"
- " FROM merchant_exchange_signing_keys"
- " WHERE exchange_pub=$9"
- " ORDER BY start_date DESC"
- " LIMIT 1)"
- "INSERT INTO merchant_deposit_confirmations"
- "(order_serial"
- ",deposit_timestamp"
- ",exchange_url"
- ",total_without_fee"
- ",wire_fee"
- ",exchange_sig"
- ",wire_transfer_deadline"
- ",signkey_serial"
- ",account_serial)"
- " SELECT "
- " order_serial"
- " ,$3, $4, $5, $6, $8, $10"
- " ,ed.signkey_serial"
- " ,md.account_serial"
- " FROM merchant_contract_terms"
- " JOIN md USING (merchant_serial)"
- " FULL OUTER JOIN ed ON TRUE"
- " WHERE h_contract_terms=$2"
- " RETURNING deposit_confirmation_serial");
+ "SELECT "
+ " out_no_instance AS no_instance"
+ " ,out_no_account AS no_account"
+ " ,out_no_order AS no_order"
+ " ,out_no_signkey AS no_signkey"
+ " ,out_conflict AS conflict"
+ " ,out_deposit_confirmation_serial AS deposit_confirmation_serial"
+ " FROM merchant_do_insert_deposit_confirmation"
+ " ($1, $2 ,$3, $4, $5, $6, $7, $8, $9, $10, $11);");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"insert_deposit_confirmation",
params,
rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ GNUNET_free (nbo_str);
+ GNUNET_break (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs);
+ if (qs < 0)
+ return qs;
+ // FIXME: in the future, return these codes to the client and
+ // return more specific error codes to the client from the API!
+ if (no_instance)
{
- /* inform taler-merchant-depositcheck about new deadline */
- struct GNUNET_TIME_AbsoluteNBO nbo;
-
- nbo = GNUNET_TIME_absolute_hton (wire_transfer_deadline.abs_time);
- GNUNET_PQ_event_notify (pg->conn,
- &es,
- &nbo,
- sizeof (nbo));
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ if (no_order)
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ if (no_account)
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ if (no_signkey)
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ if (conflict)
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
return qs;
}
diff --git a/src/backenddb/pg_insert_deposit_confirmation.sql b/src/backenddb/pg_insert_deposit_confirmation.sql
@@ -20,7 +20,7 @@ CREATE FUNCTION merchant_do_insert_deposit_confirmation (
IN in_h_contract_terms BYTEA,
IN in_deposit_timestamp INT8,
IN in_exchange_url TEXT,
- IN in_total_without_fees taler_amount_currency,
+ IN in_total_without_fee taler_amount_currency,
IN in_wire_fee taler_amount_currency,
IN in_h_wire BYTEA,
IN in_exchange_sig BYTEA,
@@ -32,7 +32,7 @@ CREATE FUNCTION merchant_do_insert_deposit_confirmation (
OUT out_no_account BOOL,
OUT out_no_signkey BOOL,
OUT out_conflict BOOL,
- OUT out_deposit_confirmation_serial)
+ OUT out_deposit_confirmation_serial INT8)
LANGUAGE plpgsql
AS $$
DECLARE
@@ -46,10 +46,11 @@ DECLARE
BEGIN
out_no_instance=TRUE;
-out_no_deposit=TRUE;
+out_no_order=TRUE;
out_no_account=TRUE;
out_no_signkey=TRUE;
out_conflict=FALSE;
+out_deposit_confirmation_serial=0;
-- Which instance are we using?
SELECT merchant_serial
@@ -73,10 +74,10 @@ THEN
END IF;
out_no_account=FALSE;
-SELECT account_serial
- INTO my_account_serial
+SELECT signkey_serial
+ INTO my_signkey_serial
FROM merchant_exchange_signing_keys
- WHERE exchange_pub=in_exchange_pub;
+ WHERE exchange_pub=in_exchange_pub
ORDER BY start_date DESC
LIMIT 1;
IF NOT FOUND
@@ -132,19 +133,22 @@ THEN
) RETURNING deposit_confirmation_serial
INTO out_deposit_confirmation_serial;
ELSE
- IF ( (in_deposit_timestamp != my_record.deposit_timestamp) ||
- (in_wire_transfer_deadline != my_record.wire_transfer_deadline) ||
- ((in_wire_fee).val != (my_record.wire_fee).val) ||
- ((in_wire_frac).val != (my_record.wire_fee).frac) ||
- (in_wire_transfer_deadline != my_record.wire_transfer_deadline) ||
- (my_account_serial != my_record.account_serial) )
+ IF (in_deposit_timestamp,
+ in_wire_transfer_deadline,
+ in_wire_fee,
+ my_account_serial)
+ IS DISTINCT FROM
+ (my_record.deposit_timestamp,
+ my_record.wire_transfer_deadline,
+ my_record.wire_fee,
+ my_record.account_serial)
THEN
out_conflict = TRUE;
out_deposit_confirmation_serial = my_record.deposit_confirmation_serial;
RETURN;
END IF;
- IF ( ((in_total_without_fee).val < (my_record.total_without_fee).val) ||
- ( ((in_total_without_fee).val = (my_record.total_without_fee).val) &&
+ IF ( ((in_total_without_fee).val < (my_record.total_without_fee).val) OR
+ ( ((in_total_without_fee).val = (my_record.total_without_fee).val) AND
((in_total_without_fee).frac <= (my_record.total_without_fee).frac) ) )
THEN
-- new amount smaller or did not change, do NOT update.
@@ -162,7 +166,7 @@ ELSE
END IF;
-- Do notify on TALER_DBEVENT_MERCHANT_NEW_WIRE_DEADLINE
-NOTIFY XFIXME,
- in_notify_arg_str;
+PERFORM pg_notify ('XBZ19D98AK2REYNX93F736A56MT14SCY2EEX7XNXQMNCQ01B121R0',
+ in_notify_arg_str);
END $$;
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
@@ -2735,7 +2735,7 @@ test_insert_deposit (const struct InstanceData *instance,
&deposit->amount_with_fee,
&deposit->deposit_fee));
TEST_COND_RET_ON_FAIL (
- expected_result ==
+ GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
plugin->insert_deposit_confirmation (plugin->cls,
instance->instance.id,
deposit->timestamp,
@@ -3348,7 +3348,7 @@ run_test_deposits (struct TestDeposits_Closure *cls)
&cls->signkey,
&cls->deposits[0],
GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
- /* Test double inserts fail */
+ /* Test double inserts are idempotent */
TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
&cls->signkey,
&cls->deposits[0],