commit 6bae1938e96164364c177b13d4f6e7d39d9e378a
parent 2c81efb092330a1ef80b7a7f6742f7b011a10691
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 14 Jun 2026 16:08:11 +0200
implement protocol v37
Diffstat:
9 files changed, 327 insertions(+), 21 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -604,6 +604,10 @@ handle_get_aml (struct TEH_RequestContext *rc,
.handler = &TEH_handler_aml_transfer_debit_get
},
{
+ .op = "wallet-credit",
+ .handler = &TEH_handler_aml_wallet_credit_get
+ },
+ {
.op = NULL,
.handler = NULL
},
diff --git a/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-transfers.c b/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-transfers.c
@@ -30,13 +30,15 @@
#include "taler-exchange-httpd_get-metrics.h"
#include "exchange-database/select_exchange_credit_transfers.h"
#include "exchange-database/select_exchange_debit_transfers.h"
+#include "exchange-database/select_wallet_merges.h"
enum TransferType
{
TT_CREDIT,
TT_DEBIT,
- TT_KYCAUTH
+ TT_KYCAUTH,
+ TT_WALLET
};
@@ -184,6 +186,17 @@ aml_transfer_get (
transfers);
query = "select_exchange_kycauth_transfers";
break;
+ case TT_WALLET:
+ qs = TALER_EXCHANGEDB_select_wallet_merges (
+ TEH_pg,
+ &threshold,
+ offset,
+ limit,
+ have_payto ? &h_payto : NULL,
+ &record_cb,
+ transfers);
+ query = "select_wallet_merges";
+ break;
}
switch (qs)
{
@@ -255,4 +268,17 @@ TEH_handler_aml_transfer_debit_get (
}
+enum MHD_Result
+TEH_handler_aml_wallet_credit_get (
+ struct TEH_RequestContext *rc,
+ const struct TALER_AmlOfficerPublicKeyP *officer_pub,
+ const char *const args[])
+{
+ return aml_transfer_get (rc,
+ officer_pub,
+ TT_WALLET,
+ args);
+}
+
+
/* end of taler-exchange-httpd_aml-decisions_get.c */
diff --git a/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-transfers.h b/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-transfers.h
@@ -76,4 +76,21 @@ TEH_handler_aml_transfer_debit_get (
const char *const args[]);
+/**
+ * Handle a GET "/aml/$OFFICER_PUB/wallet-credit" request. Parses the
+ * request details, checks the signatures and if appropriately authorized
+ * returns the matching wallet-credits.
+ *
+ * @param rc request context
+ * @param officer_pub public key of the AML officer who made the request
+ * @param args GET arguments (should be empty)
+ * @return MHD result code
+ */
+enum MHD_Result
+TEH_handler_aml_wallet_credit_get (
+ struct TEH_RequestContext *rc,
+ const struct TALER_AmlOfficerPublicKeyP *officer_pub,
+ const char *const args[]);
+
+
#endif
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 "35:0:1"
+#define EXCHANGE_PROTOCOL_VERSION "37:0:1"
/**
diff --git a/src/exchangedb/meson.build b/src/exchangedb/meson.build
@@ -229,6 +229,7 @@ libtalerexchangedb = library(
'select_reserve_open_above_serial_id.c',
'select_reserves_in_above_serial_id_by_account.c',
'select_reserves_in_above_serial_id.c',
+ 'select_wallet_merges.c',
'select_wire_out_above_serial_id_by_account.c',
'select_wire_out_above_serial_id.c',
'select_withdrawals_above_serial_id.c',
diff --git a/src/exchangedb/select_wallet_merges.c b/src/exchangedb/select_wallet_merges.c
@@ -0,0 +1,196 @@
+/*
+ This file is part of TALER
+ Copyright (C) 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/select_wallet_merges.c
+ * @brief Implementation of the select_wallet_merges function
+ * @author Christian Grothoff
+ */
+#include "taler/taler_pq_lib.h"
+#include "exchange-database/select_wallet_merges.h"
+#include "helper.h"
+
+/**
+ * Closure for #handle_aml_result.
+ */
+struct SelectTransferContext
+{
+ /**
+ * Function to call on each result.
+ */
+ TALER_EXCHANGEDB_AmlTransferCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct TALER_EXCHANGEDB_PostgresContext *pg;
+
+ /**
+ * Set to #GNUNET_SYSERR on serious errors.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results. Helper function
+ * for #TALER_EXCHANGEDB_select_wallet_merges().
+ *
+ * @param cls closure of type `struct SelectTransferContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+handle_transfer_result (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct SelectTransferContext *stc = cls;
+ struct TALER_EXCHANGEDB_PostgresContext *pg = stc->pg;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ char *payto_uri;
+ uint64_t rowid;
+ struct GNUNET_TIME_Absolute execution_time;
+ struct TALER_Amount amount;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial_id",
+ &rowid),
+ GNUNET_PQ_result_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_PQ_result_spec_absolute_time ("execution_time",
+ &execution_time),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+ &amount),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ stc->status = GNUNET_SYSERR;
+ return;
+ }
+ stc->cb (stc->cb_cls,
+ rowid,
+ payto_uri,
+ execution_time,
+ &amount);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TALER_EXCHANGEDB_select_wallet_merges (
+ struct TALER_EXCHANGEDB_PostgresContext *pg,
+ const struct TALER_Amount *threshold,
+ uint64_t offset,
+ int64_t limit,
+ const struct TALER_NormalizedPaytoHashP *h_payto,
+ TALER_EXCHANGEDB_AmlTransferCallback cb,
+ void *cb_cls)
+{
+ struct SelectTransferContext stc = {
+ .pg = pg,
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .status = GNUNET_OK
+ };
+ uint64_t ulimit = (limit > 0) ? limit : -limit;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&offset),
+ GNUNET_PQ_query_param_uint64 (&ulimit),
+ TALER_PQ_query_param_amount (pg->conn,
+ threshold),
+ NULL != h_payto
+ ? GNUNET_PQ_query_param_auto_from_type (h_payto)
+ : GNUNET_PQ_query_param_null (),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "select_wallet_merges_inc",
+ "SELECT"
+ " pd.purse_decision_serial_id AS serial_id"
+ ",wt.payto_uri"
+ ",pd.action_timestamp AS execution_time"
+ ",pr.amount_with_fee AS amount"
+ " FROM purse_decision pd"
+ " JOIN purse_requests pr"
+ " ON (pr.purse_pub = pd.purse_pub)"
+ " JOIN purse_merges pm"
+ " ON (pm.purse_pub = pd.purse_pub)"
+ " JOIN kyc_targets kt"
+ " ON (kt.target_pub = pm.reserve_pub)"
+ " JOIN wire_targets wt"
+ " ON (wt.h_normalized_payto = kt.h_normalized_payto)"
+ " WHERE kt.is_wallet"
+ " AND NOT pd.refunded"
+ " AND (pd.purse_decision_serial_id > $1)"
+ " AND ( ($4::BYTEA IS NULL) OR (wt.h_normalized_payto=$4) )"
+ " AND ( ( (pr.amount_with_fee).val > ($3::taler_amount).val)"
+ " OR ( ( (pr.amount_with_fee).val >= ($3::taler_amount).val)"
+ " AND ( (pr.amount_with_fee).frac >= ($3::taler_amount).frac) ) )"
+ " ORDER BY pd.purse_decision_serial_id ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "select_wallet_merges_dec",
+ "SELECT"
+ " pd.purse_decision_serial_id AS serial_id"
+ ",wt.payto_uri"
+ ",pd.action_timestamp AS execution_time"
+ ",pr.amount_with_fee AS amount"
+ " FROM purse_decision pd"
+ " JOIN purse_requests pr"
+ " ON (pr.purse_pub = pd.purse_pub)"
+ " JOIN purse_merges pm"
+ " ON (pm.purse_pub = pd.purse_pub)"
+ " JOIN kyc_targets kt"
+ " ON (kt.target_pub = pm.reserve_pub)"
+ " JOIN wire_targets wt"
+ " ON (wt.h_normalized_payto = kt.h_normalized_payto)"
+ " WHERE kt.is_wallet"
+ " AND NOT pd.refunded"
+ " AND (pd.purse_decision_serial_id < $1)"
+ " AND ( ($4::BYTEA IS NULL) OR (wt.h_normalized_payto=$4) )"
+ " AND ( ( (pr.amount_with_fee).val > ($3::taler_amount).val)"
+ " OR ( ( (pr.amount_with_fee).val >= ($3::taler_amount).val)"
+ " AND ( (pr.amount_with_fee).frac >= ($3::taler_amount).frac) ) )"
+ " ORDER BY pd.purse_decision_serial_id DESC"
+ " LIMIT $2");
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ (limit > 0)
+ ? "select_wallet_merges_inc"
+ : "select_wallet_merges_dec",
+ params,
+ &handle_transfer_result,
+ &stc);
+ if (GNUNET_OK != stc.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/include/exchange-database/select_exchange_debit_transfers.h b/src/include/exchange-database/select_exchange_debit_transfers.h
@@ -26,7 +26,6 @@
#include "exchangedb_lib.h"
-/* Callback typedefs */
/**
* Callback that is given AML-relevant transfer data.
*
@@ -44,6 +43,7 @@ typedef void
struct GNUNET_TIME_Absolute execution_time,
const struct TALER_Amount *amount);
+
/**
* Return AML-relevant wire transfer debit data.
*
@@ -57,21 +57,14 @@ typedef void
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
-TALER_EXCHANGEDB_select_exchange_debit_transfers (struct
- TALER_EXCHANGEDB_PostgresContext
- *
- pg,
- const struct TALER_Amount *
- threshold
- ,
- uint64_t offset,
- int64_t limit,
- const struct
- TALER_NormalizedPaytoHashP *
- h_payto,
- TALER_EXCHANGEDB_AmlTransferCallback
- cb,
- void *cb_cls);
+TALER_EXCHANGEDB_select_exchange_debit_transfers (
+ struct TALER_EXCHANGEDB_PostgresContext *pg,
+ const struct TALER_Amount *threshold,
+ uint64_t offset,
+ int64_t limit,
+ const struct TALER_NormalizedPaytoHashP *h_payto,
+ TALER_EXCHANGEDB_AmlTransferCallback cb,
+ void *cb_cls);
#endif
diff --git a/src/include/exchange-database/select_wallet_merges.h b/src/include/exchange-database/select_wallet_merges.h
@@ -0,0 +1,70 @@
+/*
+ This file is part of TALER
+ Copyright (C) 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file src/include/exchange-database/select_wallet_merges.h
+ * @brief implementation of the select_wallet_merges function
+ * @author Christian Grothoff
+ */
+#ifndef EXCHANGE_DATABASE_SELECT_WALLET_MERGES_H
+#define EXCHANGE_DATABASE_SELECT_WALLET_MERGES_H
+
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+#include "exchangedb_lib.h"
+
+
+/**
+ * Callback that is given AML-relevant transfer data.
+ *
+ * @param cls closure
+ * @param row_id current row in AML status table
+ * @param payto_uri account involved with the wire transfer
+ * @param execution_time when was the transfer made
+ * @param amount wire amount of the transfer
+ */
+typedef void
+(*TALER_EXCHANGEDB_AmlTransferCallback)(
+ void *cls,
+ uint64_t row_id,
+ const char *payto_uri,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_Amount *amount);
+
+
+/**
+ * Return AML-relevant merges (credits) into a wallet.
+ *
+ * @param pg the database context
+ * @param threshold minimum wire amount to return data for
+ * @param offset offset in table to filter by
+ * @param limit maximum number of entries to return, negative for descending
+ * @param h_payto account to filter transfer data by
+ * @param cb function to call on each result
+ * @param cb_cls closure to pass to @a cb
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TALER_EXCHANGEDB_select_wallet_merges (
+ struct TALER_EXCHANGEDB_PostgresContext *pg,
+ const struct TALER_Amount *threshold,
+ uint64_t offset,
+ int64_t limit,
+ const struct TALER_NormalizedPaytoHashP *h_payto,
+ TALER_EXCHANGEDB_AmlTransferCallback cb,
+ void *cb_cls);
+
+
+#endif
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 35
+#define EXCHANGE_PROTOCOL_CURRENT 37
/**
* How many versions are we backwards compatible with?
*/
-#define EXCHANGE_PROTOCOL_AGE 1
+#define EXCHANGE_PROTOCOL_AGE 3
/**
* Set to 1 for extra debug logging.
@@ -1244,7 +1244,6 @@ TALER_EXCHANGE_decode_keys_json_ (
key_data));
-
/*
* Parse the denomination keys, merging with the
* possibly EXISTING array as required (/keys cherry picking).