gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: remove coin and reserve historie


From: gnunet
Subject: [taler-exchange] branch master updated: remove coin and reserve histories from exchange replies
Date: Mon, 18 Sep 2023 19:00:00 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 12cff1b4 remove coin and reserve histories from exchange replies
12cff1b4 is described below

commit 12cff1b4439ab5dcc26fcf79e19518ae1bdce069
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Sep 18 18:59:53 2023 +0200

    remove coin and reserve histories from exchange replies
---
 contrib/gana                                       |   2 +-
 src/auditor/taler-helper-auditor-reserves.c        |  80 --
 src/exchange/Makefile.am                           |   1 -
 src/exchange/taler-exchange-httpd.c                |   6 +-
 src/exchange/taler-exchange-httpd_coins_get.c      | 490 ++++++++++-
 src/exchange/taler-exchange-httpd_reserves_get.c   |   2 +-
 .../taler-exchange-httpd_reserves_history.c        | 429 +++++++---
 .../taler-exchange-httpd_reserves_history.h        |   5 +-
 .../taler-exchange-httpd_reserves_status.c         | 243 ------
 .../taler-exchange-httpd_reserves_status.h         |  43 -
 src/exchange/taler-exchange-httpd_responses.c      | 911 +--------------------
 src/exchange/taler-exchange-httpd_responses.h      |  24 -
 src/exchangedb/Makefile.am                         |   2 -
 src/exchangedb/exchange_do_history_request.sql     | 101 ---
 src/exchangedb/pg_get_reserve_history.c            | 360 +-------
 src/exchangedb/pg_get_reserve_history.h            |  32 +-
 src/exchangedb/pg_insert_history_request.c         |  67 --
 src/exchangedb/pg_insert_history_request.h         |  53 --
 .../pg_select_history_requests_above_serial_id.c   | 156 ----
 .../pg_select_history_requests_above_serial_id.h   |  44 -
 src/exchangedb/plugin_exchangedb_postgres.c        |   8 -
 src/exchangedb/procedures.sql.in                   |   1 -
 src/exchangedb/test_exchangedb.c                   |   1 +
 src/include/taler_crypto_lib.h                     |  46 +-
 src/include/taler_exchange_service.h               | 182 +---
 src/include/taler_exchangedb_plugin.h              |  91 +-
 src/include/taler_testing_lib.h                    |  16 -
 src/lib/Makefile.am                                |   1 -
 src/lib/exchange_api_batch_deposit.c               |  39 +-
 src/lib/exchange_api_common.c                      | 210 +----
 src/lib/exchange_api_common.h                      |   2 -
 src/lib/exchange_api_melt.c                        |  16 -
 src/lib/exchange_api_purse_create_with_deposit.c   | 105 +--
 src/lib/exchange_api_purse_deposit.c               | 111 +--
 src/lib/exchange_api_recoup.c                      |  14 -
 src/lib/exchange_api_recoup_refresh.c              |  33 +-
 src/lib/exchange_api_refund.c                      | 314 -------
 src/lib/exchange_api_reserves_history.c            |  65 +-
 src/lib/exchange_api_reserves_open.c               |  28 +-
 src/lib/exchange_api_reserves_status.c             | 336 --------
 src/lib/exchange_api_withdraw2.c                   | 109 ---
 src/testing/Makefile.am                            |   1 -
 src/testing/test_exchange_api.c                    |   6 +-
 src/testing/test_exchange_p2p.c                    |   4 +-
 src/testing/test_kyc_api.c                         |   4 +-
 src/testing/testing_api_cmd_common.c               |  13 -
 src/testing/testing_api_cmd_reserve_history.c      |  31 +-
 src/testing/testing_api_cmd_reserve_status.c       | 397 ---------
 src/util/wallet_signatures.c                       |  76 +-
 49 files changed, 984 insertions(+), 4327 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index 45da8072..5980339e 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 45da8072036c16d1f7cd39f85d8e293069ab6482
+Subproject commit 5980339e7bf797e0cc90fb65bd1a78a442d253f3
diff --git a/src/auditor/taler-helper-auditor-reserves.c 
b/src/auditor/taler-helper-auditor-reserves.c
index 9f8c75c2..eca3c42a 100644
--- a/src/auditor/taler-helper-auditor-reserves.c
+++ b/src/auditor/taler-helper-auditor-reserves.c
@@ -1260,75 +1260,6 @@ purse_decision_cb (void *cls,
 }
 
 
-/**
- * Function called with details about
- * history requests that have been made, with
- * the goal of auditing the history request execution.
- *
- * @param cls closure
- * @param rowid unique serial ID for the deposit in our DB
- * @param history_fee fee paid for the request
- * @param ts timestamp of the request
- * @param reserve_pub reserve history was requested for
- * @param reserve_sig signature approving the @a history_fee
- * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
- */
-static enum GNUNET_GenericReturnValue
-handle_history_request (
-  void *cls,
-  uint64_t rowid,
-  const struct TALER_Amount *history_fee,
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig)
-{
-  struct ReserveContext *rc = cls;
-  struct ReserveSummary *rs;
-
-  /* should be monotonically increasing */
-  GNUNET_assert (rowid >= ppr.last_history_requests_serial_id);
-  ppr.last_history_requests_serial_id = rowid + 1;
-  if (GNUNET_OK !=
-      TALER_wallet_reserve_history_verify (ts,
-                                           history_fee,
-                                           reserve_pub,
-                                           reserve_sig))
-  {
-    TALER_ARL_report (report_bad_sig_losses,
-                      GNUNET_JSON_PACK (
-                        GNUNET_JSON_pack_string ("operation",
-                                                 "account-history"),
-                        GNUNET_JSON_pack_uint64 ("row",
-                                                 rowid),
-                        TALER_JSON_pack_amount ("loss",
-                                                history_fee),
-                        GNUNET_JSON_pack_data_auto ("key_pub",
-                                                    reserve_pub)));
-    TALER_ARL_amount_add (&total_bad_sig_loss,
-                          &total_bad_sig_loss,
-                          history_fee);
-    return GNUNET_OK;
-  }
-  rs = setup_reserve (rc,
-                      reserve_pub);
-  if (NULL == rs)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  TALER_ARL_amount_add (&balance.history_fee_balance,
-                        &balance.history_fee_balance,
-                        history_fee);
-  TALER_ARL_amount_add (&rs->curr_balance.history_fee_balance,
-                        &rs->curr_balance.history_fee_balance,
-                        history_fee);
-  TALER_ARL_amount_add (&rs->total_out,
-                        &rs->total_out,
-                        history_fee);
-  return GNUNET_OK;
-}
-
-
 /**
  * Check that the reserve summary matches what the exchange database
  * thinks about the reserve, and update our own state of the reserve.
@@ -1773,17 +1704,6 @@ analyze_reserves (void *cls)
     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     return qs;
   }
-  /* Charge history fee! */
-  qs = TALER_ARL_edb->select_history_requests_above_serial_id (
-    TALER_ARL_edb->cls,
-    ppr.last_history_requests_serial_id,
-    &handle_history_request,
-    &rc);
-  if (qs < 0)
-  {
-    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-    return qs;
-  }
   GNUNET_CONTAINER_multihashmap_iterate (rc.reserves,
                                          &verify_reserve_balance,
                                          &rc);
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index dded2b1f..86829edd 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -180,7 +180,6 @@ taler_exchange_httpd_SOURCES = \
   taler-exchange-httpd_reserves_history.c 
taler-exchange-httpd_reserves_history.h \
   taler-exchange-httpd_reserves_open.c taler-exchange-httpd_reserves_open.h \
   taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h \
-  taler-exchange-httpd_reserves_status.c 
taler-exchange-httpd_reserves_status.h \
   taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
   taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
   taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index ad4b50d2..d059e743 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -67,7 +67,6 @@
 #include "taler-exchange-httpd_reserves_history.h"
 #include "taler-exchange-httpd_reserves_open.h"
 #include "taler-exchange-httpd_reserves_purse.h"
-#include "taler-exchange-httpd_reserves_status.h"
 #include "taler-exchange-httpd_terms.h"
 #include "taler-exchange-httpd_transfers_get.h"
 #include "taler-exchange-httpd_withdraw.h"
@@ -732,10 +731,7 @@ handle_post_reserves (struct TEH_RequestContext *rc,
       .op = "withdraw",
       .handler = &TEH_handler_withdraw
     },
-    {
-      .op = "status",
-      .handler = &TEH_handler_reserves_status
-    },
+    // FIXME: change to GET!
     {
       .op = "history",
       .handler = &TEH_handler_reserves_history
diff --git a/src/exchange/taler-exchange-httpd_coins_get.c 
b/src/exchange/taler-exchange-httpd_coins_get.c
index 9f61b38f..c5cf6ba5 100644
--- a/src/exchange/taler-exchange-httpd_coins_get.c
+++ b/src/exchange/taler-exchange-httpd_coins_get.c
@@ -48,6 +48,492 @@ add_response_headers (void *cls,
 }
 
 
+/**
+ * Compile the transaction history of a coin into a JSON object.
+ *
+ * @param coin_pub public key of the coin
+ * @param tl transaction history to JSON-ify
+ * @return json representation of the @a rh, NULL on error
+ */
+static json_t *
+compile_transaction_history (
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  const struct TALER_EXCHANGEDB_TransactionList *tl)
+{
+  json_t *history;
+
+  history = json_array ();
+  if (NULL == history)
+  {
+    GNUNET_break (0); /* out of memory!? */
+    return NULL;
+  }
+  for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl;
+       NULL != pos;
+       pos = pos->next)
+  {
+    switch (pos->type)
+    {
+    case TALER_EXCHANGEDB_TT_DEPOSIT:
+      {
+        const struct TALER_EXCHANGEDB_DepositListEntry *deposit =
+          pos->details.deposit;
+        struct TALER_MerchantWireHashP h_wire;
+
+        TALER_merchant_wire_signature_hash (deposit->receiver_wire_account,
+                                            &deposit->wire_salt,
+                                            &h_wire);
+#if ENABLE_SANITY_CHECKS
+        /* internal sanity check before we hand out a bogus sig... */
+        TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
+        if (GNUNET_OK !=
+            TALER_wallet_deposit_verify (
+              &deposit->amount_with_fee,
+              &deposit->deposit_fee,
+              &h_wire,
+              &deposit->h_contract_terms,
+              deposit->no_wallet_data_hash
+              ? NULL
+              : &deposit->wallet_data_hash,
+              deposit->no_age_commitment
+              ? NULL
+              : &deposit->h_age_commitment,
+              &deposit->h_policy,
+              &deposit->h_denom_pub,
+              deposit->timestamp,
+              &deposit->merchant_pub,
+              deposit->refund_deadline,
+              coin_pub,
+              &deposit->csig))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+#endif
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                // FIXME: offset missing! (here and in all other cases!)
+                GNUNET_JSON_pack_string ("type",
+                                         "DEPOSIT"),
+                TALER_JSON_pack_amount ("amount",
+                                        &deposit->amount_with_fee),
+                TALER_JSON_pack_amount ("deposit_fee",
+                                        &deposit->deposit_fee),
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            deposit->timestamp),
+                GNUNET_JSON_pack_allow_null (
+                  GNUNET_JSON_pack_timestamp ("refund_deadline",
+                                              deposit->refund_deadline)),
+                GNUNET_JSON_pack_data_auto ("merchant_pub",
+                                            &deposit->merchant_pub),
+                GNUNET_JSON_pack_data_auto ("h_contract_terms",
+                                            &deposit->h_contract_terms),
+                GNUNET_JSON_pack_data_auto ("h_wire",
+                                            &h_wire),
+                GNUNET_JSON_pack_allow_null (
+                  deposit->no_age_commitment ?
+                  GNUNET_JSON_pack_string (
+                    "h_age_commitment", NULL) :
+                  GNUNET_JSON_pack_data_auto ("h_age_commitment",
+                                              &deposit->h_age_commitment)),
+                GNUNET_JSON_pack_data_auto ("coin_sig",
+                                            &deposit->csig))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        break;
+      }
+    case TALER_EXCHANGEDB_TT_MELT:
+      {
+        const struct TALER_EXCHANGEDB_MeltListEntry *melt =
+          pos->details.melt;
+        const struct TALER_AgeCommitmentHash *phac = NULL;
+
+#if ENABLE_SANITY_CHECKS
+        TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
+        if (GNUNET_OK !=
+            TALER_wallet_melt_verify (
+              &melt->amount_with_fee,
+              &melt->melt_fee,
+              &melt->rc,
+              &melt->h_denom_pub,
+              &melt->h_age_commitment,
+              coin_pub,
+              &melt->coin_sig))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+#endif
+
+        /* Age restriction is optional.  We communicate a NULL value to
+         * JSON_PACK below */
+        if (! melt->no_age_commitment)
+          phac = &melt->h_age_commitment;
+
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "MELT"),
+                TALER_JSON_pack_amount ("amount",
+                                        &melt->amount_with_fee),
+                TALER_JSON_pack_amount ("melt_fee",
+                                        &melt->melt_fee),
+                GNUNET_JSON_pack_data_auto ("rc",
+                                            &melt->rc),
+                GNUNET_JSON_pack_allow_null (
+                  GNUNET_JSON_pack_data_auto ("h_age_commitment",
+                                              phac)),
+                GNUNET_JSON_pack_data_auto ("coin_sig",
+                                            &melt->coin_sig))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_TT_REFUND:
+      {
+        const struct TALER_EXCHANGEDB_RefundListEntry *refund =
+          pos->details.refund;
+        struct TALER_Amount value;
+
+#if ENABLE_SANITY_CHECKS
+        TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
+        if (GNUNET_OK !=
+            TALER_merchant_refund_verify (
+              coin_pub,
+              &refund->h_contract_terms,
+              refund->rtransaction_id,
+              &refund->refund_amount,
+              &refund->merchant_pub,
+              &refund->merchant_sig))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+#endif
+        if (0 >
+            TALER_amount_subtract (&value,
+                                   &refund->refund_amount,
+                                   &refund->refund_fee))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "REFUND"),
+                TALER_JSON_pack_amount ("amount",
+                                        &value),
+                TALER_JSON_pack_amount ("refund_fee",
+                                        &refund->refund_fee),
+                GNUNET_JSON_pack_data_auto ("h_contract_terms",
+                                            &refund->h_contract_terms),
+                GNUNET_JSON_pack_data_auto ("merchant_pub",
+                                            &refund->merchant_pub),
+                GNUNET_JSON_pack_uint64 ("rtransaction_id",
+                                         refund->rtransaction_id),
+                GNUNET_JSON_pack_data_auto ("merchant_sig",
+                                            &refund->merchant_sig))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
+      {
+        struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
+          pos->details.old_coin_recoup;
+        struct TALER_ExchangePublicKeyP epub;
+        struct TALER_ExchangeSignatureP esig;
+
+        if (TALER_EC_NONE !=
+            TALER_exchange_online_confirm_recoup_refresh_sign (
+              &TEH_keys_exchange_sign_,
+              pr->timestamp,
+              &pr->value,
+              &pr->coin.coin_pub,
+              &pr->old_coin_pub,
+              &epub,
+              &esig))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        /* NOTE: we could also provide coin_pub's coin_sig, denomination key 
hash and
+           the denomination key's RSA signature over coin_pub, but as the
+           wallet should really already have this information (and cannot
+           check or do anything with it anyway if it doesn't), it seems
+           strictly unnecessary. */
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "OLD-COIN-RECOUP"),
+                TALER_JSON_pack_amount ("amount",
+                                        &pr->value),
+                GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                            &esig),
+                GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                            &epub),
+                GNUNET_JSON_pack_data_auto ("coin_pub",
+                                            &pr->coin.coin_pub),
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            pr->timestamp))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        break;
+      }
+    case TALER_EXCHANGEDB_TT_RECOUP:
+      {
+        const struct TALER_EXCHANGEDB_RecoupListEntry *recoup =
+          pos->details.recoup;
+        struct TALER_ExchangePublicKeyP epub;
+        struct TALER_ExchangeSignatureP esig;
+
+        if (TALER_EC_NONE !=
+            TALER_exchange_online_confirm_recoup_sign (
+              &TEH_keys_exchange_sign_,
+              recoup->timestamp,
+              &recoup->value,
+              coin_pub,
+              &recoup->reserve_pub,
+              &epub,
+              &esig))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "RECOUP"),
+                TALER_JSON_pack_amount ("amount",
+                                        &recoup->value),
+                GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                            &esig),
+                GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                            &epub),
+                GNUNET_JSON_pack_data_auto ("reserve_pub",
+                                            &recoup->reserve_pub),
+                GNUNET_JSON_pack_data_auto ("coin_sig",
+                                            &recoup->coin_sig),
+                GNUNET_JSON_pack_data_auto ("coin_blind",
+                                            &recoup->coin_blind),
+                GNUNET_JSON_pack_data_auto ("reserve_pub",
+                                            &recoup->reserve_pub),
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            recoup->timestamp))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_TT_RECOUP_REFRESH:
+      {
+        struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
+          pos->details.recoup_refresh;
+        struct TALER_ExchangePublicKeyP epub;
+        struct TALER_ExchangeSignatureP esig;
+
+        if (TALER_EC_NONE !=
+            TALER_exchange_online_confirm_recoup_refresh_sign (
+              &TEH_keys_exchange_sign_,
+              pr->timestamp,
+              &pr->value,
+              coin_pub,
+              &pr->old_coin_pub,
+              &epub,
+              &esig))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        /* NOTE: we could also provide coin_pub's coin_sig, denomination key
+           hash and the denomination key's RSA signature over coin_pub, but as
+           the wallet should really already have this information (and cannot
+           check or do anything with it anyway if it doesn't), it seems
+           strictly unnecessary. */
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "RECOUP-REFRESH"),
+                TALER_JSON_pack_amount ("amount",
+                                        &pr->value),
+                GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                            &esig),
+                GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                            &epub),
+                GNUNET_JSON_pack_data_auto ("old_coin_pub",
+                                            &pr->old_coin_pub),
+                GNUNET_JSON_pack_data_auto ("coin_sig",
+                                            &pr->coin_sig),
+                GNUNET_JSON_pack_data_auto ("coin_blind",
+                                            &pr->coin_blind),
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            pr->timestamp))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        break;
+      }
+
+    case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT:
+      {
+        struct TALER_EXCHANGEDB_PurseDepositListEntry *pd
+          = pos->details.purse_deposit;
+        const struct TALER_AgeCommitmentHash *phac = NULL;
+
+        if (! pd->no_age_commitment)
+          phac = &pd->h_age_commitment;
+
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "PURSE-DEPOSIT"),
+                TALER_JSON_pack_amount ("amount",
+                                        &pd->amount),
+                GNUNET_JSON_pack_string ("exchange_base_url",
+                                         NULL == pd->exchange_base_url
+                                         ? TEH_base_url
+                                         : pd->exchange_base_url),
+                GNUNET_JSON_pack_allow_null (
+                  GNUNET_JSON_pack_data_auto ("h_age_commitment",
+                                              phac)),
+                GNUNET_JSON_pack_data_auto ("purse_pub",
+                                            &pd->purse_pub),
+                GNUNET_JSON_pack_bool ("refunded",
+                                       pd->refunded),
+                GNUNET_JSON_pack_data_auto ("coin_sig",
+                                            &pd->coin_sig))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        break;
+      }
+
+    case TALER_EXCHANGEDB_TT_PURSE_REFUND:
+      {
+        const struct TALER_EXCHANGEDB_PurseRefundListEntry *prefund =
+          pos->details.purse_refund;
+        struct TALER_Amount value;
+        enum TALER_ErrorCode ec;
+        struct TALER_ExchangePublicKeyP epub;
+        struct TALER_ExchangeSignatureP esig;
+
+        if (0 >
+            TALER_amount_subtract (&value,
+                                   &prefund->refund_amount,
+                                   &prefund->refund_fee))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        ec = TALER_exchange_online_purse_refund_sign (
+          &TEH_keys_exchange_sign_,
+          &value,
+          &prefund->refund_fee,
+          coin_pub,
+          &prefund->purse_pub,
+          &epub,
+          &esig);
+        if (TALER_EC_NONE != ec)
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "PURSE-REFUND"),
+                TALER_JSON_pack_amount ("amount",
+                                        &value),
+                TALER_JSON_pack_amount ("refund_fee",
+                                        &prefund->refund_fee),
+                GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                            &esig),
+                GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                            &epub),
+                GNUNET_JSON_pack_data_auto ("purse_pub",
+                                            &prefund->purse_pub))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+      }
+      break;
+
+    case TALER_EXCHANGEDB_TT_RESERVE_OPEN:
+      {
+        struct TALER_EXCHANGEDB_ReserveOpenListEntry *role
+          = pos->details.reserve_open;
+
+        if (0 !=
+            json_array_append_new (
+              history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "RESERVE-OPEN-DEPOSIT"),
+                TALER_JSON_pack_amount ("coin_contribution",
+                                        &role->coin_contribution),
+                GNUNET_JSON_pack_data_auto ("reserve_sig",
+                                            &role->reserve_sig),
+                GNUNET_JSON_pack_data_auto ("coin_sig",
+                                            &role->coin_sig))))
+        {
+          GNUNET_break (0);
+          json_decref (history);
+          return NULL;
+        }
+        break;
+      }
+    }
+  }
+  return history;
+}
+
+
 MHD_RESULT
 TEH_handler_coins_get (struct TEH_RequestContext *rc,
                        const struct TALER_CoinSpendPublicKeyP *coin_pub)
@@ -118,8 +604,8 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc,
                        sizeof (etagp),
                        "\"%llu\"",
                        (unsigned long long) etag);
-      history = TEH_RESPONSE_compile_transaction_history (coin_pub,
-                                                          tl);
+      history = compile_transaction_history (coin_pub,
+                                             tl);
       TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
                                               tl);
       tl = NULL;
diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c 
b/src/exchange/taler-exchange-httpd_reserves_get.c
index bbaac853..a46886ef 100644
--- a/src/exchange/taler-exchange-httpd_reserves_get.c
+++ b/src/exchange/taler-exchange-httpd_reserves_get.c
@@ -253,7 +253,7 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
       {
         return TALER_MHD_reply_with_error (rc->connection,
                                            MHD_HTTP_NOT_FOUND,
-                                           
TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN,
+                                           
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
                                            args[0]);
       }
       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
diff --git a/src/exchange/taler-exchange-httpd_reserves_history.c 
b/src/exchange/taler-exchange-httpd_reserves_history.c
index ffdc6eaa..1bf73cb2 100644
--- a/src/exchange/taler-exchange-httpd_reserves_history.c
+++ b/src/exchange/taler-exchange-httpd_reserves_history.c
@@ -15,7 +15,7 @@
 */
 /**
  * @file taler-exchange-httpd_reserves_history.c
- * @brief Handle /reserves/$RESERVE_PUB/history requests
+ * @brief Handle /reserves/$RESERVE_PUB HISTORY requests
  * @author Florian Dold
  * @author Benedikt Mueller
  * @author Christian Grothoff
@@ -30,7 +30,6 @@
 #include "taler-exchange-httpd_reserves_history.h"
 #include "taler-exchange-httpd_responses.h"
 
-
 /**
  * How far do we allow a client's time to be off when
  * checking the request timestamp?
@@ -49,26 +48,11 @@ struct ReserveHistoryContext
    */
   const struct TALER_ReservePublicKeyP *reserve_pub;
 
