gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: towards support for new reserve


From: gnunet
Subject: [taler-exchange] branch master updated: towards support for new reserve history/status APIs
Date: Sun, 20 Mar 2022 13:20:51 +0100

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 427417b8 towards support for new reserve history/status APIs
427417b8 is described below

commit 427417b8352c2036dc6f5c0ca6bd20c0b7edd225
Author: Christian Grothoff <grothoff@gnunet.org>
AuthorDate: Sun Mar 20 13:20:45 2022 +0100

    towards support for new reserve history/status APIs
---
 src/exchange/taler-exchange-httpd_keys.c           |  64 +++--
 src/exchange/taler-exchange-httpd_keys.h           |  80 +++++-
 src/include/taler_exchange_service.h               | 286 +++++++++++++++++++--
 src/include/taler_testing_lib.h                    |  33 ++-
 src/lib/Makefile.am                                |   4 +-
 src/lib/exchange_api_common.c                      |  26 +-
 src/lib/exchange_api_handle.c                      |  21 ++
 src/lib/exchange_api_reserves_get.c                | 100 ++-----
 src/lib/exchange_api_reserves_history.c            | 192 +++++++-------
 src/lib/exchange_api_reserves_status.c             | 183 ++++++-------
 src/lib/exchange_api_withdraw2.c                   |   4 +-
 src/testing/Makefile.am                            |   2 +
 .../testing_api_cmd_bank_admin_add_incoming.c      |   2 +-
 src/testing/testing_api_cmd_exec_closer.c          |   2 +-
 src/testing/testing_api_cmd_recoup.c               |   2 +-
 ..._status.c => testing_api_cmd_reserve_history.c} | 121 ++++-----
 ...d_status.c => testing_api_cmd_reserve_status.c} |  87 ++++---
 src/testing/testing_api_cmd_status.c               | 226 +---------------
 src/testing/testing_api_cmd_withdraw.c             |   2 +-
 19 files changed, 761 insertions(+), 676 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_keys.c 
b/src/exchange/taler-exchange-httpd_keys.c
index 1012a8c0..658e5a34 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -280,31 +280,6 @@ struct SigningKey
 };
 
 
-/**
- * Set of global fees (and options) for a time range.
- */
-struct GlobalFee
-{
-  /**
-   * Kept in a DLL.
-   */
-  struct GlobalFee *next;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GlobalFee *prev;
-
-  struct GNUNET_TIME_Timestamp start_date;
-  struct GNUNET_TIME_Timestamp end_date;
-  struct GNUNET_TIME_Relative purse_timeout;
-  struct GNUNET_TIME_Relative kyc_timeout;
-  struct GNUNET_TIME_Relative history_expiration;
-  struct TALER_MasterSignatureP master_sig;
-  struct TALER_GlobalFeeSet fees;
-  uint32_t purse_account_limit;
-};
-
 struct TEH_KeyStateHandle
 {
 
@@ -324,12 +299,12 @@ struct TEH_KeyStateHandle
   /**
    * Head of DLL of our global fees.
    */
-  struct GlobalFee *gf_head;
+  struct TEH_GlobalFee *gf_head;
 
   /**
    * Tail of DLL of our global fees.
    */
-  struct GlobalFee *gf_tail;
+  struct TEH_GlobalFee *gf_tail;
 
   /**
    * json array with the auditors of this exchange. Contains exactly
@@ -1215,7 +1190,7 @@ static void
 destroy_key_state (struct TEH_KeyStateHandle *ksh,
                    bool free_helper)
 {
-  struct GlobalFee *gf;
+  struct TEH_GlobalFee *gf;
 
   clear_response_cache (ksh);
   while (NULL != (gf = ksh->gf_head))
@@ -2282,9 +2257,9 @@ global_fee_info_cb (
   const struct TALER_MasterSignatureP *master_sig)
 {
   struct TEH_KeyStateHandle *ksh = cls;
-  struct GlobalFee *gf;
+  struct TEH_GlobalFee *gf;
 
-  gf = GNUNET_new (struct GlobalFee);
+  gf = GNUNET_new (struct TEH_GlobalFee);
   gf->start_date = start_date;
   gf->end_date = end_date;
   gf->fees = *fees;
@@ -2517,11 +2492,32 @@ TEH_keys_get_state (void)
 }
 
 
+const struct TEH_GlobalFee *
+TEH_keys_global_fee_by_time (
+  struct TEH_KeyStateHandle *ksh,
+  struct GNUNET_TIME_Timestamp ts)
+{
+  for (const struct TEH_GlobalFee *gf = ksh->gf_head;
+       NULL != gf;
+       gf = gf->next)
+  {
+    if (GNUNET_TIME_timestamp_cmp (ts,
+                                   >=,
+                                   gf->start_date) &&
+        GNUNET_TIME_timestamp_cmp (ts,
+                                   <,
+                                   gf->end_date))
+      return gf;
+  }
+  return NULL;
+}
+
+
 struct TEH_DenominationKey *
-TEH_keys_denomination_by_hash (const struct
-                               TALER_DenominationHashP *h_denom_pub,
-                               struct MHD_Connection *conn,
-                               MHD_RESULT *mret)
+TEH_keys_denomination_by_hash (
+  const struct TALER_DenominationHashP *h_denom_pub,
+  struct MHD_Connection *conn,
+  MHD_RESULT *mret)
 {
   struct TEH_KeyStateHandle *ksh;
 
diff --git a/src/exchange/taler-exchange-httpd_keys.h 
b/src/exchange/taler-exchange-httpd_keys.h
index ee9412a6..732ee032 100644
--- a/src/exchange/taler-exchange-httpd_keys.h
+++ b/src/exchange/taler-exchange-httpd_keys.h
@@ -82,6 +82,64 @@ struct TEH_DenominationKey
 };
 
 
+/**
+ * Set of global fees (and options) for a time range.
+ */
+struct TEH_GlobalFee
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct TEH_GlobalFee *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct TEH_GlobalFee *prev;
+
+  /**
+   * Beginning of the validity period (inclusive).
+   */
+  struct GNUNET_TIME_Timestamp start_date;
+
+  /**
+   * End of the validity period (exclusive).
+   */
+  struct GNUNET_TIME_Timestamp end_date;
+
+  /**
+   * How long do unmerged purses stay around at most?
+   */
+  struct GNUNET_TIME_Relative purse_timeout;
+
+  /**
+   * How long do we keep accounts without KYC?
+   */
+  struct GNUNET_TIME_Relative kyc_timeout;
+
+  /**
+   * What is the longest history we return?
+   */
+  struct GNUNET_TIME_Relative history_expiration;
+
+  /**
+   * Signature affirming these details.
+   */
+  struct TALER_MasterSignatureP master_sig;
+
+  /**
+   * Fee structure for operations that do not depend
+   * on a denomination or wire method.
+   */
+  struct TALER_GlobalFeeSet fees;
+
+  /**
+   * Number of free purses per account.
+   */
+  uint32_t purse_account_limit;
+};
+
+
 /**
  * Snapshot of the (coin and signing) keys (including private keys) of
  * the exchange.  There can be multiple instances of this struct, as it is
@@ -129,6 +187,20 @@ void
 TEH_keys_update_states (void);
 
 
+/**
+ * Look up global fee structure by @a ts.
+ *
+ * @param ksh key state state to look in
+ * @param ts timestamp to lookup global fees at
+ * @return the global fee details, or
+ *         NULL if none are configured for @a ts
+ */
+const struct TEH_GlobalFee *
+TEH_keys_global_fee_by_time (
+  struct TEH_KeyStateHandle *ksh,
+  struct GNUNET_TIME_Timestamp ts);
+
+
 /**
  * Look up the issue for a denom public key.  Note that the result
  * must only be used in this thread and only until another key or
@@ -141,10 +213,10 @@ TEH_keys_update_states (void);
  *         or NULL if @a h_denom_pub could not be found
  */
 struct TEH_DenominationKey *
-TEH_keys_denomination_by_hash (const struct
-                               TALER_DenominationHashP *h_denom_pub,
-                               struct MHD_Connection *conn,
-                               MHD_RESULT *mret);
+TEH_keys_denomination_by_hash (
+  const struct TALER_DenominationHashP *h_denom_pub,
+  struct MHD_Connection *conn,
+  MHD_RESULT *mret);
 
 
 /**
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 56940669..f59e1b46 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -636,6 +636,19 @@ TALER_EXCHANGE_get_denomination_key (
   const struct TALER_DenominationPublicKey *pk);
 
 
+/**
+ * Obtain the global fee details from the exchange.
+ *
+ * @param keys the exchange's key set
+ * @param ts time for when to fetch the fees
+ * @return details about the fees, NULL if no fees are known at @a ts
+ */
+const struct TALER_EXCHANGE_GlobalFee *
+TALER_EXCHANGE_get_global_fee (
+  const struct TALER_EXCHANGE_Keys *keys,
+  struct GNUNET_TIME_Timestamp ts);
+
+
 /**
  * Create a copy of a denomination public key.
  *
@@ -1281,13 +1294,6 @@ TALER_EXCHANGE_csr_withdraw_cancel (
 
 /* ********************* GET /reserves/$RESERVE_PUB *********************** */
 
