summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2022-03-20 13:20:45 +0100
committerChristian Grothoff <grothoff@gnunet.org>2022-03-20 13:20:45 +0100
commit427417b8352c2036dc6f5c0ca6bd20c0b7edd225 (patch)
tree54b96b474e9af87586e12763333b04257849798a /src
parentdee45bf02284716d5dea18e94193d74e64f7e5bf (diff)
downloadexchange-427417b8352c2036dc6f5c0ca6bd20c0b7edd225.tar.gz
exchange-427417b8352c2036dc6f5c0ca6bd20c0b7edd225.tar.bz2
exchange-427417b8352c2036dc6f5c0ca6bd20c0b7edd225.zip
towards support for new reserve history/status APIs
Diffstat (limited to 'src')
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c64
-rw-r--r--src/exchange/taler-exchange-httpd_keys.h80
-rw-r--r--src/include/taler_exchange_service.h286
-rw-r--r--src/include/taler_testing_lib.h33
-rw-r--r--src/lib/Makefile.am4
-rw-r--r--src/lib/exchange_api_common.c26
-rw-r--r--src/lib/exchange_api_handle.c21
-rw-r--r--src/lib/exchange_api_reserves_get.c100
-rw-r--r--src/lib/exchange_api_reserves_history.c192
-rw-r--r--src/lib/exchange_api_reserves_status.c183
-rw-r--r--src/lib/exchange_api_withdraw2.c4
-rw-r--r--src/testing/Makefile.am2
-rw-r--r--src/testing/testing_api_cmd_bank_admin_add_incoming.c2
-rw-r--r--src/testing/testing_api_cmd_exec_closer.c2
-rw-r--r--src/testing/testing_api_cmd_recoup.c2
-rw-r--r--src/testing/testing_api_cmd_reserve_history.c413
-rw-r--r--src/testing/testing_api_cmd_reserve_status.c413
-rw-r--r--src/testing/testing_api_cmd_status.c226
-rw-r--r--src/testing/testing_api_cmd_withdraw.c2
19 files changed, 1480 insertions, 575 deletions
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index 1012a8c03..658e5a347 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 ee9412a65..732ee032d 100644
--- a/src/exchange/taler-exchange-httpd_keys.h
+++ b/src/exchange/taler-exchange-httpd_keys.h
@@ -83,6 +83,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
* reference counted and only destroyed once the last user is done
@@ -130,6 +188,20 @@ 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
* key state is resolved.
@@ -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 56940669d..f59e1b46c 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -637,6 +637,19 @@ TALER_EXCHANGE_get_denomination_key (
/**
+ * 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.
*
* @param key key to copy
@@ -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
{
/**
@@ -1454,22 +1460,58 @@ 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 a1bc5d0d9..829f9b8a6 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 7d49f53cd..730c833d7 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 160f62dc6..c9bff71f1 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 f7e877913..e0fcd2b93 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 a25350e5b..4c2886e0b 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 f7191b2ad..c0f6c42d2 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 2758a3a28..a99a080bc 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 ade6fe8a7..bc138db0f 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 39cc6cbed..30148d71a 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 5b1d8b8a9..07ee4068b 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 442fb4ce0..57346f333 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 85256c207..ef2716226 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_reserve_history.c b/src/testing/testing_api_cmd_reserve_history.c
new file mode 100644
index 000000000..fc94d8443
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_history.c
@@ -0,0 +1,413 @@
+/*
+ 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_history.c
+ * @brief Implement the /reserve/history 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 "history" CMD.
+ */
+struct HistoryState
+{
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve history" operation.
+ */
+ 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.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * 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_ReserveHistoryEntry *h1,
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *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_ReserveHistoryEntry *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_ReserveHistoryEntry *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 rs HTTP response details
+ */
+static void
+reserve_history_cb (void *cls,
+ const struct TALER_EXCHANGE_ReserveHistory *rs)
+{
+ struct HistoryState *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,
+ 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,
+ &rs->details.ok.balance))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected amount in reserve: %s\n",
+ TALER_amount_to_string (&rs->details.ok.balance));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ {
+ int found[rs->details.ok.history_len];
+
+ 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_pub,
+ cmd,
+ rs->details.ok.history_len,
+ rs->details.ok.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<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,
+ rs->details.ok.history[i].type);
+ 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
+history_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct HistoryState *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 history 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_history (is->exchange,
+ ss->reserve_priv,
+ &reserve_history_cb,
+ ss);
+}
+
+
+/**
+ * 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
+history_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct HistoryState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ ss->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_reserves_history_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+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)
+{
+ struct HistoryState *ss;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct HistoryState);
+ 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 = &history_run,
+ .cleanup = &history_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_status.c b/src/testing/testing_api_cmd_reserve_status.c
new file mode 100644
index 000000000..10f3ee99b
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_status.c
@@ -0,0 +1,413 @@
+/*
+ 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_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;
+};
+
+
+/**
+ * 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_ReserveHistoryEntry *h1,
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *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_ReserveHistoryEntry *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_ReserveHistoryEntry *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 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,
+ 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,
+ &rs->details.ok.balance))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected amount in reserve: %s\n",
+ TALER_amount_to_string (&rs->details.ok.balance));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ {
+ int found[rs->details.ok.history_len];
+
+ 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_pub,
+ cmd,
+ rs->details.ok.history_len,
+ rs->details.ok.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<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 status\n",
+ i,
+ rs->details.ok.history[i].type);
+ 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 (is->exchange,
+ 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)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ ss->is->ip,
+ 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/testing/testing_api_cmd_status.c b/src/testing/testing_api_cmd_status.c
index f13f60073..9d499571b 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"
@@ -66,251 +66,51 @@ 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 1c24d5a6c..a38233980 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).