-  /**
-   * Timestamp of the request.
-   */
-  struct GNUNET_TIME_Timestamp timestamp;
-
-  /**
-   * Client signature approving the request.
-   */
-  struct TALER_ReserveSignatureP reserve_sig;
-
   /**
    * History of the reserve, set in the callback.
    */
   struct TALER_EXCHANGEDB_ReserveHistory *rh;
 
-  /**
-   * Global fees applying to the request.
-   */
-  const struct TEH_GlobalFee *gf;
-
   /**
    * Current reserve balance.
    */
@@ -76,6 +60,305 @@ struct ReserveHistoryContext
 };
 
 
+/**
+ * Compile the history of a reserve into a JSON object.
+ *
+ * @param rh reserve history to JSON-ify
+ * @return json representation of the @a rh, NULL on error
+ */
+static json_t *
+compile_reserve_history (
+  const struct TALER_EXCHANGEDB_ReserveHistory *rh)
+{
+  json_t *json_history;
+
+  json_history = json_array ();
+  GNUNET_assert (NULL != json_history);
+  for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
+       NULL != pos;
+       pos = pos->next)
+  {
+    switch (pos->type)
+    {
+    case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
+      {
+        const struct TALER_EXCHANGEDB_BankTransfer *bank =
+          pos->details.bank;
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "CREDIT"),
+                // FIXME: offset missing! (here and in all other cases!)
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            bank->execution_date),
+                GNUNET_JSON_pack_string ("sender_account_url",
+                                         bank->sender_account_details),
+                GNUNET_JSON_pack_uint64 ("wire_reference",
+                                         bank->wire_reference),
+                TALER_JSON_pack_amount ("amount",
+                                        &bank->amount))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+        break;
+      }
+    case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
+      {
+        const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw
+          = pos->details.withdraw;
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "WITHDRAW"),
+                GNUNET_JSON_pack_data_auto ("reserve_sig",
+                                            &withdraw->reserve_sig),
+                GNUNET_JSON_pack_data_auto ("h_coin_envelope",
+                                            &withdraw->h_coin_envelope),
+                GNUNET_JSON_pack_data_auto ("h_denom_pub",
+                                            &withdraw->denom_pub_hash),
+                TALER_JSON_pack_amount ("withdraw_fee",
+                                        &withdraw->withdraw_fee),
+                TALER_JSON_pack_amount ("amount",
+                                        &withdraw->amount_with_fee))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_RO_RECOUP_COIN:
+      {
+        const struct TALER_EXCHANGEDB_Recoup *recoup
+          = pos->details.recoup;
+        struct TALER_ExchangePublicKeyP pub;
+        struct TALER_ExchangeSignatureP sig;
+
+        if (TALER_EC_NONE !=
+            TALER_exchange_online_confirm_recoup_sign (
+              &TEH_keys_exchange_sign_,
+              recoup->timestamp,
+              &recoup->value,
+              &recoup->coin.coin_pub,
+              &recoup->reserve_pub,
+              &pub,
+              &sig))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "RECOUP"),
+                GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                            &pub),
+                GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                            &sig),
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            recoup->timestamp),
+                TALER_JSON_pack_amount ("amount",
+                                        &recoup->value),
+                GNUNET_JSON_pack_data_auto ("coin_pub",
+                                            &recoup->coin.coin_pub))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
+      {
+        const struct TALER_EXCHANGEDB_ClosingTransfer *closing =
+          pos->details.closing;
+        struct TALER_ExchangePublicKeyP pub;
+        struct TALER_ExchangeSignatureP sig;
+
+        if (TALER_EC_NONE !=
+            TALER_exchange_online_reserve_closed_sign (
+              &TEH_keys_exchange_sign_,
+              closing->execution_date,
+              &closing->amount,
+              &closing->closing_fee,
+              closing->receiver_account_details,
+              &closing->wtid,
+              &pos->details.closing->reserve_pub,
+              &pub,
+              &sig))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "CLOSING"),
+                GNUNET_JSON_pack_string ("receiver_account_details",
+                                         closing->receiver_account_details),
+                GNUNET_JSON_pack_data_auto ("wtid",
+                                            &closing->wtid),
+                GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                            &pub),
+                GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                            &sig),
+                GNUNET_JSON_pack_timestamp ("timestamp",
+                                            closing->execution_date),
+                TALER_JSON_pack_amount ("amount",
+                                        &closing->amount),
+                TALER_JSON_pack_amount ("closing_fee",
+                                        &closing->closing_fee))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_RO_PURSE_MERGE:
+      {
+        const struct TALER_EXCHANGEDB_PurseMerge *merge =
+          pos->details.merge;
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "MERGE"),
+                GNUNET_JSON_pack_data_auto ("h_contract_terms",
+                                            &merge->h_contract_terms),
+                GNUNET_JSON_pack_data_auto ("merge_pub",
+                                            &merge->merge_pub),
+                GNUNET_JSON_pack_uint64 ("min_age",
+                                         merge->min_age),
+                GNUNET_JSON_pack_uint64 ("flags",
+                                         merge->flags),
+                GNUNET_JSON_pack_data_auto ("purse_pub",
+                                            &merge->purse_pub),
+                GNUNET_JSON_pack_data_auto ("reserve_sig",
+                                            &merge->reserve_sig),
+                GNUNET_JSON_pack_timestamp ("merge_timestamp",
+                                            merge->merge_timestamp),
+                GNUNET_JSON_pack_timestamp ("purse_expiration",
+                                            merge->purse_expiration),
+                TALER_JSON_pack_amount ("purse_fee",
+                                        &merge->purse_fee),
+                TALER_JSON_pack_amount ("amount",
+                                        &merge->amount_with_fee),
+                GNUNET_JSON_pack_bool ("merged",
+                                       merge->merged))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+    case TALER_EXCHANGEDB_RO_HISTORY_REQUEST:
+      {
+        const struct TALER_EXCHANGEDB_HistoryRequest *history =
+          pos->details.history;
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "HISTORY"),
+                GNUNET_JSON_pack_data_auto ("reserve_sig",
+                                            &history->reserve_sig),
+                GNUNET_JSON_pack_timestamp ("request_timestamp",
+                                            history->request_timestamp),
+                TALER_JSON_pack_amount ("amount",
+                                        &history->history_fee))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+
+    case TALER_EXCHANGEDB_RO_OPEN_REQUEST:
+      {
+        const struct TALER_EXCHANGEDB_OpenRequest *orq =
+          pos->details.open_request;
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "OPEN"),
+                GNUNET_JSON_pack_uint64 ("requested_min_purses",
+                                         orq->purse_limit),
+                GNUNET_JSON_pack_data_auto ("reserve_sig",
+                                            &orq->reserve_sig),
+                GNUNET_JSON_pack_timestamp ("request_timestamp",
+                                            orq->request_timestamp),
+                GNUNET_JSON_pack_timestamp ("requested_expiration",
+                                            orq->reserve_expiration),
+                TALER_JSON_pack_amount ("open_fee",
+                                        &orq->open_fee))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+
+    case TALER_EXCHANGEDB_RO_CLOSE_REQUEST:
+      {
+        const struct TALER_EXCHANGEDB_CloseRequest *crq =
+          pos->details.close_request;
+
+        if (0 !=
+            json_array_append_new (
+              json_history,
+              GNUNET_JSON_PACK (
+                GNUNET_JSON_pack_string ("type",
+                                         "CLOSE"),
+                GNUNET_JSON_pack_data_auto ("reserve_sig",
+                                            &crq->reserve_sig),
+                GNUNET_is_zero (&crq->target_account_h_payto)
+                ? GNUNET_JSON_pack_allow_null (
+                  GNUNET_JSON_pack_string ("h_payto",
+                                           NULL))
+                : GNUNET_JSON_pack_data_auto ("h_payto",
+                                              &crq->target_account_h_payto),
+                GNUNET_JSON_pack_timestamp ("request_timestamp",
+                                            crq->request_timestamp))))
+        {
+          GNUNET_break (0);
+          json_decref (json_history);
+          return NULL;
+        }
+      }
+      break;
+    }
+  }
+
+  return json_history;
+}
+
+
 /**
  * Send reserve history to client.
  *
@@ -90,7 +373,7 @@ reply_reserve_history_success (struct MHD_Connection 
*connection,
   const struct TALER_EXCHANGEDB_ReserveHistory *rh = rhc->rh;
   json_t *json_history;
 
-  json_history = TEH_RESPONSE_compile_reserve_history (rh);
+  json_history = compile_reserve_history (rh);
   if (NULL == json_history)
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -107,19 +390,20 @@ reply_reserve_history_success (struct MHD_Connection 
*connection,
 
 
 /**
- * Function implementing /reserves/$RID/history transaction.  Given the public
- * key of a reserve, return the associated transaction history.  Runs the
- * transaction logic; IF it returns a non-error code, the transaction logic
- * MUST NOT queue a MHD response.  IF it returns an hard error, the
- * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF it
- * returns the soft error code, the function MAY be called again to retry and
- * MUST not queue a MHD response.
+ * Function implementing /reserves/ HISTORY transaction.
+ * Execute a /reserves/ HISTORY.  Given the public key of a reserve,
+ * return the associated transaction history.  Runs the
+ * transaction logic; IF it returns a non-error code, the transaction
+ * logic MUST NOT queue a MHD response.  IF it returns an hard error,
+ * the transaction logic MUST queue a MHD response and set @a mhd_ret.
+ * IF it returns the soft error code, the function MAY be called again
+ * to retry and MUST not queue a MHD response.
  *
  * @param cls a `struct ReserveHistoryContext *`
  * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response status for @a connection,
+ * @param[out] mhd_ret set to MHD response history for @a connection,
  *             if transaction failed (!); unused
- * @return transaction status
+ * @return transaction history
  */
 static enum GNUNET_DB_QueryStatus
 reserve_history_transaction (void *cls,
@@ -129,47 +413,9 @@ reserve_history_transaction (void *cls,
   struct ReserveHistoryContext *rsc = cls;
   enum GNUNET_DB_QueryStatus qs;
 
-  if (! TALER_amount_is_zero (&rsc->gf->fees.history))
-  {
-    bool balance_ok = false;
-    bool idempotent = true;
-
-    qs = TEH_plugin->insert_history_request (TEH_plugin->cls,
-                                             rsc->reserve_pub,
-                                             &rsc->reserve_sig,
-                                             rsc->timestamp,
-                                             &rsc->gf->fees.history,
-                                             &balance_ok,
-                                             &idempotent);
-    if (GNUNET_DB_STATUS_HARD_ERROR == qs)
-    {
-      GNUNET_break (0);
-      *mhd_ret
-        = TALER_MHD_reply_with_error (connection,
-                                      MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                      TALER_EC_GENERIC_DB_FETCH_FAILED,
-                                      "get_reserve_history");
-    }
-    if (qs <= 0)
-    {
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-      return qs;
-    }
-    if (! balance_ok)
-    {
-      return TALER_MHD_reply_with_error (connection,
-                                         MHD_HTTP_CONFLICT,
-                                         
TALER_EC_EXCHANGE_GET_RESERVE_HISTORY_ERROR_INSUFFICIENT_BALANCE,
-                                         NULL);
-    }
-    if (idempotent)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Idempotent /reserves/history request observed. Is caching 
working?\n");
-    }
-  }
   qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
                                         rsc->reserve_pub,
+                                        0,
                                         &rsc->balance,
                                         &rsc->rh);
   if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -192,14 +438,13 @@ TEH_handler_reserves_history (struct TEH_RequestContext 
*rc,
 {
   struct ReserveHistoryContext rsc;
   MHD_RESULT mhd_ret;
+  uint64_t start_off = 0;
+  struct TALER_ReserveSignatureP reserve_sig;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_timestamp ("request_timestamp",
-                                &rsc.timestamp),
     GNUNET_JSON_spec_fixed_auto ("reserve_sig",
-                                 &rsc.reserve_sig),
+                                 &reserve_sig),
     GNUNET_JSON_spec_end ()
   };
-  struct GNUNET_TIME_Timestamp now;
 
   rsc.reserve_pub = reserve_pub;
   {
@@ -219,51 +464,15 @@ TEH_handler_reserves_history (struct TEH_RequestContext 
*rc,
       return MHD_YES; /* failure */
     }
   }
-  now = GNUNET_TIME_timestamp_get ();
-  if (! GNUNET_TIME_absolute_approx_eq (now.abs_time,
-                                        rsc.timestamp.abs_time,
-                                        TIMESTAMP_TOLERANCE))
-  {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW,
-                                       NULL);
-  }
-  {
-    struct TEH_KeyStateHandle *keys;
-
-    keys = TEH_keys_get_state ();
-    if (NULL == keys)
-    {
-      GNUNET_break (0);
-      GNUNET_JSON_parse_free (spec);
-      return TALER_MHD_reply_with_error (rc->connection,
-                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                         
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
-                                         NULL);
-    }
-    rsc.gf = TEH_keys_global_fee_by_time (keys,
-                                          rsc.timestamp);
-  }
-  if (NULL == rsc.gf)
-  {
-    GNUNET_break (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
-                                       NULL);
-  }
   if (GNUNET_OK !=
-      TALER_wallet_reserve_history_verify (rsc.timestamp,
-                                           &rsc.gf->fees.history,
+      TALER_wallet_reserve_history_verify (start_off,
                                            reserve_pub,
-                                           &rsc.reserve_sig))
+                                           &reserve_sig))
   {
     GNUNET_break_op (0);
     return TALER_MHD_reply_with_error (rc->connection,
                                        MHD_HTTP_FORBIDDEN,
-                                       
TALER_EC_EXCHANGE_RESERVES_HISTORY_BAD_SIGNATURE,
+                                       
TALER_EC_EXCHANGE_RESERVE_HISTORY_BAD_SIGNATURE,
                                        NULL);
   }
   rsc.rh = NULL;
@@ -281,7 +490,7 @@ TEH_handler_reserves_history (struct TEH_RequestContext *rc,
   {
     return TALER_MHD_reply_with_error (rc->connection,
                                        MHD_HTTP_NOT_FOUND,
-                                       
TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN,
+                                       
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
                                        NULL);
   }
   mhd_ret = reply_reserve_history_success (rc->connection,
diff --git a/src/exchange/taler-exchange-httpd_reserves_history.h 
b/src/exchange/taler-exchange-httpd_reserves_history.h
index e02cb4d9..9a2a9378 100644
--- a/src/exchange/taler-exchange-httpd_reserves_history.h
+++ b/src/exchange/taler-exchange-httpd_reserves_history.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -15,8 +15,9 @@
 */
 /**
  * @file taler-exchange-httpd_reserves_history.h
- * @brief Handle /reserves/$RESERVE_PUB/history requests
+ * @brief Handle /reserves/$RESERVE_PUB HISTORY requests
  * @author Florian Dold
+ * @author Benedikt Mueller
  * @author Christian Grothoff
  */
 #ifndef TALER_EXCHANGE_HTTPD_RESERVES_HISTORY_H
diff --git a/src/exchange/taler-exchange-httpd_reserves_status.c 
b/src/exchange/taler-exchange-httpd_reserves_status.c
deleted file mode 100644
index 4e7b4f47..00000000
--- a/src/exchange/taler-exchange-httpd_reserves_status.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero 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 Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_reserves_status.c
- * @brief Handle /reserves/$RESERVE_PUB STATUS requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include "taler_mhd_lib.h"
-#include "taler_json_lib.h"
-#include "taler_dbevents.h"
-#include "taler-exchange-httpd_keys.h"
-#include "taler-exchange-httpd_reserves_status.h"
-#include "taler-exchange-httpd_responses.h"
-
-/**
- * How far do we allow a client's time to be off when
- * checking the request timestamp?
- */
-#define TIMESTAMP_TOLERANCE \
-  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
-
-
-/**
- * Closure for #reserve_status_transaction.
- */
-struct ReserveStatusContext
-{
-  /**
-   * Public key of the reserve the inquiry is about.
-   */
-  const struct TALER_ReservePublicKeyP *reserve_pub;
-
-  /**
-   * History of the reserve, set in the callback.
-   */
-  struct TALER_EXCHANGEDB_ReserveHistory *rh;
-
-  /**
-   * Sum of incoming transactions within the returned history.
-   * (currently not used).
-   */
-  struct TALER_Amount balance_in;
-
-  /**
-   * Sum of outgoing transactions within the returned history.
-   * (currently not used).
-   */
-  struct TALER_Amount balance_out;
-
-  /**
-   * Current reserve balance.
-   */
-  struct TALER_Amount balance;
-};
-
-
-/**
- * Send reserve status to client.
- *
- * @param connection connection to the client
- * @param rhc reserve history to return
- * @return MHD result code
- */
-static MHD_RESULT
-reply_reserve_status_success (struct MHD_Connection *connection,
-                              const struct ReserveStatusContext *rhc)
-{
-  const struct TALER_EXCHANGEDB_ReserveHistory *rh = rhc->rh;
-  json_t *json_history;
-
-  json_history = TEH_RESPONSE_compile_reserve_history (rh);
-  if (NULL == json_history)
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
-                                       NULL);
-  return TALER_MHD_REPLY_JSON_PACK (
-    connection,
-    MHD_HTTP_OK,
-    TALER_JSON_pack_amount ("balance",
-                            &rhc->balance),
-    GNUNET_JSON_pack_array_steal ("history",
-                                  json_history));
-}
-
-
-/**
- * Function implementing /reserves/ STATUS transaction.
- * Execute a /reserves/ STATUS.  Given the public key of a reserve,
- * return the associated transaction history.  Runs the
- * transaction logic; IF it returns a non-error code, the transaction
- * logic MUST NOT queue a MHD response.  IF it returns an hard error,
- * the transaction logic MUST queue a MHD response and set @a mhd_ret.
- * IF it returns the soft error code, the function MAY be called again
- * to retry and MUST not queue a MHD response.
- *
- * @param cls a `struct ReserveStatusContext *`
- * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response status for @a connection,
- *             if transaction failed (!); unused
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-reserve_status_transaction (void *cls,
-                            struct MHD_Connection *connection,
-                            MHD_RESULT *mhd_ret)
-{
-  struct ReserveStatusContext *rsc = cls;
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = TEH_plugin->get_reserve_status (TEH_plugin->cls,
-                                       rsc->reserve_pub,
-                                       &rsc->balance_in,
-                                       &rsc->balance_out,
-                                       &rsc->rh);
-  if (GNUNET_DB_STATUS_HARD_ERROR == qs)
-  {
-    GNUNET_break (0);
-    *mhd_ret
-      = TALER_MHD_reply_with_error (connection,
-                                    MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                    TALER_EC_GENERIC_DB_FETCH_FAILED,
-                                    "get_reserve_status");
-  }
-  qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
-                                        rsc->reserve_pub,
-                                        &rsc->balance);
-  if (GNUNET_DB_STATUS_HARD_ERROR == qs)
-  {
-    GNUNET_break (0);
-    *mhd_ret
-      = TALER_MHD_reply_with_error (connection,
-                                    MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                    TALER_EC_GENERIC_DB_FETCH_FAILED,
-                                    "get_reserve_balance");
-  }
-  return qs;
-}
-
-
-MHD_RESULT
-TEH_handler_reserves_status (struct TEH_RequestContext *rc,
-                             const struct TALER_ReservePublicKeyP *reserve_pub,
-                             const json_t *root)
-{
-  struct ReserveStatusContext rsc;
-  MHD_RESULT mhd_ret;
-  struct GNUNET_TIME_Timestamp timestamp;
-  struct TALER_ReserveSignatureP reserve_sig;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_timestamp ("request_timestamp",
-                                &timestamp),
-    GNUNET_JSON_spec_fixed_auto ("reserve_sig",
-                                 &reserve_sig),
-    GNUNET_JSON_spec_end ()
-  };
-  struct GNUNET_TIME_Timestamp now;
-
-  rsc.reserve_pub = reserve_pub;
-  {
-    enum GNUNET_GenericReturnValue res;
-
-    res = TALER_MHD_parse_json_data (rc->connection,
-                                     root,
-                                     spec);
-    if (GNUNET_SYSERR == res)
-    {
-      GNUNET_break (0);
-      return MHD_NO; /* hard failure */
-    }
-    if (GNUNET_NO == res)
-    {
-      GNUNET_break_op (0);
-      return MHD_YES; /* failure */
-    }
-  }
-  now = GNUNET_TIME_timestamp_get ();
-  if (! GNUNET_TIME_absolute_approx_eq (now.abs_time,
-                                        timestamp.abs_time,
-                                        TIMESTAMP_TOLERANCE))
-  {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW,
-                                       NULL);
-  }
-  if (GNUNET_OK !=
-      TALER_wallet_reserve_status_verify (timestamp,
-                                          reserve_pub,
-                                          &reserve_sig))
-  {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_FORBIDDEN,
-                                       
TALER_EC_EXCHANGE_RESERVES_STATUS_BAD_SIGNATURE,
-                                       NULL);
-  }
-  rsc.rh = NULL;
-  if (GNUNET_OK !=
-      TEH_DB_run_transaction (rc->connection,
-                              "get reserve status",
-                              TEH_MT_REQUEST_OTHER,
-                              &mhd_ret,
-                              &reserve_status_transaction,
-                              &rsc))
-  {
-    return mhd_ret;
-  }
-  if (NULL == rsc.rh)
-  {
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_NOT_FOUND,
-                                       
TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN,
-                                       NULL);
-  }
-  mhd_ret = reply_reserve_status_success (rc->connection,
-                                          &rsc);
-  TEH_plugin->free_reserve_history (TEH_plugin->cls,
-                                    rsc.rh);
-  return mhd_ret;
-}
-
-
-/* end of taler-exchange-httpd_reserves_status.c */
diff --git a/src/exchange/taler-exchange-httpd_reserves_status.h 
b/src/exchange/taler-exchange-httpd_reserves_status.h
deleted file mode 100644
index 831b270f..00000000
--- a/src/exchange/taler-exchange-httpd_reserves_status.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2014-2020 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero 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 Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-exchange-httpd_reserves_status.h
- * @brief Handle /reserves/$RESERVE_PUB STATUS requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_EXCHANGE_HTTPD_RESERVES_STATUS_H
-#define TALER_EXCHANGE_HTTPD_RESERVES_STATUS_H
-
-#include <microhttpd.h>
-#include "taler-exchange-httpd.h"
-
-
-/**
- * Handle a POST "/reserves/$RID/status" request.
- *
- * @param rc request context
- * @param reserve_pub public key of the reserve
- * @param root uploaded body from the client
- * @return MHD result code
- */
-MHD_RESULT
-TEH_handler_reserves_status (struct TEH_RequestContext *rc,
-                             const struct TALER_ReservePublicKeyP *reserve_pub,
-                             const json_t *root);
-
-#endif
diff --git a/src/exchange/taler-exchange-httpd_responses.c 
b/src/exchange/taler-exchange-httpd_responses.c
index 13c654e6..4c8b385b 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -32,491 +32,6 @@
 #include "taler-exchange-httpd_keys.h"
 
 