-
-/**
- * @brief A /reserves/ GET Handle
- */
-struct TALER_EXCHANGE_ReservesGetHandle;
-
-
 /**
  * Ways how a reserve's balance may change.
  */
@@ -1320,7 +1326,7 @@ enum TALER_EXCHANGE_ReserveTransactionType
 /**
  * @brief Entry in the reserve's transaction history.
  */
-struct TALER_EXCHANGE_ReserveHistory
+struct TALER_EXCHANGE_ReserveHistoryEntry
 {
 
   /**
@@ -1453,23 +1459,59 @@ struct TALER_EXCHANGE_ReserveHistory
 };
 
 
+/**
+ * @brief A /reserves/ GET Handle
+ */
+struct TALER_EXCHANGE_ReservesGetHandle;
+
+
+/**
+ * @brief Reserve summary.
+ */
+struct TALER_EXCHANGE_ReserveSummary
+{
+
+  /**
+   * 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
+    {
+
+      /**
+       * Reserve balance.
+       */
+      struct TALER_Amount balance;
+
+    } 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 hr HTTP response data
- * @param balance current balance in the reserve, NULL on error
- * @param history_length number of entries in the transaction history, 0 on 
error
- * @param history detailed transaction history, NULL on error
+ * @param rs HTTP response data
  */
 typedef void
 (*TALER_EXCHANGE_ReservesGetCallback) (
   void *cls,
-  const struct TALER_EXCHANGE_HttpResponse *hr,
-  const struct TALER_Amount *balance,
-  unsigned int history_length,
-  const struct TALER_EXCHANGE_ReserveHistory *history);
+  const struct TALER_EXCHANGE_ReserveSummary *rs);
 
 
 /**
@@ -1510,6 +1552,214 @@ 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
+    {
+
+      /**
+       * Reserve balance.
+       */
+      struct TALER_Amount balance;
+
+      /**
+       * Reserve history.
+       */
+      const struct TALER_EXCHANGE_ReserveHistoryEntry *history;
+
+      /**
+       * Length of the @e history array.
+       */
+      unsigned int history_len;
+
+      /**
+       * KYC passed?
+       */
+      bool kyc_ok;
+
+      /**
+       * KYC required to withdraw?
+       */
+      bool kyc_required;
+
+    } 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 exchange the exchange handle; the exchange must be ready to operate
+ * @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 TALER_EXCHANGE_Handle *exchange,
+  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
+ */
+struct TALER_EXCHANGE_ReservesHistoryHandle;
+
+
+/**
+ * @brief Reserve history details.
+ */
+struct TALER_EXCHANGE_ReserveHistory
+{
+
+  /**
+   * 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
+    {
+
+      /**
+       * Reserve balance.
+       */
+      struct TALER_Amount balance;
+
+      /**
+       * Reserve history.
+       */
+      const struct TALER_EXCHANGE_ReserveHistoryEntry *history;
+
+      /**
+       * Length of the @e history array.
+       */
+      unsigned int history_len;
+
+      /**
+       * KYC passed?
+       */
+      bool kyc_ok;
+
+      /**
+       * KYC required to withdraw?
+       */
+      bool kyc_required;
+
+    } ok;
+
+  } details;
+
+};
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * reserve history request to a exchange.
+ *
+ * @param cls closure
+ * @param rs HTTP response data
+ */
+typedef void
+(*TALER_EXCHANGE_ReservesHistoryCallback) (
+  void *cls,
+  const struct TALER_EXCHANGE_ReserveHistory *rs);
+
+
+/**
+ * Submit a request to obtain the reserve history.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @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_ReservesHistoryHandle *
+TALER_EXCHANGE_reserves_history (
+  struct TALER_EXCHANGE_Handle *exchange,
+  const struct TALER_ReservePrivateKeyP *reserve_priv,
+  TALER_EXCHANGE_ReservesHistoryCallback cb,
+  void *cb_cls);
+
+
+/**
+ * Cancel a reserve history 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_history_cancel (
+  struct TALER_EXCHANGE_ReservesHistoryHandle *rsh);
+
+
 /* ********************* POST /reserves/$RESERVE_PUB/withdraw 
*********************** */
 
 
@@ -2451,7 +2701,7 @@ TALER_EXCHANGE_parse_reserve_history (
   const char *currency,
   struct TALER_Amount *balance,
   unsigned int history_length,
-  struct TALER_EXCHANGE_ReserveHistory *rhistory);
+  struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory);
 
 
 /**
@@ -2462,7 +2712,7 @@ TALER_EXCHANGE_parse_reserve_history (
  */
 void
 TALER_EXCHANGE_free_reserve_history (
-  struct TALER_EXCHANGE_ReserveHistory *rhistory,
+  struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory,
   unsigned int len);
 
 
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index a1bc5d0d..829f9b8a 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -1382,15 +1382,38 @@ TALER_TESTING_cmd_status (const char *label,
                           const char *expected_balance,
                           unsigned int expected_response_code);
 
+
 /**
- * Index of the deposit value trait of a deposit command.
+ * Create a POST "/reserves/$RID/history" 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.
  */
-#define TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_VALUE 0
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_history (const char *label,
+                                   const char *reserve_reference,
+                                   const char *expected_balance,
+                                   unsigned int expected_response_code);
+
 
 /**
- * Index of the deposit fee trait of a deposit command.
+ * 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.
  */
-#define TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_FEE 1
+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 "deposit" command.
@@ -2455,7 +2478,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait 
*traits,
   op (contract_terms, const json_t)                                \
   op (wire_details, const json_t)                                  \
   op (exchange_keys, const json_t)                                 \
-  op (reserve_history, const struct TALER_EXCHANGE_ReserveHistory) \
+  op (reserve_history, const struct TALER_EXCHANGE_ReserveHistoryEntry) \
   op (exchange_url, const char *)                                  \
   op (exchange_bank_account_url, const char *)                     \
   op (taler_uri, const char *)                                     \
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 7d49f53c..730c833d 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -18,7 +18,7 @@ lib_LTLIBRARIES = \
   libtalerexchange.la
 
 libtalerexchange_la_LDFLAGS = \
-  -version-info 4:0:0 \
+  -version-info 5:0:0 \
   -no-undefined
 libtalerexchange_la_SOURCES = \
   exchange_api_auditor_add_denomination.c \
@@ -51,6 +51,8 @@ libtalerexchange_la_SOURCES = \
   exchange_api_refreshes_reveal.c \
   exchange_api_refund.c \
   exchange_api_reserves_get.c \
