commit 4ebee4ebbc7dc4b3710f452a01eaa6309fc0015c
parent 23b13365faafb8fd018c151b069c1aafce7640a9
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 12 Aug 2026 23:51:54 +0200
implement protocol v39 for #10713
Diffstat:
12 files changed, 84 insertions(+), 18 deletions(-)
diff --git a/src/auditor/taler-helper-auditor-aggregation.c b/src/auditor/taler-helper-auditor-aggregation.c
@@ -787,6 +787,8 @@ check_transaction_history_for_deposit (
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param account_pay_uri where did we transfer the funds?
* @param h_payto hash over @a account_payto_uri as it is in the DB
+ * @param exchange_payto_uri which of the exchange's accounts was debited,
+ * `full_payto` NULL if not recorded; unused here
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param denom_pub denomination of @a coin_pub
@@ -803,6 +805,7 @@ wire_transfer_information_cb (
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_FullPayto account_pay_uri,
const struct TALER_FullPaytoHashP *h_payto,
+ const struct TALER_FullPayto exchange_payto_uri,
struct GNUNET_TIME_Timestamp exec_time,
const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_DenominationPublicKey *denom_pub,
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
@@ -761,6 +761,7 @@ trigger_wire_transfer (struct AggregationUnit *au)
&au->wtid,
&au->h_full_payto,
au->wa->section_name,
+ au->wa->payto_uri,
&au->final_amount,
au->extra_wire_subject_metadata);
GNUNET_log (qs >= 0
diff --git a/src/exchange/taler-exchange-httpd_get-config.h b/src/exchange/taler-exchange-httpd_get-config.h
@@ -41,7 +41,7 @@
*
* Returned via both /config and /keys endpoints.
*/
-#define EXCHANGE_PROTOCOL_VERSION "38:0:4"
+#define EXCHANGE_PROTOCOL_VERSION "39:0:5"
/**
diff --git a/src/exchange/taler-exchange-httpd_get-transfers-WTID.c b/src/exchange/taler-exchange-httpd_get-transfers-WTID.c
@@ -89,6 +89,8 @@ struct AggregatedDepositDetail
* @param total total amount that was transferred
* @param merchant_pub public key of the merchant
* @param payto_uri destination account
+ * @param exchange_payto_uri our own account that was debited, `full_payto`
+ * may be NULL if we did not record it
* @param wire_fee wire fee that was charged
* @param exec_time execution time of the wire transfer
* @param wdd_head linked list with details about the combined deposits
@@ -99,6 +101,7 @@ reply_transfer_details (struct MHD_Connection *connection,
const struct TALER_Amount *total,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_FullPayto payto_uri,
+ const struct TALER_FullPayto exchange_payto_uri,
const struct TALER_Amount *wire_fee,
struct GNUNET_TIME_Timestamp exec_time,
const struct AggregatedDepositDetail *wdd_head)
@@ -187,6 +190,11 @@ reply_transfer_details (struct MHD_Connection *connection,
merchant_pub),
GNUNET_JSON_pack_data_auto ("h_payto",
&h_payto),
+ /* Not covered by @e exchange_sig: this is a convenience for the
+ merchant's bookkeeping, not a claim the client needs to prove. */
+ GNUNET_JSON_pack_allow_null (
+ TALER_JSON_pack_full_payto ("exchange_payto_uri",
+ exchange_payto_uri)),
GNUNET_JSON_pack_timestamp ("execution_time",
exec_time),
GNUNET_JSON_pack_array_steal ("deposits",
@@ -249,6 +257,14 @@ struct WtidTransactionContext
struct TALER_FullPayto payto_uri;
/**
+ * Which of our own accounts were the funds wired from?
+ * `full_payto` is NULL if we did not record this, which is
+ * the case for all transfers aggregated before the exchange
+ * started to store it.
+ */
+ struct TALER_FullPayto exchange_payto_uri;
+
+ /**
* JSON array with details about the individual deposits.
*/
json_t *deposits;
@@ -304,6 +320,8 @@ add_refunds (struct TALER_Amount *total,
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param account_payto_uri where the funds were sent
* @param h_payto hash over @a account_payto_uri as it is in the DB
+ * @param exchange_payto_uri our own account the funds were sent from,
+ * `full_payto` NULL if we did not record it
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param denom_pub denomination public key of the @a coin_pub (ignored)
@@ -318,6 +336,7 @@ handle_deposit_data (
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_FullPayto account_payto_uri,
const struct TALER_FullPaytoHashP *h_payto,
+ const struct TALER_FullPayto exchange_payto_uri,
struct GNUNET_TIME_Timestamp exec_time,
const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_DenominationPublicKey *denom_pub,
@@ -403,6 +422,9 @@ handle_deposit_data (
/* First one we encounter, setup general information in 'ctx' */
ctx->merchant_pub = *merchant_pub;
ctx->payto_uri.full_payto = GNUNET_strdup (account_payto_uri.full_payto);
+ if (NULL != exchange_payto_uri.full_payto)
+ ctx->exchange_payto_uri.full_payto
+ = GNUNET_strdup (exchange_payto_uri.full_payto);
ctx->exec_time = exec_time;
ctx->is_valid = GNUNET_YES;
if (0 >
@@ -484,6 +506,7 @@ free_ctx (struct WtidTransactionContext *ctx)
GNUNET_free (wdd);
}
GNUNET_free (ctx->payto_uri.full_payto);
+ GNUNET_free (ctx->exchange_payto_uri.full_payto);
}
@@ -651,6 +674,7 @@ TEH_handler_transfers_get (struct TEH_RequestContext *rc,
&ctx.total,
&ctx.merchant_pub,
ctx.payto_uri,
+ ctx.exchange_payto_uri,
&ctx.fees.wire,
ctx.exec_time,
ctx.wdd_head);
diff --git a/src/exchangedb/insert_wire_out.c b/src/exchangedb/insert_wire_out.c
@@ -30,6 +30,7 @@ TALER_EXCHANGEDB_insert_wire_out (
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_FullPaytoHashP *h_payto,
const char *exchange_account_section,
+ const struct TALER_FullPayto exchange_payto_uri,
const struct TALER_Amount *amount,
const char *extra_wire_subject_metadata)
{
@@ -38,6 +39,9 @@ TALER_EXCHANGEDB_insert_wire_out (
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_string (exchange_account_section),
+ NULL == exchange_payto_uri.full_payto
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (exchange_payto_uri.full_payto),
TALER_PQ_query_param_amount (pg->conn,
amount),
NULL == extra_wire_subject_metadata
@@ -53,10 +57,11 @@ TALER_EXCHANGEDB_insert_wire_out (
",wtid_raw"
",wire_target_h_payto"
",exchange_account_section"
+ ",exchange_payto_uri"
",amount"
",extra_wire_subject_metadata"
") VALUES "
- "($1, $2, $3, $4, $5, $6);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_wire_out",
params);
diff --git a/src/exchangedb/iterate_wire_transfers.c b/src/exchangedb/iterate_wire_transfers.c
@@ -78,6 +78,9 @@ handle_wt_result (void *cls,
struct TALER_Amount deposit_fee;
struct TALER_DenominationPublicKey denom_pub;
struct TALER_FullPayto payto_uri;
+ struct TALER_FullPayto exchange_payto_uri = {
+ .full_payto = NULL
+ };
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id",
&rowid),
@@ -87,6 +90,10 @@ handle_wt_result (void *cls,
&payto_uri.full_payto),
GNUNET_PQ_result_spec_auto_from_type ("wire_target_h_payto",
&h_payto),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("exchange_payto_uri",
+ &exchange_payto_uri.full_payto),
+ NULL),
TALER_PQ_result_spec_denom_pub ("denom_pub",
&denom_pub),
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
@@ -116,6 +123,7 @@ handle_wt_result (void *cls,
&merchant_pub,
payto_uri,
&h_payto,
+ exchange_payto_uri,
exec_time,
&h_contract_terms,
&denom_pub,
@@ -155,11 +163,11 @@ TALER_EXCHANGEDB_iterate_wire_transfers (
",wt.wire_target_h_payto"
",kc.coin_pub"
",bdep.merchant_pub"
- ",wire_out.execution_date"
+ ",wo.execution_date"
",cdep.amount_with_fee"
",denom.fee_deposit"
",denom.denom_pub"
- // ",wo.payto_uri" => FIXME: #10713
+ ",wo.exchange_payto_uri"
" FROM aggregation_tracking"
" JOIN batch_deposits bdep"
" USING (batch_deposit_serial_id)"
diff --git a/src/exchangedb/sql-schema/meson.build b/src/exchangedb/sql-schema/meson.build
@@ -187,6 +187,7 @@ generated_sql = [
['exchange-0011.sql', exchange_0011_sql],
['exchange-0012.sql', exchange_0012_sql],
['exchange-0013.sql', exchange_0013_sql],
+ ['exchange-0014.sql', ['exchange-0014.sql']],
['tops-0001.sql', ['tops-0001.sql']],
]
diff --git a/src/include/exchange-database/insert_wire_out.h b/src/include/exchange-database/insert_wire_out.h
@@ -34,22 +34,21 @@
* @param h_payto identifies the receiver account of the wire transfer
* @param exchange_account_section configuration section of the exchange specifying the
* exchange's bank account being used
+ * @param exchange_payto_uri full payto://-URI of the exchange's bank account
+ * that is being debited, can be NULL
* @param amount amount that was transmitted
* @param extra_wire_subject_metadata additional meta data for the wire transfer subject, can be NULL
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
-TALER_EXCHANGEDB_insert_wire_out (struct
- TALER_EXCHANGEDB_PostgresContext *pg,
- struct GNUNET_TIME_Timestamp date,
- const struct
- TALER_WireTransferIdentifierRawP *wtid
- ,
- const struct TALER_FullPaytoHashP *
- h_payto,
- const char *exchange_account_section,
- const struct TALER_Amount *amount,
- const char *
- extra_wire_subject_metadata);
+TALER_EXCHANGEDB_insert_wire_out (
+ struct TALER_EXCHANGEDB_PostgresContext *pg,
+ struct GNUNET_TIME_Timestamp date,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_FullPaytoHashP *h_payto,
+ const char *exchange_account_section,
+ const struct TALER_FullPayto exchange_payto_uri,
+ const struct TALER_Amount *amount,
+ const char *extra_wire_subject_metadata);
#endif
diff --git a/src/include/exchange-database/iterate_wire_transfers.h b/src/include/exchange-database/iterate_wire_transfers.h
@@ -35,6 +35,9 @@
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param account_payto_uri which account did the transfer go to?
* @param h_payto hash over @a account_payto_uri as it is in the DB
+ * @param exchange_payto_uri which of the exchange's own accounts was debited;
+ * `full_payto` is NULL if the exchange did not record this (transfers
+ * made before the database tracked it)
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param denom_pub denomination of @a coin_pub
@@ -55,6 +58,7 @@ typedef void
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_FullPayto account_payto_uri,
const struct TALER_FullPaytoHashP *h_payto,
+ const struct TALER_FullPayto exchange_payto_uri,
struct GNUNET_TIME_Timestamp exec_time,
const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_DenominationPublicKey *denom_pub,
@@ -73,6 +77,9 @@ typedef void
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param account_payto_uri which account did the transfer go to?
* @param h_payto hash over @a account_payto_uri as it is in the DB
+ * @param exchange_payto_uri which of the exchange's own accounts was debited;
+ * `full_payto` is NULL if the exchange did not record this (transfers
+ * made before the database tracked it)
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param denom_pub denomination of @a coin_pub
@@ -87,6 +94,7 @@ typedef void
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_FullPayto account_payto_uri,
const struct TALER_FullPaytoHashP *h_payto,
+ const struct TALER_FullPayto exchange_payto_uri,
struct GNUNET_TIME_Timestamp exec_time,
const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_DenominationPublicKey *denom_pub,
diff --git a/src/include/taler/exchange/get-transfers-WTID.h b/src/include/taler/exchange/get-transfers-WTID.h
@@ -50,6 +50,16 @@ struct TALER_EXCHANGE_TransferData
struct TALER_FullPaytoHashP h_payto;
/**
+ * Full payto:// URI of the exchange's own bank account the transfer
+ * was made from. `full_payto` is NULL if the exchange did not provide
+ * it; the field is optional as it only exists since protocol v39 and
+ * even then only for transfers the exchange recorded it for.
+ *
+ * Note that this is NOT covered by @e exchange_sig.
+ */
+ struct TALER_FullPayto exchange_payto_uri;
+
+ /**
* Time when the exchange claims to have performed the wire transfer.
*/
struct GNUNET_TIME_Timestamp execution_time;
diff --git a/src/lib/exchange_api_get-transfers-WTID.c b/src/lib/exchange_api_get-transfers-WTID.c
@@ -114,6 +114,13 @@ check_transfers_get_response_ok (
&td->merchant_pub),
GNUNET_JSON_spec_fixed_auto ("h_payto",
&td->h_payto),
+ /* Optional: only exchanges running protocol v39 or later return
+ this, and even those only for transfers they recorded it for.
+ Aliases into @a json, so it needs no cleanup. */
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_full_payto_uri ("exchange_payto_uri",
+ &td->exchange_payto_uri),
+ NULL),
GNUNET_JSON_spec_timestamp ("execution_time",
&td->execution_time),
GNUNET_JSON_spec_array_const ("deposits",
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
@@ -35,12 +35,12 @@
* Which version of the Taler protocol is implemented
* by this library? Used to determine compatibility.
*/
-#define EXCHANGE_PROTOCOL_CURRENT 38
+#define EXCHANGE_PROTOCOL_CURRENT 39
/**
* How many versions are we backwards compatible with?
*/
-#define EXCHANGE_PROTOCOL_AGE 4
+#define EXCHANGE_PROTOCOL_AGE 5
/**
* Set to 1 for extra debug logging.