-/**
- * Compile the transaction history of a coin into a JSON object.
- *
- * @param coin_pub public key of the coin
- * @param tl transaction history to JSON-ify
- * @return json representation of the @a rh, NULL on error
- */
-json_t *
-TEH_RESPONSE_compile_transaction_history (
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  const struct TALER_EXCHANGEDB_TransactionList *tl)
-{
-  json_t *history;
-
-  history = json_array ();
-  if (NULL == history)
-  {
-    GNUNET_break (0); /* out of memory!? */
-    return NULL;
-  }
-  for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl;
-       NULL != pos;
-       pos = pos->next)
-  {
-    switch (pos->type)
-    {
-    case TALER_EXCHANGEDB_TT_DEPOSIT:
-      {
-        const struct TALER_EXCHANGEDB_DepositListEntry *deposit =
-          pos->details.deposit;
-        struct TALER_MerchantWireHashP h_wire;
-
-        TALER_merchant_wire_signature_hash (deposit->receiver_wire_account,
-                                            &deposit->wire_salt,
-                                            &h_wire);
-#if ENABLE_SANITY_CHECKS
-        /* internal sanity check before we hand out a bogus sig... */
-        TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
-        if (GNUNET_OK !=
-            TALER_wallet_deposit_verify (
-              &deposit->amount_with_fee,
-              &deposit->deposit_fee,
-              &h_wire,
-              &deposit->h_contract_terms,
-              deposit->no_wallet_data_hash
-              ? NULL
-              : &deposit->wallet_data_hash,
-              deposit->no_age_commitment
-              ? NULL
-              : &deposit->h_age_commitment,
-              &deposit->h_policy,
-              &deposit->h_denom_pub,
-              deposit->timestamp,
-              &deposit->merchant_pub,
-              deposit->refund_deadline,
-              coin_pub,
-              &deposit->csig))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-#endif
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "DEPOSIT"),
-                TALER_JSON_pack_amount ("amount",
-                                        &deposit->amount_with_fee),
-                TALER_JSON_pack_amount ("deposit_fee",
-                                        &deposit->deposit_fee),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            deposit->timestamp),
-                GNUNET_JSON_pack_allow_null (
-                  GNUNET_JSON_pack_timestamp ("refund_deadline",
-                                              deposit->refund_deadline)),
-                GNUNET_JSON_pack_data_auto ("merchant_pub",
-                                            &deposit->merchant_pub),
-                GNUNET_JSON_pack_data_auto ("h_contract_terms",
-                                            &deposit->h_contract_terms),
-                GNUNET_JSON_pack_data_auto ("h_wire",
-                                            &h_wire),
-                GNUNET_JSON_pack_allow_null (
-                  deposit->no_age_commitment ?
-                  GNUNET_JSON_pack_string (
-                    "h_age_commitment", NULL) :
-                  GNUNET_JSON_pack_data_auto ("h_age_commitment",
-                                              &deposit->h_age_commitment)),
-                GNUNET_JSON_pack_data_auto ("coin_sig",
-                                            &deposit->csig))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        break;
-      }
-    case TALER_EXCHANGEDB_TT_MELT:
-      {
-        const struct TALER_EXCHANGEDB_MeltListEntry *melt =
-          pos->details.melt;
-        const struct TALER_AgeCommitmentHash *phac = NULL;
-
-#if ENABLE_SANITY_CHECKS
-        TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
-        if (GNUNET_OK !=
-            TALER_wallet_melt_verify (
-              &melt->amount_with_fee,
-              &melt->melt_fee,
-              &melt->rc,
-              &melt->h_denom_pub,
-              &melt->h_age_commitment,
-              coin_pub,
-              &melt->coin_sig))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-#endif
-
-        /* Age restriction is optional.  We communicate a NULL value to
-         * JSON_PACK below */
-        if (! melt->no_age_commitment)
-          phac = &melt->h_age_commitment;
-
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "MELT"),
-                TALER_JSON_pack_amount ("amount",
-                                        &melt->amount_with_fee),
-                TALER_JSON_pack_amount ("melt_fee",
-                                        &melt->melt_fee),
-                GNUNET_JSON_pack_data_auto ("rc",
-                                            &melt->rc),
-                GNUNET_JSON_pack_allow_null (
-                  GNUNET_JSON_pack_data_auto ("h_age_commitment",
-                                              phac)),
-                GNUNET_JSON_pack_data_auto ("coin_sig",
-                                            &melt->coin_sig))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_TT_REFUND:
-      {
-        const struct TALER_EXCHANGEDB_RefundListEntry *refund =
-          pos->details.refund;
-        struct TALER_Amount value;
-
-#if ENABLE_SANITY_CHECKS
-        TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
-        if (GNUNET_OK !=
-            TALER_merchant_refund_verify (
-              coin_pub,
-              &refund->h_contract_terms,
-              refund->rtransaction_id,
-              &refund->refund_amount,
-              &refund->merchant_pub,
-              &refund->merchant_sig))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-#endif
-        if (0 >
-            TALER_amount_subtract (&value,
-                                   &refund->refund_amount,
-                                   &refund->refund_fee))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "REFUND"),
-                TALER_JSON_pack_amount ("amount",
-                                        &value),
-                TALER_JSON_pack_amount ("refund_fee",
-                                        &refund->refund_fee),
-                GNUNET_JSON_pack_data_auto ("h_contract_terms",
-                                            &refund->h_contract_terms),
-                GNUNET_JSON_pack_data_auto ("merchant_pub",
-                                            &refund->merchant_pub),
-                GNUNET_JSON_pack_uint64 ("rtransaction_id",
-                                         refund->rtransaction_id),
-                GNUNET_JSON_pack_data_auto ("merchant_sig",
-                                            &refund->merchant_sig))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
-      {
-        struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
-          pos->details.old_coin_recoup;
-        struct TALER_ExchangePublicKeyP epub;
-        struct TALER_ExchangeSignatureP esig;
-
-        if (TALER_EC_NONE !=
-            TALER_exchange_online_confirm_recoup_refresh_sign (
-              &TEH_keys_exchange_sign_,
-              pr->timestamp,
-              &pr->value,
-              &pr->coin.coin_pub,
-              &pr->old_coin_pub,
-              &epub,
-              &esig))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        /* NOTE: we could also provide coin_pub's coin_sig, denomination key 
hash and
-           the denomination key's RSA signature over coin_pub, but as the
-           wallet should really already have this information (and cannot
-           check or do anything with it anyway if it doesn't), it seems
-           strictly unnecessary. */
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "OLD-COIN-RECOUP"),
-                TALER_JSON_pack_amount ("amount",
-                                        &pr->value),
-                GNUNET_JSON_pack_data_auto ("exchange_sig",
-                                            &esig),
-                GNUNET_JSON_pack_data_auto ("exchange_pub",
-                                            &epub),
-                GNUNET_JSON_pack_data_auto ("coin_pub",
-                                            &pr->coin.coin_pub),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            pr->timestamp))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        break;
-      }
-    case TALER_EXCHANGEDB_TT_RECOUP:
-      {
-        const struct TALER_EXCHANGEDB_RecoupListEntry *recoup =
-          pos->details.recoup;
-        struct TALER_ExchangePublicKeyP epub;
-        struct TALER_ExchangeSignatureP esig;
-
-        if (TALER_EC_NONE !=
-            TALER_exchange_online_confirm_recoup_sign (
-              &TEH_keys_exchange_sign_,
-              recoup->timestamp,
-              &recoup->value,
-              coin_pub,
-              &recoup->reserve_pub,
-              &epub,
-              &esig))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "RECOUP"),
-                TALER_JSON_pack_amount ("amount",
-                                        &recoup->value),
-                GNUNET_JSON_pack_data_auto ("exchange_sig",
-                                            &esig),
-                GNUNET_JSON_pack_data_auto ("exchange_pub",
-                                            &epub),
-                GNUNET_JSON_pack_data_auto ("reserve_pub",
-                                            &recoup->reserve_pub),
-                GNUNET_JSON_pack_data_auto ("coin_sig",
-                                            &recoup->coin_sig),
-                GNUNET_JSON_pack_data_auto ("coin_blind",
-                                            &recoup->coin_blind),
-                GNUNET_JSON_pack_data_auto ("reserve_pub",
-                                            &recoup->reserve_pub),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            recoup->timestamp))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_TT_RECOUP_REFRESH:
-      {
-        struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
-          pos->details.recoup_refresh;
-        struct TALER_ExchangePublicKeyP epub;
-        struct TALER_ExchangeSignatureP esig;
-
-        if (TALER_EC_NONE !=
-            TALER_exchange_online_confirm_recoup_refresh_sign (
-              &TEH_keys_exchange_sign_,
-              pr->timestamp,
-              &pr->value,
-              coin_pub,
-              &pr->old_coin_pub,
-              &epub,
-              &esig))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        /* NOTE: we could also provide coin_pub's coin_sig, denomination key
-           hash and the denomination key's RSA signature over coin_pub, but as
-           the wallet should really already have this information (and cannot
-           check or do anything with it anyway if it doesn't), it seems
-           strictly unnecessary. */
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "RECOUP-REFRESH"),
-                TALER_JSON_pack_amount ("amount",
-                                        &pr->value),
-                GNUNET_JSON_pack_data_auto ("exchange_sig",
-                                            &esig),
-                GNUNET_JSON_pack_data_auto ("exchange_pub",
-                                            &epub),
-                GNUNET_JSON_pack_data_auto ("old_coin_pub",
-                                            &pr->old_coin_pub),
-                GNUNET_JSON_pack_data_auto ("coin_sig",
-                                            &pr->coin_sig),
-                GNUNET_JSON_pack_data_auto ("coin_blind",
-                                            &pr->coin_blind),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            pr->timestamp))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        break;
-      }
-
-    case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT:
-      {
-        struct TALER_EXCHANGEDB_PurseDepositListEntry *pd
-          = pos->details.purse_deposit;
-        const struct TALER_AgeCommitmentHash *phac = NULL;
-
-        if (! pd->no_age_commitment)
-          phac = &pd->h_age_commitment;
-
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "PURSE-DEPOSIT"),
-                TALER_JSON_pack_amount ("amount",
-                                        &pd->amount),
-                GNUNET_JSON_pack_string ("exchange_base_url",
-                                         NULL == pd->exchange_base_url
-                                         ? TEH_base_url
-                                         : pd->exchange_base_url),
-                GNUNET_JSON_pack_allow_null (
-                  GNUNET_JSON_pack_data_auto ("h_age_commitment",
-                                              phac)),
-                GNUNET_JSON_pack_data_auto ("purse_pub",
-                                            &pd->purse_pub),
-                GNUNET_JSON_pack_bool ("refunded",
-                                       pd->refunded),
-                GNUNET_JSON_pack_data_auto ("coin_sig",
-                                            &pd->coin_sig))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        break;
-      }
-
-    case TALER_EXCHANGEDB_TT_PURSE_REFUND:
-      {
-        const struct TALER_EXCHANGEDB_PurseRefundListEntry *prefund =
-          pos->details.purse_refund;
-        struct TALER_Amount value;
-        enum TALER_ErrorCode ec;
-        struct TALER_ExchangePublicKeyP epub;
-        struct TALER_ExchangeSignatureP esig;
-
-        if (0 >
-            TALER_amount_subtract (&value,
-                                   &prefund->refund_amount,
-                                   &prefund->refund_fee))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        ec = TALER_exchange_online_purse_refund_sign (
-          &TEH_keys_exchange_sign_,
-          &value,
-          &prefund->refund_fee,
-          coin_pub,
-          &prefund->purse_pub,
-          &epub,
-          &esig);
-        if (TALER_EC_NONE != ec)
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "PURSE-REFUND"),
-                TALER_JSON_pack_amount ("amount",
-                                        &value),
-                TALER_JSON_pack_amount ("refund_fee",
-                                        &prefund->refund_fee),
-                GNUNET_JSON_pack_data_auto ("exchange_sig",
-                                            &esig),
-                GNUNET_JSON_pack_data_auto ("exchange_pub",
-                                            &epub),
-                GNUNET_JSON_pack_data_auto ("purse_pub",
-                                            &prefund->purse_pub))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-      }
-      break;
-
-    case TALER_EXCHANGEDB_TT_RESERVE_OPEN:
-      {
-        struct TALER_EXCHANGEDB_ReserveOpenListEntry *role
-          = pos->details.reserve_open;
-
-        if (0 !=
-            json_array_append_new (
-              history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "RESERVE-OPEN-DEPOSIT"),
-                TALER_JSON_pack_amount ("coin_contribution",
-                                        &role->coin_contribution),
-                GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                            &role->reserve_sig),
-                GNUNET_JSON_pack_data_auto ("coin_sig",
-                                            &role->coin_sig))))
-        {
-          GNUNET_break (0);
-          json_decref (history);
-          return NULL;
-        }
-        break;
-      }
-    }
-  }
-  return history;
-}
-
-
 MHD_RESULT
 TEH_RESPONSE_reply_unknown_denom_pub_hash (
   struct MHD_Connection *connection,
@@ -650,48 +165,6 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
   const struct TALER_DenominationHashP *h_denom_pub,
   const struct TALER_CoinSpendPublicKeyP *coin_pub)
 {
-  struct TALER_EXCHANGEDB_TransactionList *tl;
-  enum GNUNET_DB_QueryStatus qs;
-  json_t *history;
-  uint64_t etag = 0;
-
-  TEH_plugin->rollback (TEH_plugin->cls);
-  if (GNUNET_OK !=
-      TEH_plugin->start_read_only (TEH_plugin->cls,
-                                   "get_coin_transactions"))
-  {
-    return TALER_MHD_reply_with_error (
-      connection,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_EC_GENERIC_DB_START_FAILED,
-      NULL);
-  }
-  qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
-                                          coin_pub,
-                                          &etag,
-                                          &tl);
-  TEH_plugin->rollback (TEH_plugin->cls);
-  if (0 > qs)
-  {
-    return TALER_MHD_reply_with_error (
-      connection,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_EC_GENERIC_DB_FETCH_FAILED,
-      NULL);
-  }
-
-  history = TEH_RESPONSE_compile_transaction_history (coin_pub,
-                                                      tl);
-  TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
-                                          tl);
-  if (NULL == history)
-  {
-    GNUNET_break (0);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
-                                       "Failed to generated proof of 
insufficient funds");
-  }
   return TALER_MHD_REPLY_JSON_PACK (
     connection,
     TALER_ErrorCode_get_http_status_safe (ec),
@@ -700,347 +173,7 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
                                 coin_pub),
     // FIXME: to be kept only for some of the error types!
     GNUNET_JSON_pack_data_auto ("h_denom_pub",
-                                h_denom_pub),
-    // FIXME: to be removed!
-    GNUNET_JSON_pack_array_steal ("history",
-                                  history));
-}
-
-
-json_t *
-TEH_RESPONSE_compile_reserve_history (
-  const struct TALER_EXCHANGEDB_ReserveHistory *rh)
-{
-  json_t *json_history;
-
-  json_history = json_array ();
-  GNUNET_assert (NULL != json_history);
-  for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
-       NULL != pos;
-       pos = pos->next)
-  {
-    switch (pos->type)
-    {
-    case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
-      {
-        const struct TALER_EXCHANGEDB_BankTransfer *bank =
-          pos->details.bank;
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "CREDIT"),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            bank->execution_date),
-                GNUNET_JSON_pack_string ("sender_account_url",
-                                         bank->sender_account_details),
-                GNUNET_JSON_pack_uint64 ("wire_reference",
-                                         bank->wire_reference),
-                TALER_JSON_pack_amount ("amount",
-                                        &bank->amount))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-        break;
-      }
-    case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
-      {
-        const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw
-          = pos->details.withdraw;
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "WITHDRAW"),
-                GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                            &withdraw->reserve_sig),
-                GNUNET_JSON_pack_data_auto ("h_coin_envelope",
-                                            &withdraw->h_coin_envelope),
-                GNUNET_JSON_pack_data_auto ("h_denom_pub",
-                                            &withdraw->denom_pub_hash),
-                TALER_JSON_pack_amount ("withdraw_fee",
-                                        &withdraw->withdraw_fee),
-                TALER_JSON_pack_amount ("amount",
-                                        &withdraw->amount_with_fee))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_RO_RECOUP_COIN:
-      {
-        const struct TALER_EXCHANGEDB_Recoup *recoup
-          = pos->details.recoup;
-        struct TALER_ExchangePublicKeyP pub;
-        struct TALER_ExchangeSignatureP sig;
-
-        if (TALER_EC_NONE !=
-            TALER_exchange_online_confirm_recoup_sign (
-              &TEH_keys_exchange_sign_,
-              recoup->timestamp,
-              &recoup->value,
-              &recoup->coin.coin_pub,
-              &recoup->reserve_pub,
-              &pub,
-              &sig))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "RECOUP"),
-                GNUNET_JSON_pack_data_auto ("exchange_pub",
-                                            &pub),
-                GNUNET_JSON_pack_data_auto ("exchange_sig",
-                                            &sig),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            recoup->timestamp),
-                TALER_JSON_pack_amount ("amount",
-                                        &recoup->value),
-                GNUNET_JSON_pack_data_auto ("coin_pub",
-                                            &recoup->coin.coin_pub))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
-      {
-        const struct TALER_EXCHANGEDB_ClosingTransfer *closing =
-          pos->details.closing;
-        struct TALER_ExchangePublicKeyP pub;
-        struct TALER_ExchangeSignatureP sig;
-
-        if (TALER_EC_NONE !=
-            TALER_exchange_online_reserve_closed_sign (
-              &TEH_keys_exchange_sign_,
-              closing->execution_date,
-              &closing->amount,
-              &closing->closing_fee,
-              closing->receiver_account_details,
-              &closing->wtid,
-              &pos->details.closing->reserve_pub,
-              &pub,
-              &sig))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "CLOSING"),
-                GNUNET_JSON_pack_string ("receiver_account_details",
-                                         closing->receiver_account_details),
-                GNUNET_JSON_pack_data_auto ("wtid",
-                                            &closing->wtid),
-                GNUNET_JSON_pack_data_auto ("exchange_pub",
-                                            &pub),
-                GNUNET_JSON_pack_data_auto ("exchange_sig",
-                                            &sig),
-                GNUNET_JSON_pack_timestamp ("timestamp",
-                                            closing->execution_date),
-                TALER_JSON_pack_amount ("amount",
-                                        &closing->amount),
-                TALER_JSON_pack_amount ("closing_fee",
-                                        &closing->closing_fee))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_RO_PURSE_MERGE:
-      {
-        const struct TALER_EXCHANGEDB_PurseMerge *merge =
-          pos->details.merge;
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "MERGE"),
-                GNUNET_JSON_pack_data_auto ("h_contract_terms",
-                                            &merge->h_contract_terms),
-                GNUNET_JSON_pack_data_auto ("merge_pub",
-                                            &merge->merge_pub),
-                GNUNET_JSON_pack_uint64 ("min_age",
-                                         merge->min_age),
-                GNUNET_JSON_pack_uint64 ("flags",
-                                         merge->flags),
-                GNUNET_JSON_pack_data_auto ("purse_pub",
-                                            &merge->purse_pub),
-                GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                            &merge->reserve_sig),
-                GNUNET_JSON_pack_timestamp ("merge_timestamp",
-                                            merge->merge_timestamp),
-                GNUNET_JSON_pack_timestamp ("purse_expiration",
-                                            merge->purse_expiration),
-                TALER_JSON_pack_amount ("purse_fee",
-                                        &merge->purse_fee),
-                TALER_JSON_pack_amount ("amount",
-                                        &merge->amount_with_fee),
-                GNUNET_JSON_pack_bool ("merged",
-                                       merge->merged))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-    case TALER_EXCHANGEDB_RO_HISTORY_REQUEST:
-      {
-        const struct TALER_EXCHANGEDB_HistoryRequest *history =
-          pos->details.history;
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "HISTORY"),
-                GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                            &history->reserve_sig),
-                GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                            history->request_timestamp),
-                TALER_JSON_pack_amount ("amount",
-                                        &history->history_fee))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-
-    case TALER_EXCHANGEDB_RO_OPEN_REQUEST:
-      {
-        const struct TALER_EXCHANGEDB_OpenRequest *orq =
-          pos->details.open_request;
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "OPEN"),
-                GNUNET_JSON_pack_uint64 ("requested_min_purses",
-                                         orq->purse_limit),
-                GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                            &orq->reserve_sig),
-                GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                            orq->request_timestamp),
-                GNUNET_JSON_pack_timestamp ("requested_expiration",
-                                            orq->reserve_expiration),
-                TALER_JSON_pack_amount ("open_fee",
-                                        &orq->open_fee))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-
-    case TALER_EXCHANGEDB_RO_CLOSE_REQUEST:
-      {
-        const struct TALER_EXCHANGEDB_CloseRequest *crq =
-          pos->details.close_request;
-
-        if (0 !=
-            json_array_append_new (
-              json_history,
-              GNUNET_JSON_PACK (
-                GNUNET_JSON_pack_string ("type",
-                                         "CLOSE"),
-                GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                            &crq->reserve_sig),
-                GNUNET_is_zero (&crq->target_account_h_payto)
-                ? GNUNET_JSON_pack_allow_null (
-                  GNUNET_JSON_pack_string ("h_payto",
-                                           NULL))
-                : GNUNET_JSON_pack_data_auto ("h_payto",
-                                              &crq->target_account_h_payto),
-                GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                            crq->request_timestamp))))
-        {
-          GNUNET_break (0);
-          json_decref (json_history);
-          return NULL;
-        }
-      }
-      break;
-    }
-  }
-
-  return json_history;
-}
-
-
-/**
- * Send reserve history information to client with the
- * message that we have insufficient funds for the
- * requested withdraw operation.
- *
- * @param connection connection to the client
- * @param ec error code to return
- * @param ebalance expected balance based on our database
- * @param withdraw_amount amount that the client requested to withdraw
- * @param rh reserve history to return
- * @return MHD result code
- */
-static MHD_RESULT
-reply_reserve_insufficient_funds (
-  struct MHD_Connection *connection,
-  enum TALER_ErrorCode ec,
-  const struct TALER_Amount *ebalance,
-  const struct TALER_Amount *withdraw_amount,
-  const struct TALER_EXCHANGEDB_ReserveHistory *rh)
-{
-  json_t *json_history;
-
-  json_history = TEH_RESPONSE_compile_reserve_history (rh);
-  if (NULL == json_history)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to compile reserve history\n");
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_EXCHANGE_RESERVE_HISTORY_ERROR_INSUFFICIENT_FUNDS,
-                                       NULL);
-  }
-  return TALER_MHD_REPLY_JSON_PACK (
-    connection,
-    MHD_HTTP_CONFLICT,
-    TALER_JSON_pack_ec (ec),
-    TALER_JSON_pack_amount ("balance",
-                            ebalance),
-    TALER_JSON_pack_amount ("requested_amount",
-                            withdraw_amount),
-    GNUNET_JSON_pack_array_steal ("history",
-                                  json_history));
+                                h_denom_pub));
 }
 
 