+  exchange_api_reserves_history.c \
+  exchange_api_reserves_status.c \
   exchange_api_transfers_get.c \
   exchange_api_withdraw.c \
   exchange_api_withdraw2.c \
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 160f62dc..c9bff71f 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -34,7 +34,7 @@ TALER_EXCHANGE_parse_reserve_history (
   const char *currency,
   struct TALER_Amount *balance,
   unsigned int history_length,
-  struct TALER_EXCHANGE_ReserveHistory *rhistory)
+  struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory)
 {
   struct GNUNET_HashCode uuid[history_length];
   unsigned int uuid_off;
@@ -50,7 +50,7 @@ TALER_EXCHANGE_parse_reserve_history (
   uuid_off = 0;
   for (unsigned int off = 0; off<history_length; off++)
   {
-    struct TALER_EXCHANGE_ReserveHistory *rh = &rhistory[off];
+    struct TALER_EXCHANGE_ReserveHistoryEntry *rh = &rhistory[off];
     json_t *transaction;
     struct TALER_Amount amount;
     const char *type;
@@ -368,14 +368,20 @@ TALER_EXCHANGE_parse_reserve_history (
   }
 
   /* check balance = total_in - total_out < withdraw-amount */
-  if (0 >
-      TALER_amount_subtract (balance,
-                             &total_in,
-                             &total_out))
+  if (NULL != balance)
   {
-    /* total_in < total_out, why did the exchange ever allow this!? */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
+    /* if balance is NULL, we may have a partial history
+       in which case the subtraction may fail, so we do
+       not even check that invariant in this case. */
+    if (0 >
+        TALER_amount_subtract (balance,
+                               &total_in,
+                               &total_out))
+    {
+      /* total_in < total_out, why did the exchange ever allow this!? */
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
   }
   return GNUNET_OK;
 }
@@ -383,7 +389,7 @@ TALER_EXCHANGE_parse_reserve_history (
 
 void
 TALER_EXCHANGE_free_reserve_history (
-  struct TALER_EXCHANGE_ReserveHistory *rhistory,
+  struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory,
   unsigned int len)
 {
   for (unsigned int i = 0; i<len; i++)
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index f7e87791..e0fcd2b9 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -2181,6 +2181,27 @@ TALER_EXCHANGE_get_denomination_key (
 }
 
 
+const struct TALER_EXCHANGE_GlobalFee *
+TALER_EXCHANGE_get_global_fee (
+  const struct TALER_EXCHANGE_Keys *keys,
+  struct GNUNET_TIME_Timestamp ts)
+{
+  for (unsigned int i = 0; i<keys->num_global_fees; i++)
+  {
+    const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
+
+    if (GNUNET_TIME_timestamp_cmp (ts,
+                                   >=,
+                                   gf->start_date) &&
+        GNUNET_TIME_timestamp_cmp (ts,
+                                   <,
+                                   gf->end_date))
+      return gf;
+  }
+  return NULL;
+}
+
+
 struct TALER_EXCHANGE_DenomPublicKey *
 TALER_EXCHANGE_copy_denomination_key (
   const struct TALER_EXCHANGE_DenomPublicKey *key)
diff --git a/src/lib/exchange_api_reserves_get.c 
b/src/lib/exchange_api_reserves_get.c
index a25350e5..4c2886e0 100644
--- a/src/lib/exchange_api_reserves_get.c
+++ b/src/lib/exchange_api_reserves_get.c
@@ -83,19 +83,15 @@ static enum GNUNET_GenericReturnValue
 handle_reserves_get_ok (struct TALER_EXCHANGE_ReservesGetHandle *rgh,
                         const json_t *j)
 {
-  json_t *history;
-  unsigned int len;
-  struct TALER_Amount balance;
-  struct TALER_Amount balance_from_history;
+  struct TALER_EXCHANGE_ReserveSummary rs = {
+    .hr.reply = j,
+    .hr.http_status = MHD_HTTP_OK
+  };
   struct GNUNET_JSON_Specification spec[] = {
     TALER_JSON_spec_amount_any ("balance",
-                                &balance),
+                                &rs.details.ok.balance),
     GNUNET_JSON_spec_end ()
   };
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_status = MHD_HTTP_OK
-  };
 
   if (GNUNET_OK !=
       GNUNET_JSON_parse (j,
@@ -106,55 +102,9 @@ handle_reserves_get_ok (struct 
TALER_EXCHANGE_ReservesGetHandle *rgh,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  history = json_object_get (j,
-                             "history");
-  if (NULL == history)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  len = json_array_size (history);
-  {
-    struct TALER_EXCHANGE_ReserveHistory *rhistory;
-
-    rhistory = GNUNET_new_array (len,
-                                 struct TALER_EXCHANGE_ReserveHistory);
-    if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (rgh->exchange,
-                                              history,
-                                              &rgh->reserve_pub,
-                                              balance.currency,
-                                              &balance_from_history,
-                                              len,
-                                              rhistory))
-    {
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (rhistory,
-                                           len);
-      return GNUNET_SYSERR;
-    }
-    if (0 !=
-        TALER_amount_cmp (&balance_from_history,
-                          &balance))
-    {
-      /* exchange cannot add up balances!? */
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (rhistory,
-                                           len);
-      return GNUNET_SYSERR;
-    }
-    if (NULL != rgh->cb)
-    {
-      rgh->cb (rgh->cb_cls,
-               &hr,
-               &balance,
-               len,
-               rhistory);
-      rgh->cb = NULL;
-    }
-    TALER_EXCHANGE_free_reserve_history (rhistory,
-                                         len);
-  }
+  rgh->cb (rgh->cb_cls,
+           &rs);
+  rgh->cb = NULL;
   return GNUNET_OK;
 }
 
@@ -174,61 +124,59 @@ handle_reserves_get_finished (void *cls,
 {
   struct TALER_EXCHANGE_ReservesGetHandle *rgh = cls;
   const json_t *j = response;
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_status = (unsigned int) response_code
+  struct TALER_EXCHANGE_ReserveSummary rs = {
+    .hr.reply = j,
+    .hr.http_status = (unsigned int) response_code
   };
 
   rgh->job = NULL;
   switch (response_code)
   {
   case 0:
-    hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+    rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     break;
   case MHD_HTTP_OK:
     if (GNUNET_OK !=
         handle_reserves_get_ok (rgh,
                                 j))
     {
-      hr.http_status = 0;
-      hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+      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 */
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
+    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 */
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
+    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 */
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
+    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);
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
+    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 get\n",
                 (unsigned int) response_code,
-                (int) hr.ec);
+                (int) rs.hr.ec);
     break;
   }
   if (NULL != rgh->cb)
   {
     rgh->cb (rgh->cb_cls,
-             &hr,
-             NULL,
-             0, NULL);
+             &rs);
     rgh->cb = NULL;
   }
   TALER_EXCHANGE_reserves_get_cancel (rgh);
diff --git a/src/lib/exchange_api_reserves_history.c 
b/src/lib/exchange_api_reserves_history.c
index f7191b2a..c0f6c42d 100644
--- a/src/lib/exchange_api_reserves_history.c
+++ b/src/lib/exchange_api_reserves_history.c
@@ -81,35 +81,32 @@ struct TALER_EXCHANGE_ReservesHistoryHandle
  * We received an #MHD_HTTP_OK history code. Handle the JSON
  * response.
  *
- * @param rgh handle of the request
+ * @param rsh handle of the request
  * @param j JSON response
  * @return #GNUNET_OK on success
  */
 static enum GNUNET_GenericReturnValue
-handle_reserves_history_ok (struct TALER_EXCHANGE_ReservesHistoryHandle *rgh,
+handle_reserves_history_ok (struct TALER_EXCHANGE_ReservesHistoryHandle *rsh,
                             const json_t *j)
 {
   json_t *history;
   unsigned int len;
-  bool kyc_ok;
-  bool kyc_required;
-  struct TALER_Amount balance;
-  struct TALER_Amount balance_from_history;
+  struct TALER_Amount history_balance;
+  struct TALER_EXCHANGE_ReserveHistory rs = {
+    .hr.reply = j,
+    .hr.http_status = MHD_HTTP_OK
+  };
   struct GNUNET_JSON_Specification spec[] = {
     TALER_JSON_spec_amount_any ("balance",
-                                &balance),
+                                &rs.details.ok.balance),
     GNUNET_JSON_spec_bool ("kyc_passed",
-                           &kyc_ok),
+                           &rs.details.ok.kyc_ok),
     GNUNET_JSON_spec_bool ("kyc_required",
-                           &kyc_required),
+                           &rs.details.ok.kyc_required),
     GNUNET_JSON_spec_json ("history",
                            &history),
     GNUNET_JSON_spec_end ()
   };
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_history = MHD_HTTP_OK
-  };
 
   if (GNUNET_OK !=
       GNUNET_JSON_parse (j,
@@ -122,16 +119,19 @@ handle_reserves_history_ok (struct 
TALER_EXCHANGE_ReservesHistoryHandle *rgh,
   }
   len = json_array_size (history);
   {
-    struct TALER_EXCHANGE_ReserveHistory *rhistory;
+    struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory;
 
     rhistory = GNUNET_new_array (len,
-                                 struct TALER_EXCHANGE_ReserveHistory);
+                                 struct TALER_EXCHANGE_ReserveHistoryEntry);
+    // FIXME: even this history could be partial
+    // (if the reserve is too old!); update API
+    // and return incoming & outgoing totals separately?
     if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (rgh->exchange,
+        TALER_EXCHANGE_parse_reserve_history (rsh->exchange,
                                               history,
-                                              &rgh->reserve_pub,
-                                              balance.currency,
-                                              &balance_from_history,
+                                              &rsh->reserve_pub,
+                                              rs.details.ok.balance.currency,
+                                              &history_balance,
                                               len,
                                               rhistory))
     {
@@ -141,25 +141,13 @@ handle_reserves_history_ok (struct 
TALER_EXCHANGE_ReservesHistoryHandle *rgh,
       GNUNET_JSON_parse_free (spec);
       return GNUNET_SYSERR;
     }
-    if (0 !=
-        TALER_amount_cmp (&balance_from_history,
-                          &balance))
+    if (NULL != rsh->cb)
     {
-      /* exchange cannot add up balances!? */
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (rhistory,
-                                           len);
-      GNUNET_JSON_parse_free (spec);
-      return GNUNET_SYSERR;
-    }
-    if (NULL != rgh->cb)
-    {
-      rgh->cb (rgh->cb_cls,
-               &hr,
-               &balance,
-               len,
-               rhistory);
-      rgh->cb = NULL;
+      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 (rhistory,
                                          len);
@@ -182,75 +170,72 @@ handle_reserves_history_finished (void *cls,
                                   long response_code,
                                   const void *response)
 {
-  struct TALER_EXCHANGE_ReservesHistoryHandle *rgh = cls;
+  struct TALER_EXCHANGE_ReservesHistoryHandle *rsh = cls;
   const json_t *j = response;
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_history = (unsigned int) response_code
+  struct TALER_EXCHANGE_ReserveHistory rs = {
+    .hr.reply = j,
+    .hr.http_status = (unsigned int) response_code
   };
 
-  rgh->job = NULL;
+  rsh->job = NULL;
   switch (response_code)
   {
   case 0:
-    hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+    rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     break;
   case MHD_HTTP_OK:
     if (GNUNET_OK !=
-        handle_reserves_history_ok (rgh,
+        handle_reserves_history_ok (rsh,
                                     j))
     {
-      hr.http_history = 0;
-      hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+      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);
-    hr.ec = TALER_JSON_history_error_code (j);
-    hr.hint = TALER_JSON_history_error_hint (j);
+    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);
-    hr.ec = TALER_JSON_history_error_code (j);
-    hr.hint = TALER_JSON_history_error_hint (j);
+    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 */
-    hr.ec = TALER_JSON_history_error_code (j);
-    hr.hint = TALER_JSON_history_error_hint (j);
+    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 */
-    hr.ec = TALER_JSON_history_error_code (j);
-    hr.hint = TALER_JSON_history_error_hint (j);
+    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);
-    hr.ec = TALER_JSON_history_error_code (j);
-    hr.hint = TALER_JSON_history_error_hint (j);
+    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 history\n",
                 (unsigned int) response_code,
-                (int) hr.ec);
+                (int) rs.hr.ec);
     break;
   }
-  if (NULL != rgh->cb)
+  if (NULL != rsh->cb)
   {
-    rgh->cb (rgh->cb_cls,
-             &hr,
-             NULL,
-             0,
-             NULL);
-    rgh->cb = NULL;
+    rsh->cb (rsh->cb_cls,
+             &rs);
+    rsh->cb = NULL;
   }
-  TALER_EXCHANGE_reserves_history_cancel (rgh);
+  TALER_EXCHANGE_reserves_history_cancel (rsh);
 }
 
 
@@ -261,12 +246,11 @@ TALER_EXCHANGE_reserves_history (
   TALER_EXCHANGE_ReservesHistoryCallback cb,
   void *cb_cls)
 {
-  struct TALER_EXCHANGE_ReservesHistoryHandle *rgh;
+  struct TALER_EXCHANGE_ReservesHistoryHandle *rsh;
   struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
-  const struct TALER_Amount *history_fee;
-  const struct TALER_EXCHANGE_Keys *keys;
+  struct TALER_ReserveSignatureP reserve_sig;
   struct GNUNET_TIME_Timestamp ts
     = GNUNET_TIME_timestamp_get ();
 
@@ -276,22 +260,19 @@ TALER_EXCHANGE_reserves_history (
     GNUNET_break (0);
     return NULL;
   }
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  // FIXME: extract history_fee from keys!
-  history_fee = FIXME;
-  rgh = GNUNET_new (struct TALER_EXCHANGE_ReservesHistoryHandle);
-  rgh->exchange = exchange;
-  rgh->cb = cb;
-  rgh->cb_cls = cb_cls;
+  rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesHistoryHandle);
+  rsh->exchange = exchange;
+  rsh->cb = cb;
+  rsh->cb_cls = cb_cls;
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
-                                      &rgh->reserve_pub.eddsa_pub);
+                                      &rsh->reserve_pub.eddsa_pub);
   {
     char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2];
     char *end;
 
     end = GNUNET_STRINGS_data_to_string (
-      &rgh->reserve_pub,
-      sizeof (rgh->reserve_pub),
+      &rsh->reserve_pub,
+      sizeof (rsh->reserve_pub),
       pub_str,
       sizeof (pub_str));
     *end = '\0';
@@ -300,68 +281,67 @@ TALER_EXCHANGE_reserves_history (
                      "/reserves/%s/history",
                      pub_str);
   }
