summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2022-03-21 02:39:36 +0100
committerChristian Grothoff <grothoff@gnunet.org>2022-03-21 02:39:36 +0100
commitf5f15e6531bb7072a02cb976771a43803bd044f6 (patch)
tree80cc93a627533fe4768bd5aded76c77c3d37660d
parentb560527ee3d5605310f3793dbcbf86a9b4844c91 (diff)
downloadexchange-f5f15e6531bb7072a02cb976771a43803bd044f6.tar.gz
exchange-f5f15e6531bb7072a02cb976771a43803bd044f6.tar.bz2
exchange-f5f15e6531bb7072a02cb976771a43803bd044f6.zip
first rough-cut implementation of POST /reserves//status
m---------contrib/gana0
-rw-r--r--src/exchange/Makefile.am1
-rw-r--r--src/exchange/taler-exchange-httpd.c84
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c12
-rw-r--r--src/exchange/taler-exchange-httpd_mhd.h2
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_get.c88
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_status.c199
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_status.h43
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c122
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h7
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.c35
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.h10
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c43
-rw-r--r--src/include/taler_exchangedb_plugin.h14
14 files changed, 441 insertions, 219 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject baeb820366b88befd6f5aa2a551e2827ef406da
+Subproject 4cfefdf374de55fe9be3f0f039c7a13f496ab97
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 3a07b6f46..2923aa2dc 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -108,6 +108,7 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_refreshes_reveal.c taler-exchange-httpd_refreshes_reveal.h \
taler-exchange-httpd_refund.c taler-exchange-httpd_refund.h \
taler-exchange-httpd_reserves_get.c taler-exchange-httpd_reserves_get.h \
+ taler-exchange-httpd_reserves_status.c taler-exchange-httpd_reserves_status.h \
taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index f0dc365a9..676135faf 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -48,6 +48,7 @@
#include "taler-exchange-httpd_refreshes_reveal.h"
#include "taler-exchange-httpd_refund.h"
#include "taler-exchange-httpd_reserves_get.h"
+#include "taler-exchange-httpd_reserves_status.h"
#include "taler-exchange-httpd_terms.h"
#include "taler-exchange-httpd_transfers_get.h"
#include "taler-exchange-httpd_wire.h"
@@ -212,6 +213,19 @@ typedef MHD_RESULT
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const json_t *root);
+/**
+ * Signature of functions that handle operations on reserves.
+ *
+ * @param rc request context
+ * @param reserve_pub the public key of the reserve
+ * @param root uploaded JSON data
+ * @return MHD result code
+ */
+typedef MHD_RESULT
+(*ReserveOpHandler)(struct TEH_RequestContext *rc,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const json_t *root);
+
/**
* Generate a 404 "not found" reply on @a connection with
@@ -237,8 +251,7 @@ r404 (struct MHD_Connection *connection,
*
* @param rc request context
* @param root uploaded JSON data
- * @param args array of additional options (first must be the
- * reserve public key, the second one should be "withdraw")
+ * @param args array of additional options
* @return MHD result code
*/
static MHD_RESULT
@@ -310,6 +323,71 @@ handle_post_coins (struct TEH_RequestContext *rc,
/**
+ * Handle a "/reserves/$RESERVE_PUB/$OP" POST request. Parses the "reserve_pub"
+ * EdDSA key of the reserve and demultiplexes based on $OP.
+ *
+ * @param rc request context
+ * @param root uploaded JSON data
+ * @param args array of additional options
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_post_reserves (struct TEH_RequestContext *rc,
+ const json_t *root,
+ const char *const args[2])
+{
+ struct TALER_ReservePublicKeyP reserve_pub;
+ static const struct
+ {
+ /**
+ * Name of the operation (args[1])
+ */
+ const char *op;
+
+ /**
+ * Function to call to perform the operation.
+ */
+ ReserveOpHandler handler;
+
+ } h[] = {
+ {
+ .op = "withdraw",
+ .handler = &TEH_handler_withdraw
+ },
+ {
+ .op = "status",
+ .handler = &TEH_handler_reserves_status
+ },
+ {
+ .op = NULL,
+ .handler = NULL
+ },
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (args[0],
+ strlen (args[0]),
+ &reserve_pub,
+ sizeof (reserve_pub)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_EXCHANGE_GENERIC_RESERVE_PUB_MALFORMED,
+ args[0]);
+ }
+ for (unsigned int i = 0; NULL != h[i].op; i++)
+ if (0 == strcmp (h[i].op,
+ args[1]))
+ return h[i].handler (rc,
+ &reserve_pub,
+ root);
+ return r404 (rc->connection,
+ args[1]);
+}
+
+
+/**
* Increments our request counter and checks if this
* process should commit suicide.
*/
@@ -947,7 +1025,7 @@ handle_mhd_request (void *cls,
{
.url = "reserves",
.method = MHD_HTTP_METHOD_POST,
- .handler.post = &TEH_handler_withdraw,
+ .handler.post = &handle_post_reserves,
.nargs = 2
},
/* coins */
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index a2e22f2e3..00353a401 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -205,18 +205,6 @@ deposit_transaction (void *cls,
}
-/**
- * Handle a "/coins/$COIN_PUB/deposit" request. Parses the JSON, and, if
- * successful, passes the JSON data to #deposit_transaction() to
- * further check the details of the operation specified. If everything checks
- * out, this will ultimately lead to the "/deposit" being executed, or
- * rejected.
- *
- * @param connection the MHD connection to handle
- * @param coin_pub public key of the coin
- * @param root uploaded JSON data
- * @return MHD result code
- */
MHD_RESULT
TEH_handler_deposit (struct MHD_Connection *connection,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
diff --git a/src/exchange/taler-exchange-httpd_mhd.h b/src/exchange/taler-exchange-httpd_mhd.h
index 270b0539a..563975beb 100644
--- a/src/exchange/taler-exchange-httpd_mhd.h
+++ b/src/exchange/taler-exchange-httpd_mhd.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c
index 4b1bbddec..0b5db7c88 100644
--- a/src/exchange/taler-exchange-httpd_reserves_get.c
+++ b/src/exchange/taler-exchange-httpd_reserves_get.c
@@ -165,37 +165,6 @@ db_event_cb (void *cls,
/**
- * Send reserve history to client.
- *
- * @param connection connection to the client
- * @param rh reserve history to return
- * @return MHD result code
- */
-static MHD_RESULT
-reply_reserve_history_success (struct MHD_Connection *connection,
- const struct TALER_EXCHANGEDB_ReserveHistory *rh)
-{
- json_t *json_history;
- struct TALER_Amount balance;
-
- json_history = TEH_RESPONSE_compile_reserve_history (rh,
- &balance);
- if (NULL == json_history)
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
- NULL);
- return TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_OK,
- TALER_JSON_pack_amount ("balance",
- &balance),
- GNUNET_JSON_pack_array_steal ("history",
- json_history));
-}
-
-
-/**
* Closure for #reserve_history_transaction.
*/
struct ReserveHistoryContext
@@ -205,10 +174,18 @@ struct ReserveHistoryContext
*/
struct TALER_ReservePublicKeyP reserve_pub;
+#ifndef MBOSS_DONE
/**
* History of the reserve, set in the callback.
+ * FIXME: get rid of this once benchmarking is done!
*/
struct TALER_EXCHANGEDB_ReserveHistory *rh;
+#endif
+
+ /**
+ * Balance of the reserve, set in the callback.
+ */
+ struct TALER_Amount balance;
};
@@ -226,23 +203,37 @@ struct ReserveHistoryContext
* @param cls a `struct ReserveHistoryContext *`
* @param connection MHD request which triggered the transaction
* @param[out] mhd_ret set to MHD response status for @a connection,
- * if transaction failed (!); unused
+ * if transaction failed (!)
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-reserve_history_transaction (void *cls,
+reserve_balance_transaction (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
struct ReserveHistoryContext *rsc = cls;
- struct TALER_Amount balance;
-
- (void) connection;
- (void) mhd_ret;
- return TEH_plugin->get_reserve_history (TEH_plugin->cls,
- &rsc->reserve_pub,
- &balance,
- &rsc->rh);
+ enum GNUNET_DB_QueryStatus qs;
+
+#ifdef MBOSS_DONE
+ qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
+ &rsc->reserve_pub,
+ &rsc->balance);
+#else
+ qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
+ &rsc->reserve_pub,
+ &rsc->balance,
+ &rsc->rh);
+#endif
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ GNUNET_break (0);
+ *mhd_ret
+ = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "get_reserve_balance");
+ }
+ return qs;
}
@@ -314,10 +305,10 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
rsc.rh = NULL;
if (GNUNET_OK !=
TEH_DB_run_transaction (rc->connection,
- "get reserve history",
+ "get reserve balance",
TEH_MT_REQUEST_OTHER,
&mhd_ret,
- &reserve_history_transaction,
+ &reserve_balance_transaction,
&rsc))
{
if (NULL != eh)
@@ -335,7 +326,7 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
{
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
- TALER_EC_EXCHANGE_RESERVES_GET_STATUS_UNKNOWN,
+ TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN,
args[0]);
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -358,10 +349,15 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
if (NULL != eh)
TEH_plugin->event_listen_cancel (TEH_plugin->cls,
eh);
- mhd_ret = reply_reserve_history_success (rc->connection,
- rsc.rh);
+ mhd_ret = TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_OK,
+ TALER_JSON_pack_amount ("balance",
+ &rsc.balance));
+#ifndef MBOSS_DONE
TEH_plugin->free_reserve_history (TEH_plugin->cls,
rsc.rh);
+#endif
return mhd_ret;
}
diff --git a/src/exchange/taler-exchange-httpd_reserves_status.c b/src/exchange/taler-exchange-httpd_reserves_status.c
new file mode 100644
index 000000000..0b6ee2d30
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_reserves_status.c
@@ -0,0 +1,199 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_reserves_status.c
+ * @brief Handle /reserves/$RESERVE_PUB STATUS requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include "taler_mhd_lib.h"
+#include "taler_json_lib.h"
+#include "taler_dbevents.h"
+#include "taler-exchange-httpd_keys.h"
+#include "taler-exchange-httpd_reserves_status.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Closure for #reserve_status_transaction.
+ */
+struct ReserveStatusContext
+{
+ /**
+ * Public key of the reserve the inquiry is about.
+ */
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+
+ /**
+ * History of the reserve, set in the callback.
+ */
+ struct TALER_EXCHANGEDB_ReserveHistory *rh;
+
+ /**
+ * Current reserve balance.
+ */
+ struct TALER_Amount balance;
+};
+
+
+/**
+ * Send reserve status to client.
+ *
+ * @param connection connection to the client
+ * @param rh reserve history to return
+ * @return MHD result code
+ */
+static MHD_RESULT
+reply_reserve_status_success (struct MHD_Connection *connection,
+ const struct ReserveStatusContext *rhc)
+{
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh = rhc->rh;
+ json_t *json_history;
+
+ json_history = TEH_RESPONSE_compile_reserve_history (rh);
+ if (NULL == json_history)
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
+ NULL);
+ return TALER_MHD_REPLY_JSON_PACK (
+ connection,
+ MHD_HTTP_OK,
+ TALER_JSON_pack_amount ("balance",
+ &rhc->balance),
+ GNUNET_JSON_pack_array_steal ("history",
+ json_history));
+}
+
+
+/**
+ * Function implementing /reserves/ STATUS transaction.
+ * Execute a /reserves/ STATUS. Given the public key of a reserve,
+ * return the associated transaction history. Runs the
+ * transaction logic; IF it returns a non-error code, the transaction
+ * logic MUST NOT queue a MHD response. IF it returns an hard error,
+ * the transaction logic MUST queue a MHD response and set @a mhd_ret.
+ * IF it returns the soft error code, the function MAY be called again
+ * to retry and MUST not queue a MHD response.
+ *
+ * @param cls a `struct ReserveStatusContext *`
+ * @param connection MHD request which triggered the transaction
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ * if transaction failed (!); unused
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+reserve_status_transaction (void *cls,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret)
+{
+ struct ReserveStatusContext *rsc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
+ rsc->reserve_pub,
+ &rsc->balance,
+ &rsc->rh);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ GNUNET_break (0);
+ *mhd_ret
+ = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "get_reserve_status");
+ }
+ return qs;
+}
+
+
+MHD_RESULT
+TEH_handler_reserves_status (struct TEH_RequestContext *rc,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const json_t *root)
+{
+ struct ReserveStatusContext rsc;
+ MHD_RESULT mhd_ret;
+ struct GNUNET_TIME_Timestamp timestamp;
+ struct TALER_ReserveSignatureP reserve_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_timestamp ("request_timestamp",
+ &timestamp),
+ GNUNET_JSON_spec_fixed_auto ("reserve_sig",
+ &reserve_sig),
+ GNUNET_JSON_spec_end ()
+ };
+
+ rsc.reserve_pub = reserve_pub;
+ {
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (rc->connection,
+ root,
+ spec);
+ if (GNUNET_SYSERR == res)
+ {
+ GNUNET_break (0);
+ return MHD_NO; /* hard failure */
+ }
+ if (GNUNET_NO == res)
+ {
+ GNUNET_break_op (0);
+ return MHD_YES; /* failure */
+ }
+ }
+ if (GNUNET_OK !=
+ TALER_wallet_reserve_status_verify (timestamp,
+ reserve_pub,
+ &reserve_sig))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_EXCHANGE_RESERVES_STATUS_BAD_SIGNATURE,
+ NULL);
+ }
+ rsc.rh = NULL;
+ if (GNUNET_OK !=
+ TEH_DB_run_transaction (rc->connection,
+ "get reserve status",
+ TEH_MT_REQUEST_OTHER,
+ &mhd_ret,
+ &reserve_status_transaction,
+ &rsc))
+ {
+ return mhd_ret;
+ }
+ if (NULL == rsc.rh)
+ {
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN,
+ NULL);
+ }
+ mhd_ret = reply_reserve_status_success (rc->connection,
+ &rsc);
+ TEH_plugin->free_reserve_history (TEH_plugin->cls,
+ rsc.rh);
+ return mhd_ret;
+}
+
+
+/* end of taler-exchange-httpd_reserves_status.c */
diff --git a/src/exchange/taler-exchange-httpd_reserves_status.h b/src/exchange/taler-exchange-httpd_reserves_status.h
new file mode 100644
index 000000000..831b270f7
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_reserves_status.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_reserves_status.h
+ * @brief Handle /reserves/$RESERVE_PUB STATUS requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_RESERVES_STATUS_H
+#define TALER_EXCHANGE_HTTPD_RESERVES_STATUS_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a POST "/reserves/$RID/status" request.
+ *
+ * @param rc request context
+ * @param reserve_pub public key of the reserve
+ * @param root uploaded body from the client
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_reserves_status (struct TEH_RequestContext *rc,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const json_t *root);
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index f1a219fc8..ee8c902dd 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -605,31 +605,11 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
}
-/**
- * Compile the history of a reserve into a JSON object
- * and calculate the total balance.
- *
- * @param rh reserve history to JSON-ify
- * @param[out] balance set to current reserve balance
- * @return json representation of the @a rh, NULL on error
- */
json_t *
TEH_RESPONSE_compile_reserve_history (
- const struct TALER_EXCHANGEDB_ReserveHistory *rh,
- struct TALER_Amount *balance)
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh)
{
- struct TALER_Amount credit_total;
- struct TALER_Amount withdraw_total;
json_t *json_history;
- enum InitAmounts
- {
- /** Nothing initialized */
- IA_NONE = 0,
- /** credit_total initialized */
- IA_CREDIT = 1,
- /** withdraw_total initialized */
- IA_WITHDRAW = 2
- } init = IA_NONE;
json_history = json_array ();
for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
@@ -642,20 +622,7 @@ TEH_RESPONSE_compile_reserve_history (
{
const struct TALER_EXCHANGEDB_BankTransfer *bank =
pos->details.bank;
- if (0 == (IA_CREDIT & init))
- {
- credit_total = bank->amount;
- init |= IA_CREDIT;
- }
- else if (0 >
- TALER_amount_add (&credit_total,
- &credit_total,
- &bank->amount))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
+
if (0 !=
json_array_append_new (
json_history,
@@ -681,26 +648,7 @@ TEH_RESPONSE_compile_reserve_history (
{
const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw
= pos->details.withdraw;
- struct TALER_Amount value;
- value = withdraw->amount_with_fee;
- if (0 == (IA_WITHDRAW & init))
- {
- withdraw_total = value;
- init |= IA_WITHDRAW;
- }
- else
- {
- if (0 >
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
if (0 !=
json_array_append_new (
json_history,
@@ -716,7 +664,7 @@ TEH_RESPONSE_compile_reserve_history (
TALER_JSON_pack_amount ("withdraw_fee",
&withdraw->withdraw_fee),
TALER_JSON_pack_amount ("amount",
- &value))))
+ &withdraw->amount_with_fee))))
{
GNUNET_break (0);
json_decref (json_history);
@@ -731,20 +679,6 @@ TEH_RESPONSE_compile_reserve_history (
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
- if (0 == (IA_CREDIT & init))
- {
- credit_total = recoup->value;
- init |= IA_CREDIT;
- }
- else if (0 >
- TALER_amount_add (&credit_total,
- &credit_total,
- &recoup->value))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
{
struct TALER_RecoupConfirmationPS pc = {
.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
@@ -796,26 +730,7 @@ TEH_RESPONSE_compile_reserve_history (
pos->details.closing;
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
- struct TALER_Amount value;
- value = closing->amount;
- if (0 == (IA_WITHDRAW & init))
- {
- withdraw_total = value;
- init |= IA_WITHDRAW;
- }
- else
- {
- if (0 >
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
{
struct TALER_ReserveCloseConfirmationPS rcc = {
.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED),
@@ -826,7 +741,7 @@ TEH_RESPONSE_compile_reserve_history (
};
TALER_amount_hton (&rcc.closing_amount,
- &value);
+ &closing->amount);
TALER_amount_hton (&rcc.closing_fee,
&closing->closing_fee);
TALER_payto_hash (closing->receiver_account_details,
@@ -858,7 +773,7 @@ TEH_RESPONSE_compile_reserve_history (
GNUNET_JSON_pack_timestamp ("timestamp",
closing->execution_date),
TALER_JSON_pack_amount ("amount",
- &value),
+ &closing->amount),
TALER_JSON_pack_amount ("closing_fee",
&closing->closing_fee))))
{
@@ -871,31 +786,6 @@ TEH_RESPONSE_compile_reserve_history (
}
}
- if (0 == (IA_CREDIT & init))
- {
- /* We should not have gotten here, without credits no reserve
- should exist! */
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- if (0 == (IA_WITHDRAW & init))
- {
- /* did not encounter any withdraw operations, set withdraw_total to zero */
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (credit_total.currency,
- &withdraw_total));
- }
- if (0 >
- TALER_amount_subtract (balance,
- &credit_total,
- &withdraw_total))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
-
return json_history;
}
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
index ffd2cc9e1..03841e801 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -34,17 +34,14 @@
/**
- * Compile the history of a reserve into a JSON object
- * and calculate the total balance.
+ * Compile the history of a reserve into a JSON object.
*
* @param rh reserve history to JSON-ify
- * @param[out] balance set to current reserve balance
* @return json representation of the @a rh, NULL on error
*/
json_t *
TEH_RESPONSE_compile_reserve_history (
- const struct TALER_EXCHANGEDB_ReserveHistory *rh,
- struct TALER_Amount *balance);
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh);
/**
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c
index fcf596e06..5765181b2 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -52,32 +52,19 @@ reply_withdraw_insufficient_funds (
const struct TALER_EXCHANGEDB_ReserveHistory *rh)
{
json_t *json_history;
- struct TALER_Amount balance;
- json_history = TEH_RESPONSE_compile_reserve_history (rh,
- &balance);
+ json_history = TEH_RESPONSE_compile_reserve_history (rh);
if (NULL == json_history)
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_WITHDRAW_HISTORY_ERROR_INSUFFICIENT_FUNDS,
NULL);
- if (0 !=
- TALER_amount_cmp (&balance,
- ebalance))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
- "reserve balance corrupt");
- }
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_CONFLICT,
TALER_JSON_pack_ec (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS),
TALER_JSON_pack_amount ("balance",
- &balance),
+ ebalance),
TALER_JSON_pack_amount ("requested_amount",
withdraw_amount),
GNUNET_JSON_pack_array_steal ("history",
@@ -105,7 +92,6 @@ struct WithdrawContext
*/
struct TALER_Amount amount_with_fee;
-
/**
* Blinded planchet.
*/
@@ -329,8 +315,8 @@ check_request_idempotent (struct TEH_RequestContext *rc,
MHD_RESULT
TEH_handler_withdraw (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[2])
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const json_t *root)
{
struct WithdrawContext wc;
struct GNUNET_JSON_Specification spec[] = {
@@ -348,18 +334,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
memset (&wc,
0,
sizeof (wc));
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (args[0],
- strlen (args[0]),
- &wc.collectable.reserve_pub,
- sizeof (wc.collectable.reserve_pub)))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_MERCHANT_GENERIC_RESERVE_PUB_MALFORMED,
- args[0]);
- }
+ wc.collectable.reserve_pub = *reserve_pub;
{
enum GNUNET_GenericReturnValue res;
diff --git a/src/exchange/taler-exchange-httpd_withdraw.h b/src/exchange/taler-exchange-httpd_withdraw.h
index 8d2d8c182..b754e64fd 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.h
+++ b/src/exchange/taler-exchange-httpd_withdraw.h
@@ -28,8 +28,7 @@
/**
- * Handle a "/reserves/$RESERVE_PUB/withdraw" request. Parses the
- * "reserve_pub" EdDSA key of the reserve and the requested "denom_pub" which
+ * Handle a "/reserves/$RESERVE_PUB/withdraw" request. Parses the the requested "denom_pub" which
* specifies the key/value of the coin to be withdrawn, and checks that the
* signature "reserve_sig" makes this a valid withdrawal request from the
* specified reserve. If so, the envelope with the blinded coin "coin_ev" is
@@ -37,13 +36,12 @@
*
* @param rc request context
* @param root uploaded JSON data
- * @param args array of additional options (first must be the
- * reserve public key, the second one should be "withdraw")
+ * @param reserve_pub public key of the reserve
* @return MHD result code
*/
MHD_RESULT
TEH_handler_withdraw (struct TEH_RequestContext *rc,
- const json_t *root,
- const char *const args[2]);
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const json_t *root);
#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index bb6f46f59..2856f3009 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -732,6 +732,17 @@ prepare_statements (struct PostgresClosure *pg)
" WHERE res.reserve_pub=$1;",
1),
/* Used in #postgres_select_withdrawals_above_serial_id() */
+
+ GNUNET_PQ_make_prepare (
+ "get_reserve_balance",
+ "SELECT"
+ " current_balance_val"
+ ",current_balance_frac"
+ " FROM reserves"
+ " WHERE reserve_pub=$1;",
+ 1),
+ /* Fetch deposits with rowid '\geq' the given parameter */
+
GNUNET_PQ_make_prepare (
"audit_get_reserves_out_incr",
"SELECT"
@@ -5534,6 +5545,37 @@ postgres_get_reserve_history (void *cls,
/**
+ * Get the balance of the specified reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param reserve_pub public key of the reserve
+ * @param[out] balance set to the reserve balance
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_reserve_balance (void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct TALER_Amount *balance)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ balance),
+ GNUNET_PQ_result_spec_end
+ };
+
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_reserve_balance",
+ params,
+ rs);
+}
+
+
+/**
* Check if we have the specified deposit already in the database.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
@@ -12503,6 +12545,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->do_refund = &postgres_do_refund;
plugin->do_recoup = &postgres_do_recoup;
plugin->do_recoup_refresh = &postgres_do_recoup_refresh;
+ plugin->get_reserve_balance = &postgres_get_reserve_balance;
plugin->get_reserve_history = &postgres_get_reserve_history;
plugin->free_reserve_history = &common_free_reserve_history;
plugin->count_known_coins = &postgres_count_known_coins;
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index fc909a1ba..610f20303 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -2847,6 +2847,20 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * The current reserve balance of the specified reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param reserve_pub public key of the reserve
+ * @param[out] balance set to the reserve balance
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*get_reserve_balance)(void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct TALER_Amount *balance);
+
+
+ /**
* Free memory associated with the given reserve history.
*
* @param cls the @e cls of this struct with the plugin-specific state