@@ -1051,46 +184,30 @@ TEH_RESPONSE_reply_reserve_insufficient_balance (
   const struct TALER_Amount *balance_required,
   const struct TALER_ReservePublicKeyP *reserve_pub)
 {
-  struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
   struct TALER_Amount balance;
   enum GNUNET_DB_QueryStatus qs;
-  MHD_RESULT mhd_ret;
 
-  if (GNUNET_OK !=
-      TEH_plugin->start_read_only (TEH_plugin->cls,
-                                   "get_reserve_history on insufficient 
balance"))
-  {
-    GNUNET_break (0);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       TALER_EC_GENERIC_DB_START_FAILED,
-                                       NULL);
-  }
-  /* The reserve does not have the required amount (actual
-   * amount + withdraw fee) */
-  qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
+  // FIXME: pass balance as argument to this function,
+  // instead of getting it in another transaction!
+  qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
                                         reserve_pub,
-                                        &balance,
-                                        &rh);
-  TEH_plugin->rollback (TEH_plugin->cls);
-  if ( (qs < 0) ||
-       (NULL == rh) )
+                                        &balance);
+  if (qs < 0)
   {
     GNUNET_break (0);
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
-                                       "reserve history");
+                                       "reserve balance");
   }
-  mhd_ret = reply_reserve_insufficient_funds (
+  return TALER_MHD_REPLY_JSON_PACK (
     connection,
-    ec,
-    &balance,
-    balance_required,
-    rh);
-  TEH_plugin->free_reserve_history (TEH_plugin->cls,
-                                    rh);
-  return mhd_ret;
+    MHD_HTTP_CONFLICT,
+    TALER_JSON_pack_ec (ec),
+    TALER_JSON_pack_amount ("balance",
+                            &balance),
+    TALER_JSON_pack_amount ("requested_amount",
+                            balance_required));
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd_responses.h 
b/src/exchange/taler-exchange-httpd_responses.h
index 9b525929..3e55f0b0 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -33,17 +33,6 @@
 #include <gnunet/gnunet_mhd_compat.h>
 
 
-/**
- * Compile the history of a reserve into a JSON object.
- *
- * @param rh reserve history to JSON-ify
- * @return json representation of the @a rh, NULL on error
- */
-json_t *
-TEH_RESPONSE_compile_reserve_history (
-  const struct TALER_EXCHANGEDB_ReserveHistory *rh);
-
-
 /**
  * Send assertion that the given denomination key hash
  * is unknown to us at this time.
@@ -213,19 +202,6 @@ TEH_RESPONSE_reply_purse_created (
   const struct TEH_PurseDetails *pd);
 
 
-/**
- * Compile the transaction history of a coin into a JSON object.
- *
- * @param coin_pub public key of the coin
- * @param tl transaction history to JSON-ify
- * @return json representation of the @a rh, NULL on error
- */
-json_t *
-TEH_RESPONSE_compile_transaction_history (
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  const struct TALER_EXCHANGEDB_TransactionList *tl);
-
-
 /**
  * Callback used to set headers in a response.
  *
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
index 50f9e768..3a4120af 100644
--- a/src/exchangedb/Makefile.am
+++ b/src/exchangedb/Makefile.am
@@ -164,7 +164,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
   pg_store_wire_transfer_out.h pg_store_wire_transfer_out.c \
   pg_gc.h pg_gc.c \
   pg_select_coin_deposits_above_serial_id.h 
pg_select_coin_deposits_above_serial_id.c \
-  pg_select_history_requests_above_serial_id.h 
pg_select_history_requests_above_serial_id.c \
   pg_select_purse_decisions_above_serial_id.h 
pg_select_purse_decisions_above_serial_id.c \
   pg_select_purse_deposits_by_purse.h pg_select_purse_deposits_by_purse.c \
   pg_select_refreshes_above_serial_id.h pg_select_refreshes_above_serial_id.c \
@@ -215,7 +214,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
   pg_update_auditor.h pg_update_auditor.c \
   pg_begin_revolving_shard.h pg_begin_revolving_shard.c \
   pg_get_extension_manifest.h pg_get_extension_manifest.c \
-  pg_insert_history_request.h pg_insert_history_request.c \
   pg_do_purse_merge.h pg_do_purse_merge.c \
   pg_start_read_committed.h pg_start_read_committed.c \
   pg_start_read_only.h pg_start_read_only.c \
diff --git a/src/exchangedb/exchange_do_history_request.sql 
b/src/exchangedb/exchange_do_history_request.sql
deleted file mode 100644
index 726c853f..00000000
--- a/src/exchangedb/exchange_do_history_request.sql
+++ /dev/null
@@ -1,101 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 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/>
---
-
-
-CREATE OR REPLACE FUNCTION exchange_do_history_request(
-  IN in_reserve_pub BYTEA,
-  IN in_reserve_sig BYTEA,
-  IN in_request_timestamp INT8,
-  IN in_history_fee taler_amount,
-  OUT out_balance_ok BOOLEAN,
-  OUT out_idempotent BOOLEAN)
-LANGUAGE plpgsql
-AS $$
-DECLARE
-  reserve RECORD;
-  balance taler_amount;
-  new_balance taler_amount;
-BEGIN
-
-  -- Insert and check for idempotency.
-  INSERT INTO exchange.history_requests
-  (reserve_pub
-  ,request_timestamp
-  ,reserve_sig
-  ,history_fee)
-  VALUES
-  (in_reserve_pub
-  ,in_request_timestamp
-  ,in_reserve_sig
-  ,in_history_fee)
-  ON CONFLICT DO NOTHING;
-
-  IF NOT FOUND
-  THEN
-    out_balance_ok=TRUE;
-    out_idempotent=TRUE;
-    RETURN;
-  END IF;
-
-  out_idempotent=FALSE;
-
-  SELECT *
-    INTO reserve
-    FROM exchange.reserves
-   WHERE reserve_pub=in_reserve_pub;
-
-  IF NOT FOUND
-  THEN
-    -- Reserve does not exist, we treat it the same here
-    -- as balance insufficient.
-    out_balance_ok=FALSE;
-    RETURN;
-  END IF;
-
-  balance = reserve.current_balance;
-
-  -- check balance
-  IF ( (balance.val <= in_history_fee.val) AND
-       ( (balance.frac < in_history_fee.frac) OR
-         (balance.val < in_history_fee.val) ) )
-  THEN
-    out_balance_ok=FALSE;
-    RETURN;
-  END IF;
-
-  new_balance.frac=balance.frac-in_history_fee.frac
-     + CASE
-       WHEN balance.frac < in_history_fee.frac
-       THEN 100000000
-       ELSE 0
-       END;
-  new_balance.val=balance.val-in_history_fee.val
-     - CASE
-       WHEN balance.frac < in_history_fee.frac
-       THEN 1
-       ELSE 0
-       END;
-
-  -- Update reserve balance.
-  UPDATE exchange.reserves
-     SET current_balance=new_balance
-   WHERE reserve_pub=in_reserve_pub;
-
-  ASSERT FOUND, 'reserve suddenly disappeared';
-
-  out_balance_ok=TRUE;
-
-END $$;
diff --git a/src/exchangedb/pg_get_reserve_history.c 
b/src/exchangedb/pg_get_reserve_history.c
index c0cb08f5..ba1db2a1 100644
--- a/src/exchangedb/pg_get_reserve_history.c
+++ b/src/exchangedb/pg_get_reserve_history.c
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2022 Taler Systems SA
+   Copyright (C) 2022-2023 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
@@ -424,62 +424,6 @@ add_p2p_merge (void *cls,
 }
 
 
-/**
- * Add paid for history requests to result set for
- * #TEH_PG_get_reserve_history.
- *
- * @param cls a `struct ReserveHistoryContext *`
- * @param result SQL result
- * @param num_results number of rows in @a result
- */
-static void
-add_history_requests (void *cls,
-                      PGresult *result,
-                      unsigned int num_results)
-{
-  struct ReserveHistoryContext *rhc = cls;
-  struct PostgresClosure *pg = rhc->pg;
-
-  while (0 < num_results)
-  {
-    struct TALER_EXCHANGEDB_HistoryRequest *history;
-    struct TALER_EXCHANGEDB_ReserveHistory *tail;
-
-    history = GNUNET_new (struct TALER_EXCHANGEDB_HistoryRequest);
-    {
-      struct GNUNET_PQ_ResultSpec rs[] = {
-        TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
-                                     &history->history_fee),
-        GNUNET_PQ_result_spec_timestamp ("request_timestamp",
-                                         &history->request_timestamp),
-        GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
-                                              &history->reserve_sig),
-        GNUNET_PQ_result_spec_end
-      };
-
-      if (GNUNET_OK !=
-          GNUNET_PQ_extract_result (result,
-                                    rs,
-                                    --num_results))
-      {
-        GNUNET_break (0);
-        GNUNET_free (history);
-        rhc->status = GNUNET_SYSERR;
-        return;
-      }
-    }
-    GNUNET_assert (0 <=
-                   TALER_amount_add (&rhc->balance_out,
-                                     &rhc->balance_out,
-                                     &history->history_fee));
-    history->reserve_pub = *rhc->reserve_pub;
-    tail = append_rh (rhc);
-    tail->type = TALER_EXCHANGEDB_RO_HISTORY_REQUEST;
-    tail->details.history = history;
-  }
-}
-
-
 /**
  * Add paid for history requests to result set for
  * #TEH_PG_get_reserve_history.
@@ -598,6 +542,7 @@ add_close_requests (void *cls,
 enum GNUNET_DB_QueryStatus
 TEH_PG_get_reserve_history (void *cls,
                             const struct TALER_ReservePublicKeyP *reserve_pub,
+                            uint64_t start_off,
                             struct TALER_Amount *balance,
                             struct TALER_EXCHANGEDB_ReserveHistory **rhp)
 {
@@ -629,9 +574,6 @@ TEH_PG_get_reserve_history (void *cls,
     /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */
     { "merge_by_reserve",
       &add_p2p_merge },
-    /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */
-    { "history_by_reserve",
-      &add_history_requests },
     /** #TALER_EXCHANGEDB_RO_OPEN_REQUEST */
     { "open_request_by_reserve",
       &add_open_requests },
@@ -792,14 +734,6 @@ TEH_PG_get_reserve_history (void *cls,
            " WHERE pm.reserve_pub=$1"
            "  AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */
            "  AND NOT COALESCE (pdes.refunded, FALSE);");
-  PREPARE (pg, // done
-           "history_by_reserve",
-           "SELECT"
-           " history_fee"
-           ",request_timestamp"
-           ",reserve_sig"
-           " FROM history_requests"
-           " WHERE reserve_pub=$1;");
   PREPARE (pg, // done
            "open_request_by_reserve",
            "SELECT"
@@ -866,293 +800,3 @@ TEH_PG_get_reserve_history (void *cls,
                                         &rhc.balance_out));
   return qs;
 }
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_status (void *cls,
-                           const struct TALER_ReservePublicKeyP *reserve_pub,
-                           struct TALER_Amount *balance_in,
-                           struct TALER_Amount *balance_out,
-                           struct TALER_EXCHANGEDB_ReserveHistory **rhp)
-{
-  struct PostgresClosure *pg = cls;
-  struct ReserveHistoryContext rhc;
-  struct
-  {
-    /**
-     * Name of the prepared statement to run.
-     */
-    const char *statement;
-    /**
-     * Function to use to process the results.
-     */
-    GNUNET_PQ_PostgresResultHandler cb;
-  } work[] = {
-    /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
-    { "reserves_in_get_transactions_truncated",
-      add_bank_to_exchange },
-    /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
-    { "get_reserves_out_truncated",
-      &add_withdraw_coin },
-    /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */
-    { "recoup_by_reserve_truncated",
-      &add_recoup },
-    /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
-    { "close_by_reserve_truncated",
-      &add_exchange_to_bank },
-    /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */
-    { "merge_by_reserve_truncated",
-      &add_p2p_merge },
-    /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */
-    { "history_by_reserve_truncated",
-      &add_history_requests },
-    /** #TALER_EXCHANGEDB_RO_OPEN_REQUEST */
-    { "open_request_by_reserve_truncated",
-      &add_open_requests },
-    /** #TALER_EXCHANGEDB_RO_CLOSE_REQUEST */
-    { "close_request_by_reserve_truncated",
-      &add_close_requests },
-    /* List terminator */
-    { NULL,
-      NULL }
-  };
-  enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_TIME_Absolute timelimit;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-    GNUNET_PQ_query_param_absolute_time (&timelimit),
-    GNUNET_PQ_query_param_end
-  };
-
-  PREPARE (pg,
-           "reserves_in_get_transactions_truncated",
-           /*
-           "SELECT"
-           " wire_reference"
-           ",credit"
-           ",execution_date"
-           ",payto_uri AS sender_account_details"
-           " FROM reserves_in"
-           " JOIN wire_targets"
-           "   ON (wire_source_h_payto = wire_target_h_payto)"
-           " WHERE reserve_pub=$1"
-           "   AND execution_date>=$2;",
-           */
-           "WITH ri AS MATERIALIZED ( "
-           "  SELECT * "
-           "  FROM reserves_in "
-           "  WHERE reserve_pub = $1 "
-           ") "
-           "SELECT  "
-           "  wire_reference"
-           "  ,credit"
-           "  ,execution_date"
-           "  ,payto_uri AS sender_account_details"
-           " FROM wire_targets"
-           " JOIN ri"
-           "  ON (wire_target_h_payto = wire_source_h_payto)"
-           " WHERE execution_date >= $2"
-           "  AND wire_target_h_payto = ( "
-           "  SELECT wire_source_h_payto FROM ri "
-           "); ");
-  PREPARE (pg,
-           "get_reserves_out_truncated",
-           /*
-           "SELECT"
-           " ro.h_blind_ev"
-           ",denom.denom_pub_hash"
-           ",ro.denom_sig"
-           ",ro.reserve_sig"
-           ",ro.execution_date"
-           ",ro.amount_with_fee"
-           ",denom.fee_withdraw"
-           " FROM reserves res"
-           " JOIN reserves_out_by_reserve ror"
-           "   ON (res.reserve_uuid = ror.reserve_uuid)"
-           " JOIN reserves_out ro"
-           "   ON (ro.h_blind_ev = ror.h_blind_ev)"
-           " JOIN denominations denom"
-           "   ON (ro.denominations_serial = denom.denominations_serial)"
-           " WHERE res.reserve_pub=$1"
-           "   AND execution_date>=$2;",
-           */
-           "WITH robr AS MATERIALIZED ( "
-           "  SELECT h_blind_ev "
-           "  FROM reserves_out_by_reserve "
-           "  WHERE reserve_uuid= ( "
-           "    SELECT reserve_uuid "
-           "    FROM reserves "
-           "    WHERE reserve_pub = $1 "
-           "  ) "
-           ") SELECT "
-           "  ro.h_blind_ev"
-           "  ,denom.denom_pub_hash"
-           "  ,ro.denom_sig"
-           "  ,ro.reserve_sig"
-           "  ,ro.execution_date"
-           "  ,ro.amount_with_fee"
-           "  ,denom.fee_withdraw"
-           " FROM robr"
-           " JOIN reserves_out ro"
-           "   ON (ro.h_blind_ev = robr.h_blind_ev)"
-           " JOIN denominations denom"
-           "   ON (ro.denominations_serial = denom.denominations_serial)"
-           " WHERE ro.execution_date>=$2;");
-  PREPARE (pg,
-           "recoup_by_reserve_truncated",
-           /*
-           "SELECT"
-           " recoup.coin_pub"
-           ",recoup.coin_sig"
-           ",recoup.coin_blind"
-           ",recoup.amount"
-           ",recoup.recoup_timestamp"
-           ",denominations.denom_pub_hash"
-           ",known_coins.denom_sig"
-           " FROM denominations"
-           " JOIN (known_coins"
-           "   JOIN recoup "
-           "   ON (recoup.coin_pub = known_coins.coin_pub))"
-           "  ON (known_coins.denominations_serial = 
denominations.denominations_serial)"
-           " WHERE recoup_timestamp>=$2"
-           " AND recoup.coin_pub"
-           "  IN (SELECT coin_pub"
-           "     FROM recoup_by_reserve"
-           "     JOIN (reserves_out"
-           "       JOIN (reserves_out_by_reserve"
-           "         JOIN reserves"
-           "           ON (reserves.reserve_uuid = 
reserves_out_by_reserve.reserve_uuid))"
-           "       ON (reserves_out_by_reserve.h_blind_ev = 
reserves_out.h_blind_ev))"
-           "     ON (recoup_by_reserve.reserve_out_serial_id = 
reserves_out.reserve_out_serial_id)"
-           "     WHERE reserves.reserve_pub=$1);",
-           */
-           "SELECT robr.coin_pub "
-           "  ,robr.coin_sig "
-           "  ,robr.coin_blind "
-           "  ,robr.amount"
-           "  ,robr.recoup_timestamp "
-           "  ,denominations.denom_pub_hash "
-           "  ,robr.denom_sig "
-           "FROM denominations "
-           "  JOIN exchange_do_recoup_by_reserve($1) robr"
-           "    USING (denominations_serial)"
-           " WHERE recoup_timestamp>=$2;");
-  PREPARE (pg,
-           "close_by_reserve_truncated",
-           "SELECT"
-           " amount"
-           ",closing_fee"
-           ",execution_date"
-           ",payto_uri AS receiver_account"
-           ",wtid"
-           " FROM reserves_close"
-           "   JOIN wire_targets"
-           "     USING (wire_target_h_payto)"
-           " WHERE reserve_pub=$1"
-           "   AND execution_date>=$2;");
-  PREPARE (pg,
-           "merge_by_reserve_truncated",
-           "SELECT"
-           " pr.amount_with_fee"
-           ",pr.balance"
-           ",pr.purse_fee"
-           ",pr.h_contract_terms"
-           ",pr.merge_pub"
-           ",am.reserve_sig"
-           ",pm.purse_pub"
-           ",pm.merge_timestamp"
-           ",pr.purse_expiration"
-           ",pr.age_limit"
-           ",pr.flags"
-           " FROM purse_merges pm"
-           "   JOIN purse_requests pr"
-           "     USING (purse_pub)"
-           "   JOIN purse_decision pdes"
-           "     USING (purse_pub)"
-           "   JOIN account_merges am"
-           "     ON (am.purse_pub = pm.purse_pub AND"
-           "         am.reserve_pub = pm.reserve_pub)"
-           " WHERE pm.reserve_pub=$1"
-           "  AND pm.merge_timestamp >= $2"
-           "  AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */
-           "  AND NOT pdes.refunded;");
-  PREPARE (pg,
-           "history_by_reserve_truncated",
-           "SELECT"
-           " history_fee"
-           ",request_timestamp"
-           ",reserve_sig"
-           " FROM history_requests"
-           " WHERE reserve_pub=$1"
-           "  AND request_timestamp>=$2;");
-  PREPARE (pg,
-           "open_request_by_reserve_truncated",
-           "SELECT"
-           " reserve_payment"
-           ",request_timestamp"
-           ",expiration_date"
-           ",requested_purse_limit"
-           ",reserve_sig"
-           " FROM reserves_open_requests"
-           " WHERE reserve_pub=$1"
-           "   AND request_timestamp>=$2;");
-
-  PREPARE (pg,
-           "close_request_by_reserve_truncated",
-           "SELECT"
-           " close_timestamp"
-           ",payto_uri"
-           ",reserve_sig"
-           " FROM close_requests"
-           " WHERE reserve_pub=$1"
-           "   AND close_timestamp>=$2;");
-
-  timelimit = GNUNET_TIME_absolute_subtract (
-    GNUNET_TIME_absolute_get (),
-    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS,
-                                   5));
-  rhc.reserve_pub = reserve_pub;
-  rhc.rh = NULL;
-  rhc.rh_tail = NULL;
-  rhc.pg = pg;
-  rhc.status = GNUNET_OK;
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_set_zero (pg->currency,
-                                        &rhc.balance_in));
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_set_zero (pg->currency,
-                                        &rhc.balance_out));
-  qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
-  for (unsigned int i = 0; NULL != work[i].cb; i++)
-  {
-    qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                               work[i].statement,
-                                               params,
-                                               work[i].cb,
-                                               &rhc);
-    if ( (0 > qs) ||
-         (GNUNET_OK != rhc.status) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Query %s failed\n",
-                  work[i].statement);
-      break;
-    }
-  }
-  if ( (qs < 0) ||
-       (rhc.status != GNUNET_OK) )
-  {
-    TEH_COMMON_free_reserve_history (cls,
-                                     rhc.rh);
-    rhc.rh = NULL;
-    if (qs >= 0)
-    {
-      /* status == SYSERR is a very hard error... */
-      qs = GNUNET_DB_STATUS_HARD_ERROR;
-    }
-  }
-  *rhp = rhc.rh;
-  *balance_in = rhc.balance_in;
-  *balance_out = rhc.balance_out;
-  return qs;
-}
diff --git a/src/exchangedb/pg_get_reserve_history.h 
b/src/exchangedb/pg_get_reserve_history.h
index ee47996b..ca6740c6 100644
--- a/src/exchangedb/pg_get_reserve_history.h
+++ b/src/exchangedb/pg_get_reserve_history.h
@@ -32,36 +32,18 @@
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param reserve_pub public key of the reserve
+ * @param start_off maximum starting offset in history to exclude from 
returning
  * @param[out] balance set to the reserve balance
  * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
  * @return transaction status
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_history (void *cls,
-                            const struct TALER_ReservePublicKeyP *reserve_pub,
-                            struct TALER_Amount *balance,
-                            struct TALER_EXCHANGEDB_ReserveHistory **rhp);
-
-
-/**
- * Get a truncated transaction history associated with the specified
- * reserve.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param reserve_pub public key of the reserve
- * @param[out] balance_in set to the total of inbound
- *             transactions in the returned history
- * @param[out] balance_out set to the total of outbound
- *             transactions in the returned history
- * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_status (void *cls,
-                           const struct TALER_ReservePublicKeyP *reserve_pub,
-                           struct TALER_Amount *balance_in,
-                           struct TALER_Amount *balance_out,
-                           struct TALER_EXCHANGEDB_ReserveHistory **rhp);
+TEH_PG_get_reserve_history (
+  void *cls,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  uint64_t start_off,
+  struct TALER_Amount *balance,
+  struct TALER_EXCHANGEDB_ReserveHistory **rhp);
 
 
 #endif
diff --git a/src/exchangedb/pg_insert_history_request.c 
b/src/exchangedb/pg_insert_history_request.c
deleted file mode 100644
index b13066b5..00000000
--- a/src/exchangedb/pg_insert_history_request.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-   This file is part of TALER
-   Copyright (C) 2022 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/pg_insert_history_request.c
- * @brief Implementation of the insert_history_request function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_insert_history_request.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_history_request (
-  void *cls,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  struct GNUNET_TIME_Timestamp request_timestamp,
-  const struct TALER_Amount *history_fee,
-  bool *balance_ok,
-  bool *idempotent)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
-    GNUNET_PQ_query_param_timestamp (&request_timestamp),
-    TALER_PQ_query_param_amount (pg->conn,
-                                 history_fee),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("balance_ok",
-                                balance_ok),
-    GNUNET_PQ_result_spec_bool ("idempotent",
-                                idempotent),
-    GNUNET_PQ_result_spec_end
-  };
-  /* Used in #postgres_insert_history_request() */
-  PREPARE (pg,
-           "call_history_request",
-           "SELECT"
-           "  out_balance_ok AS balance_ok"
-           " ,out_idempotent AS idempotent"
-           " FROM exchange_do_history_request"
-           "  ($1, $2, $3, $4)");
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "call_history_request",
-                                                   params,
-                                                   rs);
-}
diff --git a/src/exchangedb/pg_insert_history_request.h 
b/src/exchangedb/pg_insert_history_request.h
deleted file mode 100644
index 75004a7e..00000000
--- a/src/exchangedb/pg_insert_history_request.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-   This file is part of TALER
-   Copyright (C) 2022 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/pg_insert_history_request.h
- * @brief implementation of the insert_history_request function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_INSERT_HISTORY_REQUEST_H
-#define PG_INSERT_HISTORY_REQUEST_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-/**
- * Function called to persist a signature that
- * prove that the client requested an
- * account history.  Debits the @a history_fee from
- * the reserve (if possible).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param reserve_pub account that the history was requested for
- * @param reserve_sig signature affirming the request
- * @param request_timestamp when was the request made
- * @param history_fee how much should the @a reserve_pub be charged for the 
request
- * @param[out] balance_ok set to TRUE if the reserve balance
- *         was sufficient
- * @param[out] idempotent set to TRUE if the request is already in the DB
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_history_request (
-  void *cls,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  struct GNUNET_TIME_Timestamp request_timestamp,
-  const struct TALER_Amount *history_fee,
-  bool *balance_ok,
-  bool *idempotent);
-
-#endif
diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.c 
b/src/exchangedb/pg_select_history_requests_above_serial_id.c
deleted file mode 100644
index 2ff2f989..00000000
--- a/src/exchangedb/pg_select_history_requests_above_serial_id.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
-   This file is part of TALER
-   Copyright (C) 2022 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/pg_select_history_requests_above_serial_id.c
- * @brief Implementation of the select_history_requests_above_serial_id 
function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_select_history_requests_above_serial_id.h"
-#include "pg_helper.h"
-
-/**
- * Closure for #purse_deposit_serial_helper_cb().
- */
-struct HistoryRequestSerialContext
-{
-
-  /**
-   * Callback to call.
-   */
-  TALER_EXCHANGEDB_HistoryRequestCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
-
-  /**
-   * Status code, set to #GNUNET_SYSERR on hard errors.
-   */
-  enum GNUNET_GenericReturnValue status;
-};
-
-
-/**
- * Helper function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls closure of type `struct HistoryRequestSerialContext`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-history_request_serial_helper_cb (void *cls,
-                                  PGresult *result,
-                                  unsigned int num_results)
-{
-  struct HistoryRequestSerialContext *dsc = cls;
-  struct PostgresClosure *pg = dsc->pg;
-
-  for (unsigned int i = 0; i<num_results; i++)
-  {
-    uint64_t rowid;
-    struct TALER_Amount history_fee;
-    struct GNUNET_TIME_Timestamp ts;
-    struct TALER_ReservePublicKeyP reserve_pub;
-    struct TALER_ReserveSignatureP reserve_sig;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
-                                   &history_fee),
-      GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
-                                            &reserve_pub),
-      GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
-                                            &reserve_sig),
-      GNUNET_PQ_result_spec_uint64 ("history_request_serial_id",
-                                    &rowid),
-      GNUNET_PQ_result_spec_timestamp ("request_timestamp",
-                                       &ts),
-      GNUNET_PQ_result_spec_end
-    };
-    enum GNUNET_GenericReturnValue ret;
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      dsc->status = GNUNET_SYSERR;
-      return;
-    }
-    ret = dsc->cb (dsc->cb_cls,
-                   rowid,
-                   &history_fee,
-                   ts,
-                   &reserve_pub,
-                   &reserve_sig);
-    GNUNET_PQ_cleanup_result (rs);
-    if (GNUNET_OK != ret)
-      break;
-  }
-}
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_select_history_requests_above_serial_id (
-  void *cls,
-  uint64_t serial_id,
-  TALER_EXCHANGEDB_HistoryRequestCallback cb,
-  void *cb_cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&serial_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct HistoryRequestSerialContext dsc = {
-    .cb = cb,
-    .cb_cls = cb_cls,
-    .pg = pg,
-    .status = GNUNET_OK
-  };
-  enum GNUNET_DB_QueryStatus qs;
-  PREPARE (pg,
-           "audit_get_history_requests_incr",
-           "SELECT"
-           " history_request_serial_id"
-           ",history_fee"
-           ",request_timestamp"
-           ",reserve_pub"
-           ",reserve_sig"
-           " FROM history_requests"
-           " WHERE ("
-           "  (history_request_serial_id>=$1)"
-           " )"
-           " ORDER BY history_request_serial_id ASC;");
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "audit_get_history_requests_incr",
-                                             params,
-                                             &history_request_serial_helper_cb,
-                                             &dsc);
-  if (GNUNET_OK != dsc.status)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
-}
diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.h 
b/src/exchangedb/pg_select_history_requests_above_serial_id.h
deleted file mode 100644
index b16efdce..00000000
--- a/src/exchangedb/pg_select_history_requests_above_serial_id.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-   This file is part of TALER
-   Copyright (C) 2022 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/pg_select_history_requests_above_serial_id.h
- * @brief implementation of the select_history_requests_above_serial_id 
function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_SELECT_HISTORY_REQUESTS_ABOVE_SERIAL_ID_H
-#define PG_SELECT_HISTORY_REQUESTS_ABOVE_SERIAL_ID_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-/**
- * Select history requests above @a serial_id in monotonically increasing
- * order.
- *
- * @param cls closure
- * @param serial_id highest serial ID to exclude (select strictly larger)
- * @param cb function to call on each result
- * @param cb_cls closure for @a cb
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_select_history_requests_above_serial_id (
-  void *cls,
-  uint64_t serial_id,
-  TALER_EXCHANGEDB_HistoryRequestCallback cb,
-  void *cb_cls);
-
-#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index c6e55d01..aacc2968 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -92,7 +92,6 @@
 #include "pg_update_auditor.h"
 #include "pg_begin_revolving_shard.h"
 #include "pg_get_extension_manifest.h"
-#include "pg_insert_history_request.h"
 #include "pg_do_purse_delete.h"
 #include "pg_do_purse_merge.h"
 #include "pg_start_read_committed.h"
@@ -160,7 +159,6 @@
 #include "pg_store_wire_transfer_out.h"
 #include "pg_gc.h"
 #include "pg_select_coin_deposits_above_serial_id.h"
-#include "pg_select_history_requests_above_serial_id.h"
 #include "pg_select_purse_decisions_above_serial_id.h"
 #include "pg_select_purse_deposits_by_purse.h"
 #include "pg_select_refreshes_above_serial_id.h"
@@ -429,8 +427,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &TEH_PG_get_purse_request;
   plugin->get_reserve_history
     = &TEH_PG_get_reserve_history;
-  plugin->get_reserve_status
-    = &TEH_PG_get_reserve_status;
   plugin->get_unfinished_close_requests
     = &TEH_PG_get_unfinished_close_requests;
   plugin->insert_records_by_table
@@ -531,8 +527,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &TEH_PG_begin_revolving_shard;
   plugin->get_extension_manifest
     = &TEH_PG_get_extension_manifest;
-  plugin->insert_history_request
-    = &TEH_PG_insert_history_request;
   plugin->do_purse_merge
     = &TEH_PG_do_purse_merge;
   plugin->do_purse_delete
@@ -667,8 +661,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &TEH_PG_gc;
   plugin->select_coin_deposits_above_serial_id
     = &TEH_PG_select_coin_deposits_above_serial_id;
-  plugin->select_history_requests_above_serial_id
-    = &TEH_PG_select_history_requests_above_serial_id;
   plugin->select_purse_decisions_above_serial_id
     = &TEH_PG_select_purse_decisions_above_serial_id;
   plugin->select_purse_deposits_by_purse
diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in
index b963900c..998c2c16 100644
--- a/src/exchangedb/procedures.sql.in
+++ b/src/exchangedb/procedures.sql.in
@@ -37,7 +37,6 @@ SET search_path TO exchange;
 #include "exchange_do_purse_merge.sql"
 #include "exchange_do_reserve_purse.sql"
 #include "exchange_do_expire_purse.sql"
-#include "exchange_do_history_request.sql"
 #include "exchange_do_reserve_open_deposit.sql"
 #include "exchange_do_reserve_open.sql"
 #include "exchange_do_insert_or_update_policy_details.sql"
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 217df2bb..9a30a189 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1863,6 +1863,7 @@ run (void *cls)
 
     qs = plugin->get_reserve_history (plugin->cls,
                                       &reserve_pub,
+                                      0,
                                       &balance,
                                       &rh);
   }
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 67e5ff71..dfce91cd 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -3854,63 +3854,59 @@ TALER_wallet_recoup_refresh_sign (
 /**
  * Verify reserve history request signature.
  *
- * @param ts timestamp used
- * @param history_fee how much did the wallet say it would pay
+ * @param start_off start of the requested range
  * @param reserve_pub reserve the history request was for
  * @param reserve_sig resulting signature
  * @return #GNUNET_OK if the signature is valid
  */
 enum GNUNET_GenericReturnValue
 TALER_wallet_reserve_history_verify (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_Amount *history_fee,
+  uint64_t start_off,
   const struct TALER_ReservePublicKeyP *reserve_pub,
   const struct TALER_ReserveSignatureP *reserve_sig);
 
 
 /**
- * Create reserve history request signature.
+ * Create reserve status request signature.
  *
- * @param ts timestamp used
- * @param history_fee how much do we expect to pay
+ * @param start_off start of the requested range
  * @param reserve_priv private key of the reserve the history request is for
  * @param[out] reserve_sig resulting signature
  */
 void
 TALER_wallet_reserve_history_sign (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_Amount *history_fee,
+  uint64_t start_off,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   struct TALER_ReserveSignatureP *reserve_sig);
 
 
 /**
- * Verify reserve status request signature.
+ * Verify coin history request signature.
  *
- * @param ts timestamp used
- * @param reserve_pub reserve the status request was for
- * @param reserve_sig resulting signature
+ * @param start_off start of the requested range
+ * @param coin_pub coin the history request was for
+ * @param coin_sig resulting signature
  * @return #GNUNET_OK if the signature is valid
  */
 enum GNUNET_GenericReturnValue