-  rgh->url = TEAH_path_to_url (exchange,
+  rsh->url = TEAH_path_to_url (exchange,
                                arg_str);
-  if (NULL == rgh->url)
+  if (NULL == rsh->url)
   {
-    GNUNET_free (rgh);
+    GNUNET_free (rsh);
     return NULL;
   }
-  eh = TALER_EXCHANGE_curl_easy_history_ (rgh->url);
+  eh = TALER_EXCHANGE_curl_easy_get_ (rsh->url);
   if (NULL == eh)
   {
     GNUNET_break (0);
-    GNUNET_free (rgh->url);
-    GNUNET_free (rgh);
+    GNUNET_free (rsh->url);
+    GNUNET_free (rsh);
     return NULL;
   }
   TALER_wallet_reserve_history_sign (ts,
-                                     history_fee,
+                                     NULL, /* FIXME: fee! */
                                      reserve_priv,
                                      &reserve_sig);
   {
     json_t *history_obj = GNUNET_JSON_PACK (
       GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                  &ts),
+                                  ts),
       GNUNET_JSON_pack_data_auto ("reserve_sig",
                                   &reserve_sig));
 
     if (GNUNET_OK !=
-        TALER_curl_easy_post (&rgh->post_ctx,
+        TALER_curl_easy_post (&rsh->post_ctx,
                               eh,
                               history_obj))
-      )
-      {
-        GNUNET_break (0);
-        curl_easy_cleanup (eh);
-        json_decref (history_obj);
-        GNUNET_free (rgh->url);
-        GNUNET_free (rgh);
-        return NULL;
-      }
+    {
+      GNUNET_break (0);
+      curl_easy_cleanup (eh);
       json_decref (history_obj);
+      GNUNET_free (rsh->url);
+      GNUNET_free (rsh);
+      return NULL;
+    }
+    json_decref (history_obj);
   }
   ctx = TEAH_handle_to_context (exchange);
-  rgh->job = GNUNET_CURL_job_add (ctx,
+  rsh->job = GNUNET_CURL_job_add (ctx,
                                   eh,
                                   &handle_reserves_history_finished,
-                                  rgh);
-  return rgh;
+                                  rsh);
+  return rsh;
 }
 
 
 void
 TALER_EXCHANGE_reserves_history_cancel (
-  struct TALER_EXCHANGE_ReservesHistoryHandle *rgh)
+  struct TALER_EXCHANGE_ReservesHistoryHandle *rsh)
 {
-  if (NULL != rgh->job)
+  if (NULL != rsh->job)
   {
-    GNUNET_CURL_job_cancel (rgh->job);
-    rgh->job = NULL;
+    GNUNET_CURL_job_cancel (rsh->job);
+    rsh->job = NULL;
   }
-  TALER_curl_easy_post_finished (&rgh->post_ctx);
-  GNUNET_free (rgh->url);
-  GNUNET_free (rgh);
+  TALER_curl_easy_post_finished (&rsh->post_ctx);
+  GNUNET_free (rsh->url);
+  GNUNET_free (rsh);
 }
 
 
diff --git a/src/lib/exchange_api_reserves_status.c 
b/src/lib/exchange_api_reserves_status.c
index 2758a3a2..a99a080b 100644
--- a/src/lib/exchange_api_reserves_status.c
+++ b/src/lib/exchange_api_reserves_status.c
@@ -81,35 +81,31 @@ struct TALER_EXCHANGE_ReservesStatusHandle
  * We received an #MHD_HTTP_OK status code. Handle the JSON
  * response.
  *
