commit 1f66a0f72638f071dd1a30cc617db87f8b8dabef
parent 9ff5cad379154ed45845d02890428362a1a4b2d3
Author: Özgür Kesim <oec@codeblau.de>
Date: Mon, 14 Sep 2026 20:47:05 +0200
exchangedb: recoup procedures return the credited amount
The batch recoup responses report the amount credited per coin,
so exchange_do_recoup_to_reserve() and exchange_do_recoup_to_coin()
now return it (the residual value they credit, or the recorded amount on
an idempotent replay), and do_recoup()/do_recoup_refresh() expose it.
The table and history tests assert it.
Diffstat:
10 files changed, 89 insertions(+), 8 deletions(-)
diff --git a/src/exchangedb/do_recoup.c b/src/exchangedb/do_recoup.c
@@ -19,6 +19,7 @@
* @author Christian Grothoff
*/
#include "taler/taler_pq_lib.h"
+#include "taler/taler_pq_lib.h"
#include "exchange-database/do_recoup.h"
#include "helper.h"
@@ -34,6 +35,7 @@ TALER_EXCHANGEDB_do_recoup (
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
struct GNUNET_TIME_Timestamp *recoup_timestamp,
+ struct TALER_Amount *recoup_amount,
bool *recoup_ok,
bool *internal_failure)
{
@@ -55,11 +57,17 @@ TALER_EXCHANGEDB_do_recoup (
GNUNET_PQ_query_param_end
};
bool is_null;
+ bool amount_is_null;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
recoup_timestamp),
&is_null),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_amount ("recoup_amount",
+ pg->currency,
+ recoup_amount),
+ &amount_is_null),
GNUNET_PQ_result_spec_bool ("recoup_ok",
recoup_ok),
GNUNET_PQ_result_spec_bool ("internal_failure",
@@ -72,12 +80,23 @@ TALER_EXCHANGEDB_do_recoup (
"do_recoup",
"SELECT "
" out_recoup_timestamp AS recoup_timestamp"
+ ",out_recoup_amount AS recoup_amount"
",out_recoup_ok AS recoup_ok"
",out_internal_failure AS internal_failure"
" FROM exchange_do_recoup_to_reserve"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"do_recoup",
params,
rs);
+ if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ||
+ amount_is_null)
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pg->currency,
+ recoup_amount));
+ return qs;
+ }
}
diff --git a/src/exchangedb/do_recoup.sql b/src/exchangedb/do_recoup.sql
@@ -31,7 +31,8 @@ CREATE FUNCTION exchange_do_recoup_to_reserve(
IN in_recoup_timestamp INT8,
OUT out_recoup_ok BOOLEAN,
OUT out_internal_failure BOOLEAN,
- OUT out_recoup_timestamp INT8)
+ OUT out_recoup_timestamp INT8,
+ OUT out_recoup_amount taler_amount)
LANGUAGE plpgsql
AS $$
DECLARE
@@ -73,15 +74,21 @@ THEN
-- withdraw operation and position counts, a recoup of the same
-- coin for another operation means the coin has nothing left.
SELECT
- recoup_timestamp
+ recoup_timestamp
+ ,amount
INTO
- out_recoup_timestamp
+ rval
FROM exchange.recoup
WHERE coin_pub=in_coin_pub
AND withdraw_id=in_withdraw_id
AND coin_index=in_coin_index;
out_recoup_ok=FOUND;
+ IF FOUND
+ THEN
+ out_recoup_timestamp=rval.recoup_timestamp;
+ out_recoup_amount=rval.amount;
+ END IF;
RETURN;
END IF;
@@ -153,6 +160,7 @@ VALUES
-- Normal end, everything is fine.
out_recoup_ok=TRUE;
out_recoup_timestamp=in_recoup_timestamp;
+out_recoup_amount=tmp;
END $$;
diff --git a/src/exchangedb/do_recoup_refresh.c b/src/exchangedb/do_recoup_refresh.c
@@ -34,6 +34,7 @@ TALER_EXCHANGEDB_do_recoup_refresh (
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
struct GNUNET_TIME_Timestamp *recoup_timestamp,
+ struct TALER_Amount *recoup_amount,
bool *recoup_ok,
bool *internal_failure)
{
@@ -49,11 +50,17 @@ TALER_EXCHANGEDB_do_recoup_refresh (
GNUNET_PQ_query_param_end
};
bool is_null;
+ bool amount_is_null;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
recoup_timestamp),
&is_null),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_amount ("recoup_amount",
+ pg->currency,
+ recoup_amount),
+ &amount_is_null),
GNUNET_PQ_result_spec_bool ("recoup_ok",
recoup_ok),
GNUNET_PQ_result_spec_bool ("internal_failure",
@@ -66,13 +73,24 @@ TALER_EXCHANGEDB_do_recoup_refresh (
"do_recoup_refresh",
"SELECT "
" out_recoup_timestamp AS recoup_timestamp"
+ ",out_recoup_amount AS recoup_amount"
",out_recoup_ok AS recoup_ok"
",out_internal_failure AS internal_failure"
" FROM exchange_do_recoup_to_coin"
" ($1,$2,$3,$4,$5,$6,$7,$8);");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"do_recoup_refresh",
params,
rs);
+ if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ||
+ amount_is_null)
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pg->currency,
+ recoup_amount));
+ return qs;
+ }
}
diff --git a/src/exchangedb/do_recoup_refresh.sql b/src/exchangedb/do_recoup_refresh.sql
@@ -26,7 +26,8 @@ CREATE FUNCTION exchange_do_recoup_to_coin(
IN in_recoup_timestamp INT8,
OUT out_recoup_ok BOOLEAN,
OUT out_internal_failure BOOLEAN,
- OUT out_recoup_timestamp INT8)
+ OUT out_recoup_timestamp INT8,
+ OUT out_recoup_amount taler_amount)
LANGUAGE plpgsql
AS $$
DECLARE
@@ -65,14 +66,20 @@ THEN
-- refresh operation and position counts, a recoup of the same
-- coin for another operation means the coin has nothing left.
SELECT
- recoup_timestamp
+ recoup_timestamp
+ ,amount
INTO
- out_recoup_timestamp
+ rval
FROM recoup_refresh
WHERE coin_pub=in_coin_pub
AND refresh_id=in_refresh_id
AND coin_index=in_coin_index;
out_recoup_ok=FOUND;
+ IF FOUND
+ THEN
+ out_recoup_timestamp=rval.recoup_timestamp;
+ out_recoup_amount=rval.amount;
+ END IF;
RETURN;
END IF;
@@ -132,6 +139,7 @@ VALUES
-- Normal end, everything is fine.
out_recoup_ok=TRUE;
out_recoup_timestamp=in_recoup_timestamp;
+out_recoup_amount=tmp;
END $$;
diff --git a/src/exchangedb/test_coin_history.c b/src/exchangedb/test_coin_history.c
@@ -637,6 +637,7 @@ check_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg)
struct TALER_CoinSpendSignatureP coin_sig;
union GNUNET_CRYPTO_BlindingSecretP coin_bks;
struct GNUNET_TIME_Timestamp recoup_timestamp;
+ struct TALER_Amount recoup_amount;
struct TALER_Amount balance;
struct TALER_Amount zero = TDB_amount ("0");
struct TALER_DenominationHashP h_denom_pub;
@@ -662,6 +663,7 @@ check_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg)
known_coin_id,
&coin_sig,
&recoup_timestamp,
+ &recoup_amount,
&recoup_ok,
&internal_failure));
FAILIF (internal_failure);
@@ -783,6 +785,7 @@ check_recoup_refresh (struct TALER_EXCHANGEDB_PostgresContext *pg)
struct TALER_CoinSpendSignatureP coin_sig;
union GNUNET_CRYPTO_BlindingSecretP coin_bks;
struct GNUNET_TIME_Timestamp recoup_timestamp;
+ struct TALER_Amount recoup_amount;
struct TALER_Amount balance;
struct TALER_Amount zero = TDB_amount ("0");
struct TALER_Amount credited = TDB_amount ("0.1");
@@ -839,11 +842,15 @@ check_recoup_refresh (struct TALER_EXCHANGEDB_PostgresContext *pg)
fresh_known_coin_id,
&coin_sig,
&recoup_timestamp,
+ &recoup_amount,
&recoup_ok,
&internal_failure),
TDB_coin_free (&fresh_coin));
FAILIF_C (internal_failure || ! recoup_ok,
TDB_coin_free (&fresh_coin));
+ FAILIF_C (0 != TALER_amount_cmp (&recoup_amount,
+ &credited),
+ TDB_coin_free (&fresh_coin));
/* the old coin is credited and sees the receiver entry */
FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
diff --git a/src/exchangedb/test_recoup.c b/src/exchangedb/test_recoup.c
@@ -155,6 +155,11 @@ struct RecoupStatus
* When the recoup happened.
*/
struct GNUNET_TIME_Timestamp recoup_timestamp;
+
+ /**
+ * Amount the recoup credited.
+ */
+ struct TALER_Amount recoup_amount;
};
@@ -201,6 +206,7 @@ run_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg,
known_coin_id,
&coin_sig,
&st->recoup_timestamp,
+ &st->recoup_amount,
&st->recoup_ok,
&st->internal_failure);
}
diff --git a/src/exchangedb/test_recoup_refresh.c b/src/exchangedb/test_recoup_refresh.c
@@ -208,6 +208,11 @@ struct RecoupStatus
* When the recoup happened.
*/
struct GNUNET_TIME_Timestamp recoup_timestamp;
+
+ /**
+ * Amount the recoup credited.
+ */
+ struct TALER_Amount recoup_amount;
};
@@ -254,6 +259,7 @@ run_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg,
known_coin_id,
&coin_sig,
&st->recoup_timestamp,
+ &st->recoup_amount,
&st->recoup_ok,
&st->internal_failure);
}
diff --git a/src/exchangedb/test_reserve_history.c b/src/exchangedb/test_reserve_history.c
@@ -311,6 +311,7 @@ check_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg)
struct TALER_CoinSpendSignatureP coin_sig;
union GNUNET_CRYPTO_BlindingSecretP coin_bks;
struct GNUNET_TIME_Timestamp recoup_timestamp;
+ struct TALER_Amount recoup_amount;
struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
struct TALER_Amount balance;
struct TALER_Amount expect_value = TDB_amount ("5");
@@ -361,11 +362,15 @@ check_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg)
known_coin_id,
&coin_sig,
&recoup_timestamp,
+ &recoup_amount,
&recoup_ok,
&internal_failure),
TDB_coin_free (&coin); TDB_denom_free (&denom));
FAILIF_C (internal_failure || ! recoup_ok,
TDB_coin_free (&coin); TDB_denom_free (&denom));
+ FAILIF_C (0 != TALER_amount_cmp (&recoup_amount,
+ &expect_value),
+ TDB_coin_free (&coin); TDB_denom_free (&denom));
FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
TALER_EXCHANGEDB_get_reserve_history (pg,
&reserve_pub,
diff --git a/src/include/exchange-database/do_recoup.h b/src/include/exchange-database/do_recoup.h
@@ -39,6 +39,7 @@
* @param known_coin_id row of the @a coin_pub in the known_coins table
* @param coin_sig signature of the coin requesting the recoup
* @param[in,out] recoup_timestamp recoup timestamp, set if recoup existed
+ * @param[out] recoup_amount set to the amount credited (zero if the recoup did not happen)
* @param[out] recoup_ok set if the recoup succeeded (balance ok)
* @param[out] internal_failure set on internal failures
* @return query execution status
@@ -53,6 +54,7 @@ TALER_EXCHANGEDB_do_recoup (struct TALER_EXCHANGEDB_PostgresContext *pg,
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
struct GNUNET_TIME_Timestamp *recoup_timestamp,
+ struct TALER_Amount *recoup_amount,
bool *recoup_ok,
bool *internal_failure);
diff --git a/src/include/exchange-database/do_recoup_refresh.h b/src/include/exchange-database/do_recoup_refresh.h
@@ -40,6 +40,7 @@
* @param known_coin_id row of the @a coin_pub in the known_coins table
* @param coin_sig signature of the coin requesting the recoup
* @param[in,out] recoup_timestamp recoup timestamp, set if recoup existed
+ * @param[out] recoup_amount set to the amount credited (zero if the recoup did not happen)
* @param[out] recoup_ok set if the recoup-refresh succeeded (balance ok)
* @param[out] internal_failure set on internal failures
* @return query execution status
@@ -62,6 +63,7 @@ TALER_EXCHANGEDB_do_recoup_refresh (struct
TALER_CoinSpendSignatureP *coin_sig,
struct GNUNET_TIME_Timestamp *
recoup_timestamp,
+ struct TALER_Amount *recoup_amount,
bool *recoup_ok,
bool *internal_failure);