-TALER_wallet_reserve_status_verify (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig);
+TALER_wallet_coin_history_verify (
+  uint64_t start_off,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  const struct TALER_CoinSpendSignatureP *coin_sig);
 
 
 /**
- * Create reserve status request signature.
+ * Create coin status request signature.
  *
- * @param ts timestamp used
- * @param reserve_priv private key of the reserve the status request is for
- * @param[out] reserve_sig resulting signature
+ * @param start_off start of the requested range
+ * @param coin_priv private key of the coin the history request is for
+ * @param[out] coin_sig resulting signature
  */
 void
-TALER_wallet_reserve_status_sign (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_ReservePrivateKeyP *reserve_priv,
-  struct TALER_ReserveSignatureP *reserve_sig);
+TALER_wallet_coin_history_sign (
+  uint64_t start_off,
+  const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+  struct TALER_CoinSpendSignatureP *coin_sig);
 
 
 /* ********************* merchant signing ************************** */
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 730451d1..77d4f2ba 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1171,8 +1171,11 @@ struct TALER_EXCHANGE_BatchDepositResult
      */
     struct
     {
-      /* FIXME: returning full details is not implemented */
-      // Should have 'coin_pub' here!
+      /**
+       * The coin that had a conflict.
+       */
+      struct TALER_CoinSpendPublicKeyP coin_pub;
+
     } conflict;
 
   } details;
@@ -1611,11 +1614,6 @@ enum TALER_EXCHANGE_ReserveTransactionType
    */
   TALER_EXCHANGE_RTT_CLOSING,
 
-  /**
-   * Reserve history request.
-   */
-  TALER_EXCHANGE_RTT_HISTORY,
-
   /**
    * Reserve purse merge operation.
    */
@@ -1650,6 +1648,13 @@ struct TALER_EXCHANGE_ReserveHistoryEntry
    */
   struct TALER_Amount amount;
 
+  /**
+   * Index of this entry in the reserve history.
+   * Useful to filter requests by starting offset.
+   * Offsets are not necessarily contiguous.
+   */
+  uint64_t entry_off;
+
   /**
    * Details depending on @e type.
    */
@@ -1787,25 +1792,6 @@ struct TALER_EXCHANGE_ReserveHistoryEntry
 
     } close_details;
 
-    /**
-     * Information about a history operation of the reserve.
-     * @e type is #TALER_EXCHANGE_RTT_HISTORY.
-     */
-    struct
-    {
-
-      /**
-       * When was the request made.
-       */
-      struct GNUNET_TIME_Timestamp request_timestamp;
-
-      /**
-       * Signature by the reserve approving the history request.
-       */
-      struct TALER_ReserveSignatureP reserve_sig;
-
-    } history_details;
-
     /**
      * Information about a merge operation on the reserve.
      * @e type is #TALER_EXCHANGE_RTT_MERGE.
@@ -2031,115 +2017,6 @@ TALER_EXCHANGE_reserves_get_cancel (
   struct TALER_EXCHANGE_ReservesGetHandle *rgh);
 
 
-/**
- * @brief A /reserves/$RID/status Handle
- */
-struct TALER_EXCHANGE_ReservesStatusHandle;
-
-
-/**
- * @brief Reserve status details.
- */
-struct TALER_EXCHANGE_ReserveStatus
-{
-
-  /**
-   * High-level HTTP response details.
-   */
-  struct TALER_EXCHANGE_HttpResponse hr;
-
-  /**
-   * Details depending on @e hr.http_status.
-   */
-  union
-  {
-
-    /**
-     * Information returned on success, if
-     * @e hr.http_status is #MHD_HTTP_OK
-     */
-    struct
-    {
-
-      /**
-       * Current reserve balance.  May not be the difference between
-       * @e total_in and @e total_out because the @e may be truncated.
-       */
-      struct TALER_Amount balance;
-
-      /**
-       * Total of all inbound transactions in @e history.
-       */
-      struct TALER_Amount total_in;
-
-      /**
-       * Total of all outbound transactions in @e history.
-       */
-      struct TALER_Amount total_out;
-
-      /**
-       * Reserve history.
-       */
-      const struct TALER_EXCHANGE_ReserveHistoryEntry *history;
-
-      /**
-       * Length of the @e history array.
-       */
-      unsigned int history_len;
-
-    } ok;
-
-  } details;
-
-};
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * reserve status request to a exchange.
- *
- * @param cls closure
- * @param rs HTTP response data
- */
-typedef void
-(*TALER_EXCHANGE_ReservesStatusCallback) (
-  void *cls,
-  const struct TALER_EXCHANGE_ReserveStatus *rs);
-
-
-/**
- * Submit a request to obtain the reserve status.
- *
- * @param ctx curl context
- * @param url exchange base URL
- * @param keys exchange keys
- * @param reserve_priv private key of the reserve to inspect
- * @param cb the callback to call when a reply for this request is available
- * @param cb_cls closure for the above callback
- * @return a handle for this request; NULL if the inputs are invalid (i.e.
- *         signatures fail to verify).  In this case, the callback is not 
called.
- */
-struct TALER_EXCHANGE_ReservesStatusHandle *
-TALER_EXCHANGE_reserves_status (
-  struct GNUNET_CURL_Context *ctx,
-  const char *url,
-  struct TALER_EXCHANGE_Keys *keys,
-  const struct TALER_ReservePrivateKeyP *reserve_priv,
-  TALER_EXCHANGE_ReservesStatusCallback cb,
-  void *cb_cls);
-
-
-/**
- * Cancel a reserve status request.  This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param rsh the reserve request handle
- */
-void
-TALER_EXCHANGE_reserves_status_cancel (
-  struct TALER_EXCHANGE_ReservesStatusHandle *rsh);
-
-
 /**
  * @brief A /reserves/$RID/history Handle
  */