- * @param rgh handle of the request
+ * @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 *rgh,
+handle_reserves_status_ok (struct TALER_EXCHANGE_ReservesStatusHandle *rsh,
                            const json_t *j)
 {
   json_t *history;
   unsigned int len;
-  bool kyc_ok;
-  bool kyc_required;
-  struct TALER_Amount balance;
-  struct TALER_Amount balance_from_history;
+  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",
-                                &balance),
+                                &rs.details.ok.balance),
     GNUNET_JSON_spec_bool ("kyc_passed",
-                           &kyc_ok),
+                           &rs.details.ok.kyc_ok),
     GNUNET_JSON_spec_bool ("kyc_required",
-                           &kyc_required),
+                           &rs.details.ok.kyc_required),
     GNUNET_JSON_spec_json ("history",
                            &history),
     GNUNET_JSON_spec_end ()
   };
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_status = MHD_HTTP_OK
-  };
 
   if (GNUNET_OK !=
       GNUNET_JSON_parse (j,
@@ -122,16 +118,16 @@ handle_reserves_status_ok (struct 
TALER_EXCHANGE_ReservesStatusHandle *rgh,
   }
   len = json_array_size (history);
   {
-    struct TALER_EXCHANGE_ReserveHistory *rhistory;
+    struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory;
 
     rhistory = GNUNET_new_array (len,
-                                 struct TALER_EXCHANGE_ReserveHistory);
+                                 struct TALER_EXCHANGE_ReserveHistoryEntry);
     if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (rgh->exchange,
+        TALER_EXCHANGE_parse_reserve_history (rsh->exchange,
                                               history,
-                                              &rgh->reserve_pub,
-                                              balance.currency,
-                                              &balance_from_history,
+                                              &rsh->reserve_pub,
+                                              rs.details.ok.balance.currency,
+                                              NULL,
                                               len,
                                               rhistory))
     {
@@ -141,27 +137,13 @@ handle_reserves_status_ok (struct 
TALER_EXCHANGE_ReservesStatusHandle *rgh,
       GNUNET_JSON_parse_free (spec);
       return GNUNET_SYSERR;
     }
-    // FIXME: status history is allowed to be
-    // partial, so this is NOT ok...
-    if (0 !=
-        TALER_amount_cmp (&balance_from_history,
-                          &balance))
+    if (NULL != rsh->cb)
     {
-      /* exchange cannot add up balances!? */
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (rhistory,
-                                           len);
-      GNUNET_JSON_parse_free (spec);
-      return GNUNET_SYSERR;
-    }
-    if (NULL != rgh->cb)
-    {
-      rgh->cb (rgh->cb_cls,
-               &hr,
-               &balance,
-               len,
-               rhistory);
-      rgh->cb = NULL;
+      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 (rhistory,
                                          len);
@@ -184,75 +166,72 @@ handle_reserves_status_finished (void *cls,
                                  long response_code,
                                  const void *response)
 {
-  struct TALER_EXCHANGE_ReservesStatusHandle *rgh = cls;
+  struct TALER_EXCHANGE_ReservesStatusHandle *rsh = cls;
   const json_t *j = response;
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_status = (unsigned int) response_code
+  struct TALER_EXCHANGE_ReserveStatus rs = {
+    .hr.reply = j,
+    .hr.http_status = (unsigned int) response_code
   };
 
-  rgh->job = NULL;
+  rsh->job = NULL;
   switch (response_code)
   {
   case 0:
-    hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+    rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     break;
   case MHD_HTTP_OK:
     if (GNUNET_OK !=
-        handle_reserves_status_ok (rgh,
+        handle_reserves_status_ok (rsh,
                                    j))
     {
-      hr.http_status = 0;
-      hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+      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);
-    hr.ec = TALER_JSON_status_error_code (j);
-    hr.hint = TALER_JSON_status_error_hint (j);
+    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);
-    hr.ec = TALER_JSON_status_error_code (j);
-    hr.hint = TALER_JSON_status_error_hint (j);
+    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 */
-    hr.ec = TALER_JSON_status_error_code (j);
-    hr.hint = TALER_JSON_status_error_hint (j);
+    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 */
-    hr.ec = TALER_JSON_status_error_code (j);
-    hr.hint = TALER_JSON_status_error_hint (j);
+    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);
-    hr.ec = TALER_JSON_status_error_code (j);
-    hr.hint = TALER_JSON_status_error_hint (j);
+    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) hr.ec);
+                (int) rs.hr.ec);
     break;
   }
-  if (NULL != rgh->cb)
+  if (NULL != rsh->cb)
   {
-    rgh->cb (rgh->cb_cls,
-             &hr,
-             NULL,
-             0,
-             NULL);
-    rgh->cb = NULL;
+    rsh->cb (rsh->cb_cls,
+             &rs);
+    rsh->cb = NULL;
   }
-  TALER_EXCHANGE_reserves_status_cancel (rgh);
+  TALER_EXCHANGE_reserves_status_cancel (rsh);
 }
 
 
@@ -263,10 +242,11 @@ TALER_EXCHANGE_reserves_status (
   TALER_EXCHANGE_ReservesStatusCallback cb,
   void *cb_cls)
 {
-  struct TALER_EXCHANGE_ReservesStatusHandle *rgh;
+  struct TALER_EXCHANGE_ReservesStatusHandle *rsh;
   struct GNUNET_CURL_Context *ctx;
   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 ();
 
@@ -276,19 +256,19 @@ TALER_EXCHANGE_reserves_status (
     GNUNET_break (0);
     return NULL;
   }
-  rgh = GNUNET_new (struct TALER_EXCHANGE_ReservesStatusHandle);
-  rgh->exchange = exchange;
-  rgh->cb = cb;
-  rgh->cb_cls = cb_cls;
+  rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesStatusHandle);
+  rsh->exchange = exchange;
+  rsh->cb = cb;
+  rsh->cb_cls = cb_cls;
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
-                                      &rgh->reserve_pub.eddsa_pub);
+                                      &rsh->reserve_pub.eddsa_pub);
   {
     char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2];
     char *end;
 
     end = GNUNET_STRINGS_data_to_string (
-      &rgh->reserve_pub,
-      sizeof (rgh->reserve_pub),
+      &rsh->reserve_pub,
+      sizeof (rsh->reserve_pub),
       pub_str,
       sizeof (pub_str));
     *end = '\0';
@@ -297,19 +277,19 @@ TALER_EXCHANGE_reserves_status (
                      "/reserves/%s/status",
                      pub_str);
   }
-  rgh->url = TEAH_path_to_url (exchange,
+  rsh->url = TEAH_path_to_url (exchange,
                                arg_str);
-  if (NULL == rgh->url)
+  if (NULL == rsh->url)
   {
-    GNUNET_free (rgh);
+    GNUNET_free (rsh);
     return NULL;
   }
-  eh = TALER_EXCHANGE_curl_easy_status_ (rgh->url);
+  eh = TALER_EXCHANGE_curl_easy_get_ (rsh->url);
   if (NULL == eh)
   {
     GNUNET_break (0);
-    GNUNET_free (rgh->url);
-    GNUNET_free (rgh);
+    GNUNET_free (rsh->url);
+    GNUNET_free (rsh);
     return NULL;
   }
   TALER_wallet_reserve_status_sign (ts,
@@ -318,46 +298,45 @@ TALER_EXCHANGE_reserves_status (
   {
     json_t *status_obj = GNUNET_JSON_PACK (
       GNUNET_JSON_pack_timestamp ("request_timestamp",
-                                  &ts),
+                                  ts),
       GNUNET_JSON_pack_data_auto ("reserve_sig",
                                   &reserve_sig));
 
     if (GNUNET_OK !=
-        TALER_curl_easy_post (&rgh->post_ctx,
+        TALER_curl_easy_post (&rsh->post_ctx,
                               eh,
                               status_obj))
-      )
-      {
-        GNUNET_break (0);
-        curl_easy_cleanup (eh);
-        json_decref (status_obj);
-        GNUNET_free (rgh->url);
-        GNUNET_free (rgh);
-        return NULL;
-      }
+    {
+      GNUNET_break (0);
+      curl_easy_cleanup (eh);
       json_decref (status_obj);
+      GNUNET_free (rsh->url);
+      GNUNET_free (rsh);
+      return NULL;
+    }
+    json_decref (status_obj);
   }
   ctx = TEAH_handle_to_context (exchange);
-  rgh->job = GNUNET_CURL_job_add (ctx,
+  rsh->job = GNUNET_CURL_job_add (ctx,
                                   eh,
                                   &handle_reserves_status_finished,
-                                  rgh);
-  return rgh;
+                                  rsh);
+  return rsh;
 }
 
 
 void
 TALER_EXCHANGE_reserves_status_cancel (
-  struct TALER_EXCHANGE_ReservesStatusHandle *rgh)
+  struct TALER_EXCHANGE_ReservesStatusHandle *rsh)
 {
-  if (NULL != rgh->job)
+  if (NULL != rsh->job)
   {
-    GNUNET_CURL_job_cancel (rgh->job);
-    rgh->job = NULL;
+    GNUNET_CURL_job_cancel (rsh->job);
+    rsh->job = NULL;
   }
-  TALER_curl_easy_post_finished (&rgh->post_ctx);
-  GNUNET_free (rgh->url);
-  GNUNET_free (rgh);
+  TALER_curl_easy_post_finished (&rsh->post_ctx);
+  GNUNET_free (rsh->url);
+  GNUNET_free (rsh);
 }
 
 
diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c
index ade6fe8a..bc138db0 100644
--- a/src/lib/exchange_api_withdraw2.c
+++ b/src/lib/exchange_api_withdraw2.c
@@ -177,14 +177,14 @@ reserve_withdraw_payment_required (
      total incoming and outgoing amounts */
   len = json_array_size (history);
   {
-    struct TALER_EXCHANGE_ReserveHistory *rhistory;
+    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_ReserveHistory)
+      sizeof (struct TALER_EXCHANGE_ReserveHistoryEntry)
       * len);
     if (NULL == rhistory)
     {
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 39cc6cbe..30148d71 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -74,6 +74,8 @@ libtalertesting_la_SOURCES = \
   testing_api_cmd_recoup_refresh.c \
   testing_api_cmd_refund.c \
   testing_api_cmd_refresh.c \
+  testing_api_cmd_reserve_history.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/testing_api_cmd_bank_admin_add_incoming.c 
b/src/testing/testing_api_cmd_bank_admin_add_incoming.c
index 5b1d8b8a..07ee4068 100644
--- a/src/testing/testing_api_cmd_bank_admin_add_incoming.c
+++ b/src/testing/testing_api_cmd_bank_admin_add_incoming.c
@@ -107,7 +107,7 @@ struct AdminAddIncomingState
    * the "sender_url" field is set to a 'const char *' and
    * MUST NOT be free()'ed.
    */
-  struct TALER_EXCHANGE_ReserveHistory reserve_history;
+  struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
 
   /**
    * Set to the wire transfer's unique ID.
diff --git a/src/testing/testing_api_cmd_exec_closer.c 
b/src/testing/testing_api_cmd_exec_closer.c
index 442fb4ce..57346f33 100644
--- a/src/testing/testing_api_cmd_exec_closer.c
+++ b/src/testing/testing_api_cmd_exec_closer.c
@@ -49,7 +49,7 @@ struct CloserState
    * expect_close is true.  Will be of type
    * #TALER_EXCHANGE_RTT_RESERVE_CLOSED.
    */
-  struct TALER_EXCHANGE_ReserveHistory reserve_history;
+  struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
 
   /**
    * If the closer filled a reserve (@e expect_close is set), this is set to
diff --git a/src/testing/testing_api_cmd_recoup.c 
b/src/testing/testing_api_cmd_recoup.c
index 85256c20..ef271622 100644
--- a/src/testing/testing_api_cmd_recoup.c
+++ b/src/testing/testing_api_cmd_recoup.c
@@ -62,7 +62,7 @@ struct RecoupState
    * Reserve history entry, set if this recoup actually filled up a reserve.
    * Otherwise `reserve_history.type` will be zero.
    */
-  struct TALER_EXCHANGE_ReserveHistory reserve_history;
+  struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
 
 };
 
diff --git a/src/testing/testing_api_cmd_status.c 
b/src/testing/testing_api_cmd_reserve_history.c
similarity index 77%
copy from src/testing/testing_api_cmd_status.c
copy to src/testing/testing_api_cmd_reserve_history.c
index f13f6007..fc94d844 100644
--- a/src/testing/testing_api_cmd_status.c
+++ b/src/testing/testing_api_cmd_reserve_history.c
@@ -17,8 +17,8 @@
   <http://www.gnu.org/licenses/>
 */
 /**
- * @file testing/testing_api_cmd_status.c
- * @brief Implement the /reserve/status test command.
+ * @file testing/testing_api_cmd_history.c
+ * @brief Implement the /reserve/history test command.
  * @author Marcello Stanisci
  */
 #include "platform.h"
@@ -28,9 +28,9 @@
 
 
 /**
- * State for a "status" CMD.
+ * State for a "history" CMD.
  */