@@ -2158,34 +2035,21 @@ struct TALER_EXCHANGE_ReserveHistory
   struct TALER_EXCHANGE_HttpResponse hr;
 
   /**
-   * Timestamp of when we made the history request
-   * (client-side).
-   */
-  struct GNUNET_TIME_Timestamp ts;
-
-  /**
-   * Reserve signature affirming the history request
-   * (generated as part of the request).
-   */
-  const struct TALER_ReserveSignatureP *reserve_sig;
-
-  /**
-   * Details depending on @e hr.http_status.
+   * Details depending on @e hr.http_history.
    */
   union
   {
 
     /**
      * Information returned on success, if
-     * @e hr.http_status is #MHD_HTTP_OK
+     * @e hr.http_history is #MHD_HTTP_OK
      */
     struct
     {
 
       /**
-       * Reserve balance. May not be the difference between
-       * @e total_in and @e total_out because the @e may be truncated
-       * due to expiration.
+       * Current reserve balance.  May not be the difference between
+       * @e total_in and @e total_out because the @e may be truncated.
        */
       struct TALER_Amount balance;
 
@@ -2236,6 +2100,7 @@ typedef void
  * @param url exchange base URL
  * @param keys exchange keys
  * @param reserve_priv private key of the reserve to inspect
+ * @param start_off offset of the oldest history entry to exclude from the 
response
  * @param cb the callback to call when a reply for this request is available
  * @param cb_cls closure for the above callback
  * @return a handle for this request; NULL if the inputs are invalid (i.e.
@@ -2247,6 +2112,7 @@ TALER_EXCHANGE_reserves_history (
   const char *url,
   struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
+  uint64_t start_off,
   TALER_EXCHANGE_ReservesHistoryCallback cb,
   void *cb_cls);
 
@@ -6866,6 +6732,18 @@ struct TALER_EXCHANGE_ReserveOpenResult
 
     } payment_required;
 
+    /**
+     * Information returned if status is
+     * #MHD_HTTP_CONFLICT.
+     */
+    struct
+    {
+      /**
+       * Public key of the coin that caused the conflict.
+       */
+      struct TALER_CoinSpendPublicKeyP coin_pub;
+
+    } conflict;
 
     /**
      * Information returned if KYC is required to proceed, set if
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 8fd9ce19..cc71f777 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -2739,29 +2739,6 @@ typedef enum GNUNET_GenericReturnValue
   struct GNUNET_TIME_Timestamp merge_timestamp);
 
 
-/**
- * Function called with details about
- * history requests that have been made, with
- * the goal of auditing the history request execution.
- *
- * @param cls closure
- * @param rowid unique serial ID for the deposit in our DB
- * @param history_fee fee paid for the request
- * @param ts timestamp of the request
- * @param reserve_pub reserve history was requested for
- * @param reserve_sig signature approving the @a history_fee
- * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
- */
-typedef enum GNUNET_GenericReturnValue
-(*TALER_EXCHANGEDB_HistoryRequestCallback)(
-  void *cls,
-  uint64_t rowid,
-  const struct TALER_Amount *history_fee,
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig);
-
-
 /**
  * Function called with details about purse decisions that have been made, with
  * the goal of auditing the purse's execution.
@@ -4249,6 +4226,7 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param reserve_pub public key of the reserve
+   * @param start_off maximum starting offset in history to exclude from 
returning
    * @param[out] balance set to the reserve balance
    * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
    * @return transaction status
@@ -4256,31 +4234,11 @@ struct TALER_EXCHANGEDB_Plugin
   enum GNUNET_DB_QueryStatus
   (*get_reserve_history)(void *cls,
                          const struct TALER_ReservePublicKeyP *reserve_pub,
+                         uint64_t start_off,
                          struct TALER_Amount *balance,
                          struct TALER_EXCHANGEDB_ReserveHistory **rhp);
 
 
-  /**
-   * Get truncated transaction history associated with the specified
-   * reserve.
-   *
-   * @param cls the @e cls of this struct with the plugin-specific state
-   * @param reserve_pub public key of the reserve
-   * @param[out] balance_in set to the total of inbound
-   *             transactions in the returned history
-   * @param[out] balance_out set to the total of outbound
-   *             transactions in the returned history
-   * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
-   * @return transaction status
-   */
-  enum GNUNET_DB_QueryStatus
-  (*get_reserve_status)(void *cls,
-                        const struct TALER_ReservePublicKeyP *reserve_pub,
-                        struct TALER_Amount *balance_in,
-                        struct TALER_Amount *balance_out,
-                        struct TALER_EXCHANGEDB_ReserveHistory **rhp);
-
-
   /**
    * The current reserve balance of the specified reserve.
    *
@@ -5252,24 +5210,6 @@ struct TALER_EXCHANGEDB_Plugin
     void *cb_cls);
 
 
-  /**
-   * Select history requests above @a serial_id in monotonically increasing
-   * order.
-   *
-   * @param cls closure
-   * @param serial_id highest serial ID to exclude (select strictly larger)
-   * @param cb function to call on each result
-   * @param cb_cls closure for @a cb
-   * @return transaction status code
-   */
-  enum GNUNET_DB_QueryStatus
-  (*select_history_requests_above_serial_id)(
-    void *cls,
-    uint64_t serial_id,
-    TALER_EXCHANGEDB_HistoryRequestCallback cb,
-    void *cb_cls);
-
-
   /**
    * Select purse refunds above @a serial_id in monotonically increasing
    * order.
@@ -6589,33 +6529,6 @@ struct TALER_EXCHANGEDB_Plugin
     struct TALER_ReservePublicKeyP *reserve_pub);
 
 
-  /**
-   * Function called to persist a signature that
-   * prove that the client requested an
-   * account history.  Debits the @a history_fee from
-   * the reserve (if possible).
-   *
-   * @param cls the @e cls of this struct with the plugin-specific state
-   * @param reserve_pub account that the history was requested for
-   * @param reserve_sig signature affirming the request
-   * @param request_timestamp when was the request made
-   * @param history_fee how much should the @a reserve_pub be charged for the 
request
-   * @param[out] balance_ok set to TRUE if the reserve balance
-   *         was sufficient
-   * @param[out] idempotent set to TRUE if the request is already in the DB
-   * @return transaction status code
-   */
-  enum GNUNET_DB_QueryStatus
-  (*insert_history_request)(
-    void *cls,
-    const struct TALER_ReservePublicKeyP *reserve_pub,
-    const struct TALER_ReserveSignatureP *reserve_sig,
-    struct GNUNET_TIME_Timestamp request_timestamp,
-    const struct TALER_Amount *history_fee,
-    bool *balance_ok,
-    bool *idempotent);
-
-
   /**
    * Function called to initiate closure of an account.
    *
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 367b54bb..5506f025 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -1289,22 +1289,6 @@ TALER_TESTING_cmd_reserve_history (const char *label,
                                    unsigned int expected_response_code);
 
 
-/**
- * Create a POST "/reserves/$RID/status" command.
- *
- * @param label the command label.
- * @param reserve_reference reference to the reserve to check.
- * @param expected_balance expected balance for the reserve.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_reserve_status (const char *label,
-                                  const char *reserve_reference,
-                                  const char *expected_balance,
-                                  unsigned int expected_response_code);
-
-
 /**
  * Create a POST "/reserves/$RID/open" command.
  *
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 6ff8e237..ff5d3b80 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -73,7 +73,6 @@ libtalerexchange_la_SOURCES = \
   exchange_api_reserves_get_attestable.c \
   exchange_api_reserves_history.c \
   exchange_api_reserves_open.c \
-  exchange_api_reserves_status.c \
   exchange_api_stefan.c \
   exchange_api_transfers_get.c \
   exchange_api_withdraw.c \
diff --git a/src/lib/exchange_api_batch_deposit.c 
b/src/lib/exchange_api_batch_deposit.c
index 3aea22b6..273b25e8 100644
--- a/src/lib/exchange_api_batch_deposit.c
+++ b/src/lib/exchange_api_batch_deposit.c
@@ -464,14 +464,11 @@ handle_deposit_finished (void *cls,
     break;
   case MHD_HTTP_CONFLICT:
     {
-      struct TALER_CoinSpendPublicKeyP coin_pub;
       struct GNUNET_JSON_Specification spec[] = {
         GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                     &coin_pub),
+                                     &dr->details.conflict.coin_pub),
         GNUNET_JSON_spec_end ()
       };
-      const struct TALER_EXCHANGE_DenomPublicKey *dki;
-      bool found = false;
 
       if (GNUNET_OK !=
           GNUNET_JSON_parse (j,
@@ -483,40 +480,6 @@ handle_deposit_finished (void *cls,
         dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      for (unsigned int i = 0; i<dh->num_cdds; i++)
-      {
-        if (0 !=
-            GNUNET_memcmp (&coin_pub,
-                           &dh->cdds[i].coin_pub))
-          continue;
-        dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys,
-                                                           &dh->cdds[i].
-                                                           h_denom_pub);
-        GNUNET_assert (NULL != dki);
-        if (GNUNET_OK !=
-            TALER_EXCHANGE_check_coin_conflict_ (
-              dh->keys,
-              j,
-              dki,
-              &dh->cdds[i].coin_pub,
-              &dh->cdds[i].coin_sig,
-              &dh->cdds[i].amount))
-        {
-          GNUNET_break_op (0);
-          dr->hr.http_status = 0;
-          dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        found = true;
-        break;
-      }
-      if (! found)
-      {
-        GNUNET_break_op (0);
-        dr->hr.http_status = 0;
-        dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-        break;
-      }
       dr->hr.ec = TALER_JSON_get_error_code (j);
       dr->hr.hint = TALER_JSON_get_error_hint (j);
     }
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 609a2f7e..3ad88017 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -478,59 +478,6 @@ parse_merge (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
 }
 
 
-/**
- * Parse "history" reserve history entry.
- *
- * @param[in,out] rh entry to parse
- * @param uc our context
- * @param transaction the transaction to parse
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-parse_history (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
-               struct HistoryParseContext *uc,
-               const json_t *transaction)
-{
-  struct GNUNET_JSON_Specification history_spec[] = {
-    GNUNET_JSON_spec_fixed_auto ("reserve_sig",
-                                 &rh->details.history_details.reserve_sig),
-    GNUNET_JSON_spec_timestamp ("request_timestamp",
-                                
&rh->details.history_details.request_timestamp),
-    GNUNET_JSON_spec_end ()
-  };
-
-  rh->type = TALER_EXCHANGE_RTT_HISTORY;
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (transaction,
-                         history_spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_OK !=
-      TALER_wallet_reserve_history_verify (
-        rh->details.history_details.request_timestamp,
-        &rh->amount,
-        uc->reserve_pub,
-        &rh->details.history_details.reserve_sig))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  if (0 >
-      TALER_amount_add (uc->total_out,
-                        uc->total_out,
-                        &rh->amount))
-  {
-    /* overflow in history already!? inconceivable! Bad exchange! */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Parse "open" reserve open entry.
  *
@@ -666,7 +613,6 @@ TALER_EXCHANGE_parse_reserve_history (
     { "RECOUP", &parse_recoup },
     { "MERGE", &parse_merge },
     { "CLOSING", &parse_closing },
-    { "HISTORY", &parse_history },
     { "OPEN", &parse_open },
     { "CLOSE", &parse_close },
     { NULL, NULL }
@@ -771,8 +717,6 @@ TALER_EXCHANGE_free_reserve_history (
       break;
     case TALER_EXCHANGE_RTT_CLOSING:
       break;
-    case TALER_EXCHANGE_RTT_HISTORY:
-      break;
     case TALER_EXCHANGE_RTT_MERGE:
       break;
     case TALER_EXCHANGE_RTT_OPEN:
@@ -1867,66 +1811,6 @@ TALER_EXCHANGE_check_purse_econtract_conflict_ (
 }
 
 
-enum GNUNET_GenericReturnValue
-TALER_EXCHANGE_check_coin_amount_conflict_ (
-  const struct TALER_EXCHANGE_Keys *keys,
-  const json_t *proof,
-  struct TALER_CoinSpendPublicKeyP *coin_pub,
-  struct TALER_Amount *remaining)
-{
-  const json_t *history;
-  struct TALER_Amount total;
-  struct TALER_DenominationHashP h_denom_pub;
-  const struct TALER_EXCHANGE_DenomPublicKey *dki;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                 coin_pub),
-    GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
-                                 &h_denom_pub),
-    GNUNET_JSON_spec_array_const ("history",
-                                  &history),
-    GNUNET_JSON_spec_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (proof,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  dki = TALER_EXCHANGE_get_denomination_key_by_hash (
-    keys,
-    &h_denom_pub);
-  if (NULL == dki)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_OK !=
-      TALER_EXCHANGE_verify_coin_history (dki,
-                                          coin_pub,
-                                          history,
-                                          &total))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  if (0 >
-      TALER_amount_subtract (remaining,
-                             &dki->value,
-                             &total))
-  {
-    /* Strange 'proof': coin was double-spent
-       before our transaction?! */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Verify that @a coin_sig does NOT appear in
  * the history of @a proof and thus whatever transaction
@@ -1937,6 +1821,7 @@ TALER_EXCHANGE_check_coin_amount_conflict_ (
  * @param coin_sig signature that must not be in @a proof
  * @return #GNUNET_OK if @a coin_sig is not in @a proof
  */
+// FIXME: move to exchange_api_coin_history.c!
 enum GNUNET_GenericReturnValue
 TALER_EXCHANGE_check_coin_signature_conflict_ (
   const json_t *proof,
@@ -2011,13 +1896,25 @@ TALER_EXCHANGE_check_coin_denomination_conflict_ (
 }
 
 
+/**
+ * Check that the provided @a proof indeeds indicates
+ * a conflict for @a coin_pub.
+ *
+ * @param keys exchange keys
+ * @param proof provided conflict proof
+ * @param dk denomination of @a coin_pub that the client
+ *           used
+ * @param coin_pub public key of the coin
+ * @param required balance required on the coin for the operation
+ * @return #GNUNET_OK if @a proof holds
+ */
+// FIXME: move to exchange_api_coin_history.c!
 enum GNUNET_GenericReturnValue
 TALER_EXCHANGE_check_coin_conflict_ (
   const struct TALER_EXCHANGE_Keys *keys,
   const json_t *proof,
   const struct TALER_EXCHANGE_DenomPublicKey *dk,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  const struct TALER_CoinSpendSignatureP *coin_sig,
   const struct TALER_Amount *required)
 {
   enum TALER_ErrorCode ec;
@@ -2026,81 +1923,12 @@ TALER_EXCHANGE_check_coin_conflict_ (
   switch (ec)
   {
   case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
-    {
-      struct TALER_Amount left;
-      struct TALER_CoinSpendPublicKeyP pcoin_pub;
-
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_amount_conflict_ (
-            keys,
-            proof,
-            &pcoin_pub,
-            &left))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (0 !=
-          GNUNET_memcmp (&pcoin_pub,
-                         coin_pub))
-      {
-        /* conflict is for a different coin! */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (-1 !=
-          TALER_amount_cmp (&left,
-                            required))
-      {
-        /* Balance was sufficient after all; recoup MAY have still been 
possible */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_signature_conflict_ (
-            proof,
-            coin_sig))
-      {
-        /* Not a conflicting transaction: ours is included! */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      break;
-    }
+    /* Nothing to check anymore here, proof needs to be
+       checked in the GET /coins/$COIN_PUB handler */
+    break;
   case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
-    {
-      struct TALER_Amount left;
-      struct TALER_CoinSpendPublicKeyP pcoin_pub;
-
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_amount_conflict_ (
-            keys,
-            proof,
-            &pcoin_pub,
-            &left))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (0 !=
-          GNUNET_memcmp (&pcoin_pub,
-                         coin_pub))
-      {
-        /* conflict is for a different coin! */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_denomination_conflict_ (
-            proof,
-            &dk->h_key))
-      {
-        /* Eh, same denomination, hence no conflict */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      break;
-    }
+    // FIXME: write check!
+    break;
   default:
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h
index 1b9ddce3..0fcaac3f 100644
--- a/src/lib/exchange_api_common.h
+++ b/src/lib/exchange_api_common.h
@@ -170,7 +170,6 @@ TALER_EXCHANGE_check_coin_signature_conflict_ (
  * @param dk denomination of @a coin_pub that the client
  *           used
  * @param coin_pub public key of the coin
- * @param coin_sig signature over operation that conflicted
  * @param required balance required on the coin for the operation
  * @return #GNUNET_OK if @a proof holds
  */
@@ -180,7 +179,6 @@ TALER_EXCHANGE_check_coin_conflict_ (
   const json_t *proof,
   const struct TALER_EXCHANGE_DenomPublicKey *dk,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  const struct TALER_CoinSpendSignatureP *coin_sig,
   const struct TALER_Amount *required);
 
 
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c
index 7fbd2114..ba4241da 100644
--- a/src/lib/exchange_api_melt.c
+++ b/src/lib/exchange_api_melt.c
@@ -218,10 +218,8 @@ handle_melt_finished (void *cls,
     .hr.reply = j,
     .hr.http_status = (unsigned int) response_code
   };
-  const struct TALER_EXCHANGE_Keys *keys;
 
   mh->job = NULL;
-  keys = mh->keys;
   switch (response_code)
   {
   case 0:
@@ -254,20 +252,6 @@ handle_melt_finished (void *cls,
   case MHD_HTTP_CONFLICT:
     mr.hr.ec = TALER_JSON_get_error_code (j);
     mr.hr.hint = TALER_JSON_get_error_hint (j);
-    if (GNUNET_OK !=
-        TALER_EXCHANGE_check_coin_conflict_ (
-          keys,
-          j,
-          mh->dki,
-          &mh->coin_pub,
-          &mh->coin_sig,
-          &mh->md.melted_coin.melt_amount_with_fee))
-    {
-      GNUNET_break_op (0);
-      mr.hr.http_status = 0;
-      mr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-      break;
-    }
     break;
   case MHD_HTTP_FORBIDDEN:
     /* Nothing really to verify, exchange says one of the signatures is
diff --git a/src/lib/exchange_api_purse_create_with_deposit.c 
b/src/lib/exchange_api_purse_create_with_deposit.c
index 13874678..c64beede 100644
--- a/src/lib/exchange_api_purse_create_with_deposit.c
+++ b/src/lib/exchange_api_purse_create_with_deposit.c
@@ -277,107 +277,12 @@ handle_purse_create_deposit_finished (void *cls,
         }
         break;
       case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
-        {
-          struct TALER_Amount left;
-          struct TALER_CoinSpendPublicKeyP pcoin_pub;
-          bool found = false;
-
-          if (GNUNET_OK !=
-              TALER_EXCHANGE_check_coin_amount_conflict_ (
-                keys,
-                j,
-                &pcoin_pub,
-                &left))
-          {
-            GNUNET_break_op (0);
-            dr.hr.http_status = 0;
-            dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-            break;
-          }
-          for (unsigned int i = 0; i<pch->num_deposits; i++)
-          {
-            struct Deposit *deposit = &pch->deposits[i];
-
-            if (0 != GNUNET_memcmp (&pcoin_pub,
-                                    &deposit->coin_pub))
-              continue;
-            if (-1 !=
-                TALER_amount_cmp (&left,
-                                  &deposit->contribution))
-            {
-              /* Balance was sufficient after all; operation MAY have still 
been possible */
-              GNUNET_break_op (0);
-              continue;
-            }
-            if (GNUNET_OK !=
-                TALER_EXCHANGE_check_coin_signature_conflict_ (
-                  j,
-                  &deposit->coin_sig))
-            {
-              GNUNET_break_op (0);
-              continue;
-            }
-            found = true;
-            break;
-          }
-          if (! found)
-          {
-            /* conflict is for a different coin! */
-            GNUNET_break_op (0);
-            dr.hr.http_status = 0;
-            dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-            break;
-          }
-          break;
-        }
+        /* Nothing to check anymore here, proof needs to be
+           checked in the GET /coins/$COIN_PUB handler */
+        break;
       case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
-        {
-          struct TALER_Amount left;
-          struct TALER_CoinSpendPublicKeyP pcoin_pub;
-          bool found = false;
-
-          if (GNUNET_OK !=
-              TALER_EXCHANGE_check_coin_amount_conflict_ (
-                keys,
-                j,
-                &pcoin_pub,
-                &left))
-          {
-            GNUNET_break_op (0);
-            dr.hr.http_status = 0;
-            dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-            break;
-          }
-          for (unsigned int i = 0; i<pch->num_deposits; i++)
-          {
-            struct Deposit *deposit = &pch->deposits[i];
-
-            if (0 !=
-                GNUNET_memcmp (&pcoin_pub,
-                               &deposit->coin_pub))
-              continue;
-            if (GNUNET_OK !=
-                TALER_EXCHANGE_check_coin_denomination_conflict_ (
-                  j,
-                  &deposit->h_denom_pub))
-            {
-              /* Eh, same denomination, hence no conflict */
-              GNUNET_break_op (0);
-              continue;
-            }
-            found = true;
-          }
-          if (! found)
-          {
-            /* conflict is for a different coin! */
-            GNUNET_break_op (0);
-            dr.hr.http_status = 0;
-            dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-            break;
-          }
-          /* meta data conflict is real! */
-          break;
-        }
+        // FIXME: write check (add to exchange_api_common! */
+        break;
       case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
         {
           struct TALER_CoinSpendPublicKeyP coin_pub;
diff --git a/src/lib/exchange_api_purse_deposit.c 
b/src/lib/exchange_api_purse_deposit.c
index 7bb3b951..7db2f34c 100644
--- a/src/lib/exchange_api_purse_deposit.c
+++ b/src/lib/exchange_api_purse_deposit.c
@@ -297,114 +297,11 @@ handle_purse_deposit_finished (void *cls,
         break;
       }
     case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
-      {
-        struct TALER_CoinSpendPublicKeyP coin_pub;
-        struct TALER_Amount remaining;
-        bool found = false;
-        const struct Coin *my_coin;
-
-        if (GNUNET_OK !=
-            TALER_EXCHANGE_check_coin_amount_conflict_ (
-              keys,
-              j,
-              &coin_pub,
-              &remaining))
-        {
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        for (unsigned int i = 0; i<pch->num_deposits; i++)
-        {
-          if (0 == GNUNET_memcmp (&coin_pub,
-                                  &pch->coins[i].coin_pub))
-          {
-            found = true;
-            my_coin = &pch->coins[i];
-            break;
-          }
-        }
-        if (! found)
-        {
-          /* proof is about a coin we did not even deposit */
-          GNUNET_break_op (0);
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        if (1 == TALER_amount_cmp (&remaining,
-                                   &my_coin->contribution))
-        {
-          /* transaction should have still fit */
-          GNUNET_break_op (0);
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        if (GNUNET_OK !=
-            TALER_EXCHANGE_check_coin_signature_conflict_ (
-              j,
-              &my_coin->coin_sig))
-        {
-          /* THIS transaction must not be in the conflicting history */
-          GNUNET_break_op (0);
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        /* everything OK, proof of double-spending was provided */
-        break;
-      }
+      /* Nothing to check anymore here, proof needs to be
+         checked in the GET /coins/$COIN_PUB handler */
+      break;
     case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
-      {
-        struct TALER_CoinSpendPublicKeyP coin_pub;
-        struct TALER_Amount remaining;
-        bool found = false;
-        const struct Coin *my_coin;
-
-        if (GNUNET_OK !=
-            TALER_EXCHANGE_check_coin_amount_conflict_ (
-              keys,
-              j,
-              &coin_pub,
-              &remaining))
-        {
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        for (unsigned int i = 0; i<pch->num_deposits; i++)
-        {
-          if (0 == GNUNET_memcmp (&coin_pub,
-                                  &pch->coins[i].coin_pub))
-          {
-            found = true;
-            my_coin = &pch->coins[i];
-            break;
-          }
-        }
-        if (! found)
-        {
-          /* proof is about a coin we did not even deposit */
-          GNUNET_break_op (0);
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        if (GNUNET_OK !=
-            TALER_EXCHANGE_check_coin_denomination_conflict_ (
-              j,
-              &my_coin->h_denom_pub))
-        {
-          /* no conflicting denomination detected */
-          GNUNET_break_op (0);
-          dr.hr.http_status = 0;
-          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-          break;
-        }
-        /* everything OK, proof of conflicting denomination was provided */
-        break;
-      }
+      break;
     default:
       GNUNET_break_op (0);
       dr.hr.http_status = 0;
diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c
index e7daff16..cfd265f0 100644
--- a/src/lib/exchange_api_recoup.c
+++ b/src/lib/exchange_api_recoup.c
@@ -183,20 +183,6 @@ handle_recoup_finished (void *cls,
         rr.hr.http_status = 0;
         break;
       }
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_conflict_ (
-            ph->keys,
-            j,
-            &ph->pk,
-            &ph->coin_pub,
-            &ph->coin_sig,
-            &min_key))
-      {
-        GNUNET_break (0);
-        rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-        rr.hr.http_status = 0;
-        break;
-      }
       break;
     }
   case MHD_HTTP_FORBIDDEN:
diff --git a/src/lib/exchange_api_recoup_refresh.c 
b/src/lib/exchange_api_recoup_refresh.c
index f5745deb..0bcd44de 100644
--- a/src/lib/exchange_api_recoup_refresh.c
+++ b/src/lib/exchange_api_recoup_refresh.c
@@ -183,36 +183,9 @@ handle_recoup_refresh_finished (void *cls,
     rrr.hr.hint = TALER_JSON_get_error_hint (j);
     break;
   case MHD_HTTP_CONFLICT:
-    {
-      struct TALER_Amount min_key;
-
-      rrr.hr.ec = TALER_JSON_get_error_code (j);
-      rrr.hr.hint = TALER_JSON_get_error_hint (j);
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_get_min_denomination_ (ph->keys,
-                                                &min_key))
-      {
-        GNUNET_break (0);
-        rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-        rrr.hr.http_status = 0;
-        break;
-      }
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_conflict_ (
-            ph->keys,
-            j,
-            &ph->pk,
-            &ph->coin_pub,
-            &ph->coin_sig,
-            &min_key))
-      {
-        GNUNET_break (0);
-        rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-        rrr.hr.http_status = 0;
-        break;
-      }
-      break;
-    }
+    rrr.hr.ec = TALER_JSON_get_error_code (j);
+    rrr.hr.hint = TALER_JSON_get_error_hint (j);
+    break;
   case MHD_HTTP_GONE:
     /* Kind of normal: the money was already sent to the merchant
        (it was too late for the refund). */
diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c
index 3f12f28d..7401bfe4 100644
--- a/src/lib/exchange_api_refund.c
+++ b/src/lib/exchange_api_refund.c
@@ -157,307 +157,6 @@ verify_refund_signature_ok (struct 
TALER_EXCHANGE_RefundHandle *rh,
 }
 
 
-/**
- * Verify that the information in the "409 Conflict" response
- * from the exchange is valid and indeed shows that the refund
- * amount requested is too high.
- *
- * @param[in,out] rh refund handle (refund fee added)
- * @param json json reply with the coin transaction history
- * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
-                            const json_t *json)
-{
-  const json_t *history;
-  struct TALER_DenominationHashP h_denom_pub;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_array_const ("history",
-                                  &history),
-    GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
-                                 &h_denom_pub),
-    GNUNET_JSON_spec_end ()
-  };
-  size_t len;
-  struct TALER_Amount dtotal;
-  bool have_deposit;
-  struct TALER_Amount rtotal;
-  bool have_refund;
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (json,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  len = json_array_size (history);
-  if (0 == len)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  have_deposit = false;
-  have_refund = false;
-  for (size_t off = 0; off<len; off++)
-  {
-    json_t *transaction;
-    struct TALER_Amount amount;
-    const char *type;
-    struct GNUNET_JSON_Specification spec_glob[] = {
-      TALER_JSON_spec_amount_any ("amount",
-                                  &amount),
-      GNUNET_JSON_spec_string ("type",
-                               &type),
-      GNUNET_JSON_spec_end ()
-    };
-
-    transaction = json_array_get (history,
-                                  off);
-    if (GNUNET_OK !=
-        GNUNET_JSON_parse (transaction,
-                           spec_glob,
-                           NULL, NULL))
-    {
-      GNUNET_break_op (0);
-      return GNUNET_SYSERR;
-    }
-    if (0 == strcasecmp (type,
-                         "DEPOSIT"))
-    {
-      struct TALER_Amount deposit_fee;
-      struct TALER_MerchantWireHashP h_wire;
-      struct TALER_PrivateContractHashP h_contract_terms;
-      struct TALER_AgeCommitmentHash h_age_commitment;
-      bool no_hac;
-      struct TALER_ExtensionPolicyHashP h_policy;
-      bool no_h_policy;
-      struct GNUNET_HashCode wallet_data_hash;
-      bool no_wallet_data_hash;
-      struct GNUNET_TIME_Timestamp wallet_timestamp;
-      struct TALER_MerchantPublicKeyP merchant_pub;
-      struct GNUNET_TIME_Timestamp refund_deadline;
-      struct TALER_CoinSpendSignatureP sig;
-      struct GNUNET_JSON_Specification ispec[] = {
-        GNUNET_JSON_spec_fixed_auto ("coin_sig",
-                                     &sig),
-        GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
-                                     &h_contract_terms),
-        GNUNET_JSON_spec_fixed_auto ("h_wire",
-                                     &h_wire),
-        GNUNET_JSON_spec_mark_optional (
-          GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
-                                       &h_age_commitment),
-          &no_hac),
-        GNUNET_JSON_spec_mark_optional (
-          GNUNET_JSON_spec_fixed_auto ("h_policy",
-                                       &h_policy),
-          &no_h_policy),
-        GNUNET_JSON_spec_mark_optional (
-          GNUNET_JSON_spec_fixed_auto ("wallet_data_hash",
-                                       &wallet_data_hash),
-          &no_wallet_data_hash),
-        GNUNET_JSON_spec_timestamp ("timestamp",
-                                    &wallet_timestamp),
-        GNUNET_JSON_spec_timestamp ("refund_deadline",
-                                    &refund_deadline),
-        TALER_JSON_spec_amount_any ("deposit_fee",
-                                    &deposit_fee),
-        GNUNET_JSON_spec_fixed_auto ("merchant_pub",
-                                     &merchant_pub),
-        GNUNET_JSON_spec_end ()
-      };
-
-      if (GNUNET_OK !=
-          GNUNET_JSON_parse (transaction,
-                             ispec,
-                             NULL, NULL))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (GNUNET_OK !=
-          TALER_wallet_deposit_verify (&amount,
-                                       &deposit_fee,
-                                       &h_wire,
-                                       &h_contract_terms,
-                                       no_wallet_data_hash ? NULL :
-                                       &wallet_data_hash,
-                                       no_hac ?  NULL : &h_age_commitment,
-                                       no_h_policy ? NULL: &h_policy,
-                                       &h_denom_pub,
-                                       wallet_timestamp,
-                                       &merchant_pub,
-                                       refund_deadline,
-                                       &rh->coin_pub,
-                                       &sig))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if ( (0 != GNUNET_memcmp (&rh->h_contract_terms,
-                                &h_contract_terms)) ||
-           (0 != GNUNET_memcmp (&rh->merchant,
-                                &merchant_pub)) )
-      {
-        /* deposit information is about a different merchant/contract */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (have_deposit)
-      {
-        /* this cannot really happen, but we conservatively support it anyway 
*/
-        if (GNUNET_YES !=
-            TALER_amount_cmp_currency (&amount,
-                                       &dtotal))
-        {
-          GNUNET_break_op (0);
-          return GNUNET_SYSERR;
-        }
-        GNUNET_break (0 <=
-                      TALER_amount_add (&dtotal,
-                                        &dtotal,
-                                        &amount));
-      }
-      else
-      {
-        dtotal = amount;
-        have_deposit = true;
-      }
-    }
-    else if (0 == strcasecmp (type,
-                              "REFUND"))
-    {
-      struct TALER_MerchantSignatureP sig;
-      struct TALER_Amount refund_fee;
-      struct TALER_Amount sig_amount;
-      struct TALER_PrivateContractHashP h_contract_terms;
-      uint64_t rtransaction_id;
-      struct TALER_MerchantPublicKeyP merchant_pub;
-      struct GNUNET_JSON_Specification ispec[] = {
-        TALER_JSON_spec_amount_any ("refund_fee",
-                                    &refund_fee),
-        GNUNET_JSON_spec_fixed_auto ("merchant_sig",
-                                     &sig),
-        GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
-                                     &h_contract_terms),
-        GNUNET_JSON_spec_fixed_auto ("merchant_pub",
-                                     &merchant_pub),
-        GNUNET_JSON_spec_uint64 ("rtransaction_id",
-                                 &rtransaction_id),
-        GNUNET_JSON_spec_end ()
-      };
-
-      if (GNUNET_OK !=
-          GNUNET_JSON_parse (transaction,
-                             ispec,
-                             NULL, NULL))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (0 >
-          TALER_amount_add (&sig_amount,
-                            &refund_fee,
-                            &amount))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (GNUNET_OK !=
-          TALER_merchant_refund_verify (&rh->coin_pub,
-                                        &h_contract_terms,
-                                        rtransaction_id,
-                                        &sig_amount,
-                                        &merchant_pub,
-                                        &sig))
-      {
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if ( (0 != GNUNET_memcmp (&rh->h_contract_terms,
-                                &h_contract_terms)) ||
-           (0 != GNUNET_memcmp (&rh->merchant,
-                                &merchant_pub)) )
-      {
-        /* refund is about a different merchant/contract */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-      if (rtransaction_id == rh->rtransaction_id)
-      {
-        /* Eh, this shows either a dependency failure or idempotency,
-           but must not happen in a conflict reply. Fail! */
-        GNUNET_break_op (0);
-        return GNUNET_SYSERR;
-      }
-
-      if (have_refund)
-      {
-        if (GNUNET_YES !=
-            TALER_amount_cmp_currency (&amount,
-                                       &rtotal))
-        {
-          GNUNET_break_op (0);
-          return GNUNET_SYSERR;
-        }
-        GNUNET_break (0 <=
-                      TALER_amount_add (&rtotal,
-                                        &rtotal,
-                                        &amount));
-      }
-      else
-      {
-        rtotal = amount;
-        have_refund = true;
-      }
-    }
-    else
-    {
-      /* unexpected type, new version on server? */
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Unexpected type `%s' in response for exchange refund\n",
-                  type);
-      GNUNET_break_op (0);
-      return GNUNET_SYSERR;
-    }
-  }
-
-  if (have_refund)
-  {
-    if (0 >
-        TALER_amount_add (&rtotal,
-                          &rtotal,
-                          &rh->refund_amount))
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
-  }
-  else
-  {
-    rtotal = rh->refund_amount;
-    have_refund = true;
-  }
-  if (! have_deposit)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if (-1 != TALER_amount_cmp (&dtotal,
-                              &rtotal))
-  {
-    /* rtotal <= dtotal is fine, no conflict! */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  /* dtotal < rtotal: that's a conflict! */
-  return GNUNET_OK;
-}
-
-
 /**
  * Verify that the information on the "412 Dependency Failed" response
  * from the exchange is valid and indeed shows that there is a refund
@@ -615,19 +314,6 @@ handle_refund_finished (void *cls,
     break;
   case MHD_HTTP_CONFLICT:
     /* Requested total refunds exceed deposited amount */
-    if (GNUNET_OK !=
-        verify_conflict_history_ok (rh,
-                                    j))
-    {
-      GNUNET_break (0);
-      json_dumpf (j,
-                  stderr,
-                  JSON_INDENT (2));
-      rr.hr.http_status = 0;
-      rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE;
-      rr.hr.hint = "conflict information provided by exchange is invalid";
-      break;
-    }
     rr.hr.ec = TALER_JSON_get_error_code (j);
     rr.hr.hint = TALER_JSON_get_error_hint (j);
     break;
diff --git a/src/lib/exchange_api_reserves_history.c 
b/src/lib/exchange_api_reserves_history.c
index d4366eb3..c92fad5e 100644
--- a/src/lib/exchange_api_reserves_history.c
+++ b/src/lib/exchange_api_reserves_history.c
@@ -64,25 +64,15 @@ struct TALER_EXCHANGE_ReservesHistoryHandle
    */
   TALER_EXCHANGE_ReservesHistoryCallback cb;
 
-  /**
-   * Closure for @a cb.
-   */
-  void *cb_cls;
-
   /**
    * Public key of the reserve we are querying.
    */
   struct TALER_ReservePublicKeyP reserve_pub;
 
   /**
-   * Our signature.
-   */
-  struct TALER_ReserveSignatureP reserve_sig;
-
-  /**
-   * When did we make the request.
+   * Closure for @a cb.
    */
-  struct GNUNET_TIME_Timestamp ts;
+  void *cb_cls;
 
 };
 
@@ -103,9 +93,7 @@ handle_reserves_history_ok (struct 
TALER_EXCHANGE_ReservesHistoryHandle *rsh,
   unsigned int len;
   struct TALER_EXCHANGE_ReserveHistory rs = {
     .hr.reply = j,
-    .hr.http_status = MHD_HTTP_OK,
-    .ts = rsh->ts,
-    .reserve_sig = &rsh->reserve_sig
+    .hr.http_status = MHD_HTTP_OK
   };
   struct GNUNET_JSON_Specification spec[] = {
     TALER_JSON_spec_amount_any ("balance",
@@ -143,6 +131,7 @@ handle_reserves_history_ok (struct 
TALER_EXCHANGE_ReservesHistoryHandle *rsh,
       GNUNET_break_op (0);
       TALER_EXCHANGE_free_reserve_history (len,
                                            rhistory);
+      GNUNET_JSON_parse_free (spec);
       return GNUNET_SYSERR;
     }
     if (NULL != rsh->cb)
@@ -191,7 +180,6 @@ handle_reserves_history_finished (void *cls,
         handle_reserves_history_ok (rsh,
                                     j))
     {
-      GNUNET_break_op (0);
       rs.hr.http_status = 0;
       rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     }
@@ -216,11 +204,6 @@ handle_reserves_history_finished (void *cls,
     rs.hr.ec = TALER_JSON_get_error_code (j);
     rs.hr.hint = TALER_JSON_get_error_hint (j);
     break;
-  case MHD_HTTP_CONFLICT:
-    /* Insufficient balance to inquire for reserve history */
-    rs.hr.ec = TALER_JSON_get_error_code (j);
-    rs.hr.hint = TALER_JSON_get_error_hint (j);
-    break;
   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     /* Server had an internal issue; we should retry, but this API
        leaves this to the application */
@@ -254,18 +237,18 @@ TALER_EXCHANGE_reserves_history (
   const char *url,
   struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
+  uint64_t start_off,
   TALER_EXCHANGE_ReservesHistoryCallback cb,
   void *cb_cls)
 {
   struct TALER_EXCHANGE_ReservesHistoryHandle *rsh;
   CURL *eh;
-  char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
-  const struct TALER_EXCHANGE_GlobalFee *gf;
+  char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 64];
+  struct TALER_ReserveSignatureP reserve_sig;
 
   rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesHistoryHandle);
   rsh->cb = cb;
   rsh->cb_cls = cb_cls;
-  rsh->ts = GNUNET_TIME_timestamp_get ();
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
                                       &rsh->reserve_pub.eddsa_pub);
   {
@@ -278,10 +261,17 @@ TALER_EXCHANGE_reserves_history (
       pub_str,
       sizeof (pub_str));
     *end = '\0';
-    GNUNET_snprintf (arg_str,
-                     sizeof (arg_str),
-                     "reserves/%s/history",
-                     pub_str);
+    if (0 != start_off)
+      GNUNET_snprintf (arg_str,
+                       sizeof (arg_str),
+                       "reserves/%s/history?start=%llu",
+                       pub_str,
+                       (unsigned long long) start_off);
+    else
+      GNUNET_snprintf (arg_str,
+                       sizeof (arg_str),
+                       "reserves/%s/history",
+                       pub_str);
   }
   rsh->url = TALER_url_join (url,
                              arg_str,
@@ -299,26 +289,13 @@ TALER_EXCHANGE_reserves_history (
     GNUNET_free (rsh);
     return NULL;
   }
-  gf = TALER_EXCHANGE_get_global_fee (keys,
-                                      rsh->ts);
-  if (NULL == gf)
-  {
-    GNUNET_break_op (0);
-    curl_easy_cleanup (eh);
-    GNUNET_free (rsh->url);
-    GNUNET_free (rsh);
-    return NULL;
-  }
-  TALER_wallet_reserve_history_sign (rsh->ts,
-                                     &gf->fees.history,
+  TALER_wallet_reserve_history_sign (start_off,
                                      reserve_priv,
-                                     &rsh->reserve_sig);
+                                     &reserve_sig);
   {
     json_t *history_obj = GNUNET_JSON_PACK (
-      GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                  rsh->ts),
       GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                  &rsh->reserve_sig));
+                                  &reserve_sig));
 
     if (GNUNET_OK !=
         TALER_curl_easy_post (&rsh->post_ctx,
diff --git a/src/lib/exchange_api_reserves_open.c 
b/src/lib/exchange_api_reserves_open.c
index 536efdb1..36e43568 100644
--- a/src/lib/exchange_api_reserves_open.c
+++ b/src/lib/exchange_api_reserves_open.c
@@ -322,11 +322,9 @@ handle_reserves_open_finished (void *cls,
   case MHD_HTTP_CONFLICT:
     {
       const struct CoinData *cd = NULL;
-      struct TALER_CoinSpendPublicKeyP coin_pub;
-      const struct TALER_EXCHANGE_DenomPublicKey *dk;
       struct GNUNET_JSON_Specification spec[] = {
         GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                     &coin_pub),
+                                     &rs.details.conflict.coin_pub),
         GNUNET_JSON_spec_end ()
       };
 
@@ -345,7 +343,7 @@ handle_reserves_open_finished (void *cls,
       {
         const struct CoinData *cdi = &roh->coins[i];
 
-        if (0 == GNUNET_memcmp (&coin_pub,
+        if (0 == GNUNET_memcmp (&rs.details.conflict.coin_pub,
                                 &cdi->coin_pub))
         {
           cd = cdi;
@@ -359,28 +357,6 @@ handle_reserves_open_finished (void *cls,
         rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      dk = TALER_EXCHANGE_get_denomination_key_by_hash (roh->keys,
-                                                        &cd->h_denom_pub);
-      if (NULL == dk)
-      {
-        GNUNET_break_op (0);
-        rs.hr.http_status = 0;
-        rs.hr.ec = TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR;
-        break;
-      }
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_conflict_ (roh->keys,
-                                               j,
-                                               dk,
-                                               &coin_pub,
-                                               &cd->coin_sig,
-                                               &cd->contribution))
-      {
-        GNUNET_break_op (0);
-        rs.hr.http_status = 0;
-        rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-        break;
-      }
       rs.hr.ec = TALER_JSON_get_error_code (j);
       rs.hr.hint = TALER_JSON_get_error_hint (j);
       break;
diff --git a/src/lib/exchange_api_reserves_status.c 
b/src/lib/exchange_api_reserves_status.c
deleted file mode 100644
index 2ea64e8a..00000000
--- a/src/lib/exchange_api_reserves_status.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2014-2023 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 lib/exchange_api_reserves_status.c
- * @brief Implementation of the POST /reserves/$RESERVE_PUB/status requests
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_json_lib.h>
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "exchange_api_curl_defaults.h"
-
-
-/**
- * @brief A /reserves/$RID/status Handle
- */
-struct TALER_EXCHANGE_ReservesStatusHandle
-{
-
-  /**
-   * The keys of the exchange this request handle will use
-   */
-  struct TALER_EXCHANGE_Keys *keys;
-
-  /**
-   * The url for this request.
-   */
-  char *url;
-
-  /**
-   * Handle for the request.
-   */
-  struct GNUNET_CURL_Job *job;
-
-  /**
-   * Context for #TEH_curl_easy_post(). Keeps the data that must
-   * persist for Curl to make the upload.
-   */
-  struct TALER_CURL_PostContext post_ctx;
-
-  /**
-   * Function to call with the result.
-   */
-  TALER_EXCHANGE_ReservesStatusCallback cb;
-
-  /**
-   * Public key of the reserve we are querying.
-   */
-  struct TALER_ReservePublicKeyP reserve_pub;
-
-  /**
-   * Closure for @a cb.
-   */
-  void *cb_cls;
-
-};
-
-
-/**
- * We received an #MHD_HTTP_OK status code. Handle the JSON
- * response.
- *
- * @param rsh handle of the request
- * @param j JSON response
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-handle_reserves_status_ok (struct TALER_EXCHANGE_ReservesStatusHandle *rsh,
-                           const json_t *j)
-{
-  const json_t *history;
-  unsigned int len;
-  struct TALER_EXCHANGE_ReserveStatus rs = {
-    .hr.reply = j,
-    .hr.http_status = MHD_HTTP_OK
-  };
-  struct GNUNET_JSON_Specification spec[] = {
-    TALER_JSON_spec_amount_any ("balance",
-                                &rs.details.ok.balance),
-    GNUNET_JSON_spec_array_const ("history",
-                                  &history),
-    GNUNET_JSON_spec_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (j,
-                         spec,
-                         NULL,
-                         NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  len = json_array_size (history);
-  {
-    struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory;
-
-    rhistory = GNUNET_new_array (len,
-                                 struct TALER_EXCHANGE_ReserveHistoryEntry);
-    if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (rsh->keys,
-                                              history,
-                                              &rsh->reserve_pub,
-                                              rs.details.ok.balance.currency,
-                                              &rs.details.ok.total_in,
-                                              &rs.details.ok.total_out,
-                                              len,
-                                              rhistory))
-    {
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (len,
-                                           rhistory);
-      GNUNET_JSON_parse_free (spec);
-      return GNUNET_SYSERR;
-    }
-    if (NULL != rsh->cb)
-    {
-      rs.details.ok.history = rhistory;
-      rs.details.ok.history_len = len;
-      rsh->cb (rsh->cb_cls,
-               &rs);
-      rsh->cb = NULL;
-    }
-    TALER_EXCHANGE_free_reserve_history (len,
-                                         rhistory);
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /reserves/$RID/status request.
- *
- * @param cls the `struct TALER_EXCHANGE_ReservesStatusHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response parsed JSON result, NULL on error
- */
-static void
-handle_reserves_status_finished (void *cls,
-                                 long response_code,
-                                 const void *response)
-{
-  struct TALER_EXCHANGE_ReservesStatusHandle *rsh = cls;
-  const json_t *j = response;
-  struct TALER_EXCHANGE_ReserveStatus rs = {
-    .hr.reply = j,
-    .hr.http_status = (unsigned int) response_code
-  };
-
-  rsh->job = NULL;
-  switch (response_code)
-  {
-  case 0:
-    rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
-    break;
-  case MHD_HTTP_OK:
-    if (GNUNET_OK !=
-        handle_reserves_status_ok (rsh,
-                                   j))
-    {
-      rs.hr.http_status = 0;
-      rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-    }
-    break;
-  case MHD_HTTP_BAD_REQUEST:
-    /* This should never happen, either us or the exchange is buggy
-       (or API version conflict); just pass JSON reply to the application */
-    GNUNET_break (0);
-    rs.hr.ec = TALER_JSON_get_error_code (j);
-    rs.hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  case MHD_HTTP_FORBIDDEN:
-    /* This should never happen, either us or the exchange is buggy
-       (or API version conflict); just pass JSON reply to the application */
-    GNUNET_break (0);
-    rs.hr.ec = TALER_JSON_get_error_code (j);
-    rs.hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  case MHD_HTTP_NOT_FOUND:
-    /* Nothing really to verify, this should never
-       happen, we should pass the JSON reply to the application */
-    rs.hr.ec = TALER_JSON_get_error_code (j);
-    rs.hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  case MHD_HTTP_INTERNAL_SERVER_ERROR:
-    /* Server had an internal issue; we should retry, but this API
-       leaves this to the application */
-    rs.hr.ec = TALER_JSON_get_error_code (j);
-    rs.hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  default:
-    /* unexpected response code */
-    GNUNET_break_op (0);
-    rs.hr.ec = TALER_JSON_get_error_code (j);
-    rs.hr.hint = TALER_JSON_get_error_hint (j);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unexpected response code %u/%d for reserves status\n",
-                (unsigned int) response_code,
-                (int) rs.hr.ec);
-    break;
-  }
-  if (NULL != rsh->cb)
-  {
-    rsh->cb (rsh->cb_cls,
-             &rs);
-    rsh->cb = NULL;
-  }
-  TALER_EXCHANGE_reserves_status_cancel (rsh);
-}
-
-
-struct TALER_EXCHANGE_ReservesStatusHandle *
-TALER_EXCHANGE_reserves_status (
-  struct GNUNET_CURL_Context *ctx,
-  const char *url,
-  struct TALER_EXCHANGE_Keys *keys,
-  const struct TALER_ReservePrivateKeyP *reserve_priv,
-  TALER_EXCHANGE_ReservesStatusCallback cb,
-  void *cb_cls)
-{
-  struct TALER_EXCHANGE_ReservesStatusHandle *rsh;
-  CURL *eh;
-  char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
-  struct TALER_ReserveSignatureP reserve_sig;
-  struct GNUNET_TIME_Timestamp ts
-    = GNUNET_TIME_timestamp_get ();
-
-  rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesStatusHandle);
-  rsh->cb = cb;
-  rsh->cb_cls = cb_cls;
-  GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
-                                      &rsh->reserve_pub.eddsa_pub);
-  {
-    char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2];
-    char *end;
-
-    end = GNUNET_STRINGS_data_to_string (
-      &rsh->reserve_pub,
-      sizeof (rsh->reserve_pub),
-      pub_str,
-      sizeof (pub_str));
-    *end = '\0';
-    GNUNET_snprintf (arg_str,
-                     sizeof (arg_str),
-                     "reserves/%s/status",
-                     pub_str);
-  }
-  rsh->url = TALER_url_join (url,
-                             arg_str,
-                             NULL);
-  if (NULL == rsh->url)
-  {
-    GNUNET_free (rsh);
-    return NULL;
-  }
-  eh = TALER_EXCHANGE_curl_easy_get_ (rsh->url);
-  if (NULL == eh)
-  {
-    GNUNET_break (0);
-    GNUNET_free (rsh->url);
-    GNUNET_free (rsh);
-    return NULL;
-  }
-  TALER_wallet_reserve_status_sign (ts,
-                                    reserve_priv,
-                                    &reserve_sig);
-  {
-    json_t *status_obj = GNUNET_JSON_PACK (
-      GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                  ts),
-      GNUNET_JSON_pack_data_auto ("reserve_sig",
-                                  &reserve_sig));
-
-    if (GNUNET_OK !=
-        TALER_curl_easy_post (&rsh->post_ctx,
-                              eh,
-                              status_obj))
-    {
-      GNUNET_break (0);
-      curl_easy_cleanup (eh);
-      json_decref (status_obj);
-      GNUNET_free (rsh->url);
-      GNUNET_free (rsh);
-      return NULL;
-    }
-    json_decref (status_obj);
-  }
-  rsh->keys = TALER_EXCHANGE_keys_incref (keys);
-  rsh->job = GNUNET_CURL_job_add2 (ctx,
-                                   eh,
-                                   rsh->post_ctx.headers,
-                                   &handle_reserves_status_finished,
-                                   rsh);
-  return rsh;
-}
-
-
-void
-TALER_EXCHANGE_reserves_status_cancel (
-  struct TALER_EXCHANGE_ReservesStatusHandle *rsh)
-{
-  if (NULL != rsh->job)
-  {
-    GNUNET_CURL_job_cancel (rsh->job);
-    rsh->job = NULL;
-  }
-  TALER_curl_easy_post_finished (&rsh->post_ctx);
-  GNUNET_free (rsh->url);
-  TALER_EXCHANGE_keys_decref (rsh->keys);
-  GNUNET_free (rsh);
-}
-
-
-/* end of exchange_api_reserves_status.c */
diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c
index 6de7adcc..53a5934d 100644
--- a/src/lib/exchange_api_withdraw2.c
+++ b/src/lib/exchange_api_withdraw2.c
@@ -128,101 +128,6 @@ reserve_withdraw_ok (struct 
TALER_EXCHANGE_Withdraw2Handle *wh,
 }
 
 
-/**
- * We got a 409 CONFLICT response for the /reserves/$RESERVE_PUB/withdraw 
operation.
- * Check the signatures on the withdraw transactions in the provided
- * history and that the balances add up.  We don't do anything directly
- * with the information, as the JSON will be returned to the application.
- * However, our job is ensuring that the exchange followed the protocol, and
- * this in particular means checking all of the signatures in the history.
- *
- * @param wh operation handle
- * @param json reply from the exchange
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static enum GNUNET_GenericReturnValue
-reserve_withdraw_payment_required (
-  struct TALER_EXCHANGE_Withdraw2Handle *wh,
-  const json_t *json)
-{
-  struct TALER_Amount balance;
-  struct TALER_Amount total_in_from_history;
-  struct TALER_Amount total_out_from_history;
-  json_t *history;
-  size_t len;
-  struct GNUNET_JSON_Specification spec[] = {
-    TALER_JSON_spec_amount_any ("balance",
-                                &balance),
-    GNUNET_JSON_spec_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (json,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  history = json_object_get (json,
-                             "history");
-  if (NULL == history)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-
-  /* go over transaction history and compute
-     total incoming and outgoing amounts */
-  len = json_array_size (history);
-  {
-    struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory;
-
-    /* Use heap allocation as "len" may be very big and thus this may
-       not fit on the stack. Use "GNUNET_malloc_large" as a malicious
-       exchange may theoretically try to crash us by giving a history
-       that does not fit into our memory. */
-    rhistory = GNUNET_malloc_large (
-      sizeof (struct TALER_EXCHANGE_ReserveHistoryEntry)
-      * len);
-    if (NULL == rhistory)
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
-
-    if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (wh->keys,
-                                              history,
-                                              &wh->reserve_pub,
-                                              balance.currency,
-                                              &total_in_from_history,
-                                              &total_out_from_history,
-                                              len,
-                                              rhistory))
-    {
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (len,
-                                           rhistory);
-      return GNUNET_SYSERR;
-    }
-    TALER_EXCHANGE_free_reserve_history (len,
-                                         rhistory);
-  }
-
-  /* Check that funds were really insufficient */
-  if (0 >= TALER_amount_cmp (&wh->requested_amount,
-                             &balance))
-  {
-    /* Requested amount is smaller or equal to reported balance,
-       so this should not have failed. */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Function called when we're done processing the
  * HTTP /reserves/$RESERVE_PUB/withdraw request.
@@ -287,20 +192,6 @@ handle_reserve_withdraw_finished (void *cls,
   case MHD_HTTP_CONFLICT:
     w2r.hr.ec = TALER_JSON_get_error_code (j);
     w2r.hr.hint = TALER_JSON_get_error_hint (j);
-
-    if (TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED == w2r.hr.ec)
-      break;
-
-    /* The exchange says that the reserve has insufficient funds;
-       check the signatures in the history... */
-    if (GNUNET_OK !=
-        reserve_withdraw_payment_required (wh,
-                                           j))
-    {
-      GNUNET_break_op (0);
-      w2r.hr.http_status = 0;
-      w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
-    }
     break;
   case MHD_HTTP_GONE:
     /* could happen if denomination was revoked */
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 957f028d..3a4f0632 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -100,7 +100,6 @@ libtalertesting_la_SOURCES = \
   testing_api_cmd_reserve_history.c \
   testing_api_cmd_reserve_open.c \
   testing_api_cmd_reserve_purse.c \
-  testing_api_cmd_reserve_status.c \
   testing_api_cmd_revoke.c \
   testing_api_cmd_revoke_denom_key.c \
   testing_api_cmd_revoke_sign_key.c \
diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c
index 41b8301a..e3ef5a5b 100644
--- a/src/testing/test_exchange_api.c
+++ b/src/testing/test_exchange_api.c
@@ -1154,12 +1154,8 @@ run (void *cls,
                               MHD_HTTP_OK),
     TALER_TESTING_cmd_reserve_history ("history-batch-1",
                                        "create-batch-reserve-1",
-                                       "EUR:0",
+                                       "EUR:0.01",
                                        MHD_HTTP_OK),
-    TALER_TESTING_cmd_status ("status-batch-2",
-                              "create-batch-reserve-1",
-                              "EUR:0.0",
-                              MHD_HTTP_OK),
     /**
      * Spend the coins.
      */
diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c
index 2fd7dfb2..6f25dd2b 100644
--- a/src/testing/test_exchange_p2p.c
+++ b/src/testing/test_exchange_p2p.c
@@ -202,7 +202,7 @@ run (void *cls,
       "EUR:1.02",
       MHD_HTTP_OK),
     /* POST history doesn't yet support P2P transfers */
-    TALER_TESTING_cmd_reserve_status (
+    TALER_TESTING_cmd_reserve_history (
       "push-check-post-merge-reserve-balance-post",
       "create-reserve-1",
       "EUR:1.02",
@@ -256,7 +256,7 @@ run (void *cls,
       "create-reserve-1",
       "EUR:2.01",
       MHD_HTTP_OK),
-    TALER_TESTING_cmd_reserve_status (
+    TALER_TESTING_cmd_reserve_history (
       "push-check-post-merge-reserve-balance-post",
       "create-reserve-1",
       "EUR:2.01",
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index 5f51b86e..71f1216a 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -335,7 +335,7 @@ run (void *cls,
       "p2p_create-reserve-1",
       "EUR:1.03",
       MHD_HTTP_OK),
-    TALER_TESTING_cmd_reserve_status (
+    TALER_TESTING_cmd_reserve_history (
       "push-check-post-merge-reserve-balance-post",
       "p2p_create-reserve-1",
       "EUR:1.03",
@@ -399,7 +399,7 @@ run (void *cls,
       "p2p_create-reserve-3",
       "EUR:1.02",
       MHD_HTTP_OK),
-    TALER_TESTING_cmd_reserve_status (
+    TALER_TESTING_cmd_reserve_history (
       "push-check-post-merge-reserve-balance-post",
       "p2p_create-reserve-3",
       "EUR:1.02",
diff --git a/src/testing/testing_api_cmd_common.c 
b/src/testing/testing_api_cmd_common.c
index 2c29f4ec..9ed0f16b 100644
--- a/src/testing/testing_api_cmd_common.c
+++ b/src/testing/testing_api_cmd_common.c
@@ -97,19 +97,6 @@ TALER_TESTING_history_entry_cmp (
                             &h2->details.close_details.fee)) )
       return 0;
     return 1;
-  case TALER_EXCHANGE_RTT_HISTORY:
-    if ( (0 ==
-          TALER_amount_cmp (&h1->amount,
-                            &h2->amount)) &&
-         (GNUNET_TIME_timestamp_cmp (
-            h1->details.history_details.request_timestamp,
-            ==,
-            h2->details.history_details.request_timestamp)) &&
-         (0 ==
-          GNUNET_memcmp (&h1->details.history_details.reserve_sig,
-                         &h2->details.history_details.reserve_sig)) )
-      return 0;
-    return 1;
   case TALER_EXCHANGE_RTT_MERGE:
     if ( (0 ==
           TALER_amount_cmp (&h1->amount,
diff --git a/src/testing/testing_api_cmd_reserve_history.c 
b/src/testing/testing_api_cmd_reserve_history.c
index ff0a8a55..4b08e78e 100644
--- a/src/testing/testing_api_cmd_reserve_history.c
+++ b/src/testing/testing_api_cmd_reserve_history.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 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
@@ -64,12 +64,6 @@ struct HistoryState
    */
   struct TALER_TESTING_Interpreter *is;
 
-  /**
-   * Reserve history entry that corresponds to this operation.
-   * Will be of type #TALER_EXCHANGE_RTT_HISTORY.
-   */
-  struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
-
   /**
    * Expected HTTP response code.
    */
@@ -232,21 +226,6 @@ reserve_history_cb (void *cls,
   struct TALER_Amount eb;
 
   ss->rsh = NULL;
-  if (MHD_HTTP_OK == rs->hr.http_status)
-  {
-    struct TALER_EXCHANGE_Keys *keys;
-    const struct TALER_EXCHANGE_GlobalFee *gf;
-
-    ss->reserve_history.type = TALER_EXCHANGE_RTT_HISTORY;
-    keys = TALER_TESTING_get_keys (is);
-    GNUNET_assert (NULL != keys);
-    gf = TALER_EXCHANGE_get_global_fee (keys,
-                                        rs->ts);
-    GNUNET_assert (NULL != gf);
-    ss->reserve_history.amount = gf->fees.history;
-    ss->reserve_history.details.history_details.request_timestamp = rs->ts;
-    ss->reserve_history.details.history_details.reserve_sig = *rs->reserve_sig;
-  }
   if (ss->expected_response_code != rs->hr.http_status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -366,6 +345,7 @@ history_run (void *cls,
     TALER_TESTING_get_exchange_url (is),
     TALER_TESTING_get_keys (is),
     ss->reserve_priv,
+    0,
     &reserve_history_cb,
     ss);
 }
@@ -388,16 +368,11 @@ history_traits (void *cls,
 {
   struct HistoryState *hs = cls;
   struct TALER_TESTING_Trait traits[] = {
-    /* history entry MUST be first due to response code logic below! */
-    TALER_TESTING_make_trait_reserve_history (0,
-                                              &hs->reserve_history),
     TALER_TESTING_make_trait_reserve_pub (&hs->reserve_pub),
     TALER_TESTING_trait_end ()
   };
 
-  return TALER_TESTING_get_trait ((hs->expected_response_code == MHD_HTTP_OK)
-                                  ? &traits[0]   /* we have reserve history */
-                                  : &traits[1],  /* skip reserve history */
+  return TALER_TESTING_get_trait (traits,
                                   ret,
                                   trait,
                                   index);
diff --git a/src/testing/testing_api_cmd_reserve_status.c 
b/src/testing/testing_api_cmd_reserve_status.c
deleted file mode 100644
index 2438b2c2..00000000
--- a/src/testing/testing_api_cmd_reserve_status.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2014-2020 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 testing/testing_api_cmd_reserve_status.c
- * @brief Implement the /reserve/$RID/status test command.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "status" CMD.
- */
-struct StatusState
-{
-  /**
-   * Label to the command which created the reserve to check,
-   * needed to resort the reserve key.
-   */
-  const char *reserve_reference;
-
-  /**
-   * Handle to the "reserve status" operation.
-   */
-  struct TALER_EXCHANGE_ReservesStatusHandle *rsh;
-
-  /**
-   * Expected reserve balance.
-   */
-  const char *expected_balance;
-
-  /**
-   * Private key of the reserve being analyzed.
-   */
-  const struct TALER_ReservePrivateKeyP *reserve_priv;
-
-  /**
-   * Public key of the reserve being analyzed.
-   */
-  struct TALER_ReservePublicKeyP reserve_pub;
-
-  /**
-   * Expected HTTP response code.
-   */
-  unsigned int expected_response_code;
-
-  /**
-   * Interpreter state.
-   */
-  struct TALER_TESTING_Interpreter *is;
-};
-
-/**
- * Closure for analysis_cb().
- */
-struct AnalysisContext
-{
-  /**
-   * Reserve public key we are looking at.
-   */
-  const struct TALER_ReservePublicKeyP *reserve_pub;
-
-  /**
-   * Length of the @e history array.
-   */
-  unsigned int history_length;
-
-  /**
-   * Array of history items to match.
-   */
-  const struct TALER_EXCHANGE_ReserveHistoryEntry *history;
-
-  /**
-   * Array of @e history_length of matched entries.
-   */
-  bool *found;
-
-  /**
-   * Set to true if an entry could not be found.
-   */
-  bool failure;
-};
-
-
-/**
- * Check if @a cmd changed the reserve, if so, find the
- * entry in our history and set the respective index in found
- * to true. If the entry is not found, set failure.
- *
- * @param cls our `struct AnalysisContext *`
- * @param cmd command to analyze for impact on history
- */
-static void
-analyze_command (void *cls,
-                 const struct TALER_TESTING_Command *cmd)
-{
-  struct AnalysisContext *ac = cls;
-  const struct TALER_ReservePublicKeyP *reserve_pub = ac->reserve_pub;
-  const struct TALER_EXCHANGE_ReserveHistoryEntry *history = ac->history;
-  unsigned int history_length = ac->history_length;
-  bool *found = ac->found;
-
-  if (TALER_TESTING_cmd_is_batch (cmd))
-  {
-    struct TALER_TESTING_Command *cur;
-    struct TALER_TESTING_Command *bcmd;
-
-    cur = TALER_TESTING_cmd_batch_get_current (cmd);
-    if (GNUNET_OK !=
-        TALER_TESTING_get_trait_batch_cmds (cmd,
-                                            &bcmd))
-    {
-      GNUNET_break (0);
-      ac->failure = true;
-      return;
-    }
-    for (unsigned int i = 0; NULL != bcmd[i].label; i++)
-    {
-      struct TALER_TESTING_Command *step = &bcmd[i];
-
-      if (step == cur)
-        break; /* if *we* are in a batch, make sure not to analyze commands 
past 'now' */
-      analyze_command (ac,
-                       step);
-      if (ac->failure)
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Entry for batch step `%s' missing in history\n",
-                    step->label);
-        return;
-      }
-    }
-    return;
-  }
-
-  {
-    const struct TALER_ReservePublicKeyP *rp;
-
-    if (GNUNET_OK !=
-        TALER_TESTING_get_trait_reserve_pub (cmd,
-                                             &rp))
-      return; /* command does nothing for reserves */
-    if (0 !=
-        GNUNET_memcmp (rp,
-                       reserve_pub))
-      return; /* command affects some _other_ reserve */
-    for (unsigned int j = 0; true; j++)
-    {
-      const struct TALER_EXCHANGE_ReserveHistoryEntry *he;
-      bool matched = false;
-
-      if (GNUNET_OK !=
-          TALER_TESTING_get_trait_reserve_history (cmd,
-                                                   j,
-                                                   &he))
-      {
-        /* NOTE: only for debugging... */
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "Command `%s' has the reserve_pub trait, but does not 
reserve history trait\n",
-                    cmd->label);
-        return; /* command does nothing for reserves */
-      }
-      for (unsigned int i = 0; i<history_length; i++)
-      {
-        if (found[i])
-          continue; /* already found, skip */
-        if (0 ==
-            TALER_TESTING_history_entry_cmp (he,
-                                             &history[i]))
-        {
-          found[i] = true;
-          matched = true;
-          break;
-        }
-      }
-      if (! matched)
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Command `%s' reserve history entry #%u not found\n",
-                    cmd->label,
-                    j);
-        ac->failure = true;
-        return;
-      }
-    }
-  }
-}
-
-
-/**
- * Check that the reserve balance and HTTP response code are
- * both acceptable.
- *
- * @param cls closure.
- * @param rs HTTP response details
- */
-static void
-reserve_status_cb (void *cls,
-                   const struct TALER_EXCHANGE_ReserveStatus *rs)
-{
-  struct StatusState *ss = cls;
-  struct TALER_TESTING_Interpreter *is = ss->is;
-  struct TALER_Amount eb;
-
-  ss->rsh = NULL;
-  if (ss->expected_response_code != rs->hr.http_status)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unexpected HTTP response code: %d in %s:%u\n",
-                rs->hr.http_status,
-                __FILE__,
-                __LINE__);
-    json_dumpf (rs->hr.reply,
-                stderr,
-                JSON_INDENT (2));
-    TALER_TESTING_interpreter_fail (ss->is);
-    return;
-  }
-  if (MHD_HTTP_OK != rs->hr.http_status)
-  {
-    TALER_TESTING_interpreter_next (is);
-    return;
-  }
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_string_to_amount (ss->expected_balance,
-                                         &eb));
-
-  if (0 != TALER_amount_cmp (&eb,
-                             &rs->details.ok.balance))
-  {
-    GNUNET_break (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unexpected amount in reserve: %s\n",
-                TALER_amount_to_string (&rs->details.ok.balance));
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Expected balance of: %s\n",
-                TALER_amount_to_string (&eb));
-    TALER_TESTING_interpreter_fail (ss->is);
-    return;
-  }
-  {
-    bool found[rs->details.ok.history_len];
-    struct AnalysisContext ac = {
-      .reserve_pub = &ss->reserve_pub,
-      .history = rs->details.ok.history,
-      .history_length = rs->details.ok.history_len,
-      .found = found
-    };
-
-    memset (found,
-            0,
-            sizeof (found));
-    TALER_TESTING_iterate (is,
-                           true,
-                           &analyze_command,
-                           &ac);
-    if (ac.failure)
-    {
-      json_dumpf (rs->hr.reply,
-                  stderr,
-                  JSON_INDENT (2));
-      TALER_TESTING_interpreter_fail (ss->is);
-      return;
-    }
-    for (unsigned int i = 0; i<rs->details.ok.history_len; i++)
-    {
-      if (found[i])
-        continue;
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "History entry at index %u of type %d not justified by 
command status\n",
-                  i,
-                  rs->details.ok.history[i].type);
-      json_dumpf (rs->hr.reply,
-                  stderr,
-                  JSON_INDENT (2));
-      TALER_TESTING_interpreter_fail (ss->is);
-      return;
-    }
-  }
-  TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command being executed.
- * @param is the interpreter state.
- */
-static void
-status_run (void *cls,
-            const struct TALER_TESTING_Command *cmd,
-            struct TALER_TESTING_Interpreter *is)
-{
-  struct StatusState *ss = cls;
-  const struct TALER_TESTING_Command *create_reserve;
-
-  ss->is = is;
-  create_reserve
-    = TALER_TESTING_interpreter_lookup_command (is,
-                                                ss->reserve_reference);
-
-  if (NULL == create_reserve)
-  {
-    GNUNET_break (0);
-    TALER_TESTING_interpreter_fail (is);
-    return;
-  }
-  if (GNUNET_OK !=
-      TALER_TESTING_get_trait_reserve_priv (create_reserve,
-                                            &ss->reserve_priv))
-  {
-    GNUNET_break (0);
-    TALER_LOG_ERROR ("Failed to find reserve_priv for status query\n");
-    TALER_TESTING_interpreter_fail (is);
-    return;
-  }
-  GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
-                                      &ss->reserve_pub.eddsa_pub);
-  ss->rsh = TALER_EXCHANGE_reserves_status (
-    TALER_TESTING_interpreter_get_context (is),
-    TALER_TESTING_get_exchange_url (is),
-    TALER_TESTING_get_keys (is),
-    ss->reserve_priv,
-    &reserve_status_cb,
-    ss);
-}
-
-
-/**
- * Cleanup the state from a "reserve status" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-status_cleanup (void *cls,
-                const struct TALER_TESTING_Command *cmd)
-{
-  struct StatusState *ss = cls;
-
-  if (NULL != ss->rsh)
-  {
-    TALER_TESTING_command_incomplete (ss->is,
-                                      cmd->label);
-    TALER_EXCHANGE_reserves_status_cancel (ss->rsh);
-    ss->rsh = NULL;
-  }
-  GNUNET_free (ss);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_reserve_status (const char *label,
-                                  const char *reserve_reference,
-                                  const char *expected_balance,
-                                  unsigned int expected_response_code)
-{
-  struct StatusState *ss;
-
-  GNUNET_assert (NULL != reserve_reference);
-  ss = GNUNET_new (struct StatusState);
-  ss->reserve_reference = reserve_reference;
-  ss->expected_balance = expected_balance;
-  ss->expected_response_code = expected_response_code;
-  {
-    struct TALER_TESTING_Command cmd = {
-      .cls = ss,
-      .label = label,
-      .run = &status_run,
-      .cleanup = &status_cleanup
-    };
-
-    return cmd;
-  }
-}
diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c
index 4b2fab6e..897f7f98 100644
--- a/src/util/wallet_signatures.c
+++ b/src/util/wallet_signatures.c
@@ -790,9 +790,7 @@ GNUNET_NETWORK_STRUCT_BEGIN
 
 
 /**
- * Response by which a wallet requests a full
- * reserve history and indicates it is willing
- * to pay for it.
+ * Response by which a wallet requests a reserve history.
  */
 struct TALER_ReserveHistoryRequestPS
 {
@@ -803,36 +801,27 @@ struct TALER_ReserveHistoryRequestPS
   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
 
   /**
-   * When did the wallet make the request.
+   * Which entries to exclude. Only return above this offset.
    */
-  struct GNUNET_TIME_TimestampNBO request_timestamp;
-
-  /**
-   * How much does the exchange charge for the history?
-   */
-  struct TALER_AmountNBO history_fee;
+  uint64_t start_off;
 
 };
 
-
 GNUNET_NETWORK_STRUCT_END
 
 
 enum GNUNET_GenericReturnValue
 TALER_wallet_reserve_history_verify (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_Amount *history_fee,
+  uint64_t start_off,
   const struct TALER_ReservePublicKeyP *reserve_pub,
   const struct TALER_ReserveSignatureP *reserve_sig)
 {
   struct TALER_ReserveHistoryRequestPS rhr = {
     .purpose.size = htonl (sizeof (rhr)),
     .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY),
-    .request_timestamp = GNUNET_TIME_timestamp_hton (ts)
+    .start_off = GNUNET_htonll (start_off)
   };
 
-  TALER_amount_hton (&rhr.history_fee,
-                     history_fee);
   return GNUNET_CRYPTO_eddsa_verify (
     TALER_SIGNATURE_WALLET_RESERVE_HISTORY,
     &rhr,
@@ -843,19 +832,16 @@ TALER_wallet_reserve_history_verify (
 
 void
 TALER_wallet_reserve_history_sign (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_Amount *history_fee,
+  uint64_t start_off,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   struct TALER_ReserveSignatureP *reserve_sig)
 {
   struct TALER_ReserveHistoryRequestPS rhr = {
     .purpose.size = htonl (sizeof (rhr)),
     .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY),
-    .request_timestamp = GNUNET_TIME_timestamp_hton (ts)
+    .start_off = GNUNET_htonll (start_off)
   };
 
-  TALER_amount_hton (&rhr.history_fee,
-                     history_fee);
   GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
                             &rhr,
                             &reserve_sig->eddsa_signature);
@@ -865,60 +851,60 @@ TALER_wallet_reserve_history_sign (
 GNUNET_NETWORK_STRUCT_BEGIN
 
 /**
- * Response by which a wallet requests an account status.
+ * Response by which a wallet requests a coin history.
  */
-struct TALER_ReserveStatusRequestPS
+struct TALER_CoinHistoryRequestPS
 {
 
   /**
-   * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_STATUS
+   * Purpose is #TALER_SIGNATURE_WALLET_COIN_HISTORY
    */
   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
 
   /**
-   * When did the wallet make the request.
+   * Which entries to exclude. Only return above this offset.
    */
-  struct GNUNET_TIME_TimestampNBO request_timestamp;
+  uint64_t start_off;
 
 };
 
 GNUNET_NETWORK_STRUCT_END
 
 enum GNUNET_GenericReturnValue
-TALER_wallet_reserve_status_verify (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig)
+TALER_wallet_coin_history_verify (
+  uint64_t start_off,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  const struct TALER_CoinSpendSignatureP *coin_sig)
 {
-  struct TALER_ReserveStatusRequestPS rsr = {
+  struct TALER_CoinHistoryRequestPS rsr = {
     .purpose.size = htonl (sizeof (rsr)),
-    .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_STATUS),
-    .request_timestamp = GNUNET_TIME_timestamp_hton (ts)
+    .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY),
+    .start_off = GNUNET_htonll (start_off)
   };
 
   return GNUNET_CRYPTO_eddsa_verify (
-    TALER_SIGNATURE_WALLET_RESERVE_STATUS,
+    TALER_SIGNATURE_WALLET_COIN_HISTORY,
     &rsr,
-    &reserve_sig->eddsa_signature,
-    &reserve_pub->eddsa_pub);
+    &coin_sig->eddsa_signature,
+    &coin_pub->eddsa_pub);
 }
 
 
 void
-TALER_wallet_reserve_status_sign (
-  const struct GNUNET_TIME_Timestamp ts,
-  const struct TALER_ReservePrivateKeyP *reserve_priv,
-  struct TALER_ReserveSignatureP *reserve_sig)
+TALER_wallet_coin_history_sign (
+  uint64_t start_off,
+  const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+  struct TALER_CoinSpendSignatureP *coin_sig)
 {
-  struct TALER_ReserveStatusRequestPS rsr = {
+  struct TALER_CoinHistoryRequestPS rsr = {
     .purpose.size = htonl (sizeof (rsr)),
-    .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_STATUS),
-    .request_timestamp = GNUNET_TIME_timestamp_hton (ts)
+    .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY),
+    .start_off = GNUNET_htonll (start_off)
   };
 
-  GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
+  GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
                             &rsr,
-                            &reserve_sig->eddsa_signature);
+                            &coin_sig->eddsa_signature);
 }
 
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]