-struct StatusState
+struct HistoryState
 {
   /**
    * Label to the command which created the reserve to check,
@@ -39,19 +39,24 @@ struct StatusState
   const char *reserve_reference;
 
   /**
-   * Handle to the "reserve status" operation.
+   * Handle to the "reserve history" operation.
    */
-  struct TALER_EXCHANGE_ReservesGetHandle *rsh;
+  struct TALER_EXCHANGE_ReservesHistoryHandle *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.
    */
-  const struct TALER_ReservePublicKeyP *reserve_pubp;
+  struct TALER_ReservePublicKeyP reserve_pub;
 
   /**
    * Expected HTTP response code.
@@ -73,8 +78,8 @@ struct StatusState
  * @return 0 if @a h1 and @a h2 are equal
  */
 static int
-history_entry_cmp (const struct TALER_EXCHANGE_ReserveHistory *h1,
-                   const struct TALER_EXCHANGE_ReserveHistory *h2)
+history_entry_cmp (const struct TALER_EXCHANGE_ReserveHistoryEntry *h1,
+                   const struct TALER_EXCHANGE_ReserveHistoryEntry *h2)
 {
   if (h1->type != h2->type)
     return 1;
@@ -151,7 +156,7 @@ static enum GNUNET_GenericReturnValue
 analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub,
                  const struct TALER_TESTING_Command *cmd,
                  unsigned int history_length,
-                 const struct TALER_EXCHANGE_ReserveHistory *history,
+                 const struct TALER_EXCHANGE_ReserveHistoryEntry *history,
                  int *found)
 {
   if (TALER_TESTING_cmd_is_batch (cmd))
@@ -186,7 +191,7 @@ analyze_command (const struct TALER_ReservePublicKeyP 
*reserve_pub,
   else
   {
     const struct TALER_ReservePublicKeyP *rp;
-    const struct TALER_EXCHANGE_ReserveHistory *he;
+    const struct TALER_EXCHANGE_ReserveHistoryEntry *he;
 
     if (GNUNET_OK !=
         TALER_TESTING_get_trait_reserve_pub (cmd,
@@ -231,53 +236,50 @@ analyze_command (const struct TALER_ReservePublicKeyP 
*reserve_pub,
  * both acceptable.
  *
  * @param cls closure.
- * @param hr HTTP response details
- * @param balance current balance in the reserve, NULL on error.
- * @param history_length number of entries in the transaction
- *        history, 0 on error.
- * @param history detailed transaction history, NULL on error.
+ * @param rs HTTP response details
  */
 static void
-reserve_status_cb (void *cls,
-                   const struct TALER_EXCHANGE_HttpResponse *hr,
-                   const struct TALER_Amount *balance,
-                   unsigned int history_length,
-                   const struct TALER_EXCHANGE_ReserveHistory *history)
+reserve_history_cb (void *cls,
+                    const struct TALER_EXCHANGE_ReserveHistory *rs)
 {
-  struct StatusState *ss = cls;
+  struct HistoryState *ss = cls;
   struct TALER_TESTING_Interpreter *is = ss->is;
   struct TALER_Amount eb;
 
   ss->rsh = NULL;
-  if (ss->expected_response_code != hr->http_status)
+  if (ss->expected_response_code != rs->hr.http_status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unexpected HTTP response code: %d in %s:%u\n",
-                hr->http_status,
+                rs->hr.http_status,
                 __FILE__,
                 __LINE__);
-    json_dumpf (hr->reply,
+    json_dumpf (rs->hr.reply,
                 stderr,
                 0);
     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,
-                             balance))
+                             &rs->details.ok.balance))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unexpected amount in reserve: %s\n",
-                TALER_amount_to_string (balance));
+                TALER_amount_to_string (&rs->details.ok.balance));
     TALER_TESTING_interpreter_fail (ss->is);
     return;
   }
   {
-    int found[history_length];
+    int found[rs->details.ok.history_len];
 
     memset (found,
             0,
@@ -287,10 +289,10 @@ reserve_status_cb (void *cls,
       struct TALER_TESTING_Command *cmd = &is->commands[i];
 
       if (GNUNET_OK !=
-          analyze_command (ss->reserve_pubp,
+          analyze_command (&ss->reserve_pub,
                            cmd,
-                           history_length,
-                           history,
+                           rs->details.ok.history_len,
+                           rs->details.ok.history,
                            found))
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -300,13 +302,13 @@ reserve_status_cb (void *cls,
         return;
       }
     }
-    for (unsigned int i = 0; i<history_length; i++)
+    for (unsigned int i = 0; i<rs->details.ok.history_len; i++)
       if (! found[i])
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                     "History entry at index %u of type %d not justified by 
command history\n",
                     i,
-                    history[i].type);
+                    rs->details.ok.history[i].type);
         TALER_TESTING_interpreter_fail (ss->is);
         return;
       }
@@ -323,11 +325,11 @@ reserve_status_cb (void *cls,
  * @param is the interpreter state.
  */
 static void
-status_run (void *cls,
-            const struct TALER_TESTING_Command *cmd,
-            struct TALER_TESTING_Interpreter *is)
+history_run (void *cls,
+             const struct TALER_TESTING_Command *cmd,
+             struct TALER_TESTING_Interpreter *is)
 {
-  struct StatusState *ss = cls;
+  struct HistoryState *ss = cls;
   const struct TALER_TESTING_Command *create_reserve;
 
   ss->is = is;
@@ -342,34 +344,35 @@ status_run (void *cls,
     return;
   }
   if (GNUNET_OK !=
-      TALER_TESTING_get_trait_reserve_pub (create_reserve,
-                                           &ss->reserve_pubp))
+      TALER_TESTING_get_trait_reserve_priv (create_reserve,
+                                            &ss->reserve_priv))
   {
     GNUNET_break (0);
-    TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
+    TALER_LOG_ERROR ("Failed to find reserve_priv for history query\n");
     TALER_TESTING_interpreter_fail (is);
     return;
   }
-  ss->rsh = TALER_EXCHANGE_reserves_get (is->exchange,
-                                         ss->reserve_pubp,
-                                         GNUNET_TIME_UNIT_ZERO,
-                                         &reserve_status_cb,
-                                         ss);
+  GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
+                                      &ss->reserve_pub.eddsa_pub);
+  ss->rsh = TALER_EXCHANGE_reserves_history (is->exchange,
+                                             ss->reserve_priv,
+                                             &reserve_history_cb,
+                                             ss);
 }
 
 
 /**
- * Cleanup the state from a "reserve status" CMD, and possibly
+ * Cleanup the state from a "reserve history" 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)
+history_cleanup (void *cls,
+                 const struct TALER_TESTING_Command *cmd)
 {
-  struct StatusState *ss = cls;
+  struct HistoryState *ss = cls;
 
   if (NULL != ss->rsh)
   {
@@ -377,7 +380,7 @@ status_cleanup (void *cls,
                 "Command %u (%s) did not complete\n",
                 ss->is->ip,
                 cmd->label);
-    TALER_EXCHANGE_reserves_get_cancel (ss->rsh);
+    TALER_EXCHANGE_reserves_history_cancel (ss->rsh);
     ss->rsh = NULL;
   }
   GNUNET_free (ss);
@@ -385,15 +388,15 @@ status_cleanup (void *cls,
 
 
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_status (const char *label,
-                          const char *reserve_reference,
-                          const char *expected_balance,
-                          unsigned int expected_response_code)
+TALER_TESTING_cmd_reserve_history (const char *label,
+                                   const char *reserve_reference,
+                                   const char *expected_balance,
+                                   unsigned int expected_response_code)
 {
-  struct StatusState *ss;
+  struct HistoryState *ss;
 
   GNUNET_assert (NULL != reserve_reference);
-  ss = GNUNET_new (struct StatusState);
+  ss = GNUNET_new (struct HistoryState);
   ss->reserve_reference = reserve_reference;
   ss->expected_balance = expected_balance;
   ss->expected_response_code = expected_response_code;
@@ -401,8 +404,8 @@ TALER_TESTING_cmd_status (const char *label,
     struct TALER_TESTING_Command cmd = {
       .cls = ss,
       .label = label,
-      .run = &status_run,
-      .cleanup = &status_cleanup
+      .run = &history_run,
+      .cleanup = &history_cleanup
     };
 
     return cmd;
diff --git a/src/testing/testing_api_cmd_status.c 
b/src/testing/testing_api_cmd_reserve_status.c
similarity index 82%
copy from src/testing/testing_api_cmd_status.c
copy to src/testing/testing_api_cmd_reserve_status.c
index f13f6007..10f3ee99 100644
--- a/src/testing/testing_api_cmd_status.c
+++ b/src/testing/testing_api_cmd_reserve_status.c
@@ -18,7 +18,7 @@
 */
 /**
  * @file testing/testing_api_cmd_status.c
- * @brief Implement the /reserve/status test command.
+ * @brief Implement the /reserve/$RID/status test command.
  * @author Marcello Stanisci
  */
 #include "platform.h"
@@ -41,17 +41,22 @@ struct StatusState
   /**
    * Handle to the "reserve status" operation.
    */
-  struct TALER_EXCHANGE_ReservesGetHandle *rsh;
+  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.
    */
-  const struct TALER_ReservePublicKeyP *reserve_pubp;
+  struct TALER_ReservePublicKeyP reserve_pub;
 
   /**
    * Expected HTTP response code.
@@ -73,8 +78,8 @@ struct StatusState
  * @return 0 if @a h1 and @a h2 are equal
  */
 static int
-history_entry_cmp (const struct TALER_EXCHANGE_ReserveHistory *h1,
-                   const struct TALER_EXCHANGE_ReserveHistory *h2)
+history_entry_cmp (const struct TALER_EXCHANGE_ReserveHistoryEntry *h1,
+                   const struct TALER_EXCHANGE_ReserveHistoryEntry *h2)
 {
   if (h1->type != h2->type)
     return 1;
@@ -151,7 +156,7 @@ static enum GNUNET_GenericReturnValue
 analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub,
                  const struct TALER_TESTING_Command *cmd,
                  unsigned int history_length,
-                 const struct TALER_EXCHANGE_ReserveHistory *history,
+                 const struct TALER_EXCHANGE_ReserveHistoryEntry *history,
                  int *found)
 {
   if (TALER_TESTING_cmd_is_batch (cmd))
@@ -186,7 +191,7 @@ analyze_command (const struct TALER_ReservePublicKeyP 
*reserve_pub,
   else
   {
     const struct TALER_ReservePublicKeyP *rp;
-    const struct TALER_EXCHANGE_ReserveHistory *he;
+    const struct TALER_EXCHANGE_ReserveHistoryEntry *he;
 
     if (GNUNET_OK !=
         TALER_TESTING_get_trait_reserve_pub (cmd,
@@ -231,53 +236,50 @@ analyze_command (const struct TALER_ReservePublicKeyP 
*reserve_pub,
  * both acceptable.
  *
  * @param cls closure.
- * @param hr HTTP response details
- * @param balance current balance in the reserve, NULL on error.
- * @param history_length number of entries in the transaction
- *        history, 0 on error.
- * @param history detailed transaction history, NULL on error.
+ * @param rs HTTP response details
  */
 static void
 reserve_status_cb (void *cls,
-                   const struct TALER_EXCHANGE_HttpResponse *hr,
-                   const struct TALER_Amount *balance,
-                   unsigned int history_length,
-                   const struct TALER_EXCHANGE_ReserveHistory *history)
+                   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 != hr->http_status)
+  if (ss->expected_response_code != rs->hr.http_status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unexpected HTTP response code: %d in %s:%u\n",
-                hr->http_status,
+                rs->hr.http_status,
                 __FILE__,
                 __LINE__);
-    json_dumpf (hr->reply,
+    json_dumpf (rs->hr.reply,
                 stderr,
                 0);
     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,
-                             balance))
+                             &rs->details.ok.balance))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unexpected amount in reserve: %s\n",
-                TALER_amount_to_string (balance));
+                TALER_amount_to_string (&rs->details.ok.balance));
     TALER_TESTING_interpreter_fail (ss->is);
     return;
   }
   {
-    int found[history_length];
+    int found[rs->details.ok.history_len];
 
     memset (found,
             0,
@@ -287,10 +289,10 @@ reserve_status_cb (void *cls,
       struct TALER_TESTING_Command *cmd = &is->commands[i];
 
       if (GNUNET_OK !=
-          analyze_command (ss->reserve_pubp,
+          analyze_command (&ss->reserve_pub,
                            cmd,
-                           history_length,
-                           history,
+                           rs->details.ok.history_len,
+                           rs->details.ok.history,
                            found))
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -300,13 +302,13 @@ reserve_status_cb (void *cls,
         return;
       }
     }
-    for (unsigned int i = 0; i<history_length; i++)
+    for (unsigned int i = 0; i<rs->details.ok.history_len; i++)
       if (! found[i])
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "History entry at index %u of type %d not justified by 
command history\n",
+                    "History entry at index %u of type %d not justified by 
command status\n",
                     i,
-                    history[i].type);
+                    rs->details.ok.history[i].type);
         TALER_TESTING_interpreter_fail (ss->is);
         return;
       }
@@ -342,19 +344,20 @@ status_run (void *cls,
     return;
   }
   if (GNUNET_OK !=
-      TALER_TESTING_get_trait_reserve_pub (create_reserve,
-                                           &ss->reserve_pubp))
+      TALER_TESTING_get_trait_reserve_priv (create_reserve,
+                                            &ss->reserve_priv))
   {
     GNUNET_break (0);
-    TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
+    TALER_LOG_ERROR ("Failed to find reserve_priv for status query\n");
     TALER_TESTING_interpreter_fail (is);
     return;
   }
-  ss->rsh = TALER_EXCHANGE_reserves_get (is->exchange,
-                                         ss->reserve_pubp,
-                                         GNUNET_TIME_UNIT_ZERO,
-                                         &reserve_status_cb,
-                                         ss);
+  GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
+                                      &ss->reserve_pub.eddsa_pub);
+  ss->rsh = TALER_EXCHANGE_reserves_status (is->exchange,
+                                            ss->reserve_priv,
+                                            &reserve_status_cb,
+                                            ss);
 }
 
 
@@ -377,7 +380,7 @@ status_cleanup (void *cls,
                 "Command %u (%s) did not complete\n",
                 ss->is->ip,
                 cmd->label);
-    TALER_EXCHANGE_reserves_get_cancel (ss->rsh);
+    TALER_EXCHANGE_reserves_status_cancel (ss->rsh);
     ss->rsh = NULL;
   }
   GNUNET_free (ss);
@@ -385,10 +388,10 @@ status_cleanup (void *cls,
 
 
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_status (const char *label,
-                          const char *reserve_reference,
-                          const char *expected_balance,
-                          unsigned int expected_response_code)
+TALER_TESTING_cmd_reserve_status (const char *label,
+                                  const char *reserve_reference,
+                                  const char *expected_balance,
+                                  unsigned int expected_response_code)
 {
   struct StatusState *ss;
 
diff --git a/src/testing/testing_api_cmd_status.c 
b/src/testing/testing_api_cmd_status.c
index f13f6007..9d499571 100644
--- a/src/testing/testing_api_cmd_status.c
+++ b/src/testing/testing_api_cmd_status.c
@@ -18,7 +18,7 @@
 */
 /**
  * @file testing/testing_api_cmd_status.c
- * @brief Implement the /reserve/status test command.
+ * @brief Implement the GET /reserve/$RID test command.
  * @author Marcello Stanisci
  */
 #include "platform.h"
@@ -65,252 +65,52 @@ struct StatusState
 };
 
 
-/**
- * Compare @a h1 and @a h2.
- *
- * @param h1 a history entry
- * @param h2 a history entry
- * @return 0 if @a h1 and @a h2 are equal
- */
-static int
-history_entry_cmp (const struct TALER_EXCHANGE_ReserveHistory *h1,
-                   const struct TALER_EXCHANGE_ReserveHistory *h2)
-{
-  if (h1->type != h2->type)
-    return 1;
-  switch (h1->type)
-  {
-  case TALER_EXCHANGE_RTT_CREDIT:
-    if ( (0 ==
-          TALER_amount_cmp (&h1->amount,
-                            &h2->amount)) &&
-         (0 == strcasecmp (h1->details.in_details.sender_url,
-                           h2->details.in_details.sender_url)) &&
-         (h1->details.in_details.wire_reference ==
-          h2->details.in_details.wire_reference) &&
-         (GNUNET_TIME_timestamp_cmp (h1->details.in_details.timestamp,
-                                     ==,
-                                     h2->details.in_details.timestamp)) )
-      return 0;
-    return 1;
-  case TALER_EXCHANGE_RTT_WITHDRAWAL:
-    if ( (0 ==
-          TALER_amount_cmp (&h1->amount,
-                            &h2->amount)) &&
-         (0 ==
-          TALER_amount_cmp (&h1->details.withdraw.fee,
-                            &h2->details.withdraw.fee)) )
-      /* testing_api_cmd_withdraw doesn't set the out_authorization_sig,
-         so we cannot test for it here. but if the amount matches,
-         that should be good enough. */
-      return 0;
-    return 1;
-  case TALER_EXCHANGE_RTT_RECOUP:
-    /* exchange_sig, exchange_pub and timestamp are NOT available
-       from the original recoup response, hence here NOT check(able/ed) */
-    if ( (0 ==
-          TALER_amount_cmp (&h1->amount,
-                            &h2->amount)) &&
-         (0 ==
-          GNUNET_memcmp (&h1->details.recoup_details.coin_pub,
-                         &h2->details.recoup_details.coin_pub)) )
-      return 0;
-    return 1;
-  case TALER_EXCHANGE_RTT_CLOSE:
-    /* testing_api_cmd_exec_closer doesn't set the
-       receiver_account_details, exchange_sig, exchange_pub or wtid or 
timestamp
-       so we cannot test for it here. but if the amount matches,
-       that should be good enough. */
-    if ( (0 ==
-          TALER_amount_cmp (&h1->amount,
-                            &h2->amount)) &&
-         (0 ==
-          TALER_amount_cmp (&h1->details.close_details.fee,
-                            &h2->details.close_details.fee)) )
-      return 0;
-    return 1;
-  }
-  GNUNET_assert (0);
-  return 1;
-}
-
-
-/**
- * Check if @a cmd changed the reserve, if so, find the
- * entry in @a history and set the respective index in @a found
- * to #GNUNET_YES. If the entry is not found, return #GNUNET_SYSERR.
- *
- * @param reserve_pub public key of the reserve for which we have the @a 
history
- * @param cmd command to analyze for impact on history
- * @param history_length number of entries in @a history and @a found
- * @param history history to check
- * @param[in,out] found array to update
- * @return #GNUNET_OK if @a cmd action on reserve was found in @a history
- */
-static enum GNUNET_GenericReturnValue
-analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub,
-                 const struct TALER_TESTING_Command *cmd,
-                 unsigned int history_length,
-                 const struct TALER_EXCHANGE_ReserveHistory *history,
-                 int *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);
-      return GNUNET_SYSERR;
-    }
-    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' */
-      if (GNUNET_OK !=
-          analyze_command (reserve_pub,
-                           step,
-                           history_length,
-                           history,
-                           found))
-        return GNUNET_SYSERR;
-    }
-    return GNUNET_OK;
-  }
-  else
-  {
-    const struct TALER_ReservePublicKeyP *rp;
-    const struct TALER_EXCHANGE_ReserveHistory *he;
-
-    if (GNUNET_OK !=
-        TALER_TESTING_get_trait_reserve_pub (cmd,
-                                             &rp))
-      return GNUNET_OK; /* command does nothing for reserves */
-    if (0 !=
-        GNUNET_memcmp (rp,
-                       reserve_pub))
-      return GNUNET_OK; /* command affects some _other_ reserve */
-    if (GNUNET_OK !=
-        TALER_TESTING_get_trait_reserve_history (cmd,
-                                                 &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 GNUNET_OK; /* command does nothing for reserves */
-    }
-    for (unsigned int i = 0; i<history_length; i++)
-    {
-      if (found[i])
-        continue; /* already found, skip */
-      if (0 ==
-          history_entry_cmp (he,
-                             &history[i]))
-      {
-        found[i] = GNUNET_YES;
-        return GNUNET_OK;
-      }
-    }
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Command `%s' reserve history entry not found\n",
-                cmd->label);
-    return GNUNET_SYSERR;
-  }
-}
-
-
 /**
  * Check that the reserve balance and HTTP response code are
  * both acceptable.
  *
  * @param cls closure.
- * @param hr HTTP response details
- * @param balance current balance in the reserve, NULL on error.
- * @param history_length number of entries in the transaction
- *        history, 0 on error.
- * @param history detailed transaction history, NULL on error.
+ * @param rs HTTP response details
  */
 static void
 reserve_status_cb (void *cls,
-                   const struct TALER_EXCHANGE_HttpResponse *hr,
-                   const struct TALER_Amount *balance,
-                   unsigned int history_length,
-                   const struct TALER_EXCHANGE_ReserveHistory *history)
+                   const struct TALER_EXCHANGE_ReserveSummary *rs)
 {
   struct StatusState *ss = cls;
   struct TALER_TESTING_Interpreter *is = ss->is;
   struct TALER_Amount eb;
 
   ss->rsh = NULL;
-  if (ss->expected_response_code != hr->http_status)
+  if (ss->expected_response_code != rs->hr.http_status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unexpected HTTP response code: %d in %s:%u\n",
-                hr->http_status,
+                rs->hr.http_status,
                 __FILE__,
                 __LINE__);
-    json_dumpf (hr->reply,
+    json_dumpf (rs->hr.reply,
                 stderr,
                 0);
     TALER_TESTING_interpreter_fail (ss->is);
     return;
   }
-
+  if (MHD_HTTP_OK != ss->expected_response_code)
+  {
+    TALER_TESTING_interpreter_next (is);
+    return;
+  }
   GNUNET_assert (GNUNET_OK ==
                  TALER_string_to_amount (ss->expected_balance,
                                          &eb));
-
   if (0 != TALER_amount_cmp (&eb,
-                             balance))
+                             &rs->details.ok.balance))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unexpected amount in reserve: %s\n",
-                TALER_amount_to_string (balance));
+                TALER_amount_to_string (&rs->details.ok.balance));
     TALER_TESTING_interpreter_fail (ss->is);
     return;
   }
-  {
-    int found[history_length];
-
-    memset (found,
-            0,
-            sizeof (found));
-    for (unsigned int i = 0; i<= (unsigned int) is->ip; i++)
-    {
-      struct TALER_TESTING_Command *cmd = &is->commands[i];
-
-      if (GNUNET_OK !=
-          analyze_command (ss->reserve_pubp,
-                           cmd,
-                           history_length,
-                           history,
-                           found))
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Entry for command `%s' missing in history\n",
-                    cmd->label);
-        TALER_TESTING_interpreter_fail (ss->is);
-        return;
-      }
-    }
-    for (unsigned int i = 0; i<history_length; i++)
-      if (! found[i])
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "History entry at index %u of type %d not justified by 
command history\n",
-                    i,
-                    history[i].type);
-        TALER_TESTING_interpreter_fail (ss->is);
-        return;
-      }
-  }
   TALER_TESTING_interpreter_next (is);
 }
 
diff --git a/src/testing/testing_api_cmd_withdraw.c 
b/src/testing/testing_api_cmd_withdraw.c
index 1c24d5a6..a3823398 100644
--- a/src/testing/testing_api_cmd_withdraw.c
+++ b/src/testing/testing_api_cmd_withdraw.c
@@ -148,7 +148,7 @@ struct WithdrawState
    * Reserve history entry that corresponds to this operation.
    * Will be of type #TALER_EXCHANGE_RTT_WITHDRAWAL.
    */
-  struct TALER_EXCHANGE_ReserveHistory reserve_history;
+  struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
 
   /**
    * Withdraw handle (while operation is running).

-- 
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]