diff options
57 files changed, 17 insertions, 8602 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 2fe09eec..9ece7912 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -28,14 +28,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \ taler-merchant-httpd_get-orders-ID.c \ taler-merchant-httpd_get-orders-ID.h \ - taler-merchant-httpd_get-rewards-ID.c \ - taler-merchant-httpd_get-rewards-ID.h \ taler-merchant-httpd_helper.c \ taler-merchant-httpd_helper.h \ - taler-merchant-httpd_private-get-rewards.c \ - taler-merchant-httpd_private-get-rewards.h \ - taler-merchant-httpd_private-get-rewards-ID.c \ - taler-merchant-httpd_private-get-rewards-ID.h \ taler-merchant-httpd_mhd.c \ taler-merchant-httpd_mhd.h \ taler-merchant-httpd_private-delete-account-ID.c \ @@ -50,8 +44,6 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-delete-orders-ID.h \ taler-merchant-httpd_private-delete-otp-devices-ID.c \ taler-merchant-httpd_private-delete-otp-devices-ID.h \ - taler-merchant-httpd_private-delete-reserves-ID.c \ - taler-merchant-httpd_private-delete-reserves-ID.h \ taler-merchant-httpd_private-delete-templates-ID.c \ taler-merchant-httpd_private-delete-templates-ID.h \ taler-merchant-httpd_private-delete-token-families-SLUG.c \ @@ -82,10 +74,6 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-get-otp-devices.h \ taler-merchant-httpd_private-get-otp-devices-ID.c \ taler-merchant-httpd_private-get-otp-devices-ID.h \ - taler-merchant-httpd_private-get-reserves.c \ - taler-merchant-httpd_private-get-reserves.h \ - taler-merchant-httpd_private-get-reserves-ID.c \ - taler-merchant-httpd_private-get-reserves-ID.h \ taler-merchant-httpd_private-get-transfers.c \ taler-merchant-httpd_private-get-transfers.h \ taler-merchant-httpd_private-get-templates.c \ @@ -134,10 +122,6 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-post-otp-devices.h \ taler-merchant-httpd_private-post-products-ID-lock.c \ taler-merchant-httpd_private-post-products-ID-lock.h \ - taler-merchant-httpd_private-post-reserves.c \ - taler-merchant-httpd_private-post-reserves.h \ - taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c \ - taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h \ taler-merchant-httpd_private-post-templates.c \ taler-merchant-httpd_private-post-templates.h \ taler-merchant-httpd_private-post-token-families.c \ @@ -156,14 +140,10 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_post-orders-ID-paid.h \ taler-merchant-httpd_post-orders-ID-refund.c \ taler-merchant-httpd_post-orders-ID-refund.h \ - taler-merchant-httpd_post-rewards-ID-pickup.c \ - taler-merchant-httpd_post-rewards-ID-pickup.h \ taler-merchant-httpd_post-using-templates.c \ taler-merchant-httpd_post-using-templates.h \ taler-merchant-httpd_qr.c \ taler-merchant-httpd_qr.h \ - taler-merchant-httpd_reserves.c \ - taler-merchant-httpd_reserves.h \ taler-merchant-httpd_spa.c \ taler-merchant-httpd_spa.h \ taler-merchant-httpd_statics.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 608a00a6..42cf08ee 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -31,7 +31,6 @@ #include "taler-merchant-httpd_config.h" #include "taler-merchant-httpd_exchanges.h" #include "taler-merchant-httpd_get-orders-ID.h" -#include "taler-merchant-httpd_get-rewards-ID.h" #include "taler-merchant-httpd_mhd.h" #include "taler-merchant-httpd_private-delete-account-ID.h" #include "taler-merchant-httpd_private-delete-instances-ID.h" @@ -39,7 +38,6 @@ #include "taler-merchant-httpd_private-delete-products-ID.h" #include "taler-merchant-httpd_private-delete-orders-ID.h" #include "taler-merchant-httpd_private-delete-otp-devices-ID.h" -#include "taler-merchant-httpd_private-delete-reserves-ID.h" #include "taler-merchant-httpd_private-delete-templates-ID.h" #include "taler-merchant-httpd_private-delete-token-families-SLUG.h" #include "taler-merchant-httpd_private-delete-transfers-ID.h" @@ -55,10 +53,6 @@ #include "taler-merchant-httpd_private-get-orders-ID.h" #include "taler-merchant-httpd_private-get-otp-devices.h" #include "taler-merchant-httpd_private-get-otp-devices-ID.h" -#include "taler-merchant-httpd_private-get-reserves.h" -#include "taler-merchant-httpd_private-get-reserves-ID.h" -#include "taler-merchant-httpd_private-get-rewards-ID.h" -#include "taler-merchant-httpd_private-get-rewards.h" #include "taler-merchant-httpd_private-get-templates.h" #include "taler-merchant-httpd_private-get-templates-ID.h" #include "taler-merchant-httpd_private-get-token-families.h" @@ -83,8 +77,6 @@ #include "taler-merchant-httpd_private-post-orders-ID-refund.h" #include "taler-merchant-httpd_private-post-products.h" #include "taler-merchant-httpd_private-post-products-ID-lock.h" -#include "taler-merchant-httpd_private-post-reserves.h" -#include "taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h" #include "taler-merchant-httpd_private-post-templates.h" #include "taler-merchant-httpd_private-post-token-families.h" #include "taler-merchant-httpd_private-post-transfers.h" @@ -95,8 +87,6 @@ #include "taler-merchant-httpd_post-orders-ID-pay.h" #include "taler-merchant-httpd_post-using-templates.h" #include "taler-merchant-httpd_post-orders-ID-refund.h" -#include "taler-merchant-httpd_post-rewards-ID-pickup.h" -#include "taler-merchant-httpd_reserves.h" #include "taler-merchant-httpd_spa.h" #include "taler-merchant-httpd_statics.h" @@ -405,13 +395,10 @@ do_shutdown (void *cls) { (void) cls; TMH_force_orders_resume (); - TMH_force_reward_resume (); TMH_force_ac_resume (); TMH_force_pc_resume (); TMH_force_kyc_resume (); - TMH_force_rc_resume (); TMH_force_gorc_resume (); - TMH_force_reward_pickup_resume (); TMH_force_wallet_get_order_resume (); TMH_force_wallet_refund_order_resume (); { @@ -421,7 +408,6 @@ do_shutdown (void *cls) if (NULL != mhd) MHD_stop_daemon (mhd); } - TMH_RESERVES_done (); if (NULL != instance_eh) { TMH_db->event_listen_cancel (instance_eh); @@ -1034,73 +1020,6 @@ url_handler (void *cls, .allow_deleted_instance = true, .handler = &TMH_private_delete_orders_ID }, - /* POST /reserves: */ - { - .url_prefix = "/reserves", - .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_reserves, - /* the body should be pretty small, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, - /* DELETE /reserves/$ID: */ - { - .url_prefix = "/reserves/", - .have_id_segment = true, - .allow_deleted_instance = true, - .method = MHD_HTTP_METHOD_DELETE, - .handler = &TMH_private_delete_reserves_ID - }, - /* POST /reserves/$ID/authorize-reward: */ - { - .url_prefix = "/reserves/", - .url_suffix = "authorize-reward", - .have_id_segment = true, - .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_reserves_ID_authorize_reward, - /* the body should be pretty small, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, - /* POST /rewards: */ - { - .url_prefix = "/rewards", - .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_rewards, - /* the body should be pretty small, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, - /* GET /rewards: */ - { - .url_prefix = "/rewards", - .allow_deleted_instance = true, - .method = MHD_HTTP_METHOD_GET, - .handler = &TMH_private_get_rewards - }, - /* GET /rewards/$ID: */ - { - .url_prefix = "/rewards/", - .method = MHD_HTTP_METHOD_GET, - .allow_deleted_instance = true, - .have_id_segment = true, - .handler = &TMH_private_get_rewards_ID - }, - /* GET /reserves: */ - { - .url_prefix = "/reserves", - .allow_deleted_instance = true, - .method = MHD_HTTP_METHOD_GET, - .handler = &TMH_private_get_reserves - }, - /* GET /reserves/$ID: */ - { - .url_prefix = "/reserves/", - .allow_deleted_instance = true, - .have_id_segment = true, - .method = MHD_HTTP_METHOD_GET, - .handler = &TMH_private_get_reserves_ID - }, /* POST /transfers: */ { .url_prefix = "/transfers", @@ -1463,26 +1382,6 @@ url_handler (void *cls, .have_id_segment = true, .handler = &TMH_get_orders_ID }, - /* GET /rewards/$ID: */ - { - .url_prefix = "/rewards/", - .method = MHD_HTTP_METHOD_GET, - .allow_deleted_instance = true, - .have_id_segment = true, - .handler = &TMH_get_rewards_ID - }, - /* POST /rewards/$ID/pickup: */ - { - .url_prefix = "/rewards/", - .method = MHD_HTTP_METHOD_POST, - .have_id_segment = true, - .allow_deleted_instance = true, - .url_suffix = "pickup", - .handler = &TMH_post_rewards_ID_pickup, - /* wallet may give us many coins to sign, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, /* GET /static/ *: */ { .url_prefix = "/static/", @@ -2385,8 +2284,6 @@ run (void *cls, load_instances (NULL, NULL, 0); - /* start watching reserves */ - TMH_RESERVES_init (); fh = TALER_MHD_bind (cfg, "merchant", &port); diff --git a/src/backend/taler-merchant-httpd_config.c b/src/backend/taler-merchant-httpd_config.c index 3c318b1a..784bdcf9 100644 --- a/src/backend/taler-merchant-httpd_config.c +++ b/src/backend/taler-merchant-httpd_config.c @@ -42,7 +42,7 @@ * #MERCHANT_PROTOCOL_CURRENT and #MERCHANT_PROTOCOL_AGE in * merchant_api_config.c! */ -#define MERCHANT_PROTOCOL_VERSION "8:1:4" +#define MERCHANT_PROTOCOL_VERSION "8:2:0" /** diff --git a/src/backend/taler-merchant-httpd_get-rewards-ID.c b/src/backend/taler-merchant-httpd_get-rewards-ID.c deleted file mode 100644 index e1232735..00000000 --- a/src/backend/taler-merchant-httpd_get-rewards-ID.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - This file is part of TALER - (C) 2014-2023 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 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 taler-merchant-httpd_get-rewards-ID.c - * @brief implementation of GET /rewards/$ID - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <jansson.h> -#include <taler/taler_signatures.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_templating_lib.h> -#include "taler-merchant-httpd_get-rewards-ID.h" -#include "taler-merchant-httpd_helper.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_qr.h" - - -char * -TMH_make_taler_reward_uri (struct MHD_Connection *con, - const struct TALER_RewardIdentifierP *reward_id, - const char *instance_id) -{ - struct GNUNET_Buffer buf = { 0 }; - - GNUNET_assert (NULL != instance_id); - GNUNET_assert (NULL != reward_id); - if (GNUNET_OK != - TMH_taler_uri_by_connection (con, - "reward", - instance_id, - &buf)) - { - GNUNET_break (0); - return NULL; - } - /* Ensure previous part is slash-terminated */ - GNUNET_buffer_write_path (&buf, - ""); - GNUNET_buffer_write_data_encoded (&buf, - reward_id, - sizeof (*reward_id)); - return GNUNET_buffer_reap_str (&buf); -} - - -char * -TMH_make_reward_status_url (struct MHD_Connection *con, - const struct TALER_RewardIdentifierP *reward_id, - const char *instance_id) -{ - struct GNUNET_Buffer buf; - - GNUNET_assert (NULL != instance_id); - GNUNET_assert (NULL != reward_id); - if (GNUNET_OK != - TMH_base_url_by_connection (con, - instance_id, - &buf)) - { - GNUNET_break (0); - return NULL; - } - GNUNET_buffer_write_path (&buf, - "rewards/"); - GNUNET_buffer_write_data_encoded (&buf, - reward_id, - sizeof (*reward_id)); - return GNUNET_buffer_reap_str (&buf); -} - - -MHD_RESULT -TMH_get_rewards_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TALER_RewardIdentifierP reward_id; - enum GNUNET_DB_QueryStatus qs; - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - struct GNUNET_TIME_Timestamp expiration; - char *exchange_url; - char *next_url; - struct TALER_ReservePrivateKeyP reserve_priv; - - (void) rh; - if (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (hc->infix, - &reward_id.hash)) - { - /* reward_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - - TMH_db->preflight (TMH_db->cls); - qs = TMH_db->lookup_reward (TMH_db->cls, - hc->instance->settings.id, - &reward_id, - &total_authorized, - &total_picked_up, - &expiration, - &exchange_url, - &next_url, - &reserve_priv); - if (0 > qs) - { - /* single, read-only SQL statements should never cause - serialization problems */ - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); - /* Always report on hard error as well to enable diagnostics */ - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - NULL); - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Unknown reward id given: `%s'\n", - hc->infix); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN, - hc->infix); - } - - /* Build response */ - { - struct TALER_Amount remaining; - MHD_RESULT ret; - - GNUNET_break (0 <= - TALER_amount_subtract (&remaining, - &total_authorized, - &total_picked_up)); - if (TMH_MHD_test_html_desired (connection)) - { - char *qr; - char *uri; - char *reward_status_url; - - uri = TMH_make_taler_reward_uri (connection, - &reward_id, - hc->instance->settings.id); - reward_status_url = TMH_make_reward_status_url (connection, - &reward_id, - hc->instance->settings.id); - qr = TMH_create_qrcode (uri); - if (NULL == qr) - { - GNUNET_break (0); - GNUNET_free (uri); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_ALLOCATION_FAILURE, - "during QR code generation"); - } - else - { - json_t *context; - - context = GNUNET_JSON_PACK ( - TALER_JSON_pack_amount ("remaining_reward", - &remaining), - GNUNET_JSON_pack_string ("taler_reward_uri", - uri), - GNUNET_JSON_pack_string ("next_url", - next_url), - GNUNET_JSON_pack_string ("taler_reward_qrcode_svg", - qr)); - ret = TALER_TEMPLATING_reply (connection, - ( (0 == remaining.value) && - (0 == remaining.fraction) ) - ? MHD_HTTP_GONE - : MHD_HTTP_OK, - ( (0 == remaining.value) && - (0 == remaining.fraction) ) - ? "depleted_reward" - : "offer_reward", - hc->instance->settings.id, - uri, - context); - json_decref (context); - } - GNUNET_free (reward_status_url); - GNUNET_free (uri); - GNUNET_free (qr); - } - else - { - ret = TALER_MHD_REPLY_JSON_PACK ( - connection, - TALER_amount_is_zero (&remaining) - ? MHD_HTTP_GONE - : MHD_HTTP_OK, - GNUNET_JSON_pack_string ("exchange_url", - exchange_url), - GNUNET_JSON_pack_string ("next_url", - next_url), - TALER_JSON_pack_amount ("reward_amount", - &remaining), - GNUNET_JSON_pack_timestamp ("expiration", - expiration)); - } - GNUNET_free (exchange_url); - GNUNET_free (next_url); - return ret; - } -} - - -/* end of taler-merchant-httpd_get-rewards-ID.c */ diff --git a/src/backend/taler-merchant-httpd_get-rewards-ID.h b/src/backend/taler-merchant-httpd_get-rewards-ID.h deleted file mode 100644 index 29a3c122..00000000 --- a/src/backend/taler-merchant-httpd_get-rewards-ID.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of TALER - (C) 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 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 taler-merchant-httpd_get-rewards-ID.h - * @brief implementation of GET /rewards/$ID - * @author Marcello Stanisci - */ -#ifndef TALER_MERCHANT_HTTPD_GET_REWARDS_ID_H -#define TALER_MERCHANT_HTTPD_GET_REWARDS_ID_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - -/** - * Create a taler://reward/ URI for the given @a con and @a reward_id - * and @a instance_id. - * - * @param con HTTP connection - * @param reward_id the reward id - * @param instance_id instance, may be "default" - * @return corresponding taler://reward/ URI, or NULL on missing "host" - */ -char * -TMH_make_taler_reward_uri (struct MHD_Connection *con, - const struct TALER_RewardIdentifierP *reward_id, - const char *instance_id); - -/** - * Create a http(s):// URL for the given @a con and @a reward_id - * and @a instance_id. - * - * @param con HTTP connection - * @param reward_id the reward id - * @param instance_id instance, may be "default" - * @return corresponding taler://reward/ URI, or NULL on missing "host" - */ -char * -TMH_make_reward_status_url (struct MHD_Connection *con, - const struct TALER_RewardIdentifierP *reward_id, - const char *instance_id); - -/** - * Handle a GET "/rewards/$ID" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_get_rewards_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - -#endif diff --git a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c b/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c deleted file mode 100644 index cd8d03a6..00000000 --- a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* - This file is part of TALER - (C) 2017-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_post-rewards-ID-pickup.c - * @brief implementation of a POST /rewards/ID/pickup handler - * @author Christian Grothoff - */ -#include "platform.h" -#include <microhttpd.h> -#include <jansson.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_signatures.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_helper.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_post-rewards-ID-pickup.h" - - -/** - * How often do we retry on serialization errors? - */ -#define MAX_RETRIES 3 - -/** - * How long do we give the exchange operation to complete withdrawing - * all of the planchets? - */ -#define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_SECONDS, 45) - - -/** - * Active pickup operations. - */ -struct PickupContext; - - -/** - * Handle for an individual planchet we are processing for a reward. - */ -struct PlanchetOperation -{ - /** - * Active pickup operation this planchet belongs with. - */ - struct PickupContext *pc; - - /** - * Kept in a DLL. - */ - struct PlanchetOperation *prev; - - /** - * Kept in a DLL. - */ - struct PlanchetOperation *next; - - /** - * Find operation (while active), later NULL. - */ - struct TMH_EXCHANGES_KeysOperation *fo; - - /** - * Withdraw handle (NULL while @e fo is active). - */ - struct TALER_EXCHANGE_BatchWithdraw2Handle *w2h; - - /** - * Details about the planchet for withdrawing. - */ - struct TALER_PlanchetDetail pd; - - /** - * Offset of this planchet in the original request. - */ - unsigned int offset; -}; - - -/** - * Active pickup operations. - */ -struct PickupContext -{ - /** - * Kept in a DLL. - */ - struct PickupContext *next; - - /** - * Kept in a DLL. - */ - struct PickupContext *prev; - - /** - * The connection. - */ - struct MHD_Connection *connection; - - /** - * Request context. - */ - struct TMH_HandlerContext *hc; - - /** - * Base URL of the exchange we withdraw from. - */ - char *exchange_url; - - /** - * Timeout task. - */ - struct GNUNET_SCHEDULER_Task *tt; - - /** - * Head of DLL of exchange operations on planchets. - */ - struct PlanchetOperation *po_head; - - /** - * Tail of DLL of exchange operations on planchets. - */ - struct PlanchetOperation *po_tail; - - /** - * HTTP response to return (set on errors). - */ - struct MHD_Response *response; - - /** - * Find operation (while active), later NULL. - */ - struct TMH_EXCHANGES_KeysOperation *fo; - - /** - * Which reserve are we draining? - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * Which reward is being picked up? - */ - struct TALER_RewardIdentifierP reward_id; - - /** - * What is the ID of the pickup operation? (Basically a - * hash over the key inputs). - */ - struct TALER_PickupIdentifierP pickup_id; - - /** - * Array of our planchets. - */ - struct TALER_PlanchetDetail *planchets; - - /** - * Length of the @e planchets array. - */ - unsigned int planchets_length; - - /** - * HTTP status to use (set on errors). - */ - unsigned int http_status; - - /** - * Total amount requested in the pick up operation. Computed by - * totaling up the amounts of all the @e planchets. - */ - struct TALER_Amount total_requested; - - /** - * True if @e total_requested has been initialized. - */ - bool tr_initialized; - - /** - * Should we generate a DB notification at the end for the pickup? Used to - * wake up long pollers upon reward pickup. Not done transactionally as there - * are potentially several coins individually added to the DB as - * transactions, and doing a notification per coin would be excessive. - * (And missing an event in the very rare case where our process fails - * hard between a DB operation and generating an HTTP reply is not a problem - * in this case.) However, if we in the future do group all DB transactions - * into one larger transaction, the notification should become part of it. - */ - bool do_notify; -}; - - -/** - * Head of DLL. - */ -static struct PickupContext *pc_head; - -/** - * Tail of DLL. - */ -static struct PickupContext *pc_tail; - - -/** - * Stop all ongoing operations associated with @a pc. - */ -static void -stop_operations (struct PickupContext *pc) -{ - struct PlanchetOperation *po; - - if (NULL != pc->tt) - { - GNUNET_SCHEDULER_cancel (pc->tt); - pc->tt = NULL; - } - if (NULL != pc->fo) - { - TMH_EXCHANGES_keys4exchange_cancel (pc->fo); - pc->fo = NULL; - } - while (NULL != (po = pc->po_head)) - { - if (NULL != po->fo) - { - TMH_EXCHANGES_keys4exchange_cancel (po->fo); - po->fo = NULL; - } - if (NULL != po->w2h) - { - TALER_EXCHANGE_batch_withdraw2_cancel (po->w2h); - po->w2h = NULL; - } - GNUNET_CONTAINER_DLL_remove (pc->po_head, - pc->po_tail, - po); - GNUNET_free (po); - } -} - - -/** - * Function called to clean up. - * - * @param cls a `struct PickupContext *` to clean up - */ -static void -pick_context_cleanup (void *cls) -{ - struct PickupContext *pc = cls; - - if (pc->do_notify) - { - struct TMH_RewardPickupEventP reward_eh = { - .header.size = htons (sizeof (reward_eh)), - .header.type = htons (TALER_DBEVENT_MERCHANT_REWARD_PICKUP), - .reward_id = pc->reward_id - }; - - GNUNET_CRYPTO_hash (pc->hc->instance->settings.id, - strlen (pc->hc->instance->settings.id), - &reward_eh.h_instance); - TMH_db->event_notify (TMH_db->cls, - &reward_eh.header, - NULL, - 0); - } - stop_operations (pc); /* should not be any... */ - for (unsigned int i = 0; i<pc->planchets_length; i++) - TALER_planchet_detail_free (&pc->planchets[i]); - GNUNET_array_grow (pc->planchets, - pc->planchets_length, - 0); - GNUNET_free (pc->exchange_url); - GNUNET_free (pc); -} - - -void -TMH_force_reward_pickup_resume () -{ - struct PickupContext *nxt; - - for (struct PickupContext *pc = pc_head; - NULL != pc; - pc = nxt) - { - nxt = pc->next; - stop_operations (pc); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - } -} - - -/** - * Callbacks of this type are used to serve the result of submitting a - * withdraw request to a exchange without the (un)blinding factor. - * We persist the result in the database and, if we were the last - * planchet operation, resume HTTP processing. - * - * @param cls closure with a `struct PlanchetOperation *` - * @param w2r response data - */ -static void -withdraw_cb (void *cls, - const struct TALER_EXCHANGE_BatchWithdraw2Response *w2r) -{ - struct PlanchetOperation *po = cls; - const struct TALER_EXCHANGE_HttpResponse *hr = &w2r->hr; - struct PickupContext *pc = po->pc; - enum GNUNET_DB_QueryStatus qs; - - GNUNET_CONTAINER_DLL_remove (pc->po_head, - pc->po_tail, - po); - TMH_db->preflight (TMH_db->cls); - if (MHD_HTTP_OK != hr->http_status) - { - GNUNET_free (po); - stop_operations (pc); - pc->http_status = MHD_HTTP_BAD_GATEWAY; - pc->response = - TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec (TALER_EC_MERCHANT_REWARD_PICKUP_EXCHANGE_ERROR), - TMH_pack_exchange_reply (hr)); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - GNUNET_assert (1 == w2r->details.ok.blind_sigs_length); - qs = TMH_db->insert_pickup_blind_signature (TMH_db->cls, - &pc->pickup_id, - po->offset, - &w2r->details.ok.blind_sigs[0]); - GNUNET_free (po); - if (qs < 0) - { - stop_operations (pc); - pc->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; - pc->response = TALER_MHD_make_error ( - TALER_EC_GENERIC_DB_STORE_FAILED, - "blind signature"); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - pc->do_notify = true; - if (NULL != pc->po_head) - return; /* More pending */ - stop_operations (pc); /* stops timeout job */ - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * Function called with the result of a #TMH_EXCHANGES_keys4exchange() - * operation as part of a withdraw objective. If the exchange is ready, - * withdraws the planchet from the exchange. - * - * @param cls closure, with our `struct PlanchetOperation *` - * @param keys keys for the exchange - * @param exchange representation of the exchange - */ -static void -do_withdraw (void *cls, - struct TALER_EXCHANGE_Keys *keys, - struct TMH_Exchange *exchange) -{ - struct PlanchetOperation *po = cls; - struct PickupContext *pc = po->pc; - - (void) exchange; - po->fo = NULL; - TMH_db->preflight (TMH_db->cls); - if (NULL == keys) - { - stop_operations (pc); - GNUNET_CONTAINER_DLL_remove (pc->po_head, - pc->po_tail, - po); - GNUNET_free (po); - pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - pc->response = TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT)); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - /* FIXME: actually use *batch* withdraw instead of - doing this coin-by-coin non-sense */ - po->w2h = TALER_EXCHANGE_batch_withdraw2 (TMH_curl_ctx, - pc->exchange_url, - keys, - &pc->reserve_priv, - 1, - &po->pd, - &withdraw_cb, - po); -} - - -/** - * Withdraw @a planchet from @a exchange_url for @a pc operation at planchet - * @a offset. Sets up the respective operation and adds it @a pc's operation - * list. Once the operation is complete, the resulting blind signature is - * committed to the merchant's database. If all planchet operations are - * completed, the HTTP processing is resumed. - * - * @param[in,out] pc a pending pickup operation that includes @a planchet - * @param planchet details about the coin to pick up - * @param offset offset of @a planchet in the list, needed to process the reply - */ -static void -try_withdraw (struct PickupContext *pc, - const struct TALER_PlanchetDetail *planchet, - unsigned int offset) -{ - struct PlanchetOperation *po; - - TMH_db->preflight (TMH_db->cls); - po = GNUNET_new (struct PlanchetOperation); - po->pc = pc; - po->pd = *planchet; - po->offset = offset; - po->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url, - false, - &do_withdraw, - po); - GNUNET_assert (NULL != po->fo); - GNUNET_CONTAINER_DLL_insert (pc->po_head, - pc->po_tail, - po); -} - - -/** - * Handle timeout for pickup. - * - * @param cls a `struct PickupContext *` - */ -static void -do_timeout (void *cls) -{ - struct PickupContext *pc = cls; - - pc->tt = NULL; - stop_operations (pc); - pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - pc->response = TALER_MHD_make_error ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, - NULL); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * Function called with the result of a #TMH_EXCHANGES_keys4exchange() - * operation as part of a withdraw objective. Here, we initialize - * the "total_requested" amount by adding up the cost of the planchets - * provided by the client. - * - * @param cls closure, with our `struct PickupContext *` - * @param keys the keys of the exchange - * @param exchange representation of the exchange - */ -static void -compute_total_requested (void *cls, - struct TALER_EXCHANGE_Keys *keys, - struct TMH_Exchange *exchange) -{ - struct PickupContext *pc = cls; - bool have_request = false; - - (void) exchange; - pc->fo = NULL; - stop_operations (pc); /* stops timeout job */ - if (NULL == keys) - { - pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - pc->response = TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE)); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - struct TALER_PlanchetDetail *pd = &pc->planchets[i]; - const struct TALER_EXCHANGE_DenomPublicKey *dpk; - - dpk = TALER_EXCHANGE_get_denomination_key_by_hash (keys, - &pd->denom_pub_hash); - if (NULL == dpk) - { - pc->http_status = MHD_HTTP_CONFLICT; - pc->response = - TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_REWARD_PICKUP_DENOMINATION_UNKNOWN)); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - if (have_request) - { - if (GNUNET_YES != - TALER_amount_cmp_currency (&pc->total_requested, - &dpk->value)) - { - pc->http_status = MHD_HTTP_BAD_REQUEST; - pc->response = - TALER_MHD_make_error (TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, - "Must not mix currencies when picking up rewards"); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - if (0 > - TALER_amount_add (&pc->total_requested, - &pc->total_requested, - &dpk->value)) - { - pc->http_status = MHD_HTTP_BAD_REQUEST; - pc->response = - TALER_MHD_make_error (TALER_EC_MERCHANT_REWARD_PICKUP_SUMMATION_FAILED, - "Could not add up values to compute pickup total"); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - } - else - { - pc->total_requested = dpk->value; - have_request = true; - } - } - if (! have_request) - { - pc->http_status = MHD_HTTP_BAD_REQUEST; - pc->response = - TALER_MHD_make_error (TALER_EC_MERCHANT_REWARD_PICKUP_SUMMATION_FAILED, - "Empty request array not allowed"); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - pc->tr_initialized = true; - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * The reward lookup operation failed. Generate an error response based on the @a qs. - * - * @param connection connection to generate error for - * @param qs DB status to base error creation on - * @return MHD result code - */ -static MHD_RESULT -reply_lookup_reward_failed (struct MHD_Connection *connection, - enum GNUNET_DB_QueryStatus qs) -{ - unsigned int response_code; - enum TALER_ErrorCode ec; - - TMH_db->rollback (TMH_db->cls); - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ec = TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN; - response_code = MHD_HTTP_NOT_FOUND; - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_COMMIT_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - NULL); -} - - -MHD_RESULT -TMH_post_rewards_ID_pickup (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct PickupContext *pc = hc->ctx; - char *next_url; - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - struct TALER_Amount total_remaining; - struct GNUNET_TIME_Timestamp expiration; - enum GNUNET_DB_QueryStatus qs; - unsigned int num_retries; - - if (NULL == pc) - { - const json_t *planchets; - json_t *planchet; - size_t index; - - pc = GNUNET_new (struct PickupContext); - hc->ctx = pc; - hc->cc = &pick_context_cleanup; - pc->hc = hc; - GNUNET_assert (NULL != hc->infix); - if (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (hc->infix, - &pc->reward_id.hash)) - { - /* reward_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("planchets", - &planchets), - GNUNET_JSON_spec_end () - }; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_OK != res) - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - } - GNUNET_array_grow (pc->planchets, - pc->planchets_length, - json_array_size (planchets)); - json_array_foreach (planchets, index, planchet) { - struct TALER_PlanchetDetail *pd = &pc->planchets[index]; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", - &pd->denom_pub_hash), - TALER_JSON_spec_blinded_planchet ("coin_ev", - &pd->blinded_planchet), - GNUNET_JSON_spec_end () - }; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - planchet, - spec); - if (GNUNET_OK != res) - { - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - } - } - { - struct GNUNET_HashContext *hc; - - hc = GNUNET_CRYPTO_hash_context_start (); - GNUNET_CRYPTO_hash_context_read (hc, - &pc->reward_id, - sizeof (pc->reward_id)); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - struct TALER_PlanchetDetail *pd = &pc->planchets[i]; - - GNUNET_CRYPTO_hash_context_read (hc, - &pd->denom_pub_hash, - sizeof (pd->denom_pub_hash)); - TALER_blinded_planchet_hash_ (&pd->blinded_planchet, - hc); - } - GNUNET_CRYPTO_hash_context_finish (hc, - &pc->pickup_id.hash); - } - } - - if (NULL != pc->response) - { - MHD_RESULT ret; - - ret = MHD_queue_response (connection, - pc->http_status, - pc->response); - pc->response = NULL; - return ret; - } - - if (! pc->tr_initialized) - { - char *next_url; - - qs = TMH_db->lookup_reward (TMH_db->cls, - hc->instance->settings.id, - &pc->reward_id, - &total_authorized, - &total_picked_up, - &expiration, - &pc->exchange_url, - &next_url, - &pc->reserve_priv); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - return reply_lookup_reward_failed (connection, - qs); - GNUNET_free (next_url); - MHD_suspend_connection (connection); - pc->connection = connection; - pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, - &do_timeout, - pc); - pc->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url, - false, - &compute_total_requested, - pc); - return MHD_YES; - } - - - TMH_db->preflight (TMH_db->cls); - num_retries = 0; -RETRY: - num_retries++; - if (num_retries > MAX_RETRIES) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_SOFT_FAILURE, - NULL); - } - if (GNUNET_OK != - TMH_db->start (TMH_db->cls, - "pickup reward")) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, - NULL); - } - { - struct TALER_BlindedDenominationSignature sigs[ - GNUNET_NZL (pc->planchets_length)]; - - memset (sigs, - 0, - sizeof (sigs)); - GNUNET_free (pc->exchange_url); - qs = TMH_db->lookup_pickup (TMH_db->cls, - hc->instance->settings.id, - &pc->reward_id, - &pc->pickup_id, - &pc->exchange_url, - &pc->reserve_priv, - pc->planchets_length, - sigs); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Lookup pickup `%s' resulted in %d\n", - GNUNET_h2s (&pc->pickup_id.hash), - qs); - if (qs > GNUNET_DB_STATUS_SUCCESS_ONE_RESULT) - qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) - { - bool rollback = false; - - for (unsigned int i = 0; i< pc->planchets_length; i++) - { - if (NULL != sigs[i].blinded_sig) - continue; - if (! rollback) - { - TMH_db->rollback (TMH_db->cls); - MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (pc_head, - pc_tail, - pc); - pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, - &do_timeout, - pc); - rollback = true; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Lookup pickup `%s' initiated withdraw #%u\n", - GNUNET_h2s (&pc->pickup_id.hash), - i); - try_withdraw (pc, - &pc->planchets[i], - i); - } - if (rollback) - return MHD_YES; - /* we got _all_ signatures, can continue! */ - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs) - { - unsigned int response_code; - enum TALER_ErrorCode ec; - - TMH_db->rollback (TMH_db->cls); - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - { - json_t *blind_sigs; - - blind_sigs = json_array (); - GNUNET_assert (NULL != blind_sigs); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - GNUNET_assert (0 == - json_array_append_new ( - blind_sigs, - GNUNET_JSON_PACK ( - TALER_JSON_pack_blinded_denom_sig ("blind_sig", - &sigs[i])))); - TALER_blinded_denom_sig_free (&sigs[i]); - } - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("blind_sigs", - blind_sigs)); - } - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - goto RETRY; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_FETCH_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - NULL); - } - } - GNUNET_free (pc->exchange_url); - qs = TMH_db->lookup_reward (TMH_db->cls, - hc->instance->settings.id, - &pc->reward_id, - &total_authorized, - &total_picked_up, - &expiration, - &pc->exchange_url, - &next_url, - &pc->reserve_priv); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_db->rollback (TMH_db->cls); - goto RETRY; - } - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - TMH_db->rollback (TMH_db->cls); - return reply_lookup_reward_failed (connection, - qs); - } - GNUNET_free (next_url); - if (GNUNET_TIME_absolute_is_past (expiration.abs_time)) - { - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_GONE, - TALER_EC_MERCHANT_REWARD_PICKUP_HAS_EXPIRED, - hc->infix); - } - if (GNUNET_OK != - TALER_amount_cmp_currency (&total_authorized, - &total_picked_up)) - { - /* This could theoretically happen if the exchange changed - its currency between us approving the reward - and the client then picks it up with the new - exchange currency. And of course the backend - would have had to get the new /keys of the - exchange already as well. Very theoretical case. */ - GNUNET_break_op (0); - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, - "picked up amount does not use same currency as authorized amount"); - } - if (0 > - TALER_amount_subtract (&total_remaining, - &total_authorized, - &total_picked_up)) - { - GNUNET_break_op (0); - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "picked up amount exceeds authorized amount"); - } - - if (0 > - TALER_amount_cmp (&total_remaining, - &pc->total_requested)) - { - /* total_remaining < pc->total_requested */ - GNUNET_break_op (0); - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_MERCHANT_REWARD_PICKUP_AMOUNT_EXCEEDS_REWARD_REMAINING, - hc->infix); - } - - GNUNET_assert (0 < - TALER_amount_add (&total_picked_up, - &total_picked_up, - &pc->total_requested)); - qs = TMH_db->insert_pickup (TMH_db->cls, - hc->instance->settings.id, - &pc->reward_id, - &total_picked_up, - &pc->pickup_id, - &pc->total_requested); - if (qs < 0) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "pickup"); - } - qs = TMH_db->commit (TMH_db->cls); - if (qs < 0) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_COMMIT_FAILED, - NULL); - } - MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (pc_head, - pc_tail, - pc); - pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, - &do_timeout, - pc); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - try_withdraw (pc, - &pc->planchets[i], - i); - } - return MHD_YES; -} diff --git a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.h b/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.h deleted file mode 100644 index ea929e51..00000000 --- a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - This file is part of TALER - (C) 2017 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 taler-merchant-httpd_post-rewards-ID-pickup.h - * @brief headers for POST /rewards/ID/pickup handler - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_POST_REWARDS_ID_PICKUP_H -#define TALER_MERCHANT_HTTPD_POST_REWARDS_ID_PICKUP_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * We are shutting down, force resuming all suspended pickup operations. - */ -void -TMH_force_reward_pickup_resume (void); - - -/** - * Manages a POST /rewards/$ID/pickup call, checking that the reward is authorized, - * and if so, returning the blind signatures. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_post_rewards_ID_pickup (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-delete-reserves-ID.c b/src/backend/taler-merchant-httpd_private-delete-reserves-ID.c deleted file mode 100644 index b6daf9e6..00000000 --- a/src/backend/taler-merchant-httpd_private-delete-reserves-ID.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - This file is part of TALER - (C) 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 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 taler-merchant-httpd_private-delete-reserves-ID.c - * @brief implement DELETE /reserves/$ID - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler-merchant-httpd_private-delete-reserves-ID.h" -#include <taler/taler_json_lib.h> - - -/** - * Handle a DELETE "/reserves/$ID" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_delete_reserves_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TMH_MerchantInstance *mi = hc->instance; - enum GNUNET_DB_QueryStatus qs; - struct TALER_ReservePublicKeyP reserve_pub; - const char *purge; - - (void) rh; - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (hc->infix, - strlen (hc->infix), - &reserve_pub, - sizeof (reserve_pub))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, - hc->infix); - } - purge = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "purge"); - GNUNET_assert (NULL != mi); - if ( (NULL != purge) && - (0 == strcasecmp (purge, - "yes")) ) - qs = TMH_db->purge_reserve (TMH_db->cls, - mi->settings.id, - &reserve_pub); - else - qs = TMH_db->delete_reserve (TMH_db->cls, - mi->settings.id, - &reserve_pub); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - NULL); - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_SOFT_FAILURE, - "Serialization error for single SQL statement"); - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_MERCHANT_PRIVATE_DELETE_RESERVES_NO_SUCH_RESERVE, - hc->infix); - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); - } - GNUNET_assert (0); - return MHD_NO; -} - - -/* end of taler-merchant-httpd_private-delete-reserves-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-delete-reserves-ID.h b/src/backend/taler-merchant-httpd_private-delete-reserves-ID.h deleted file mode 100644 index 9180767f..00000000 --- a/src/backend/taler-merchant-httpd_private-delete-reserves-ID.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of TALER - (C) 2019, 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 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 taler-merchant-httpd_private-delete-reserves-ID.h - * @brief implement DELETE /reserves/$ID/ - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_DELETE_RESERVES_ID_H -#define TALER_MERCHANT_HTTPD_PRIVATE_DELETE_RESERVES_ID_H - -#include "taler-merchant-httpd.h" - - -/** - * Handle a DELETE "/reserves/$ID" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_delete_reserves_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - -/* end of taler-merchant-httpd_private-delete-reserves-ID.h */ -#endif diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c b/src/backend/taler-merchant-httpd_private-get-reserves-ID.c deleted file mode 100644 index a9855379..00000000 --- a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - This file is part of TALER - (C) 2018, 2020, 2021 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 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 taler-merchant-httpd_private-get-reserves-ID.c - * @brief implement GET /reserves/$RESERVE_PUB endpoint - * @author Christian Grothoff - */ -#include "platform.h" -#include <jansson.h> -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_helper.h" -#include "taler-merchant-httpd_private-get-reserves-ID.h" - - -/** - * Closure for handle_reserve_details(). - */ -struct GetReserveContext -{ - /** - * Connection we are handling. - */ - struct MHD_Connection *connection; - - /** - * Value to return from the callback. - */ - MHD_RESULT res; - - /** - * Should we return details about rewards? - */ - bool rewards; -}; - - -/** - * Callback with reserve details. - * - * @param cls closure with a `struct GetReserveContext` - * @param creation_time time when the reserve was setup - * @param expiration_time time when the reserve will be closed by the exchange - * @param merchant_initial_amount initial amount that the merchant claims to have filled the - * reserve with - * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param picked_up_amount total of rewards that were picked up from this reserve - * @param committed_amount total of rewards that the merchant committed to, but that were not - * picked up yet - * @param active true if the reserve is still active (we have the private key) - * @param master_pub master public key of the exchange - * @param exchange_url URL of the exchange, NULL if not active - * @param rewards_length length of the @a rewards array - * @param rewards information about the rewards created by this reserve - */ -static void -handle_reserve_details ( - void *cls, - struct GNUNET_TIME_Timestamp creation_time, - struct GNUNET_TIME_Timestamp expiration_time, - const struct TALER_Amount *merchant_initial_amount, - const struct TALER_Amount *exchange_initial_amount, - const struct TALER_Amount *picked_up_amount, - const struct TALER_Amount *committed_amount, - bool active, - const struct TALER_MasterPublicKeyP *master_pub, - const char *exchange_url, - unsigned int rewards_length, - const struct TALER_MERCHANTDB_RewardDetails *rewards) -{ - struct GetReserveContext *ctx = cls; - json_t *rewards_json; - json_t *accounts; - - if (NULL != rewards) - { - rewards_json = json_array (); - GNUNET_assert (NULL != rewards_json); - for (unsigned int i = 0; i<rewards_length; i++) - { - GNUNET_assert (0 == - json_array_append_new ( - rewards_json, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("reward_id", - &rewards[i].reward_id), - TALER_JSON_pack_amount ("total_amount", - &rewards[i].total_amount), - GNUNET_JSON_pack_string ("reason", - rewards[i].reason)))); - } - } - else - { - rewards_json = NULL; - } - accounts = TMH_exchange_accounts_by_method (master_pub, - NULL); - ctx->res = TALER_MHD_REPLY_JSON_PACK ( - ctx->connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_timestamp ("creation_time", - creation_time), - GNUNET_JSON_pack_timestamp ("expiration_time", - expiration_time), - TALER_JSON_pack_amount ("merchant_initial_amount", - merchant_initial_amount), - TALER_JSON_pack_amount ("exchange_initial_amount", - exchange_initial_amount), - TALER_JSON_pack_amount ("pickup_amount", - picked_up_amount), - TALER_JSON_pack_amount ("committed_amount", - committed_amount), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_steal ("rewards", - rewards_json)), - GNUNET_JSON_pack_bool ("active", - active), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("exchange_url", - exchange_url)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_steal ("accounts", - accounts))); -} - - -/** - * Manages a GET /reserves/$RESERVE_PUB call. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TALER_ReservePublicKeyP reserve_pub; - bool rewards; - - (void) rh; - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (hc->infix, - strlen (hc->infix), - &reserve_pub, - sizeof (reserve_pub))) - { - /* reward_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - { - const char *tstr; - - tstr = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "rewards"); - rewards = (NULL != tstr) - ? 0 == strcasecmp (tstr, "yes") - : false; - } - { - struct GetReserveContext ctx = { - .connection = connection, - .rewards = rewards - }; - enum GNUNET_DB_QueryStatus qs; - - TMH_db->preflight (TMH_db->cls); - qs = TMH_db->lookup_reserve (TMH_db->cls, - hc->instance->settings.id, - &reserve_pub, - rewards, - &handle_reserve_details, - &ctx); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - unsigned int response_code; - enum TALER_ErrorCode ec; - - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ec = TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN; - response_code = MHD_HTTP_NOT_FOUND; - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_FETCH_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - hc->infix); - } - return ctx.res; - } -} - - -/* end of taler-merchant-httpd_private-get-reserves-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.h b/src/backend/taler-merchant-httpd_private-get-reserves-ID.h deleted file mode 100644 index 83ea48ee..00000000 --- a/src/backend/taler-merchant-httpd_private-get-reserves-ID.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - This file is part of TALER - (C) 2017 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 taler-merchant-httpd_private-get-reserves-ID.h - * @brief headers for /reward-query handler - * @author Florian Dold - */ -#ifndef TALER_MERCHANT_HTTPD_GET_RESERVES_ID_H -#define TALER_MERCHANT_HTTPD_GET_RESERVES_ID_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - -/** - * Manages a GET /reserves/$RESERVE_PUB call. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - -#endif diff --git a/src/backend/taler-merchant-httpd_private-get-reserves.c b/src/backend/taler-merchant-httpd_private-get-reserves.c deleted file mode 100644 index 6621ffb4..00000000 --- a/src/backend/taler-merchant-httpd_private-get-reserves.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - This file is part of TALER - (C) 2019-2021 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 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 taler-merchant-httpd_private-get-reserves.c - * @brief implement GET /reserves - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_json_lib.h> -#include "taler-merchant-httpd_private-get-reserves.h" - - -/** - * Add reserve details to our JSON array. - * - * @param cls a `json_t *` JSON array to build - * @param reserve_pub public key of the reserve - * @param creation_time time when the reserve was setup - * @param expiration_time time when the reserve will be closed by the exchange - * @param merchant_initial_amount initial amount that the merchant claims to have filled the - * reserve with - * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param pickup_amount total of tips that were picked up from this reserve - * @param committed_amount total of tips that the merchant committed to, but that were not - * picked up yet - * @param active true if the reserve is still active (we have the private key) - */ -static void -add_reserve (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct GNUNET_TIME_Timestamp creation_time, - struct GNUNET_TIME_Timestamp expiration_time, - const struct TALER_Amount *merchant_initial_amount, - const struct TALER_Amount *exchange_initial_amount, - const struct TALER_Amount *pickup_amount, - const struct TALER_Amount *committed_amount, - bool active) -{ - json_t *pa = cls; - - GNUNET_assert (0 == - json_array_append_new ( - pa, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("reserve_pub", - reserve_pub), - GNUNET_JSON_pack_timestamp ("creation_time", - creation_time), - GNUNET_JSON_pack_timestamp ("expiration_time", - expiration_time), - TALER_JSON_pack_amount ("merchant_initial_amount", - merchant_initial_amount), - TALER_JSON_pack_amount ("exchange_initial_amount", - exchange_initial_amount), - TALER_JSON_pack_amount ("pickup_amount", - pickup_amount), - TALER_JSON_pack_amount ("committed_amount", - committed_amount), - GNUNET_JSON_pack_bool ("active", - active)))); -} - - -/** - * Handle a GET "/reserves" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_reserves (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - json_t *ra; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_TIME_Timestamp created_after - = GNUNET_TIME_UNIT_ZERO_TS; - enum TALER_EXCHANGE_YesNoAll active; - enum TALER_EXCHANGE_YesNoAll failures; - - (void) rh; - if (! (TALER_arg_to_yna (connection, - "active", - TALER_EXCHANGE_YNA_ALL, - &active)) ) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "active"); - } - - if (! (TALER_arg_to_yna (connection, - "failures", - TALER_EXCHANGE_YNA_ALL, - &failures)) ) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "failures"); - } - - ra = json_array (); - GNUNET_assert (NULL != ra); - qs = TMH_db->lookup_reserves (TMH_db->cls, - hc->instance->settings.id, - created_after, - active, - failures, - &add_reserve, - ra); - if (0 > qs) - { - GNUNET_break (0); - json_decref (ra); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "reserves"); - } - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("reserves", - ra)); -} - - -/* end of taler-merchant-httpd_private-get-reserves.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-reserves.h b/src/backend/taler-merchant-httpd_private-get-reserves.h deleted file mode 100644 index 705f0761..00000000 --- a/src/backend/taler-merchant-httpd_private-get-reserves.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of TALER - (C) 2019, 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 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 taler-merchant-httpd_private-get-reserves.h - * @brief implement GET /reserves - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_RESERVES_H -#define TALER_MERCHANT_HTTPD_PRIVATE_GET_RESERVES_H - -#include "taler-merchant-httpd.h" - - -/** - * Handle a GET "/reserves" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_reserves (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - -/* end of taler-merchant-httpd_private-get-reserves.h */ -#endif diff --git a/src/backend/taler-merchant-httpd_private-get-rewards-ID.c b/src/backend/taler-merchant-httpd_private-get-rewards-ID.c deleted file mode 100644 index a20be319..00000000 --- a/src/backend/taler-merchant-httpd_private-get-rewards-ID.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - This file is part of TALER - (C) 2017-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_get-rewards-ID.c - * @brief implementation of a GET /rewards/ID handler - * @author Christian Grothoff - */ -#include "platform.h" -#include <microhttpd.h> -#include <jansson.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_exchanges.h" - - -/** - * Information we keep per /kyc request. - */ -struct RewardContext -{ - /** - * Stored in a DLL. - */ - struct RewardContext *next; - - /** - * Stored in a DLL. - */ - struct RewardContext *prev; - - /** - * Connection we are handling. - */ - struct MHD_Connection *connection; - - /** - * Our handler context. - */ - struct TMH_HandlerContext *hc; - - /** - * Database event we are waiting on to be resuming. - */ - struct GNUNET_DB_EventHandler *eh; - - /** - * Response to return, NULL if we don't have one yet. - */ - struct MHD_Response *response; - - /** - * When does this request time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * ID of the reward being queried. - */ - struct TALER_RewardIdentifierP reward_id; - - /** - * Minimum reward amount picked up we should return to the - * client. - */ - struct TALER_Amount min_amount; - - /** - * #GNUNET_NO if the @e connection was not suspended, - * #GNUNET_YES if the @e connection was suspended, - * #GNUNET_SYSERR if @e connection was resumed to as - * part of #MH_force_pc_resume during shutdown. - */ - enum GNUNET_GenericReturnValue suspended; - - /** - * Is the "pickups" argument set to "yes"? - */ - bool fpu; - - /** - * True if @e min_amount was provided. - */ - bool have_min_amount; -}; - - -/** - * Head of DLL. - */ -static struct RewardContext *tc_head; - -/** - * Tail of DLL. - */ -static struct RewardContext *tc_tail; - - -void -TMH_force_reward_resume () -{ - for (struct RewardContext *tc = tc_head; - NULL != tc; - tc = tc->next) - { - if (GNUNET_YES == tc->suspended) - { - tc->suspended = GNUNET_SYSERR; - MHD_resume_connection (tc->connection); - } - } -} - - -/** - * Custom cleanup routine for a `struct RewardContext`. - * - * @param cls the `struct RewardContext` to clean up. - */ -static void -reward_context_cleanup (void *cls) -{ - struct RewardContext *tc = cls; - - if (NULL != tc->response) - { - MHD_destroy_response (tc->response); - tc->response = NULL; - } - if (NULL != tc->eh) - { - TMH_db->event_listen_cancel (tc->eh); - tc->eh = NULL; - } - GNUNET_CONTAINER_DLL_remove (tc_head, - tc_tail, - tc); - GNUNET_free (tc); -} - - -/** - * We have received a trigger from the database - * that we should (possibly) resume the request. - * - * @param cls a `struct RewardContext` to resume - * @param extra usually NULL - * @param extra_size number of bytes in @a extra - */ -static void -resume_by_event (void *cls, - const void *extra, - size_t extra_size) -{ - struct RewardContext *tc = cls; - - (void) extra; - (void) extra_size; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Resuming request %p by trigger\n", - tc); - if (GNUNET_NO == tc->suspended) - return; /* duplicate event is possible */ - tc->suspended = GNUNET_NO; - GNUNET_CONTAINER_DLL_remove (tc_head, - tc_tail, - tc); - MHD_resume_connection (tc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -MHD_RESULT -TMH_private_get_rewards_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct RewardContext *tc = hc->ctx; - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - char *reason; - struct GNUNET_TIME_Timestamp expiration; - struct TALER_ReservePublicKeyP reserve_pub; - unsigned int pickups_length = 0; - struct TALER_MERCHANTDB_PickupDetails *pickups = NULL; - enum GNUNET_DB_QueryStatus qs; - json_t *pickups_json = NULL; - - (void) rh; - if (NULL == tc) - { - tc = GNUNET_new (struct RewardContext); - hc->ctx = tc; - hc->cc = &reward_context_cleanup; - GNUNET_CONTAINER_DLL_insert (tc_head, - tc_tail, - tc); - tc->connection = connection; - tc->hc = hc; - GNUNET_assert (NULL != hc->infix); - if (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (hc->infix, - &tc->reward_id.hash)) - { - /* reward_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - { - const char *pstr; - - pstr = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "pickups"); - tc->fpu = (NULL != pstr) - ? 0 == strcasecmp (pstr, "yes") - : false; - } - { - const char *min_amount; - - min_amount = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "min_amount"); - if (NULL != min_amount) - { - if (GNUNET_OK != - TALER_string_to_amount (min_amount, - &tc->min_amount)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "min_amount"); - } - tc->have_min_amount = true; - } - } - TALER_MHD_parse_request_timeout (connection, - &tc->timeout); - if (! GNUNET_TIME_absolute_is_future (tc->timeout)) - { - struct TMH_RewardPickupEventP reward_eh = { - .header.size = htons (sizeof (reward_eh)), - .header.type = htons (TALER_DBEVENT_MERCHANT_REWARD_PICKUP), - .reward_id = tc->reward_id - }; - - GNUNET_CRYPTO_hash (hc->instance->settings.id, - strlen (hc->instance->settings.id), - &reward_eh.h_instance); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Subscribing to payment triggers for %p\n", - tc); - tc->eh = TMH_db->event_listen ( - TMH_db->cls, - &reward_eh.header, - GNUNET_TIME_absolute_get_remaining (tc->timeout), - &resume_by_event, - tc); - } - } - - GNUNET_assert (GNUNET_YES != tc->suspended); - TMH_db->preflight (TMH_db->cls); - qs = TMH_db->lookup_reward_details (TMH_db->cls, - hc->instance->settings.id, - &tc->reward_id, - tc->fpu, - &total_authorized, - &total_picked_up, - &reason, - &expiration, - &reserve_pub, - &pickups_length, - &pickups); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - unsigned int response_code; - enum TALER_ErrorCode ec; - - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ec = TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN; - response_code = MHD_HTTP_NOT_FOUND; - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_COMMIT_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - NULL); - } - /* do not allow timeout above reward expiration */ - tc->timeout = GNUNET_TIME_absolute_min (tc->timeout, - expiration.abs_time); - if ( (NULL != tc->eh) && - (GNUNET_TIME_absolute_is_future (tc->timeout)) && - (tc->have_min_amount) && - (GNUNET_YES == - TALER_amount_cmp_currency (&tc->min_amount, - &total_picked_up)) && - (1 == TALER_amount_cmp (&tc->min_amount, - &total_picked_up)) ) - { - MHD_suspend_connection (connection); - tc->suspended = GNUNET_YES; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Suspending REWARD request handling as pickup is below threshold requested by client\n"); - GNUNET_array_grow (pickups, - pickups_length, - 0); - GNUNET_free (reason); - return MHD_YES; - } - if (tc->fpu) - { - pickups_json = json_array (); - GNUNET_assert (NULL != pickups_json); - for (unsigned int i = 0; i<pickups_length; i++) - { - GNUNET_assert (0 == - json_array_append_new ( - pickups_json, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("pickup_id", - &pickups[i].pickup_id), - GNUNET_JSON_pack_uint64 ("num_planchets", - pickups[i].num_planchets), - TALER_JSON_pack_amount ("requested_amount", - &pickups[i].requested_amount)))); - } - } - GNUNET_array_grow (pickups, - pickups_length, - 0); - { - MHD_RESULT ret; - - ret = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("total_authorized", - &total_authorized), - TALER_JSON_pack_amount ("total_picked_up", - &total_picked_up), - GNUNET_JSON_pack_string ("reason", - reason), - GNUNET_JSON_pack_timestamp ("expiration", - expiration), - GNUNET_JSON_pack_data_auto ("reserve_pub", - &reserve_pub), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_steal ("pickups", - pickups_json))); - GNUNET_free (reason); - return ret; - } -} diff --git a/src/backend/taler-merchant-httpd_private-get-rewards-ID.h b/src/backend/taler-merchant-httpd_private-get-rewards-ID.h deleted file mode 100644 index fc9cc9ae..00000000 --- a/src/backend/taler-merchant-httpd_private-get-rewards-ID.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of TALER - (C) 2017, 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_get-rewards-ID.h - * @brief headers for GET /rewards/ID handler - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_ID_H -#define TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_ID_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * Force wake-up of all suspended rewardping long-pollers. - */ -void -TMH_force_reward_resume (void); - - -/** - * Manages a GET /rewards/$ID call, returning the status of the reward. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_rewards_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-get-rewards.c b/src/backend/taler-merchant-httpd_private-get-rewards.c deleted file mode 100644 index 2ced8316..00000000 --- a/src/backend/taler-merchant-httpd_private-get-rewards.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - This file is part of TALER - (C) 2020-2021 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 taler-merchant-httpd_private-get-rewards.c - * @brief implementation of a GET /private/rewards handler - * @author Jonathan Buchanan - */ -#include "platform.h" -#include "taler-merchant-httpd_private-get-rewards.h" -#include <taler/taler_json_lib.h> - -/** - * Add reward details to our JSON array. - * - * @param[in,out] cls a `json_t *` JSON array to build - * @param row_id row number of the reward - * @param reward_id ID of the reward - * @param amount the amount of the reward - */ -static void -add_reward (void *cls, - uint64_t row_id, - struct TALER_RewardIdentifierP reward_id, - struct TALER_Amount amount) -{ - json_t *pa = cls; - - GNUNET_assert (0 == - json_array_append_new ( - pa, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_uint64 ("row_id", - row_id), - GNUNET_JSON_pack_data_auto ("reward_id", - &reward_id), - TALER_JSON_pack_amount ("reward_amount", - &amount)))); -} - - -MHD_RESULT -TMH_private_get_rewards (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - json_t *pa; - enum GNUNET_DB_QueryStatus qs; - enum TALER_EXCHANGE_YesNoAll expired; - uint64_t offset; - int64_t limit; - - (void) rh; - if (! (TALER_arg_to_yna (connection, - "expired", - TALER_EXCHANGE_YNA_NO, - &expired)) ) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "expired"); - { - const char *limit_str; - - limit_str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "limit"); - if (NULL == limit_str) - { - limit = -20; - } - else - { - char dummy[2]; - long long ll; - - if (1 != - sscanf (limit_str, - "%lld%1s", - &ll, - dummy)) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "limit"); - limit = (uint64_t) ll; - } - } - { - const char *offset_str; - - offset_str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "offset"); - if (NULL == offset_str) - { - if (limit > 0) - offset = 0; - else - offset = INT64_MAX; - } - else - { - char dummy[2]; - unsigned long long ull; - - if (1 != - sscanf (offset_str, - "%llu%1s", - &ull, - dummy)) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "offset"); - offset = (uint64_t) ull; - } - } - - pa = json_array (); - GNUNET_assert (NULL != pa); - qs = TMH_db->lookup_rewards (TMH_db->cls, - hc->instance->settings.id, - expired, - limit, - offset, - &add_reward, - pa); - - if (0 > qs) - { - GNUNET_break (0); - json_decref (pa); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "rewards"); - } - - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("rewards", - pa)); -} diff --git a/src/backend/taler-merchant-httpd_private-get-rewards.h b/src/backend/taler-merchant-httpd_private-get-rewards.h deleted file mode 100644 index 67b3bc52..00000000 --- a/src/backend/taler-merchant-httpd_private-get-rewards.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of TALER - (C) 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 taler-merchant-httpd_private-get-rewards.h - * @brief headers for GET /private/rewards handler - * @author Jonathan Buchanan - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_H -#define TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * Manages a GET /private/rewards call. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_rewards (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c deleted file mode 100644 index 0d102a2b..00000000 --- a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - This file is part of TALER - (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 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 taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c - * @brief implement API for authorizing rewards to be paid to visitors - * @author Christian Grothoff - */ -#include "platform.h" -#include <jansson.h> -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_get-rewards-ID.h" -#include "taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h" - - -/** - * Handle a "reward-authorize" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @param reserve_pub reserve to use, or NULL for "any" - * @return MHD result code - */ -static MHD_RESULT -authorize_reward (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - enum TALER_ErrorCode ec; - struct GNUNET_TIME_Timestamp expiration; - struct TALER_RewardIdentifierP reward_id; - const char *justification; - const char *next_url; - struct TALER_Amount amount; - { - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("amount", - &amount), - GNUNET_JSON_spec_string ("justification", - &justification), - GNUNET_JSON_spec_string ("next_url", - &next_url), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_YES != res) - { - GNUNET_break_op (0); - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - } - TMH_db->preflight (TMH_db->cls); - ec = TMH_db->authorize_reward (TMH_db->cls, - hc->instance->settings.id, - reserve_pub, - &amount, - justification, - next_url, - &reward_id, - &expiration); - /* handle errors */ - if (TALER_EC_NONE != ec) - { - unsigned int http_status; - - switch (ec) - { - case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS: - http_status = MHD_HTTP_PRECONDITION_FAILED; - break; - case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED: - http_status = MHD_HTTP_GONE; - break; - case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_UNKNOWN: - http_status = MHD_HTTP_SERVICE_UNAVAILABLE; - break; - case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND: - http_status = MHD_HTTP_NOT_FOUND; - break; - default: - http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - return TALER_MHD_reply_with_error (connection, - http_status, - ec, - NULL); - } - - /* generate success response */ - { - char *taler_reward_uri; - char *reward_status_url; - struct GNUNET_CRYPTO_HashAsciiEncoded hash_enc; - MHD_RESULT res; - - GNUNET_CRYPTO_hash_to_enc (&reward_id.hash, - &hash_enc); - taler_reward_uri = TMH_make_taler_reward_uri (connection, - &reward_id, - hc->instance->settings.id); - if (NULL == taler_reward_uri) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MISSING, - "host"); - } - reward_status_url = TMH_make_reward_status_url (connection, - &reward_id, - hc->instance->settings.id); - GNUNET_assert (NULL != reward_status_url); - GNUNET_assert (! GNUNET_TIME_absolute_is_zero (expiration.abs_time)); - res = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_string ("reward_id", - (const char *) hash_enc.encoding), - GNUNET_JSON_pack_string ("taler_reward_uri", - taler_reward_uri), - GNUNET_JSON_pack_string ("reward_status_url", - reward_status_url), - GNUNET_JSON_pack_timestamp ("reward_expiration", - expiration)); - GNUNET_free (taler_reward_uri); - GNUNET_free (reward_status_url); - return res; - } -} - - -MHD_RESULT -TMH_private_post_reserves_ID_authorize_reward (const struct - TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TALER_ReservePublicKeyP reserve_pub; - - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (hc->infix, - strlen (hc->infix), - &reserve_pub, - sizeof (reserve_pub))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, - hc->infix); - } - return authorize_reward (rh, - connection, - hc, - &reserve_pub); -} - - -MHD_RESULT -TMH_private_post_rewards (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - return authorize_reward (rh, - connection, - hc, - NULL); -} - - -/* end of taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h deleted file mode 100644 index 12c94b1c..00000000 --- a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of TALER - (C) 2017, 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 taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h - * @brief headers for /reserves/ID/reward-authorize - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_ID_AUTHORIZE_REWARD_H -#define TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_ID_AUTHORIZE_REWARD_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * Handle a "/reserves/$ID/reward-authorize" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_post_reserves_ID_authorize_reward (const struct - TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -/** - * Handle a POST "/rewards" request. - * Here the client does not specify the reserve public key, so we - * are free to pick "any" available reserve. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_post_rewards (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.c b/src/backend/taler-merchant-httpd_private-post-reserves.c deleted file mode 100644 index 4d1ea3c9..00000000 --- a/src/backend/taler-merchant-httpd_private-post-reserves.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - This file is part of TALER - (C) 2021-2023 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 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 taler-merchant-httpd_private-post-reserves.c - * @brief implementing POST /reserves request handling - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_private-post-reserves.h" -#include "taler-merchant-httpd_helper.h" -#include "taler-merchant-httpd_reserves.h" -#include <taler/taler_json_lib.h> - - -/** - * How long to wait before giving up processing with the exchange? - */ -#define EXCHANGE_GENERIC_TIMEOUT (GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_SECONDS, \ - 15)) - - -/** - * Information we keep for an individual call to the POST /reserves handler. - */ -struct PostReserveContext -{ - - /** - * Stored in a DLL. - */ - struct PostReserveContext *next; - - /** - * Stored in a DLL. - */ - struct PostReserveContext *prev; - - /** - * Array with @e coins_cnt coins we are despositing. - */ - struct DepositConfirmation *dc; - - /** - * MHD connection to return to - */ - struct MHD_Connection *connection; - - /** - * Details about the client's request. - */ - struct TMH_HandlerContext *hc; - - /** - * URL of the exchange. - */ - const char *exchange_url; - - /** - * Wire method the client wants to use for the payment. - */ - const char *wire_method; - - /** - * Array of accounts that could be used. - */ - json_t *accounts; - - /** - * Handle for contacting the exchange for /keys. - */ - struct TMH_EXCHANGES_KeysOperation *fo; - - /** - * Master public key of the exchange matching - * @e exchange_url. - */ - struct TALER_MasterPublicKeyP master_pub; - - /** - * Initial balance of the reserve. - */ - struct TALER_Amount initial_balance; - - /** - * When will the reserve expire. - */ - struct GNUNET_TIME_Timestamp reserve_expiration; - - /** - * Which HTTP status should we return? - */ - unsigned int http_status; - - /** - * Which error code should we return? - */ - enum TALER_ErrorCode ec; - - /** - * Did we suspend @a connection and are thus in - * the #rc_head DLL (#GNUNET_YES). Set to - * #GNUNET_NO if we are not suspended, and to - * #GNUNET_SYSERR if we should close the connection - * without a response due to shutdown. - */ - enum GNUNET_GenericReturnValue suspended; - - /** - * True if we already force reloaded /keys. - */ - bool force_reload; -}; - - -/** - * Stored in a DLL. - */ -static struct PostReserveContext *rc_head; - -/** - * Stored in a DLL. - */ -static struct PostReserveContext *rc_tail; - - -/** - * Force all post reserve contexts to be resumed as we are about - * to shut down MHD. - */ -void -TMH_force_rc_resume () -{ - struct PostReserveContext *rcn; - - for (struct PostReserveContext *rc = rc_head; - NULL != rc; - rc = rcn) - { - rcn = rc->next; - if (GNUNET_YES == rc->suspended) - { - rc->suspended = GNUNET_SYSERR; - MHD_resume_connection (rc->connection); - GNUNET_CONTAINER_DLL_remove (rc_head, - rc_tail, - rc); - } - if (NULL != rc->fo) - { - TMH_EXCHANGES_keys4exchange_cancel (rc->fo); - rc->fo = NULL; - } - } -} - - -/** - * Custom cleanup routine for a `struct PostReserveContext`. - * - * @param cls the `struct PostReserveContext` to clean up. - */ -static void -reserve_context_cleanup (void *cls) -{ - struct PostReserveContext *rc = cls; - - if (NULL != rc->fo) - { - TMH_EXCHANGES_keys4exchange_cancel (rc->fo); - rc->fo = NULL; - } - GNUNET_assert (GNUNET_YES != rc->suspended); - json_decref (rc->accounts); - GNUNET_free (rc); -} - - -/** - * Resume request handling. - * - * @param[in,out] rc request to resume - */ -static void -resume_request (struct PostReserveContext *rc) -{ - rc->suspended = GNUNET_NO; - MHD_resume_connection (rc->connection); - GNUNET_CONTAINER_DLL_remove (rc_head, - rc_tail, - rc); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * Function called with the result of a #TMH_EXCHANGES_keys4exchange() - * operation. - * - * @param cls closure with our `struct PostReserveContext *` - * @param keys exchange keys - * @param exchange representation of the exchange - */ -static void -handle_exchange (void *cls, - struct TALER_EXCHANGE_Keys *keys, - struct TMH_Exchange *exchange) -{ - struct PostReserveContext *rc = cls; - - rc->fo = NULL; - if (NULL == keys) - { - GNUNET_break_op (0); - rc->ec = TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE; - rc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - resume_request (rc); - return; - } - if (! keys->rewards_allowed) - { - if (! rc->force_reload) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Forcing %s/keys reload (rewards not allowed)\n", - rc->exchange_url); - rc->force_reload = true; - rc->fo = TMH_EXCHANGES_keys4exchange (rc->exchange_url, - true, - &handle_exchange, - rc); - return; - } - rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_REWARDS_NOT_ALLOWED; - rc->http_status = MHD_HTTP_CONFLICT; - resume_request (rc); - return; - } - rc->master_pub = keys->master_pub; - rc->reserve_expiration - = GNUNET_TIME_relative_to_timestamp (keys->reserve_closing_delay); - rc->accounts = TMH_exchange_accounts_by_method ( - &rc->master_pub, - rc->wire_method); - if ( (NULL == rc->accounts) || - (0 == json_array_size (rc->accounts)) ) - { - if (! rc->force_reload) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Forcing %s/keys reload (no accounts)\n", - rc->exchange_url); - rc->force_reload = true; - rc->fo = TMH_EXCHANGES_keys4exchange (rc->exchange_url, - true, - &handle_exchange, - rc); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Wire method `%s' not supported\n", - rc->wire_method); - rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_UNSUPPORTED_WIRE_METHOD; - rc->http_status = MHD_HTTP_CONFLICT; - resume_request (rc); - return; - } - resume_request (rc); -} - - -MHD_RESULT -TMH_private_post_reserves (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct PostReserveContext *rc = hc->ctx; - struct TMH_MerchantInstance *mi = hc->instance; - - GNUNET_assert (NULL != mi); - if (NULL == rc) - { - rc = GNUNET_new (struct PostReserveContext); - rc->connection = connection; - rc->hc = hc; - hc->ctx = rc; - hc->cc = &reserve_context_cleanup; - - { - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_web_url ("exchange_url", - &rc->exchange_url), - GNUNET_JSON_spec_string ("wire_method", - &rc->wire_method), - TALER_JSON_spec_amount_any ("initial_balance", - &rc->initial_balance), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_OK != res) - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - rc->fo = TMH_EXCHANGES_keys4exchange (rc->exchange_url, - false, - &handle_exchange, - rc); - rc->suspended = GNUNET_YES; - GNUNET_CONTAINER_DLL_insert (rc_head, - rc_tail, - rc); - MHD_suspend_connection (connection); - return MHD_YES; - } - if (GNUNET_SYSERR == rc->suspended) - return MHD_NO; /* we are in shutdown */ - if (TALER_EC_NONE != rc->ec) - { - return TALER_MHD_reply_with_error (connection, - rc->http_status, - rc->ec, - NULL); - } - GNUNET_assert (GNUNET_NO == rc->suspended); - GNUNET_assert (! GNUNET_TIME_absolute_is_zero ( - rc->reserve_expiration.abs_time)); - { - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_ReservePrivateKeyP reserve_priv; - enum GNUNET_DB_QueryStatus qs; - - GNUNET_CRYPTO_eddsa_key_create (&reserve_priv.eddsa_priv); - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - qs = TMH_db->insert_reserve (TMH_db->cls, - mi->settings.id, - &reserve_priv, - &reserve_pub, - &rc->master_pub, - rc->exchange_url, - &rc->initial_balance, - rc->reserve_expiration); - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); - TMH_RESERVES_check (mi->settings.id, - rc->exchange_url, - &reserve_pub, - &rc->initial_balance); - if (qs < 0) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "reserve"); - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_data_auto ("reserve_pub", - &reserve_pub), - GNUNET_JSON_pack_array_incref ("accounts", - rc->accounts)); - } -} - - -/* end of taler-merchant-httpd_private-post-reserves.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.h b/src/backend/taler-merchant-httpd_private-post-reserves.h deleted file mode 100644 index ca06fe2f..00000000 --- a/src/backend/taler-merchant-httpd_private-post-reserves.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of TALER - (C) 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 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 taler-merchant-httpd_private-post-reserves.h - * @brief implementing POST /reserves request handling - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_H -#define TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_H -#include "taler-merchant-httpd.h" - -/** - * Force all post reserve contexts to be resumed as we are about - * to shut down MHD. - */ -void -TMH_force_rc_resume (); - - -/** - * Generate a reserve entry in our inventory. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_post_reserves (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - -#endif diff --git a/src/backend/taler-merchant-httpd_reserves.c b/src/backend/taler-merchant-httpd_reserves.c deleted file mode 100644 index 31dec87f..00000000 --- a/src/backend/taler-merchant-httpd_reserves.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - This file is part of TALER - (C) 2020, 2021 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 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 taler-merchant-httpd_reserves.c - * @brief logic for initially tracking a reserve's status - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_json_lib.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_reserves.h" - -/** - * How long do we keep the long-poller open? - * Not very long here, as if the money has not - * yet arrived, there is a fair chance that it'll - * take much longer, and in that case we rather - * enter into the delay created by try_later(). - */ -#define LONGPOLL_DELAY GNUNET_TIME_UNIT_MINUTES - -/** - * Our representation of a reserve that we are (still) checking the status of. - */ -struct Reserve -{ - - /** - * Kept in a DLL. - */ - struct Reserve *next; - - /** - * Kept in a DLL. - */ - struct Reserve *prev; - - /** - * Reserve's public key. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Amount the merchant expects to see in the reserve initially. - * We log a warning if there is a mismatch. - */ - struct TALER_Amount expected_amount; - - /** - * URL of the exchange hosting this reserve. - */ - char *exchange_url; - - /** - * Instance this reserve belongs with. - */ - char *instance_id; - - /** - * Task scheduled waiting for a timeout for this reserve. - */ - struct GNUNET_SCHEDULER_Task *tt; - - /** - * Get operation with the exchange. - */ - struct TALER_EXCHANGE_ReservesGetHandle *gh; - - /** - * How long do we wait before trying this reserve again? - */ - struct GNUNET_TIME_Relative delay; - -}; - - -/** - * Head of DLL of pending reserves. - */ -static struct Reserve *reserves_head; - -/** - * Tail of DLL of pending reserves. - */ -static struct Reserve *reserves_tail; - - -/** - * Function called to probe a reserve now. - * - * @param cls a `struct Reserve` to query - */ -static void -try_now (void *cls); - - -/** - * Free reserve data structure. - * - * @param r reserve to free - */ -static void -free_reserve (struct Reserve *r) -{ - GNUNET_CONTAINER_DLL_remove (reserves_head, - reserves_tail, - r); - if (NULL != r->gh) - { - TALER_EXCHANGE_reserves_get_cancel (r->gh); - r->gh = NULL; - } - if (NULL != r->tt) - { - GNUNET_SCHEDULER_cancel (r->tt); - r->tt = NULL; - } - GNUNET_free (r->exchange_url); - GNUNET_free (r->instance_id); - GNUNET_free (r); -} - - -/** - * Schedule a job to probe a reserve later again. - * - * @param r reserve to try again later - */ -static void -try_later (struct Reserve *r) -{ - /* minimum delay is the #LONGPOLL_DELAY */ - r->delay = GNUNET_TIME_relative_max (LONGPOLL_DELAY, - r->delay); - /* STD_BACKOFF has a maximum of 15 minutes */ - r->delay = GNUNET_TIME_STD_BACKOFF (r->delay); - r->tt = GNUNET_SCHEDULER_add_delayed (r->delay, - &try_now, - r); -} - - -/** - * Callbacks of this type are used to serve the result of submitting a - * reserve status request to a exchange. - * - * @param cls closure with a `struct Reserve *` - * @param rs HTTP response data - */ -static void -reserve_cb (void *cls, - const struct TALER_EXCHANGE_ReserveSummary *rs) -{ - struct Reserve *r = cls; - enum GNUNET_DB_QueryStatus qs; - - r->gh = NULL; - if (MHD_HTTP_OK != rs->hr.http_status) - { - try_later (r); - return; - } - if (GNUNET_OK != - TALER_amount_cmp_currency (&r->expected_amount, - &rs->details.ok.balance)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Reserve currency disagreement: exchange `%s' has %s, expected %s\n", - r->exchange_url, - rs->details.ok.balance.currency, - r->expected_amount.currency); - free_reserve (r); - return; - } - if (0 != - TALER_amount_cmp (&r->expected_amount, - &rs->details.ok.balance)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Reserve initial balance disagreement: exchange `%s' received `%s'\n", - r->exchange_url, - TALER_amount2s (&rs->details.ok.balance)); - } - qs = TMH_db->activate_reserve (TMH_db->cls, - r->instance_id, - &r->reserve_pub, - &rs->details.ok.balance); - if (qs <= 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to commit reserve activation to database (%d)\n", - (int) qs); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Reserve activated with initial balance %s\n", - TALER_amount2s (&rs->details.ok.balance)); - } - free_reserve (r); -} - - -/** - * Function called to probe a reserve now. - * - * @param cls a `struct Reserve` to query - */ -static void -try_now (void *cls) -{ - struct Reserve *r = cls; - - r->tt = NULL; - r->gh = TALER_EXCHANGE_reserves_get (TMH_curl_ctx, - r->exchange_url, - &r->reserve_pub, - LONGPOLL_DELAY, - &reserve_cb, - r); - if (NULL == r->gh) - { - try_later (r); - return; - } -} - - -/** - * Function called with information about a reserve that we need - * to check the status from at the exchange to see if/when it has - * been filled (and with what amount). - * - * @param cls closure, NULL - * @param instance_id for which instance is this reserve - * @param exchange_url base URL of the exchange at which the reserve lives - * @param reserve_pub public key of the reserve - * @param expected_amount how much do we expect to see in the reserve - */ -static void -add_reserve (void *cls, - const char *instance_id, - const char *exchange_url, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *expected_amount) -{ - struct Reserve *r; - - (void) cls; - r = GNUNET_new (struct Reserve); - r->exchange_url = GNUNET_strdup (exchange_url); - r->instance_id = GNUNET_strdup (instance_id); - r->reserve_pub = *reserve_pub; - r->expected_amount = *expected_amount; - GNUNET_CONTAINER_DLL_insert (reserves_head, - reserves_tail, - r); - try_now (r); -} - - -void -TMH_RESERVES_init (void) -{ - TMH_db->lookup_pending_reserves (TMH_db->cls, - &add_reserve, - NULL); -} - - -void -TMH_RESERVES_check (const char *instance_id, - const char *exchange_url, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *expected_amount) -{ - add_reserve (NULL, - instance_id, - exchange_url, - reserve_pub, - expected_amount); -} - - -void -TMH_RESERVES_done (void) -{ - while (NULL != reserves_head) - free_reserve (reserves_head); -} - - -/* end of taler-merchant-httpd_reserves.c */ diff --git a/src/backend/taler-merchant-httpd_reserves.h b/src/backend/taler-merchant-httpd_reserves.h deleted file mode 100644 index af4133b1..00000000 --- a/src/backend/taler-merchant-httpd_reserves.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of TALER - (C) 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 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 taler-merchant-httpd_reserves.h - * @brief logic for initially tracking a reserve's status - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_RESERVES_H -#define TALER_MERCHANT_HTTPD_RESERVES_H - -#include <jansson.h> -#include <gnunet/gnunet_util_lib.h> -#include <taler/taler_util.h> -#include <taler/taler_exchange_service.h> -#include "taler-merchant-httpd.h" - - -/** - * Load information about reserves and start querying reserve status. - * Must be called after the database is available. - */ -void -TMH_RESERVES_init (void); - - -/** - * Add a reserve to the list of reserves to check. - * - * @param instance_id which instance is the reserve for - * @param exchange_url URL of the exchange with the reserve - * @param reserve_pub public key of the reserve to check - * @param expected_amount amount the merchant expects to see initially in the reserve - */ -void -TMH_RESERVES_check (const char *instance_id, - const char *exchange_url, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *expected_amount); - - -/** - * Stop checking reserve status. - */ -void -TMH_RESERVES_done (void); - - -#endif diff --git a/src/backend/taler-merchant-wirewatch.c b/src/backend/taler-merchant-wirewatch.c index 77428da3..e1605bc1 100644 --- a/src/backend/taler-merchant-wirewatch.c +++ b/src/backend/taler-merchant-wirewatch.c @@ -342,7 +342,8 @@ credit_cb ( { case 0: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid HTTP response from bank\n"); + "Invalid HTTP response (HTTP status: 0, %d) from bank\n", + ec); w->delay = GNUNET_TIME_STD_BACKOFF (w->delay); break; case MHD_HTTP_OK: @@ -443,6 +444,7 @@ credit_cb ( = GNUNET_TIME_relative_max (w->bank_timeout, GNUNET_TIME_UNIT_SECONDS); w->delay = GNUNET_TIME_STD_BACKOFF (w->delay); + break; default: /* Something went wrong, try again, but with back-off */ w->delay = GNUNET_TIME_STD_BACKOFF (w->delay); diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am index 149a43ed..e7fb15cf 100644 --- a/src/backenddb/Makefile.am +++ b/src/backenddb/Makefile.am @@ -75,10 +75,6 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \ pg_insert_transfer.h pg_insert_transfer.c \ pg_insert_transfer_details.h pg_insert_transfer_details.c \ pg_store_wire_fee_by_exchange.h pg_store_wire_fee_by_exchange.c \ - pg_insert_reserve.h pg_insert_reserve.c \ - pg_activate_reserve.h pg_activate_reserve.c \ - pg_authorize_reward.h pg_authorize_reward.c \ - pg_insert_pickup.h pg_insert_pickup.c \ pg_select_open_transfers.h pg_select_open_transfers.c \ pg_lookup_instances.h pg_lookup_instances.c \ pg_lookup_transfers.h pg_lookup_transfers.c \ @@ -91,7 +87,6 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \ pg_delete_login_token.h pg_delete_login_token.c \ pg_select_login_token.h pg_select_login_token.c \ pg_select_account_by_uri.h pg_select_account_by_uri.c \ - pg_lookup_reserves.h pg_lookup_reserves.c \ pg_lookup_instance_auth.h pg_lookup_instance_auth.c \ pg_lookup_pending_deposits.h pg_lookup_pending_deposits.c \ pg_insert_instance.h pg_insert_instance.c \ @@ -163,15 +158,6 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \ pg_lookup_transfer.h pg_lookup_transfer.c \ pg_lookup_transfer_summary.h pg_lookup_transfer_summary.c \ pg_lookup_transfer_details.h pg_lookup_transfer_details.c \ - pg_lookup_pending_reserves.h pg_lookup_pending_reserves.c \ - pg_lookup_reserve.h pg_lookup_reserve.c \ - pg_delete_reserve.h pg_delete_reserve.c \ - pg_purge_reserve.h pg_purge_reserve.c \ - pg_lookup_pickup.h pg_lookup_pickup.c \ - pg_lookup_reward.h pg_lookup_reward.c \ - pg_lookup_rewards.h pg_lookup_rewards.c \ - pg_lookup_reward_details.h pg_lookup_reward_details.c \ - pg_insert_pickup_blind_signature.h pg_insert_pickup_blind_signature.c \ pg_lookup_webhooks.h pg_lookup_webhooks.c \ pg_lookup_webhook.h pg_lookup_webhook.c \ pg_delete_webhook.h pg_delete_webhook.c \ diff --git a/src/backenddb/merchant-0004.sql b/src/backenddb/merchant-0004.sql index 47fa71af..711026a2 100644 --- a/src/backenddb/merchant-0004.sql +++ b/src/backenddb/merchant-0004.sql @@ -1,6 +1,6 @@ -- -- This file is part of TALER --- Copyright (C) 2022-2023 Taler Systems SA +-- Copyright (C) 2024 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 @@ -16,9 +16,15 @@ BEGIN; -- Check patch versioning is in place. --- SELECT _v.register_patch('merchant-0004', NULL, NULL); +SELECT _v.register_patch('merchant-0004', NULL, NULL); SET search_path TO merchant; +DROP TABLE merchant_reward_pickup_signatures; +DROP TABLE merchant_reward_pickups; +DROP TABLE merchant_rewards; +DROP TABLE merchant_reward_reserve_keys; +DROP TABLE merchant_reward_reserves; + COMMIT; diff --git a/src/backenddb/pg_activate_reserve.c b/src/backenddb/pg_activate_reserve.c deleted file mode 100644 index d7a4ff48..00000000 --- a/src/backenddb/pg_activate_reserve.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_activate_reserve.c - * @brief Implementation of the activate_reserve function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_activate_reserve.h" -#include "pg_helper.h" - - -enum GNUNET_DB_QueryStatus -TMH_PG_activate_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *initial_exchange_balance) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - TALER_PQ_query_param_amount_with_currency (pg->conn, - initial_exchange_balance), - GNUNET_PQ_query_param_end - }; - - PREPARE (pg, - "activate_reserve", - "UPDATE merchant_reward_reserves SET" - " exchange_initial_balance=$3" - " WHERE reserve_pub=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "activate_reserve", - params); -} diff --git a/src/backenddb/pg_activate_reserve.h b/src/backenddb/pg_activate_reserve.h deleted file mode 100644 index 3b7c8a3d..00000000 --- a/src/backenddb/pg_activate_reserve.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_activate_reserve.h - * @brief implementation of the activate_reserve function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_ACTIVATE_RESERVE_H -#define PG_ACTIVATE_RESERVE_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - - -/** - * Confirms @a credit as the amount the exchange claims to have received and - * thus really 'activates' the reserve. This has to happen before rewards can - * be authorized. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance is the reserve tied to - * @param reserve_pub which reserve is topped up or created - * @param initial_exchange_balance how much money was be added to the reserve - * according to the exchange - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - */ -enum GNUNET_DB_QueryStatus -TMH_PG_activate_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *initial_exchange_balance); - -#endif diff --git a/src/backenddb/pg_authorize_reward.c b/src/backenddb/pg_authorize_reward.c deleted file mode 100644 index 5038f4fa..00000000 --- a/src/backenddb/pg_authorize_reward.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_authorize_reward.c - * @brief Implementation of the authorize_reward function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_authorize_reward.h" -#include "pg_helper.h" - - -/** - * How often do we re-try if we run into a DB serialization error? - */ -#define MAX_RETRIES 3 - - -/** - * Closure for #lookup_reserve_for_reward_cb(). - */ -struct LookupReserveForRewardContext -{ - /** - * Postgres context. - */ - struct PostgresClosure *pg; - - /** - * Public key of the reserve we found. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * How much money must be left in the reserve. - */ - struct TALER_Amount required_amount; - - /** - * Set to the expiration time of the reserve we found. - * #GNUNET_TIME_UNIT_FOREVER_ABS if we found none. - */ - struct GNUNET_TIME_Timestamp expiration; - - /** - * Error status. - */ - enum TALER_ErrorCode ec; - - /** - * Did we find a good reserve? - */ - bool ok; -}; - - -/** - * How long must a reserve be at least still valid before we use - * it for a reward? - */ -#define MIN_EXPIRATION GNUNET_TIME_UNIT_HOURS - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about accounts. - * - * @param[in,out] cls of type `struct LookupReserveForRewardContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_reserve_for_reward_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupReserveForRewardContext *lac = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_Amount committed_amount; - struct TALER_Amount remaining; - struct TALER_Amount initial_balance; - struct GNUNET_TIME_Timestamp expiration; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - &reserve_pub), - TALER_PQ_result_spec_amount_with_currency ("exchange_initial_balance", - &initial_balance), - TALER_PQ_result_spec_amount_with_currency ("rewards_committed", - &committed_amount), - GNUNET_PQ_result_spec_timestamp ("expiration", - &expiration), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - lac->ec = TALER_EC_GENERIC_DB_FETCH_FAILED; - return; - } - if ( (GNUNET_YES != - TALER_amount_cmp_currency (&initial_balance, - &committed_amount)) || - (GNUNET_YES != - TALER_amount_cmp_currency (&initial_balance, - &lac->required_amount)) ) - { - /* insufficient balance */ - if (lac->ok) - continue; /* got another reserve */ - lac->ec = TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH; - continue; - } - if (0 > - TALER_amount_subtract (&remaining, - &initial_balance, - &committed_amount)) - { - GNUNET_break (0); - continue; - } - if (0 > - TALER_amount_cmp (&remaining, - &lac->required_amount)) - { - /* insufficient balance */ - if (lac->ok) - continue; /* got another reserve */ - lac->ec = - TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS; - continue; - } - if ( (! GNUNET_TIME_absolute_is_never (lac->expiration.abs_time)) && - GNUNET_TIME_timestamp_cmp (expiration, - >, - lac->expiration) && - GNUNET_TIME_relative_cmp ( - GNUNET_TIME_absolute_get_remaining (lac->expiration.abs_time), - >, - MIN_EXPIRATION) ) - { - /* reserve expired */ - if (lac->ok) - continue; /* got another reserve */ - lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED; - continue; - } - lac->ok = true; - lac->ec = TALER_EC_NONE; - lac->expiration = expiration; - lac->reserve_pub = reserve_pub; - } -} - - -enum TALER_ErrorCode -TMH_PG_authorize_reward (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - const char *justification, - const char *next_url, - struct TALER_RewardIdentifierP *reward_id, - struct GNUNET_TIME_Timestamp *expiration) -{ - struct PostgresClosure *pg = cls; - unsigned int retries = 0; - enum GNUNET_DB_QueryStatus qs; - struct TALER_Amount rewards_committed; - struct TALER_Amount exchange_initial_balance; - const struct TALER_ReservePublicKeyP *reserve_pubp; - struct LookupReserveForRewardContext lac = { - .pg = pg, - .required_amount = *amount, - .expiration = GNUNET_TIME_UNIT_FOREVER_TS - }; - - check_connection (pg); - PREPARE (pg, - "lookup_reserve_for_reward", - "SELECT" - " reserve_pub" - ",expiration" - ",exchange_initial_balance" - ",rewards_committed" - " FROM merchant_reward_reserves" - " WHERE" - " merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - PREPARE (pg, - "lookup_reserve_status", - "SELECT" - " expiration" - ",exchange_initial_balance" - ",rewards_committed" - " FROM merchant_reward_reserves" - " WHERE reserve_pub = $2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - PREPARE (pg, - "update_reserve_rewards_committed", - "UPDATE merchant_reward_reserves SET" - " rewards_committed=$3" - " WHERE reserve_pub=$2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - PREPARE (pg, - "insert_reward", - "INSERT INTO merchant_rewards" - "(reserve_serial" - ",reward_id" - ",justification" - ",next_url" - ",expiration" - ",amount" - ",picked_up" - ") " - "SELECT" - " reserve_serial, $3, $4, $5, $6, $7, $8" - " FROM merchant_reward_reserves" - " WHERE reserve_pub=$2" - " AND merchant_serial = " - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); -RETRY: - reserve_pubp = reserve_pub; - if (MAX_RETRIES < ++retries) - { - GNUNET_break (0); - return - TALER_EC_GENERIC_DB_SOFT_FAILURE; - } - if (GNUNET_OK != - TMH_PG_start (pg, - "authorize reward")) - { - GNUNET_break (0); - return TALER_EC_GENERIC_DB_START_FAILED; - } - if (NULL == reserve_pubp) - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_reserve_for_reward", - params, - &lookup_reserve_for_reward_cb, - &lac); - switch (qs) - { - case GNUNET_DB_STATUS_SOFT_ERROR: - TMH_PG_rollback (pg); - goto RETRY; - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_DB_FETCH_FAILED; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - TMH_PG_rollback (pg); - return TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - default: - break; - } - if (TALER_EC_NONE != lac.ec) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Enabling reward reserved failed with status %d\n", - lac.ec); - TMH_PG_rollback (pg); - return lac.ec; - } - GNUNET_assert (lac.ok); - reserve_pubp = &lac.reserve_pub; - } - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pubp), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_timestamp ("expiration", - expiration), - TALER_PQ_result_spec_amount_with_currency ("rewards_committed", - &rewards_committed), - TALER_PQ_result_spec_amount_with_currency ("exchange_initial_balance", - &exchange_initial_balance), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_reserve_status", - params, - rs); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_PG_rollback (pg); - goto RETRY; - } - if (qs < 0) - { - GNUNET_break (0); - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_DB_FETCH_FAILED; - } - if (0 == qs) - { - TMH_PG_rollback (pg); - return TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND; - } - } - { - struct TALER_Amount remaining; - - if (0 > - TALER_amount_subtract (&remaining, - &exchange_initial_balance, - &rewards_committed)) - { - GNUNET_break (0); - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_DB_INVARIANT_FAILURE; - } - if (GNUNET_YES != - TALER_amount_cmp_currency (&remaining, - amount)) - { - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_CURRENCY_MISMATCH; - } - - if (0 > - TALER_amount_cmp (&remaining, - amount)) - { - TMH_PG_rollback (pg); - return TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS; - } - } - GNUNET_assert (0 <= - TALER_amount_add (&rewards_committed, - &rewards_committed, - amount)); - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pubp), - TALER_PQ_query_param_amount_with_currency (pg->conn, - &rewards_committed), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_reserve_rewards_committed", - params); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_PG_rollback (pg); - goto RETRY; - } - if (qs < 0) - { - GNUNET_break (0); - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_DB_STORE_FAILED; - } - } - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - reward_id, - sizeof (*reward_id)); - { - struct TALER_Amount zero; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pubp), - GNUNET_PQ_query_param_auto_from_type (reward_id), - GNUNET_PQ_query_param_string (justification), - GNUNET_PQ_query_param_string (next_url), - GNUNET_PQ_query_param_timestamp (expiration), - TALER_PQ_query_param_amount_with_currency (pg->conn, - amount), - TALER_PQ_query_param_amount_with_currency (pg->conn, - &zero), - GNUNET_PQ_query_param_end - }; - - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (amount->currency, - &zero)); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_reward", - params); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_PG_rollback (pg); - goto RETRY; - } - if (qs < 0) - { - GNUNET_break (0); - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_DB_STORE_FAILED; - } - } - qs = TMH_PG_commit (pg); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - if (qs < 0) - { - GNUNET_break (0); - TMH_PG_rollback (pg); - return TALER_EC_GENERIC_DB_COMMIT_FAILED; - } - return TALER_EC_NONE; -} diff --git a/src/backenddb/pg_authorize_reward.h b/src/backenddb/pg_authorize_reward.h deleted file mode 100644 index 4ef56bf3..00000000 --- a/src/backenddb/pg_authorize_reward.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_authorize_reward.h - * @brief implementation of the authorize_reward function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_AUTHORIZE_REWARD_H -#define PG_AUTHORIZE_REWARD_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - - -/** - * Authorize a reward over @a amount from reserve @a reserve_pub. Remember - * the authorization under @a reward_id for later, together with the - * @a justification. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should generate the reward - * @param reserve_pub which reserve is debited, NULL to pick one in the DB - * @param amount how high is the reward (with fees) - * @param justification why was the reward approved - * @param next_url where to send the URL post reward pickup - * @param[out] reward_id set to the unique ID for the reward - * @param[out] expiration set to when the reward expires - * @return transaction status, - * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired - * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known - * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left - * #TALER_EC_GENERIC_DB_START_FAILED on hard DB errors - * #TALER_EC_GENERIC_DB_FETCH_FAILED on hard DB errors - * #TALER_EC_GENERIC_DB_STORE_FAILED on hard DB errors - * #TALER_EC_GENERIC_DB_INVARIANT_FAILURE on hard DB errors - * #TALER_EC_GENERIC_DB_SOFT_FAILURE soft DB errors (client should retry) - * #TALER_EC_NONE upon success - */ -enum TALER_ErrorCode -TMH_PG_authorize_reward (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - const char *justification, - const char *next_url, - struct TALER_RewardIdentifierP *reward_id, - struct GNUNET_TIME_Timestamp *expiration); - - -#endif diff --git a/src/backenddb/pg_delete_reserve.c b/src/backenddb/pg_delete_reserve.c deleted file mode 100644 index f31e7c7a..00000000 --- a/src/backenddb/pg_delete_reserve.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_delete_reserve.c - * @brief Implementation of the delete_reserve function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_delete_reserve.h" -#include "pg_helper.h" - -enum GNUNET_DB_QueryStatus -TMH_PG_delete_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - PREPARE (pg, - "delete_reserve", - "DELETE" - " FROM merchant_reward_reserve_keys" - " WHERE reserve_serial=" - " (SELECT reserve_serial" - " FROM merchant_reward_reserves" - " WHERE reserve_pub=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1))"); - - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "delete_reserve", - params); -} diff --git a/src/backenddb/pg_delete_reserve.h b/src/backenddb/pg_delete_reserve.h deleted file mode 100644 index f3aa2403..00000000 --- a/src/backenddb/pg_delete_reserve.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_delete_reserve.h - * @brief implementation of the delete_reserve function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_DELETE_RESERVE_H -#define PG_DELETE_RESERVE_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Delete a reserve's private key. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance is the reserve tied to - * @param reserve_pub which reserve is to be deleted - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - */ -enum GNUNET_DB_QueryStatus -TMH_PG_delete_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub); - -#endif diff --git a/src/backenddb/pg_insert_pickup.c b/src/backenddb/pg_insert_pickup.c deleted file mode 100644 index 4094d748..00000000 --- a/src/backenddb/pg_insert_pickup.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_insert_pickup.c - * @brief Implementation of the insert_pickup function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_insert_pickup.h" -#include "pg_helper.h" - - -enum GNUNET_DB_QueryStatus -TMH_PG_insert_pickup ( - void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - const struct TALER_Amount *total_picked_up, - const struct TALER_PickupIdentifierP *pickup_id, - const struct TALER_Amount *total_requested) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - - PREPARE (pg, - "insert_pickup", - "INSERT INTO merchant_reward_pickups" - "(reward_serial" - ",pickup_id" - ",amount" - ") " - "SELECT" - " reward_serial, $3, $4" - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " WHERE reward_id=$2" - " AND merchant_serial = " - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - PREPARE (pg, - "update_picked_up_reward", - "UPDATE merchant_rewards SET" - " picked_up=$2" - ",was_picked_up = (CAST($2 AS taler_amount_currency) = amount)" - " WHERE reward_id = $1"); - PREPARE (pg, - "lookup_picked_up_reserve", - "SELECT" - " reserve_serial" - ",rewards_picked_up" - " FROM merchant_reward_reserves" - " JOIN merchant_rewards USING (reserve_serial)" - " WHERE reward_id=$2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - PREPARE (pg, - "update_picked_up_reserve", - "UPDATE merchant_reward_reserves SET" - " rewards_picked_up=$2" - " WHERE reserve_serial = $1"); - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reward_id), - GNUNET_PQ_query_param_auto_from_type (pickup_id), - TALER_PQ_query_param_amount_with_currency (pg->conn, - total_requested), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_pickup", - params); - if (0 > qs) - return qs; - } - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reward_id), - TALER_PQ_query_param_amount_with_currency (pg->conn, - total_picked_up), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_picked_up_reward", - params); - if (0 > qs) - return qs; - } - { - uint64_t reserve_serial; - struct TALER_Amount reserve_picked_up; - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reward_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("reserve_serial", - &reserve_serial), - TALER_PQ_result_spec_amount_with_currency ("rewards_picked_up", - &reserve_picked_up), - GNUNET_PQ_result_spec_end - - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_picked_up_reserve", - params, - rs); - if (0 > qs) - return qs; - } - if (GNUNET_OK != - TALER_amount_cmp_currency (&reserve_picked_up, - total_requested)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - if (0 >= - TALER_amount_add (&reserve_picked_up, - &reserve_picked_up, - total_requested)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&reserve_serial), - TALER_PQ_query_param_amount_with_currency (pg->conn, - &reserve_picked_up), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_picked_up_reserve", - params); - if (0 > qs) - return qs; - } - } - return qs; -} diff --git a/src/backenddb/pg_insert_pickup.h b/src/backenddb/pg_insert_pickup.h deleted file mode 100644 index d9e960c5..00000000 --- a/src/backenddb/pg_insert_pickup.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_insert_pickup.h - * @brief implementation of the insert_pickup function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_INSERT_PICKUP_H -#define PG_INSERT_PICKUP_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - - -/** - * Insert details about a reward pickup operation. The @a total_picked_up - * UPDATES the total amount under the @a reward_id, while the @a - * total_requested is the amount to be associated with this @a pickup_id. - * While there is usually only one pickup event that picks up the entire - * amount, our schema allows for wallets to pick up the amount incrementally - * over mulrewardle pick up operations. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance gave the reward - * @param reward_id the unique ID for the reward - * @param total_picked_up how much was picked up overall at this - * point (includes @a total_requested) - * @param pickup_id unique ID for the operation - * @param total_requested how much is being picked up in this operation - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known - */ -enum GNUNET_DB_QueryStatus -TMH_PG_insert_pickup ( - void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - const struct TALER_Amount *total_picked_up, - const struct TALER_PickupIdentifierP *pickup_id, - const struct TALER_Amount *total_requested); - -#endif diff --git a/src/backenddb/pg_insert_pickup_blind_signature.c b/src/backenddb/pg_insert_pickup_blind_signature.c deleted file mode 100644 index 89d51346..00000000 --- a/src/backenddb/pg_insert_pickup_blind_signature.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_insert_pickup_blind_signature.c - * @brief Implementation of the insert_pickup_blind_signature function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_insert_pickup_blind_signature.h" -#include "pg_helper.h" - -enum GNUNET_DB_QueryStatus -TMH_PG_insert_pickup_blind_signature (void *cls, - const struct TALER_PickupIdentifierP *pickup_id, - uint32_t offset, - const struct TALER_BlindedDenominationSignature *blind_sig) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (pickup_id), - GNUNET_PQ_query_param_uint32 (&offset), - TALER_PQ_query_param_blinded_denom_sig (blind_sig), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - PREPARE (pg, - "insert_pickup_blind_signature", - "INSERT INTO merchant_reward_pickup_signatures" - "(pickup_serial" - ",coin_offset" - ",blind_sig" - ") " - "SELECT" - " pickup_serial, $2, $3" - " FROM merchant_reward_pickups" - " WHERE pickup_id=$1"); - - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_pickup_blind_signature", - params); -} diff --git a/src/backenddb/pg_insert_pickup_blind_signature.h b/src/backenddb/pg_insert_pickup_blind_signature.h deleted file mode 100644 index a4f98275..00000000 --- a/src/backenddb/pg_insert_pickup_blind_signature.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_insert_pickup_blind_signature.h - * @brief implementation of the insert_pickup_blind_signature function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_INSERT_PICKUP_BLIND_SIGNATURE_H -#define PG_INSERT_PICKUP_BLIND_SIGNATURE_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Insert blind signature obtained from the exchange during a - * reward pickup operation. - * - * @param cls closure, typically a connection to the db - * @param pickup_id unique ID for the operation - * @param offset offset of the blind signature for the pickup - * @param blind_sig the blind signature - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known - */ -enum GNUNET_DB_QueryStatus -TMH_PG_insert_pickup_blind_signature (void *cls, - const struct TALER_PickupIdentifierP *pickup_id, - uint32_t offset, - const struct TALER_BlindedDenominationSignature *blind_sig); - -#endif diff --git a/src/backenddb/pg_insert_reserve.c b/src/backenddb/pg_insert_reserve.c deleted file mode 100644 index 173d9304..00000000 --- a/src/backenddb/pg_insert_reserve.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_insert_reserve.c - * @brief Implementation of the insert_reserve function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_insert_reserve.h" -#include "pg_helper.h" - -/** - * How often do we re-try if we run into a DB serialization error? - */ -#define MAX_RETRIES 3 - - -enum TALER_ErrorCode -TMH_PG_insert_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePrivateKeyP *reserve_priv, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_MasterPublicKeyP *master_pub, - const char *exchange_url, - const struct TALER_Amount *initial_balance, - struct GNUNET_TIME_Timestamp expiration) -{ - struct PostgresClosure *pg = cls; - unsigned int retries; - enum GNUNET_DB_QueryStatus qs; - - retries = 0; - check_connection (pg); - PREPARE (pg, - "insert_reserve", - "INSERT INTO merchant_reward_reserves" - "(reserve_pub" - ",merchant_serial" - ",creation_time" - ",expiration" - ",merchant_initial_balance" - ",exchange_initial_balance" - ",rewards_committed" - ",rewards_picked_up" - ")" - "SELECT $2, merchant_serial, $3, $4, $5, $6, $6, $6" - " FROM merchant_instances" - " WHERE merchant_id=$1"); -RETRY: - if (MAX_RETRIES < ++retries) - return TALER_EC_GENERIC_DB_SOFT_FAILURE; - if (GNUNET_OK != - TMH_PG_start (pg, - "insert reserve")) - { - GNUNET_break (0); - return TALER_EC_GENERIC_DB_START_FAILED; - } - - /* Setup reserve */ - { - struct TALER_Amount zero; - struct GNUNET_TIME_Timestamp now; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_timestamp (&now), - GNUNET_PQ_query_param_timestamp (&expiration), - TALER_PQ_query_param_amount_with_currency (pg->conn, - initial_balance), - TALER_PQ_query_param_amount_with_currency (pg->conn, - &zero), - GNUNET_PQ_query_param_end - }; - - now = GNUNET_TIME_timestamp_get (); - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (initial_balance->currency, - &zero)); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_reserve", - params); - if (0 > qs) - { - TMH_PG_rollback (pg); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return qs; - } - } - /* Store private key */ - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_auto_from_type (reserve_priv), - GNUNET_PQ_query_param_string (exchange_url), - GNUNET_PQ_query_param_auto_from_type (master_pub), - GNUNET_PQ_query_param_end - }; - - PREPARE(pg, - "insert_reserve_key", - "INSERT INTO merchant_reward_reserve_keys" - "(reserve_serial" - ",reserve_priv" - ",exchange_url" - ",master_pub" - ")" - "SELECT reserve_serial, $3, $4, $5" - " FROM merchant_reward_reserves" - " WHERE reserve_pub=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_reserve_key", - params); - if (0 > qs) - { - TMH_PG_rollback (pg); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return qs; - } - } - qs = TMH_PG_commit (pg); - if (0 <= qs) - return TALER_EC_NONE; /* success */ - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return qs; -} diff --git a/src/backenddb/pg_insert_reserve.h b/src/backenddb/pg_insert_reserve.h deleted file mode 100644 index 41bae2ce..00000000 --- a/src/backenddb/pg_insert_reserve.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_insert_reserve.h - * @brief implementation of the insert_reserve function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_INSERT_RESERVE_H -#define PG_INSERT_RESERVE_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Add @a credit to a reserve to be used for rewardping. Note that - * this function does not actually perform any wire transfers to - * credit the reserve, it merely tells the merchant backend that - * a reserve now exists. This has to happen before rewards can be - * authorized. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance is the reserve tied to - * @param reserve_priv which reserve is topped up or created - * @param reserve_pub which reserve is topped up or created - * @param master_pub master public key of the exchange - * @param exchange_url what URL is the exchange reachable at where the reserve is located - * @param initial_balance how much money will be added to the reserve - * @param expiration when does the reserve expire? - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - */ -enum TALER_ErrorCode -TMH_PG_insert_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePrivateKeyP *reserve_priv, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_MasterPublicKeyP *master_pub, - const char *exchange_url, - const struct TALER_Amount *initial_balance, - struct GNUNET_TIME_Timestamp expiration); - -#endif diff --git a/src/backenddb/pg_lookup_pending_reserves.c b/src/backenddb/pg_lookup_pending_reserves.c deleted file mode 100644 index f35021c6..00000000 --- a/src/backenddb/pg_lookup_pending_reserves.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_pending_reserves.c - * @brief Implementation of the lookup_pending_reserves function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_pending_reserves.h" -#include "pg_helper.h" - -/** - * Closure for #lookup_pending_reserves_cb. - */ -struct LookupPendingReservesContext -{ - /** - * Postgres context. - */ - struct PostgresClosure *pg; - - /** - * Function to call with the results - */ - TALER_MERCHANTDB_PendingReservesCallback cb; - - /** - * Closure for @e cb - */ - void *cb_cls; - - /** - * Set in case of errors. - */ - enum GNUNET_DB_QueryStatus qs; - -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about accounts. - * - * @param[in,out] cls of type `struct LookupReservesContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_pending_reserves_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupPendingReservesContext *lrc = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_Amount merchant_initial_balance; - char *exchange_url; - char *instance_id; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - &reserve_pub), - GNUNET_PQ_result_spec_string ("merchant_id", - &instance_id), - GNUNET_PQ_result_spec_string ("exchange_url", - &exchange_url), - TALER_PQ_result_spec_amount_with_currency ("merchant_initial_balance", - &merchant_initial_balance), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - lrc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - lrc->cb (lrc->cb_cls, - instance_id, - exchange_url, - &reserve_pub, - &merchant_initial_balance); - GNUNET_PQ_cleanup_result (rs); - } -} - - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_pending_reserves (void *cls, - TALER_MERCHANTDB_PendingReservesCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct LookupPendingReservesContext lrc = { - .pg = pg, - .cb = cb, - .cb_cls = cb_cls - }; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - PREPARE (pg, - "lookup_pending_reserves", - "SELECT" - " reserve_pub" - ",merchant_id" - ",exchange_url" - ",merchant_initial_balance" - " FROM merchant_reward_reserves mrr" - " JOIN merchant_instances USING (merchant_serial)" - " JOIN merchant_reward_reserve_keys USING (reserve_serial)" - " WHERE (mrr.exchange_initial_balance).val=0" - " AND (mrr.exchange_initial_balance).frac=0"); - - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_pending_reserves", - params, - &lookup_pending_reserves_cb, - &lrc); - if (lrc.qs < 0) - return lrc.qs; - return qs; -} diff --git a/src/backenddb/pg_lookup_pending_reserves.h b/src/backenddb/pg_lookup_pending_reserves.h deleted file mode 100644 index 4ffff78f..00000000 --- a/src/backenddb/pg_lookup_pending_reserves.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_pending_reserves.h - * @brief implementation of the lookup_pending_reserves function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_LOOKUP_PENDING_RESERVES_H -#define PG_LOOKUP_PENDING_RESERVES_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Lookup reserves pending activation across all instances. - * - * @param cls closure - * @param cb function to call with reserve summary data - * @param cb_cls closure for @a cb - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_pending_reserves (void *cls, - TALER_MERCHANTDB_PendingReservesCallback cb, - void *cb_cls); - -#endif diff --git a/src/backenddb/pg_lookup_pickup.c b/src/backenddb/pg_lookup_pickup.c deleted file mode 100644 index f10b948b..00000000 --- a/src/backenddb/pg_lookup_pickup.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_pickup.c - * @brief Implementation of the lookup_pickup function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_pickup.h" -#include "pg_helper.h" - -/** - * Closure for #lookup_signatures_cb(). - */ -struct LookupSignaturesContext -{ - /** - * Length of the @e sigs array - */ - unsigned int sigs_length; - - /** - * Where to store the signatures. - */ - struct TALER_BlindedDenominationSignature *sigs; -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about accounts. - * - * @param[in,out] cls of type `struct LookupSignaturesContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_signatures_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupSignaturesContext *lsc = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - uint32_t offset; - struct TALER_BlindedDenominationSignature bsig; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint32 ("coin_offset", - &offset), - TALER_PQ_result_spec_blinded_denom_sig ("blind_sig", - &bsig), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - return; - } - if (offset >= lsc->sigs_length) - { - GNUNET_break_op (0); - GNUNET_PQ_cleanup_result (rs); - continue; - } - /* Must be NULL due to UNIQUE constraint on offset and - requirement that client launched us with 'sigs' - pre-initialized to NULL. */ - lsc->sigs[offset] = bsig; - } -} - - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_pickup (void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - const struct TALER_PickupIdentifierP *pickup_id, - char **exchange_url, - struct TALER_ReservePrivateKeyP *reserve_priv, - unsigned int sigs_length, - struct TALER_BlindedDenominationSignature sigs[]) -{ - struct PostgresClosure *pg = cls; - uint64_t pickup_serial; - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reward_id), - GNUNET_PQ_query_param_auto_from_type (pickup_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_string ("exchange_url", - exchange_url), - GNUNET_PQ_result_spec_auto_from_type ("reserve_priv", - reserve_priv), - GNUNET_PQ_result_spec_uint64 ("pickup_serial", - &pickup_serial), - GNUNET_PQ_result_spec_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - PREPARE (pg, - "lookup_pickup", - "SELECT" - " exchange_url" - ",reserve_priv" - ",pickup_serial" - " FROM merchant_reward_pickups" - " JOIN merchant_rewards USING (reward_serial)" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " JOIN merchant_reward_reserve_keys USING (reserve_serial)" - " WHERE pickup_id = $3" - " AND reward_id = $2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_pickup", - params, - rs); - if (qs <= 0) - return qs; - } - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&pickup_serial), - GNUNET_PQ_query_param_end - }; - struct LookupSignaturesContext lsc = { - .sigs_length = sigs_length, - .sigs = sigs - }; - - PREPARE (pg, - "lookup_pickup_signatures", - "SELECT" - " coin_offset" - ",blind_sig" - " FROM merchant_reward_pickup_signatures" - " WHERE pickup_serial = $1"); - - return GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_pickup_signatures", - params, - &lookup_signatures_cb, - &lsc); - } -} diff --git a/src/backenddb/pg_lookup_pickup.h b/src/backenddb/pg_lookup_pickup.h deleted file mode 100644 index b3814731..00000000 --- a/src/backenddb/pg_lookup_pickup.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_pickup.h - * @brief implementation of the lookup_pickup function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_LOOKUP_PICKUP_H -#define PG_LOOKUP_PICKUP_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Lookup pickup details for pickup @a pickup_id. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup reward details for - * @param reward_id which reward should we lookup details on - * @param pickup_id which pickup should we lookup details on - * @param[out] exchange_url which exchange is the reward withdrawn from - * @param[out] reserve_priv private key the reward is withdrawn from (set if still available!) - * @param sigs_length length of the @a sigs array - * @param[out] sigs set to the (blind) signatures we have for this @a pickup_id, - * those that are unavailable are left at NULL - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_pickup (void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - const struct TALER_PickupIdentifierP *pickup_id, - char **exchange_url, - struct TALER_ReservePrivateKeyP *reserve_priv, - unsigned int sigs_length, - struct TALER_BlindedDenominationSignature sigs[]); - -#endif diff --git a/src/backenddb/pg_lookup_reserve.c b/src/backenddb/pg_lookup_reserve.c deleted file mode 100644 index 392db057..00000000 --- a/src/backenddb/pg_lookup_reserve.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reserve.c - * @brief Implementation of the lookup_reserve function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_reserve.h" -#include "pg_helper.h" - -/** - * Closure for #lookup_reserve_rewards_cb(). - */ -struct LookupRewardsContext -{ - /** - * Postgres context. - */ - struct PostgresClosure *pg; - - /** - * Array with information about rewards generated from this reserve. - */ - struct TALER_MERCHANTDB_RewardDetails *rewards; - - /** - * Length of the @e rewards array. - */ - unsigned int rewards_length; - - /** - * Set in case of errors. - */ - enum GNUNET_DB_QueryStatus qs; -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about accounts. - * - * @param[in,out] cls of type `struct LookupRewardsContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_reserve_rewards_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupRewardsContext *ltc = cls; - - GNUNET_array_grow (ltc->rewards, - ltc->rewards_length, - num_results); - for (unsigned int i = 0; i < num_results; i++) - { - struct TALER_MERCHANTDB_RewardDetails *td = <c->rewards[i]; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_string ("justification", - &td->reason), - GNUNET_PQ_result_spec_auto_from_type ("reward_id", - &td->reward_id), - TALER_PQ_result_spec_amount_with_currency ("amount", - &td->total_amount), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - ltc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - } -} - - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_rewards, - TALER_MERCHANTDB_ReserveDetailsCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct LookupRewardsContext ltc = { - .pg = pg, - .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT - }; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_TIME_Timestamp creation_time; - struct GNUNET_TIME_Timestamp expiration_time; - struct TALER_Amount merchant_initial_balance; - struct TALER_Amount exchange_initial_balance; - struct TALER_Amount pickup_amount; - struct TALER_Amount committed_amount; - struct TALER_MasterPublicKeyP master_pub; - bool active; - char *exchange_url = NULL; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_timestamp ("creation_time", - &creation_time), - GNUNET_PQ_result_spec_timestamp ("expiration", - &expiration_time), - TALER_PQ_result_spec_amount_with_currency ("merchant_initial_balance", - &merchant_initial_balance), - TALER_PQ_result_spec_amount_with_currency ("exchange_initial_balance", - &exchange_initial_balance), - TALER_PQ_result_spec_amount_with_currency ("rewards_picked_up", - &pickup_amount), - TALER_PQ_result_spec_amount_with_currency ("rewards_committed", - &committed_amount), - GNUNET_PQ_result_spec_auto_from_type ("master_pub", - &master_pub), - GNUNET_PQ_result_spec_bool ("active", - &active), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_string ("exchange_url", - &exchange_url), - NULL), - GNUNET_PQ_result_spec_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - PREPARE (pg, - "lookup_reserve", - "SELECT" - " creation_time" - ",expiration" - ",merchant_initial_balance" - ",exchange_initial_balance" - ",rewards_committed" - ",rewards_picked_up" - ",reserve_priv IS NOT NULL AS active" - ",exchange_url" - ",master_pub" - " FROM merchant_reward_reserves" - " FULL OUTER JOIN merchant_reward_reserve_keys USING (reserve_serial)" - " WHERE reserve_pub = $2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_reserve", - params, - rs); - if (qs < 0) - return qs; - if (! fetch_rewards) - { - cb (cb_cls, - creation_time, - expiration_time, - &merchant_initial_balance, - &exchange_initial_balance, - &pickup_amount, - &committed_amount, - active, - &master_pub, - exchange_url, - 0, - NULL); - GNUNET_PQ_cleanup_result (rs); - return qs; - } - - PREPARE (pg, - "lookup_reserve_rewards", - "SELECT" - " justification" - ",reward_id" - ",amount" - " FROM merchant_rewards" - " WHERE reserve_serial =" - " (SELECT reserve_serial" - " FROM merchant_reward_reserves" - " WHERE reserve_pub=$2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1))"); - - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_reserve_rewards", - params, - &lookup_reserve_rewards_cb, - <c); - if (qs < 0) - return qs; - if (ltc.qs >= 0) - { - cb (cb_cls, - creation_time, - expiration_time, - &merchant_initial_balance, - &exchange_initial_balance, - &pickup_amount, - &committed_amount, - active, - &master_pub, - exchange_url, - ltc.rewards_length, - ltc.rewards); - } - for (unsigned int i = 0; i<ltc.rewards_length; i++) - GNUNET_free (ltc.rewards[i].reason); - GNUNET_array_grow (ltc.rewards, - ltc.rewards_length, - 0); - GNUNET_PQ_cleanup_result (rs); - return ltc.qs; -} diff --git a/src/backenddb/pg_lookup_reserve.h b/src/backenddb/pg_lookup_reserve.h deleted file mode 100644 index 53bb05f8..00000000 --- a/src/backenddb/pg_lookup_reserve.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reserve.h - * @brief implementation of the lookup_reserve function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_LOOKUP_RESERVE_H -#define PG_LOOKUP_RESERVE_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Lookup reserve details. - * - * @param cls closure - * @param instance_id instance to lookup payments for - * @param reserve_pub public key of the reserve to inspect - * @param fetch_rewards if true, also return information about rewards - * @param cb function to call with reserve summary data - * @param cb_cls closure for @a cb - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_rewards, - TALER_MERCHANTDB_ReserveDetailsCallback cb, - void *cb_cls); - -#endif diff --git a/src/backenddb/pg_lookup_reserves.c b/src/backenddb/pg_lookup_reserves.c deleted file mode 100644 index 48601e5b..00000000 --- a/src/backenddb/pg_lookup_reserves.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reserves.c - * @brief Implementation of the lookup_reserves function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_reserves.h" -#include "pg_helper.h" - - -/** - * Closure for #lookup_reserves_cb. - */ -struct LookupReservesContext -{ - /** - * Postgres context. - */ - struct PostgresClosure *pg; - - /** - * Function to call with the results - */ - TALER_MERCHANTDB_ReservesCallback cb; - - /** - * Closure for @e cb - */ - void *cb_cls; - - /** - * Filter by active reserves. - */ - enum TALER_EXCHANGE_YesNoAll active; - - /** - * Filter by failures (mismatch in exchange claimed and - * merchant claimed initial amounts). - */ - enum TALER_EXCHANGE_YesNoAll failures; - - /** - * Set in case of errors. - */ - enum GNUNET_DB_QueryStatus qs; - -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about accounts. - * - * @param[in,out] cls of type `struct LookupReservesContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_reserves_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupReservesContext *lrc = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - struct TALER_ReservePublicKeyP reserve_pub; - struct GNUNET_TIME_Timestamp creation_time; - struct GNUNET_TIME_Timestamp expiration_time; - struct TALER_Amount merchant_initial_balance; - struct TALER_Amount exchange_initial_balance; - struct TALER_Amount pickup_amount; - struct TALER_Amount committed_amount; - uint8_t active; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - &reserve_pub), - GNUNET_PQ_result_spec_timestamp ("creation_time", - &creation_time), - GNUNET_PQ_result_spec_timestamp ("expiration", - &expiration_time), - TALER_PQ_result_spec_amount_with_currency ("merchant_initial_balance", - &merchant_initial_balance), - TALER_PQ_result_spec_amount_with_currency ("exchange_initial_balance", - &exchange_initial_balance), - TALER_PQ_result_spec_amount_with_currency ("rewards_committed", - &committed_amount), - TALER_PQ_result_spec_amount_with_currency ("rewards_picked_up", - &pickup_amount), - GNUNET_PQ_result_spec_auto_from_type ("active", - &active), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - lrc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - switch (lrc->active) - { - case TALER_EXCHANGE_YNA_YES: - if (0 == active) - continue; - break; - case TALER_EXCHANGE_YNA_NO: - if (0 != active) - continue; - break; - case TALER_EXCHANGE_YNA_ALL: - break; - } - switch (lrc->failures) - { - case TALER_EXCHANGE_YNA_YES: - if (0 == - TALER_amount_cmp (&merchant_initial_balance, - &exchange_initial_balance)) - continue; - break; - case TALER_EXCHANGE_YNA_NO: - if (0 != - TALER_amount_cmp (&merchant_initial_balance, - &exchange_initial_balance)) - continue; - break; - case TALER_EXCHANGE_YNA_ALL: - break; - } - lrc->cb (lrc->cb_cls, - &reserve_pub, - creation_time, - expiration_time, - &merchant_initial_balance, - &exchange_initial_balance, - &pickup_amount, - &committed_amount, - (0 != active)); - } -} - - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reserves (void *cls, - const char *instance_id, - struct GNUNET_TIME_Timestamp created_after, - enum TALER_EXCHANGE_YesNoAll active, - enum TALER_EXCHANGE_YesNoAll failures, - TALER_MERCHANTDB_ReservesCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct LookupReservesContext lrc = { - .pg = pg, - .active = active, - .failures = failures, - .cb = cb, - .cb_cls = cb_cls - }; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_timestamp (&created_after), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - PREPARE (pg, - "lookup_reserves", - "SELECT" - " reserve_pub" - ",creation_time" - ",expiration" - ",merchant_initial_balance" - ",exchange_initial_balance" - ",rewards_committed" - ",rewards_picked_up" - ",reserve_priv IS NOT NULL AS active" - " FROM merchant_reward_reserves" - " FULL OUTER JOIN merchant_reward_reserve_keys USING (reserve_serial)" - " WHERE creation_time > $2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_reserves", - params, - &lookup_reserves_cb, - &lrc); - if (lrc.qs < 0) - return lrc.qs; - return qs; -} diff --git a/src/backenddb/pg_lookup_reserves.h b/src/backenddb/pg_lookup_reserves.h deleted file mode 100644 index bf16edc1..00000000 --- a/src/backenddb/pg_lookup_reserves.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reserves.h - * @brief implementation of the lookup_reserves function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_LOOKUP_RESERVES_H -#define PG_LOOKUP_RESERVES_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - - -/** - * Lookup reserves. - * - * @param cls closure - * @param instance_id instance to lookup payments for - * @param created_after filter by reserves created after this date - * @param active filter by active reserves - * @param failures filter by reserves with a disagreement on the initial balance - * @param cb function to call with reserve summary data - * @param cb_cls closure for @a cb - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reserves (void *cls, - const char *instance_id, - struct GNUNET_TIME_Timestamp created_after, - enum TALER_EXCHANGE_YesNoAll active, - enum TALER_EXCHANGE_YesNoAll failures, - TALER_MERCHANTDB_ReservesCallback cb, - void *cb_cls); - - -#endif diff --git a/src/backenddb/pg_lookup_reward.c b/src/backenddb/pg_lookup_reward.c deleted file mode 100644 index cb887586..00000000 --- a/src/backenddb/pg_lookup_reward.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reward.c - * @brief Implementation of the lookup_reward function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_reward.h" -#include "pg_helper.h" - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reward (void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - struct TALER_Amount *total_authorized, - struct TALER_Amount *total_picked_up, - struct GNUNET_TIME_Timestamp *expiration, - char **exchange_url, - char **next_url, - struct TALER_ReservePrivateKeyP *reserve_priv) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reward_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_amount_with_currency ("amount", - total_authorized), - TALER_PQ_result_spec_amount_with_currency ("picked_up", - total_picked_up), - GNUNET_PQ_result_spec_timestamp ("expiration", - expiration), - GNUNET_PQ_result_spec_string ("exchange_url", - exchange_url), - GNUNET_PQ_result_spec_string ("next_url", - next_url), - GNUNET_PQ_result_spec_auto_from_type ("reserve_priv", - reserve_priv), - GNUNET_PQ_result_spec_end - }; - - check_connection (pg); - PREPARE (pg, - "lookup_reward", - "SELECT" - " amount" - ",picked_up" - ",merchant_rewards.expiration" - ",exchange_url" - ",next_url" - ",reserve_priv" - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " JOIN merchant_reward_reserve_keys USING (reserve_serial)" - " WHERE reward_id = $2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_reward", - params, - rs); -} diff --git a/src/backenddb/pg_lookup_reward.h b/src/backenddb/pg_lookup_reward.h deleted file mode 100644 index fc23c9ea..00000000 --- a/src/backenddb/pg_lookup_reward.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reward.h - * @brief implementation of the lookup_reward function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_LOOKUP_REWARD_H -#define PG_LOOKUP_REWARD_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Lookup reward details for reward @a reward_id. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup reward details for - * @param reward_id which reward should we lookup details on - * @param[out] total_authorized amount how high is the reward (with fees) - * @param[out] total_picked_up how much of the reward was so far picked up (with fees) - * @param[out] expiration set to when the reward expires - * @param[out] exchange_url set to the exchange URL where the reserve is - * @param[out] next_url set to the URL where the wallet should navigate after getting the reward - * @param[out] reserve_priv set to private key of reserve to be debited - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reward (void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - struct TALER_Amount *total_authorized, - struct TALER_Amount *total_picked_up, - struct GNUNET_TIME_Timestamp *expiration, - char **exchange_url, - char **next_url, - struct TALER_ReservePrivateKeyP *reserve_priv); - -#endif diff --git a/src/backenddb/pg_lookup_reward_details.c b/src/backenddb/pg_lookup_reward_details.c deleted file mode 100644 index 062fbdd4..00000000 --- a/src/backenddb/pg_lookup_reward_details.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reward_details.c - * @brief Implementation of the lookup_reward_details function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_reward_details.h" -#include "pg_helper.h" - -/** - * Closure for #lookup_pickup_details_cb(). - */ -struct LookupRewardDetailsContext -{ - /** - * Length of the @e sigs array - */ - unsigned int *pickups_length; - - /** - * Where to store the signatures. - */ - struct TALER_MERCHANTDB_PickupDetails **pickups; - - /** - * Database handle. - */ - struct PostgresClosure *pg; - - /** - * Transaction status. - */ - enum GNUNET_DB_QueryStatus qs; - -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about pickups. - * - * @param[in,out] cls of type `struct LookupRewardDetailsContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_pickup_details_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupRewardDetailsContext *ltdc = cls; - - *ltdc->pickups_length = num_results; - *ltdc->pickups = GNUNET_new_array (num_results, - struct TALER_MERCHANTDB_PickupDetails); - for (unsigned int i = 0; i < num_results; i++) - { - struct TALER_MERCHANTDB_PickupDetails *pd = &((*ltdc->pickups)[i]); - uint64_t num_planchets = 0; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("pickup_id", - &pd->pickup_id), - TALER_PQ_result_spec_amount_with_currency ("amount", - &pd->requested_amount), - GNUNET_PQ_result_spec_uint64 ("num_planchets", - &num_planchets), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR; - GNUNET_array_grow (*ltdc->pickups, - *ltdc->pickups_length, - 0); - return; - } - - pd->num_planchets = num_planchets; - } -} - - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reward_details (void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - bool fpu, - struct TALER_Amount *total_authorized, - struct TALER_Amount *total_picked_up, - char **justification, - struct GNUNET_TIME_Timestamp *expiration, - struct TALER_ReservePublicKeyP *reserve_pub, - unsigned int *pickups_length, - struct TALER_MERCHANTDB_PickupDetails **pickups) -{ - struct PostgresClosure *pg = cls; - uint64_t reward_serial; - enum GNUNET_DB_QueryStatus qs; - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reward_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("reward_serial", - &reward_serial), - TALER_PQ_result_spec_amount_with_currency ("amount", - total_authorized), - TALER_PQ_result_spec_amount_with_currency ("picked_up", - total_picked_up), - GNUNET_PQ_result_spec_string ("justification", - justification), - GNUNET_PQ_result_spec_timestamp ("expiration", - expiration), - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - reserve_pub), - GNUNET_PQ_result_spec_end - }; - - check_connection (pg); - PREPARE (pg, - "lookup_reward_details", - "SELECT" - " reward_serial" - ",amount" - ",picked_up" - ",justification" - ",merchant_rewards.expiration" - ",reserve_pub" - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " WHERE reward_id = $2" - " AND merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_reward_details", - params, - rs); - if (qs <= 0) - return qs; - if (! fpu) - { - *pickups_length = 0; - *pickups = NULL; - return qs; - } - } - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&reward_serial), - GNUNET_PQ_query_param_end - }; - - struct LookupRewardDetailsContext ltdc = { - .pickups_length = pickups_length, - .pickups = pickups, - .pg = pg, - .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT - }; - - PREPARE (pg, - "lookup_pickup_details", - "SELECT" - " pickup_id" - ",amount" - ",COUNT(blind_sig) AS num_planchets" - " FROM merchant_reward_pickups" - " JOIN merchant_reward_pickup_signatures USING (pickup_serial)" - " WHERE reward_serial = $1" - " GROUP BY pickup_serial"); - - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_pickup_details", - params, - &lookup_pickup_details_cb, - <dc); - if (qs < 0) - return qs; - return ltdc.qs; - } -} diff --git a/src/backenddb/pg_lookup_reward_details.h b/src/backenddb/pg_lookup_reward_details.h deleted file mode 100644 index 61ff301f..00000000 --- a/src/backenddb/pg_lookup_reward_details.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_reward_details.h - * @brief implementation of the lookup_reward_details function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_LOOKUP_REWARD_DETAILS_H -#define PG_LOOKUP_REWARD_DETAILS_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Lookup reward details for reward @a reward_id. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup reward details for - * @param reward_id which reward should we lookup details on - * @param fpu should we fetch details about individual pickups - * @param[out] total_authorized amount how high is the reward (with fees) - * @param[out] total_picked_up how much of the reward was so far picked up (with fees) - * @param[out] justification why was the reward approved - * @param[out] expiration set to when the reward expires - * @param[out] reserve_pub set to which reserve is debited - * @param[out] pickups_length set to the length of @e pickups - * @param[out] pickups if @a fpu is true, set to details about the pickup operations - * @return transaction status, - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_reward_details (void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - bool fpu, - struct TALER_Amount *total_authorized, - struct TALER_Amount *total_picked_up, - char **justification, - struct GNUNET_TIME_Timestamp *expiration, - struct TALER_ReservePublicKeyP *reserve_pub, - unsigned int *pickups_length, - struct TALER_MERCHANTDB_PickupDetails **pickups); - -#endif diff --git a/src/backenddb/pg_lookup_rewards.c b/src/backenddb/pg_lookup_rewards.c deleted file mode 100644 index 4914ad58..00000000 --- a/src/backenddb/pg_lookup_rewards.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_rewards.c - * @brief Implementation of the lookup_rewards function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_lookup_rewards.h" -#include "pg_helper.h" - -/** - * Context used for postgres_lookup_rewards(). - */ -struct LookupMerchantRewardsContext -{ - /** - * Postgres context. - */ - struct PostgresClosure *pg; - - /** - * Function to call with the results. - */ - TALER_MERCHANTDB_RewardsCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Internal result. - */ - enum GNUNET_DB_QueryStatus qs; -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about rewards. - * - * @param[in,out] cls of type `struct LookupRewardsContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_rewards_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupMerchantRewardsContext *plc = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - uint64_t row_id; - struct TALER_RewardIdentifierP reward_id; - struct TALER_Amount reward_amount; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("reward_serial", - &row_id), - GNUNET_PQ_result_spec_auto_from_type ("reward_id", - &reward_id), - TALER_PQ_result_spec_amount_with_currency ("amount", - &reward_amount), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - plc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - plc->cb (plc->cb_cls, - row_id, - reward_id, - reward_amount); - GNUNET_PQ_cleanup_result (rs); - } -} - - -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_rewards (void *cls, - const char *instance_id, - enum TALER_EXCHANGE_YesNoAll expired, - int64_t limit, - uint64_t offset, - TALER_MERCHANTDB_RewardsCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct LookupMerchantRewardsContext plc = { - .pg = pg, - .cb = cb, - .cb_cls = cb_cls - }; - uint64_t ulimit = (limit > 0) ? limit : -limit; - uint8_t bexpired; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_uint64 (&ulimit), - GNUNET_PQ_query_param_uint64 (&offset), - GNUNET_PQ_query_param_absolute_time (&now), - GNUNET_PQ_query_param_auto_from_type (&bexpired), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - char stmt[128]; - - bexpired = (TALER_EXCHANGE_YNA_YES == expired); - GNUNET_snprintf (stmt, - sizeof (stmt), - "lookup_rewards_%s%s", - (limit > 0) ? "inc" : "dec", - (TALER_EXCHANGE_YNA_ALL == expired) ? "" : "_expired"); - - check_connection (pg); - PREPARE (pg, - "lookup_rewards_inc", - "SELECT" - " reward_serial" - ",reward_id" - ",amount" - ",CAST($4 as BIGINT)" /* otherwise $4 is unused and Postgres unhappy */ - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " WHERE merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " reward_serial > $3" - " ORDER BY reward_serial ASC" - " LIMIT $2"); - PREPARE (pg, - "lookup_rewards_dec", - "SELECT" - " reward_serial" - ",reward_id" - ",amount" - ",CAST($4 as BIGINT)" /* otherwise $4 is unused and Postgres unhappy */ - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " WHERE merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " reward_serial < $3" - " ORDER BY reward_serial DESC" - " LIMIT $2"); - PREPARE (pg, - "lookup_rewards_inc_expired", - "SELECT" - " reward_serial" - ",reward_id" - ",amount" - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " WHERE merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " reward_serial > $3" - " AND" - " CAST($5 as BOOL) = (merchant_rewards.expiration < $4)" - " ORDER BY reward_serial ASC" - " LIMIT $2"); - PREPARE (pg, - "lookup_rewards_dec_expired", - "SELECT" - " reward_serial" - ",reward_id" - ",amount" - " FROM merchant_rewards" - " JOIN merchant_reward_reserves USING (reserve_serial)" - " WHERE merchant_serial =" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " reward_serial < $3" - " AND" - " CAST($5 as BOOL) = (merchant_rewards.expiration < $4)" - " ORDER BY reward_serial DESC" - " LIMIT $2"); - - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - stmt, - params, - &lookup_rewards_cb, - &plc); - if (0 != plc.qs) - return plc.qs; - return qs; -} diff --git a/src/backenddb/pg_lookup_rewards.h b/src/backenddb/pg_lookup_rewards.h deleted file mode 100644 index a4fc61ec..00000000 --- a/src/backenddb/pg_lookup_rewards.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_lookup_rewards.h - * @brief implementation of the lookup_rewards function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_LOOKUP_REWARDS_H -#define PG_LOOKUP_REWARDS_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Lookup rewards - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup rewards for - * @param expired should we include expired rewards? - * @param limit maximum number of results to return, positive for - * ascending row id, negative for descending - * @param offset row id to start returning results from - * @param cb function to call with reward data - * @param cb_cls closure for @a cb - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TMH_PG_lookup_rewards (void *cls, - const char *instance_id, - enum TALER_EXCHANGE_YesNoAll expired, - int64_t limit, - uint64_t offset, - TALER_MERCHANTDB_RewardsCallback cb, - void *cb_cls); - -#endif diff --git a/src/backenddb/pg_purge_reserve.c b/src/backenddb/pg_purge_reserve.c deleted file mode 100644 index cb01069a..00000000 --- a/src/backenddb/pg_purge_reserve.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_purge_reserve.c - * @brief Implementation of the purge_reserve function for Postgres - * @author Iván Ávalos - */ -#include "platform.h" -#include <taler/taler_error_codes.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_pq_lib.h> -#include "pg_purge_reserve.h" -#include "pg_helper.h" - -enum GNUNET_DB_QueryStatus -TMH_PG_purge_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - PREPARE (pg, - "purge_reserve", - "DELETE" - " FROM merchant_reward_reserves" - " WHERE reserve_pub=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"); - - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "purge_reserve", - params); -} diff --git a/src/backenddb/pg_purge_reserve.h b/src/backenddb/pg_purge_reserve.h deleted file mode 100644 index 83c1b44f..00000000 --- a/src/backenddb/pg_purge_reserve.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file backenddb/pg_purge_reserve.h - * @brief implementation of the purge_reserve function for Postgres - * @author Iván Ávalos - */ -#ifndef PG_PURGE_RESERVE_H -#define PG_PURGE_RESERVE_H - -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler_merchantdb_plugin.h" - -/** - * Purge all of the information about a reserve, including rewards. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance is the reserve tied to - * @param reserve_pub which reserve is to be purged - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - */ -enum GNUNET_DB_QueryStatus -TMH_PG_purge_reserve (void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub); - -#endif diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 40fb1d19..e09b4827 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -50,7 +50,6 @@ #include "pg_delete_exchange_accounts.h" #include "pg_select_accounts_by_exchange.h" #include "pg_insert_exchange_account.h" -#include "pg_lookup_reserves.h" #include "pg_lookup_instance_auth.h" #include "pg_lookup_otp_devices.h" #include "pg_update_transfer_status.h" @@ -113,15 +112,6 @@ #include "pg_lookup_transfer.h" #include "pg_lookup_transfer_summary.h" #include "pg_lookup_transfer_details.h" -#include "pg_lookup_pending_reserves.h" -#include "pg_lookup_reserve.h" -#include "pg_delete_reserve.h" -#include "pg_purge_reserve.h" -#include "pg_lookup_pickup.h" -#include "pg_lookup_reward.h" -#include "pg_lookup_rewards.h" -#include "pg_lookup_reward_details.h" -#include "pg_insert_pickup_blind_signature.h" #include "pg_lookup_webhooks.h" #include "pg_lookup_webhook.h" #include "pg_delete_webhook.h" @@ -143,10 +133,6 @@ #include "pg_insert_transfer.h" #include "pg_insert_transfer_details.h" #include "pg_store_wire_fee_by_exchange.h" -#include "pg_insert_reserve.h" -#include "pg_activate_reserve.h" -#include "pg_authorize_reward.h" -#include "pg_insert_pickup.h" #include "pg_insert_token_family.h" #include "pg_lookup_token_family.h" #include "pg_lookup_token_families.h" @@ -225,7 +211,7 @@ postgres_create_tables (void *cls) * @param es specification of the event to listen for * @param timeout how long to wait for the event * @param cb function to call when the event happens, possibly - * mulrewardle times (until cancel is invoked) + * multiple times (until cancel is invoked) * @param cb_cls closure for @a cb * @return handle useful to cancel the listener */ @@ -533,26 +519,6 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) = &TMH_PG_select_account; plugin->select_accounts = &TMH_PG_select_accounts; - plugin->lookup_reserves - = &TMH_PG_lookup_reserves; - plugin->lookup_pending_reserves - = &TMH_PG_lookup_pending_reserves; - plugin->lookup_reserve - = &TMH_PG_lookup_reserve; - plugin->delete_reserve - = &TMH_PG_delete_reserve; - plugin->purge_reserve - = &TMH_PG_purge_reserve; - plugin->lookup_pickup - = &TMH_PG_lookup_pickup; - plugin->lookup_reward - = &TMH_PG_lookup_reward; - plugin->lookup_rewards - = &TMH_PG_lookup_rewards; - plugin->lookup_reward_details - = &TMH_PG_lookup_reward_details; - plugin->insert_pickup_blind_signature - = &TMH_PG_insert_pickup_blind_signature; plugin->select_open_transfers = &TMH_PG_select_open_transfers; plugin->insert_exchange_keys @@ -567,14 +533,6 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) = &TMH_PG_insert_transfer_details; plugin->store_wire_fee_by_exchange = &TMH_PG_store_wire_fee_by_exchange; - plugin->insert_reserve - = &TMH_PG_insert_reserve; - plugin->activate_reserve - = &TMH_PG_activate_reserve; - plugin->authorize_reward - = &TMH_PG_authorize_reward; - plugin->insert_pickup - = &TMH_PG_insert_pickup; plugin->lookup_webhooks = &TMH_PG_lookup_webhooks; plugin->lookup_webhook diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c index dbec520b..2b9368f1 100644 --- a/src/backenddb/test_merchantdb.c +++ b/src/backenddb/test_merchantdb.c @@ -2029,7 +2029,7 @@ run_test_orders (struct TestOrders_Closure *cls) return 1; } } - /* Test lookups on mulrewardle orders */ + /* Test lookups on multiple orders */ TEST_RET_ON_FAIL (test_insert_order (&cls->instance, &cls->orders[1], GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); @@ -3131,7 +3131,7 @@ run_test_deposits (struct TestDeposits_Closure *cls) &cls->deposits[0].coin_pub, 1, cls->deposits)); - /* Test mulrewardle deposits */ + /* Test multiple deposits */ TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance, &cls->signkey, &cls->deposits[1], @@ -4349,1313 +4349,6 @@ test_transfers (void) } -/* Reserves and rewards */ - - -struct ReserveData -{ - /** - * The reserve public key - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * The reserve private key - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * The reserve initial amount - */ - struct TALER_Amount initial_amount; - - /** - * The exchange url - */ - const char *exchange_url; - - /** - * The exchange master public key. - */ - struct TALER_MasterPublicKeyP master_pub; - - /** - * The expiration date - */ - struct GNUNET_TIME_Timestamp expiration; -}; - - -/** - * Tests inserting a reserve into the database. - * @paper instance the instance the reserve is for. - * @param reserve the reserve to insert. - * @param expected_result the result we expect to receive from the db. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_insert_reserve (const struct InstanceData *instance, - const struct ReserveData *reserve, - enum TALER_ErrorCode expected_result) -{ - TEST_COND_RET_ON_FAIL (expected_result == - plugin->insert_reserve (plugin->cls, - instance->instance.id, - &reserve->reserve_priv, - &reserve->reserve_pub, - &reserve->master_pub, - reserve->exchange_url, - &reserve->initial_amount, - reserve->expiration), - "Insert reserve failed\n"); - return 0; -} - - -/** - * Container for looking up reserves. - */ -struct TestLookupReserve_Closure -{ - /** - * The reserve we expect to find. - */ - const struct ReserveData *reserve_to_cmp; - - /** - * The length of @e rewards. - */ - unsigned int rewards_length; - - /** - * The rewards that have been authorized from the reserve. - */ - const struct TALER_MERCHANTDB_RewardDetails *rewards; - - /** - * 1 if the result matches, 0 otherwise. - */ - int result_matches; -}; - - -/** - * Called after test_lookup_reserve. - * @param cls a pointer to TestLookupReserve_Closure. - * @param creation_time time when the reserve was setup - * @param expiration_time time when the reserve will be closed by the exchange - * @param merchant_initial_amount initial amount that the merchant claims to have filled the - * reserve with - * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param picked_up_amount total of rewards that were picked up from this reserve - * @param committed_amount total of rewards that the merchant committed to, but that were not - * picked up yet - * @param active true if the reserve is still active (we have the private key) - * @param exchange_url base URL of the exchange hosting the reserve, NULL if not @a active - * @param payto_uri URI to use to fund the reserve, NULL if not @a active - * @param rewards_length length of the @a rewards array - * @param rewards information about the rewards created by this reserve - * - * @return 0 on success, 1 otherwise. - */ -static void -lookup_reserve_cb (void *cls, - struct GNUNET_TIME_Timestamp creation_time, - struct GNUNET_TIME_Timestamp expiration_time, - const struct TALER_Amount *merchant_initial_amount, - const struct TALER_Amount *exchange_initial_amount, - const struct TALER_Amount *picked_up_amount, - const struct TALER_Amount *committed_amount, - bool active, - const struct TALER_MasterPublicKeyP *master_pub, - const char *exchange_url, - unsigned int rewards_length, - const struct TALER_MERCHANTDB_RewardDetails *rewards) -{ - struct TestLookupReserve_Closure *cmp = cls; - unsigned int reward_cmp_results[GNUNET_NZL (rewards_length)]; - - if (NULL == cmp) - return; - if (GNUNET_TIME_timestamp_cmp (cmp->reserve_to_cmp->expiration, - !=, - expiration_time) || - (GNUNET_OK != - TALER_amount_cmp_currency ( - &cmp->reserve_to_cmp->initial_amount, - merchant_initial_amount)) || - (0 != TALER_amount_cmp (&cmp->reserve_to_cmp->initial_amount, - merchant_initial_amount)) || - (cmp->rewards_length != rewards_length)) - { - cmp->result_matches = 1; - return; - } - if (0 != strcmp (exchange_url, - "https://exch-url/")) - { - GNUNET_break (0); - cmp->result_matches = 0; - return; - } - if (0 != GNUNET_memcmp (&cmp->reserve_to_cmp->master_pub, - master_pub)) - { - GNUNET_break (0); - cmp->result_matches = 0; - return; - } - memset (reward_cmp_results, - 0, - sizeof (reward_cmp_results)); - for (unsigned int i = 0; rewards_length > i; ++i) - { - for (unsigned int j = 0; rewards_length > j; ++j) - { - if ((GNUNET_OK == TALER_amount_cmp_currency ( - &cmp->rewards[i].total_amount, - &rewards[j].total_amount)) && - (0 == TALER_amount_cmp (&cmp->rewards[i].total_amount, - &rewards[j].total_amount)) && - (0 == strcmp (cmp->rewards[i].reason, - rewards[j].reason))) - { - reward_cmp_results[i] += 1; - } - } - } - for (unsigned int i = 0; rewards_length > i; ++i) - { - if (1 != reward_cmp_results[i]) - { - cmp->result_matches = 1; - return; - } - } - cmp->result_matches = 0; -} - - -/** - * Tests looking up details of a reserve from the database. - * @param instance the instance to lookup the reserve from. - * @param reserve_pub the public key of the reserve we are looking for. - * @param reserve the data we expect to find. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_reserve (const struct InstanceData *instance, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct ReserveData *reserve) -{ - struct TestLookupReserve_Closure cmp = { - .reserve_to_cmp = reserve, - .rewards_length = 0, - .rewards = NULL, - .result_matches = 0 - }; - if (1 != plugin->lookup_reserve (plugin->cls, - instance->instance.id, - reserve_pub, - false, - &lookup_reserve_cb, - &cmp)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reserve failed\n"); - return 1; - } - if (0 != cmp.result_matches) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reserve failed: result does not match\n"); - return 1; - } - return 0; -} - - -/** - * Container for looking up mulrewardle reserves. - */ -struct TestLookupReserves_Closure -{ - /** - * The length of @e reserves_to_cmp. - */ - unsigned int reserves_to_cmp_length; - - /** - * The reserves we expect to find from the lookup. - */ - const struct ReserveData *reserves_to_cmp; - - /** - * The number of results matching each reserve we were looking for. - */ - unsigned int *results_matching; - - /** - * The total number of results found from the lookup. - */ - unsigned int results_length; -}; - - -/** - * Called after test_lookup_reserves. - * @param cls pointer to a TestLookupReserves_Closure. - * @param reserve_pub public key of the reserve - * @param creation_time time when the reserve was setup - * @param expiration_time time when the reserve will be closed by the exchange - * @param merchant_initial_amount initial amount that the merchant claims to have filled the - * reserve with - * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param pickup_amount total of rewards that were picked up from this reserve - * @param committed_amount total of rewards that the merchant committed to, but that were not - * picked up yet - * @param active true if the reserve is still active (we have the private key) - */ -static void -lookup_reserves_cb (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct GNUNET_TIME_Timestamp creation_time, - struct GNUNET_TIME_Timestamp expiration_time, - const struct TALER_Amount *merchant_initial_amount, - const struct TALER_Amount *exchange_initial_amount, - const struct TALER_Amount *pickup_amount, - const struct TALER_Amount *committed_amount, - bool active) -{ - struct TestLookupReserves_Closure *cmp = cls; - if (NULL == cmp) - return; - for (unsigned int i = 0; cmp->reserves_to_cmp_length > i; ++i) - { - if ((0 == - GNUNET_memcmp (&cmp->reserves_to_cmp[i].reserve_pub, - reserve_pub)) && - (GNUNET_TIME_timestamp_cmp (cmp->reserves_to_cmp[i].expiration, - ==, - expiration_time)) && - (GNUNET_OK == - TALER_amount_cmp_currency ( - &cmp->reserves_to_cmp[i].initial_amount, - merchant_initial_amount)) && - (0 == TALER_amount_cmp (&cmp->reserves_to_cmp[i].initial_amount, - merchant_initial_amount))) - { - cmp->results_matching[i] += 1; - } - } - cmp->results_length += 1; -} - - -/** - * Test looking up reserves for an instance. - * @param instance the instance to get the reserves from. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_reserves (const struct InstanceData *instance, - unsigned int reserves_length, - const struct ReserveData *reserves) -{ - unsigned int results_matching[reserves_length]; - struct TestLookupReserves_Closure cmp = { - .reserves_to_cmp_length = reserves_length, - .reserves_to_cmp = reserves, - .results_matching = results_matching, - .results_length = 0 - }; - memset (results_matching, 0, sizeof (unsigned int) * reserves_length); - if (1 != plugin->lookup_reserves (plugin->cls, - instance->instance.id, - GNUNET_TIME_UNIT_ZERO_TS, - TALER_EXCHANGE_YNA_ALL, - TALER_EXCHANGE_YNA_ALL, - &lookup_reserves_cb, - &cmp)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reserves failed\n"); - return 1; - } - if (reserves_length != cmp.results_length) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reserves failed: incorrect number of results (%d)\n", - cmp.results_length); - return 1; - } - for (unsigned int i = 0; reserves_length > i; ++i) - { - if (1 != cmp.results_matching[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reserves failed: mismatched data\n"); - return 1; - } - } - return 0; -} - - -/** - * Called after test_lookup_pending_reserves. - * @param cls pointer to a TestLookupReserves_Closure. - * @param instance_id the id of the instance the reserve belongs to. - * @param exchange_url url of the exchange for this reserve. - * @param reserve_pub public key of this reserve. - * @param expected_amount what the amount in the reserve is, according to the db. - */ -static void -lookup_pending_reserves_cb (void *cls, - const char *instance_id, - const char *exchange_url, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *expected_amount) -{ - struct TestLookupReserves_Closure *cmp = cls; - if (NULL == cmp) - return; - for (unsigned int i = 0; cmp->reserves_to_cmp_length > i; ++i) - { - if ((0 == GNUNET_memcmp (&cmp->reserves_to_cmp[i].reserve_pub, - reserve_pub)) && - (0 == strcmp (cmp->reserves_to_cmp[i].exchange_url, - exchange_url)) && - (GNUNET_OK == TALER_amount_cmp_currency ( - &cmp->reserves_to_cmp[i].initial_amount, - expected_amount)) && - (0 == TALER_amount_cmp (&cmp->reserves_to_cmp[i].initial_amount, - expected_amount))) - { - cmp->results_matching[i] += 1; - } - } - cmp->results_length += 1; -} - - -/** - * Tests looking up reserves that are not activated from the database. - * @param reserves_length length of @e reserves. - * @param reserves the reserves that the db is expected to return. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_pending_reserves (unsigned int reserves_length, - const struct ReserveData *reserves) -{ - unsigned int results_matching[GNUNET_NZL (reserves_length)]; - struct TestLookupReserves_Closure cmp = { - .reserves_to_cmp_length = reserves_length, - .reserves_to_cmp = reserves, - .results_matching = results_matching, - .results_length = 0 - }; - memset (results_matching, 0, sizeof (unsigned int) * reserves_length); - if (0 > plugin->lookup_pending_reserves (plugin->cls, - &lookup_pending_reserves_cb, - &cmp)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup pending reserves failed\n"); - return 1; - } - if (reserves_length != cmp.results_length) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup pending reserves failed: incorrect number of results (%d)\n", - cmp.results_length); - return 1; - } - for (unsigned int i = 0; reserves_length > i; ++i) - { - if (1 != cmp.results_matching[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup pending reserves failed: mismatched data\n"); - return 1; - } - } - return 0; -} - - -/** - * Container for all reward data relevant to the database. - */ -struct RewardData -{ - /** - * The details of the reward. - */ - struct TALER_MERCHANTDB_RewardDetails details; - - /** - * Where the user should be redirected. - */ - const char *next_url; - - /** - * When the reward expires. - */ - struct GNUNET_TIME_Timestamp expiration; -}; - - -/** - * Creates a reward for testing. - * @param reward the reward to fill with data. - */ -static void -make_reward (struct RewardData *reward) -{ - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount ("EUR:0.99", - &reward->details.total_amount)); - reward->details.reason = "because"; - reward->next_url = "https://taler.net"; -} - - -/** - * Tests authorizing a reward. - * @param instance the instance authorizing the reward. - * @param reserve where the reward is coming from. - * @param reward the reward to authorize. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_authorize_reward (const struct InstanceData *instance, - const struct ReserveData *reserve, - struct RewardData *reward) -{ - TEST_COND_RET_ON_FAIL (TALER_EC_NONE == - plugin->authorize_reward (plugin->cls, - instance->instance.id, - &reserve->reserve_pub, - &reward->details.total_amount, - reward->details.reason, - reward->next_url, - &reward->details.reward_id, - &reward->expiration), - "Authorize reward failed\n"); - return 0; -} - - -/** - * Tests looking up a reward from the database. - * @param instance the instance to look up rewards from. - * @param reserve the reserve to look up rewards from. - * @param reward the reward we expect to find (uses @e reward_id to perform lookup). - * @param expected_total_picked_up how much of the reward should have been - * picked up. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_reward (const struct InstanceData *instance, - const struct ReserveData *reserve, - const struct RewardData *reward, - const struct TALER_Amount *expected_total_picked_up) -{ - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - struct GNUNET_TIME_Timestamp expiration; - char *exchange_url = NULL; - char *next_url = NULL; - struct TALER_ReservePrivateKeyP reserve_priv; - - if (1 != plugin->lookup_reward (plugin->cls, - instance->instance.id, - &reward->details.reward_id, - &total_authorized, - &total_picked_up, - &expiration, - &exchange_url, - &next_url, - &reserve_priv)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reward failed\n"); - GNUNET_free (exchange_url); - return 1; - } - if ((GNUNET_OK != - TALER_amount_cmp_currency (&reward->details.total_amount, - &total_authorized)) || - (0 != TALER_amount_cmp (&reward->details.total_amount, - &total_authorized)) || - (GNUNET_OK != - TALER_amount_cmp_currency (expected_total_picked_up, - &total_picked_up)) || - (0 != TALER_amount_cmp (expected_total_picked_up, - &total_picked_up)) || - (GNUNET_TIME_timestamp_cmp (reward->expiration, - !=, - expiration)) || - (0 != strcmp (reserve->exchange_url, - exchange_url)) || - (0 != GNUNET_memcmp (&reserve->reserve_priv, - &reserve_priv))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reward failed: mismatched data\n"); - GNUNET_free (exchange_url); - GNUNET_free (next_url); - return 1; - } - GNUNET_free (exchange_url); - GNUNET_free (next_url); - return 0; -} - - -/** - * Tests looking up the details of a reward from the database. - * - * @param instance the instance the reward is in. - * @param reserve the reserve the reward was authorized from. - * @param reward the reward we expect to find (uses @e reward_id to perform lookup). - * @param expected_total_picked_up how much of the reward should have been - * picked up. - * @param expected_pickups_length the length of @e expected_pickups. - * @param expected_pickups the pickups that we expect to be associated with - * the reward. - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_reward_details ( - const struct InstanceData *instance, - const struct ReserveData *reserve, - const struct RewardData *reward, - const struct TALER_Amount *expected_total_picked_up, - unsigned int expected_pickups_length, - const struct TALER_MERCHANTDB_PickupDetails *expected_pickups) -{ - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - char *justification = NULL; - struct GNUNET_TIME_Timestamp expiration; - struct TALER_ReservePublicKeyP reserve_pub; - unsigned int pickups_length; - struct TALER_MERCHANTDB_PickupDetails *pickups = NULL; - unsigned int results_matching[GNUNET_NZL (expected_pickups_length)]; - - if (0 > - plugin->lookup_reward_details (plugin->cls, - instance->instance.id, - &reward->details.reward_id, - true, - &total_authorized, - &total_picked_up, - &justification, - &expiration, - &reserve_pub, - &pickups_length, - &pickups)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reward details failed\n"); - GNUNET_free (justification); - GNUNET_free (pickups); - return 1; - } - if ( (GNUNET_OK != - TALER_amount_cmp_currency (&reward->details.total_amount, - &total_authorized)) || - (0 != TALER_amount_cmp (&reward->details.total_amount, - &total_authorized)) || - (GNUNET_OK != - TALER_amount_cmp_currency (expected_total_picked_up, - &total_picked_up)) || - (0 != TALER_amount_cmp (expected_total_picked_up, - &total_picked_up)) || - (0 != strcmp (reward->details.reason, - justification)) || - (GNUNET_TIME_timestamp_cmp (reward->expiration, - !=, - expiration)) || - (0 != GNUNET_memcmp (&reserve->reserve_pub, - &reserve_pub)) || - (expected_pickups_length != pickups_length) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reward details failed: mismatched data\n"); - GNUNET_free (justification); - GNUNET_free (pickups); - return 1; - } - memset (results_matching, - 0, - sizeof (unsigned int) * expected_pickups_length); - for (unsigned int i = 0; expected_pickups_length > i; ++i) - { - for (unsigned int j = 0; pickups_length > j; ++j) - { - /* Compare expected_pickups[i] with pickups[j] */ - if ((0 == GNUNET_memcmp (&expected_pickups[i].pickup_id, - &pickups[j].pickup_id)) && - (GNUNET_OK == TALER_amount_cmp_currency ( - &expected_pickups[i].requested_amount, - &pickups[j].requested_amount)) && - (0 == TALER_amount_cmp (&expected_pickups[i].requested_amount, - &pickups[j].requested_amount)) && - (expected_pickups[i].num_planchets == pickups[j].num_planchets)) - { - results_matching[i] += 1; - } - } - } - for (unsigned int i = 0; expected_pickups_length > i; ++i) - { - if (1 != results_matching[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup reward details failed: mismatched data\n"); - GNUNET_free (justification); - GNUNET_free (pickups); - return 1; - } - } - GNUNET_free (justification); - GNUNET_free (pickups); - return 0; -} - - -/** - * Utility function for freeing an array of RSA signatures. - * @param sigs_length length of @e sigs. - * @param sigs the signatures to free. - */ -static void -free_signature_array (unsigned int sigs_length, - struct TALER_BlindedDenominationSignature *sigs) -{ - for (unsigned int i = 0; sigs_length > i; ++i) - TALER_blinded_denom_sig_free (&sigs[i]); -} - - -/** - * Tests looking up a reward pickup. - * @param instance the instance to look up from. - * @param reward the reward the pickup was made for. - * @param pickup_id id of the pickup to look up. - * @param expected_exchange_url exchange url for the pickup. - * @param expected_reserve_priv reserve private key for the pickup. - * @param expected_sigs_length length of @e expected_sigs. - * @param expected_sigs the signatures we expect to be made for the pickup. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_pickup ( - const struct InstanceData *instance, - const struct RewardData *reward, - const struct TALER_PickupIdentifierP *pickup_id, - const char *expected_exchange_url, - const struct TALER_ReservePrivateKeyP *expected_reserve_priv, - unsigned int expected_sigs_length, - const struct TALER_BlindedDenominationSignature *expected_sigs) -{ - char *exchange_url = NULL; - struct TALER_ReservePrivateKeyP reserve_priv; - struct TALER_BlindedDenominationSignature sigs[GNUNET_NZL ( - expected_sigs_length)]; - unsigned int results_matching[GNUNET_NZL (expected_sigs_length)]; - - memset (sigs, - 0, - sizeof (sigs)); - if (0 > plugin->lookup_pickup (plugin->cls, - instance->instance.id, - &reward->details.reward_id, - pickup_id, - &exchange_url, - &reserve_priv, - expected_sigs_length, - sigs)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup pickup failed\n"); - GNUNET_free (exchange_url); - free_signature_array (expected_sigs_length, - sigs); - return 1; - } - if ((0 != strcmp (expected_exchange_url, - exchange_url)) || - (0 != GNUNET_memcmp (expected_reserve_priv, - &reserve_priv))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup pickup failed: mismatched data\n"); - GNUNET_free (exchange_url); - free_signature_array (expected_sigs_length, - sigs); - return 1; - } - memset (results_matching, - 0, - sizeof (unsigned int) * expected_sigs_length); - for (unsigned int i = 0; expected_sigs_length > i; ++i) - { - for (unsigned int j = 0; expected_sigs_length > j; ++j) - { - /* compare expected_sigs[i] to sigs[j] */ - if (0 == - TALER_blinded_denom_sig_cmp (&expected_sigs[i], - &sigs[j])) - { - results_matching[i] += 1; - } - } - } - for (unsigned int i = 0; expected_sigs_length > i; ++i) - { - if (1 != results_matching[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup pickup failed: mismatched data\n"); - GNUNET_free (exchange_url); - free_signature_array (expected_sigs_length, - sigs); - return 1; - } - } - GNUNET_free (exchange_url); - free_signature_array (expected_sigs_length, - sigs); - return 0; -} - - -/** - * Closure for testing lookup_rewards. - */ -struct TestLookupRewards_Closure -{ - /** - * The length of @e rewards_to_cmp. - */ - unsigned int rewards_to_cmp_length; - - /** - * The rewards that we are expecting to find. - */ - const struct RewardData *rewards_to_cmp; - - /** - * The number of results found from the lookup. - */ - unsigned int results_length; - - /** - * Whether each result matches with the corresponding reward in @rewards_to_cmp. - */ - bool *results_match; -}; - - -/** - * Called after test_lookup_rewards. - * @param cls pointer to a TestLookupRewards_Closure. - * @param row_id the row id of the reward. - * @param reward_id the id of the reward. - * @param amount the amount of the reward. - */ -static void -lookup_rewards_cb (void *cls, - uint64_t row_id, - struct TALER_RewardIdentifierP reward_id, - struct TALER_Amount amount) -{ - struct TestLookupRewards_Closure *cmp = cls; - if (NULL == cmp) - return; - unsigned int i = cmp->results_length; - cmp->results_length += 1; - if (cmp->rewards_to_cmp_length > i) - { - if ((0 == GNUNET_memcmp (&cmp->rewards_to_cmp[i].details.reward_id, - &reward_id)) && - (GNUNET_OK == TALER_amount_cmp_currency ( - &cmp->rewards_to_cmp[i].details.total_amount, - &amount)) && - (0 == TALER_amount_cmp (&cmp->rewards_to_cmp[i].details.total_amount, - &amount))) - cmp->results_match[i] = true; - else - cmp->results_match[i] = false; - } -} - - -/** - * Tests looking up the rewards from the database. - * @param instance the instance to look up rewards from. - * @param expired how to filter expired rewards. - * @param offset where to start retrieving rewards. - * @param rewards_length length of @e rewards. - * @param rewards the rewards that we expect to find. - * - * @return 0 on success, 1 otherwise. - */ -static int -test_lookup_rewards (const struct InstanceData *instance, - enum TALER_EXCHANGE_YesNoAll expired, - int64_t limit, - uint64_t offset, - unsigned int rewards_length, - const struct RewardData *rewards) -{ - bool results_match[rewards_length]; - struct TestLookupRewards_Closure cmp = { - .rewards_to_cmp_length = rewards_length, - .rewards_to_cmp = rewards, - .results_length = 0, - .results_match = results_match - }; - - memset (results_match, - 0, - sizeof (bool) * rewards_length); - if (0 > plugin->lookup_rewards (plugin->cls, - instance->instance.id, - expired, - limit, - offset, - &lookup_rewards_cb, - &cmp)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup rewards failed\n"); - return 1; - } - if (rewards_length != cmp.results_length) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup rewards failed: incorrect number of results (%d)\n", - cmp.results_length); - return 1; - } - for (unsigned int i = 0; i < rewards_length; ++i) - { - if (true != cmp.results_match[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup rewards failed: mismatched data\n"); - return 1; - } - } - return 0; -} - - -/** - * Convenience function for testing lookup rewards with filters - * @param rewards_length length of @e rewards. - * @param rewards the array of rewards to reverse. - */ -static void -reverse_reward_data_array (unsigned int rewards_length, - struct RewardData *rewards) -{ - struct RewardData tmp[rewards_length]; - for (unsigned int i = 0; i < rewards_length; ++i) - tmp[i] = rewards[rewards_length - 1 - i]; - for (unsigned int i = 0; i < rewards_length; ++i) - rewards[i] = tmp[i]; -} - - -/** - * Container for data for testing rewards. - */ -struct TestRewards_Closure -{ - /** - * The instance. - */ - struct InstanceData instance; - - /** - * The reward reserve data. - */ - struct ReserveData reserve; - - /** - * Reserve data that is expired. - */ - struct ReserveData expired_reserve; - - /** - * A normal reward. - */ - struct RewardData reward; - - /** - * A reward that is too large to authorize. - */ - struct RewardData bigreward; - - /** - * Array of rewards for testing lookups. - */ - struct RewardData rewards[5]; - - /** - * Id of a pickup. - */ - struct TALER_PickupIdentifierP pickup_id; - - /** - * Private key of the pickup. - */ - struct GNUNET_CRYPTO_RsaPrivateKey *pickup_priv; - - /** - * Signature for the pickup. - */ - struct TALER_BlindedDenominationSignature pickup_sig; -}; - - -/** - * Prepares for testing rewards functionality. - * @param cls the data to prepare. - */ -static void -pre_test_rewards (struct TestRewards_Closure *cls) -{ - struct GNUNET_CRYPTO_BlindedSignature *us; - - /* Instance */ - make_instance ("test_inst_rewards", - &cls->instance); - - /* Reserve */ - GNUNET_CRYPTO_eddsa_key_create (&cls->reserve.reserve_priv.eddsa_priv); - GNUNET_CRYPTO_eddsa_key_get_public (&cls->reserve.reserve_priv.eddsa_priv, - &cls->reserve.reserve_pub.eddsa_pub); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount ("EUR:99.99", - &cls->reserve.initial_amount)); - cls->reserve.exchange_url = "https://exch-url/"; - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &cls->reserve.master_pub, - sizeof (cls->reserve.master_pub)); - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &cls->pickup_id, - sizeof (cls->pickup_id)); - cls->reserve.expiration = GNUNET_TIME_relative_to_timestamp ( - GNUNET_TIME_UNIT_WEEKS); - - GNUNET_CRYPTO_eddsa_key_create ( - &cls->expired_reserve.reserve_priv.eddsa_priv); - GNUNET_CRYPTO_eddsa_key_get_public ( - &cls->expired_reserve.reserve_priv.eddsa_priv, - &cls->expired_reserve.reserve_pub. - eddsa_pub); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount ("EUR:99.99", - &cls->expired_reserve.initial_amount)); - cls->expired_reserve.exchange_url = "exch-url"; - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &cls->expired_reserve.master_pub, - sizeof (cls->expired_reserve.master_pub)); - cls->expired_reserve.expiration = GNUNET_TIME_UNIT_ZERO_TS; - - /* Reward/pickup */ - make_reward (&cls->reward); - make_reward (&cls->bigreward); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount ("EUR:99.90", - &cls->bigreward.details.total_amount)); - for (unsigned int i = 0; i < 5; ++i) - { - char amount[16]; - make_reward (&cls->rewards[i]); - GNUNET_snprintf (amount, - 16, - "EUR:0.%u0", - i + 1); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (amount, - &cls->rewards[i].details.total_amount)); - } - - cls->pickup_priv = GNUNET_CRYPTO_rsa_private_key_create (2048); - us = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); - cls->pickup_sig.blinded_sig = us; - us->cipher = GNUNET_CRYPTO_BSA_RSA; - us->rc = 1; - us->details.blinded_rsa_signature - = GNUNET_CRYPTO_rsa_sign_fdh (cls->pickup_priv, - &cls->pickup_id.hash, - sizeof (cls->pickup_id.hash)); -} - - -/** - * Cleans up after testing rewards. - * @param cls the data to clean up. - */ -static void -post_test_rewards (struct TestRewards_Closure *cls) -{ - free_instance_data (&cls->instance); - GNUNET_CRYPTO_rsa_private_key_free (cls->pickup_priv); - TALER_blinded_denom_sig_free (&cls->pickup_sig); -} - - -/** - * Runs tests for rewards. - * @param cls container of test data. - * - * @return 0 on success, 1 on failure. - */ -static int -run_test_rewards (struct TestRewards_Closure *cls) -{ - struct TALER_Amount zero; - - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero ("EUR", - &zero)); - TEST_RET_ON_FAIL (test_insert_instance (&cls->instance, - GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); - /* Test insert reserve */ - TEST_RET_ON_FAIL (test_insert_reserve (&cls->instance, - &cls->reserve, - TALER_EC_NONE)); - /* Test lookup reserve */ - TEST_RET_ON_FAIL (test_lookup_reserve (&cls->instance, - &cls->reserve.reserve_pub, - &cls->reserve)); - /* Test lookup pending reserves */ - TEST_RET_ON_FAIL (test_lookup_pending_reserves (1, - &cls->reserve)); - /* Test reserve activation */ - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == - plugin->activate_reserve (plugin->cls, - cls->instance.instance.id, - &cls->reserve.reserve_pub, - &cls->reserve.initial_amount), - "Activate reserve failed\n"); - TEST_RET_ON_FAIL (test_lookup_pending_reserves (0, - NULL)); - /* Test inserting a reward */ - TEST_RET_ON_FAIL (test_authorize_reward (&cls->instance, - &cls->reserve, - &cls->reward)); - /* Test lookup reward */ - TEST_RET_ON_FAIL (test_lookup_reward (&cls->instance, - &cls->reserve, - &cls->reward, - &zero)); - /* Test lookup reward details */ - TEST_RET_ON_FAIL (test_lookup_reward_details (&cls->instance, - &cls->reserve, - &cls->reward, - &zero, - 0, - NULL)); - /* Test insert pickup */ - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == - plugin->insert_pickup (plugin->cls, - cls->instance.instance.id, - &cls->reward.details.reward_id, - &cls->reward.details. - total_amount, - &cls->pickup_id, - &cls->reward.details. - total_amount), - "Insert pickup failed\n"); - /* Test lookup pickup */ - TEST_RET_ON_FAIL (test_lookup_pickup (&cls->instance, - &cls->reward, - &cls->pickup_id, - cls->reserve.exchange_url, - &cls->reserve.reserve_priv, - 0, - NULL)); - /* Test insert pickup blind signature */ - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == - plugin->insert_pickup_blind_signature (plugin->cls, - &cls->pickup_id, - 0, - &cls->pickup_sig), - "Insert pickup blind signature failed\n"); - /* Test that overdrawing the reserve fails */ - TEST_COND_RET_ON_FAIL (TALER_EC_NONE != - plugin->authorize_reward (plugin->cls, - cls->instance.instance.id, - &cls->reserve.reserve_pub, - &cls->bigreward.details. - total_amount, - cls->bigreward.details.reason, - cls->bigreward.next_url, - &cls->bigreward.details. - reward_id, - &cls->reserve.expiration), - "Authorize reward failed\n"); - /* Test lookup rewards */ - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_ALL, - 1, - 0, - 1, - &cls->reward)); - /* Test lookup reserves */ - TEST_RET_ON_FAIL (test_lookup_reserves (&cls->instance, - 1, - &cls->reserve)); - { - /* Test lookup rewards & friends */ - struct RewardData expected_rewards[6]; - expected_rewards[0] = cls->reward; - TEST_RET_ON_FAIL (test_insert_reserve (&cls->instance, - &cls->expired_reserve, - TALER_EC_NONE)); - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == - plugin->activate_reserve (plugin->cls, - cls->instance.instance.id, - &cls->expired_reserve. - reserve_pub, - &cls->expired_reserve. - initial_amount), - "Activate reserve failed\n"); - for (unsigned int i = 0; i < 5; ++i) - { - if (i % 2 == 0) - { - TEST_RET_ON_FAIL (test_authorize_reward (&cls->instance, - &cls->expired_reserve, - &cls->rewards[i])); - } - else - { - TEST_RET_ON_FAIL (test_authorize_reward (&cls->instance, - &cls->reserve, - &cls->rewards[i])); - } - } - GNUNET_memcpy (&expected_rewards[1], - cls->rewards, - sizeof (struct RewardData) * 5); - /* Test lookup rewards inc */ - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_ALL, - 6, - 0, - 6, - expected_rewards)); - reverse_reward_data_array (6, - expected_rewards); - /* Test lookup rewards dec */ - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_ALL, - -6, - 10, - 6, - expected_rewards)); - /* Test lookup rewards expired inc */ - expected_rewards[0] = cls->rewards[0]; - expected_rewards[1] = cls->rewards[2]; - expected_rewards[2] = cls->rewards[4]; - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_YES, - 6, - 0, - 3, - expected_rewards)); - /* Test lookup rewards expired dec */ - reverse_reward_data_array (3, - expected_rewards); - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_YES, - -6, - 10, - 3, - expected_rewards)); - /* Test lookup rewards unexpired inc */ - expected_rewards[0] = cls->reward; - expected_rewards[1] = cls->rewards[1]; - expected_rewards[2] = cls->rewards[3]; - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_NO, - 6, - 0, - 3, - expected_rewards)); - /* Test lookup rewards unexpired dec */ - reverse_reward_data_array (3, - expected_rewards); - TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, - TALER_EXCHANGE_YNA_NO, - -6, - 10, - 3, - expected_rewards)); - } - /* Test delete reserve private key */ - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == - plugin->delete_reserve (plugin->cls, - cls->instance.instance.id, - &cls->reserve.reserve_pub), - "Delete reserve private key failed\n"); - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == - plugin->delete_reserve (plugin->cls, - cls->instance.instance.id, - &cls->reserve.reserve_pub), - "Delete reserve private key failed\n"); - /* Test purging a reserve */ - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == - plugin->purge_reserve (plugin->cls, - cls->instance.instance.id, - &cls->reserve.reserve_pub), - "Purge reserve failed\n"); - TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == - plugin->purge_reserve (plugin->cls, - cls->instance.instance.id, - &cls->reserve.reserve_pub), - "Purge reserve failed\n"); - - return 0; -} - - -/** - * Handles all logic for testing rewards in the database. - * - * @return 0 on success, 1 on failure. - */ -static int -test_rewards (void) -{ - struct TestRewards_Closure test_cls; - - pre_test_rewards (&test_cls); - int test_result = run_test_rewards (&test_cls); - post_test_rewards (&test_cls); - return test_result; -} - - /** * Closure for testing lookup_refunds. */ @@ -8366,7 +7059,6 @@ run_tests (void) TEST_RET_ON_FAIL (test_orders ()); TEST_RET_ON_FAIL (test_deposits ()); TEST_RET_ON_FAIL (test_transfers ()); - TEST_RET_ON_FAIL (test_rewards ()); TEST_RET_ON_FAIL (test_refunds ()); TEST_RET_ON_FAIL (test_lookup_orders_all_filters ()); TEST_RET_ON_FAIL (test_kyc ()); diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h index 640bbdd7..1983f732 100644 --- a/src/include/taler_merchantdb_plugin.h +++ b/src/include/taler_merchantdb_plugin.h @@ -911,74 +911,6 @@ typedef void /** - * Callback with reserve details. - * - * @param cls closure - * @param reserve_pub public key of the reserve - * @param creation_time time when the reserve was setup - * @param expiration_time time when the reserve will be closed by the exchange - * @param merchant_initial_amount initial amount that the merchant claims to have filled the - * reserve with - * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param pickup_amount total of rewards that were picked up from this reserve - * @param committed_amount total of rewards that the merchant committed to, but that were not - * picked up yet - * @param active true if the reserve is still active (we have the private key) - */ -typedef void -(*TALER_MERCHANTDB_ReservesCallback)( - void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct GNUNET_TIME_Timestamp creation_time, - struct GNUNET_TIME_Timestamp expiration_time, - const struct TALER_Amount *merchant_initial_amount, - const struct TALER_Amount *exchange_initial_amount, - const struct TALER_Amount *pickup_amount, - const struct TALER_Amount *committed_amount, - bool active); - - -/** - * Callback with details about a reserve pending exchange confirmation. - * - * @param cls closure - * @param instance_id for which instance is this reserve - * @param exchange_url base URL of the exchange - * @param reserve_pub public key of the reserve - * @param expected_amount how much do we expect to see in the reserve - */ -typedef void -(*TALER_MERCHANTDB_PendingReservesCallback)( - void *cls, - const char *instance_id, - const char *exchange_url, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *expected_amount); - - -/** - * Details about a reward. - */ -struct TALER_MERCHANTDB_RewardDetails -{ - /** - * ID of the reward. - */ - struct TALER_RewardIdentifierP reward_id; - - /** - * Total amount of the reward. - */ - struct TALER_Amount total_amount; - - /** - * Reason given for granting the reward. - */ - char *reason; -}; - - -/** * Function called with information about a coin that was deposited. * * @param cls closure @@ -1001,55 +933,6 @@ typedef void /** - * Callback with reserve details. - * - * @param cls closure - * @param creation_time time when the reserve was setup - * @param expiration_time time when the reserve will be closed by the exchange - * @param merchant_initial_amount initial amount that the merchant claims to have filled the - * reserve with - * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param picked_up_amount total of rewards that were picked up from this reserve - * @param committed_amount total of rewards that the merchant committed to, but that were not - * picked up yet - * @param active true if the reserve is still active (we have the private key) - * @param master_pub master public key of the exchange - * @param exchange_url base URL of the exchange hosting the reserve, NULL if not @a active - * @param rewards_length length of the @a rewards array - * @param rewards information about the rewards created by this reserve - */ -typedef void -(*TALER_MERCHANTDB_ReserveDetailsCallback)( - void *cls, - struct GNUNET_TIME_Timestamp creation_time, - struct GNUNET_TIME_Timestamp expiration_time, - const struct TALER_Amount *merchant_initial_amount, - const struct TALER_Amount *exchange_initial_amount, - const struct TALER_Amount *picked_up_amount, - const struct TALER_Amount *committed_amount, - bool active, - const struct TALER_MasterPublicKeyP *master_pub, - const char *exchange_url, - unsigned int rewards_length, - const struct TALER_MERCHANTDB_RewardDetails *rewards); - - -/** - * Typically called by `lookup_rewards`. - * - * @param cls closure - * @param row_id row of the reward in the database - * @param reward_id id of the reward - * @param amount amount of the reward - */ -typedef void -(*TALER_MERCHANTDB_RewardsCallback)(void *cls, - uint64_t row_id, - struct TALER_RewardIdentifierP reward_id, - struct TALER_Amount amount); - - -/** * Function called with information about a coin that was deposited. * * @param cls closure @@ -1080,28 +963,6 @@ typedef void /** - * Details about a pickup operation executed by the merchant. - */ -struct TALER_MERCHANTDB_PickupDetails -{ - /** - * Identifier for the pickup operation. - */ - struct TALER_PickupIdentifierP pickup_id; - - /** - * Total amount requested for this @e pickup_id. - */ - struct TALER_Amount requested_amount; - - /** - * Number of planchets involved in the request. - */ - unsigned int num_planchets; - -}; - -/** * Possible token family kinds. */ enum TALER_MERCHANTDB_TokenFamilyKind @@ -1306,7 +1167,7 @@ struct TALER_MERCHANTDB_Plugin * @param es specification of the event to listen for * @param timeout how long to wait for the event * @param cb function to call when the event happens, possibly - * mulrewardle times (until cancel is invoked) + * multiple times (until cancel is invoked) * @param cb_cls closure for @a cb * @return handle useful to cancel the listener */ @@ -2425,7 +2286,7 @@ struct TALER_MERCHANTDB_Plugin * Function called when some backoffice staff decides to award or * increase the refund on an existing contract. This function * MUST be called from within a transaction scope setup by the - * caller as it executes mulrewardle SQL statements. + * caller as it executes multiple SQL statements. * * @param cls closure * @param instance_id instance identifier @@ -2891,324 +2752,6 @@ struct TALER_MERCHANTDB_Plugin /** - * Add @a credit to a reserve to be used for rewardping. Note that - * this function does not actually perform any wire transfers to - * credit the reserve, it merely tells the merchant backend that - * a reserve now exists. This has to happen before rewards can be - * authorized. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance is the reserve tied to - * @param reserve_priv which reserve is topped up or created - * @param reserve_pub which reserve is topped up or created - * @param master_pub master public key of the exchange - * @param exchange_url what URL is the exchange reachable at where the reserve is located - * @param initial_balance how much money will be added to the reserve - * @param expiration when does the reserve expire? - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - */ - enum TALER_ErrorCode - (*insert_reserve)(void *cls, - const char *instance_id, - const struct TALER_ReservePrivateKeyP *reserve_priv, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_MasterPublicKeyP *master_pub, - const char *exchange_url, - const struct TALER_Amount *initial_balance, - struct GNUNET_TIME_Timestamp expiration); - - - /** - * Confirms @a credit as the amount the exchange claims to have received and - * thus really 'activates' the reserve. This has to happen before rewards can - * be authorized. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance is the reserve tied to - * @param reserve_pub which reserve is topped up or created - * @param initial_exchange_balance how much money was be added to the reserve - * according to the exchange - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - */ - enum GNUNET_DB_QueryStatus - (*activate_reserve)(void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *initial_exchange_balance); - - - /** - * Lookup reserves. - * - * @param cls closure - * @param instance_id instance to lookup payments for - * @param created_after filter by reserves created after this date - * @param active filter by active reserves - * @param failures filter by reserves with a disagreement on the initial balance - * @param cb function to call with reserve summary data - * @param cb_cls closure for @a cb - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_reserves)(void *cls, - const char *instance_id, - struct GNUNET_TIME_Timestamp created_after, - enum TALER_EXCHANGE_YesNoAll active, - enum TALER_EXCHANGE_YesNoAll failures, - TALER_MERCHANTDB_ReservesCallback cb, - void *cb_cls); - - - /** - * Lookup reserves pending activation across all instances. - * - * @param cls closure - * @param cb function to call with reserve data - * @param cb_cls closure for @a cb - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_pending_reserves)(void *cls, - TALER_MERCHANTDB_PendingReservesCallback cb, - void *cb_cls); - - - /** - * Lookup reserve details. - * - * @param cls closure - * @param instance_id instance to lookup payments for - * @param reserve_pub public key of the reserve to inspect - * @param fetch_rewards if true, also return information about rewards - * @param cb function to call with reserve summary data - * @param cb_cls closure for @a cb - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_reserve)(void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_rewards, - TALER_MERCHANTDB_ReserveDetailsCallback cb, - void *cb_cls); - - - /** - * Delete private key of a reserve. - * - * @param cls closure - * @param instance_id instance to lookup payments for - * @param reserve_pub public key of the reserve to delete - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*delete_reserve)(void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub); - - /** - * Purge all information about a reserve (including rewards from it). - * - * @param cls closure - * @param instance_id instance to lookup payments for - * @param reserve_pub public key of the reserve to purge - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*purge_reserve)(void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub); - - - /** - * Authorize a reward over @a amount from reserve @a reserve_pub. Remember - * the authorization under @a reward_id for later, together with the - * @a justification. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should generate the reward - * @param reserve_pub which reserve is debited, NULL to pick one in the DB - * @param amount how high is the reward (with fees) - * @param justification why was the reward approved - * @param next_url where to send the URL post reward pickup - * @param[out] reward_id set to the unique ID for the reward - * @param[out] expiration set to when the reward expires - * @return transaction status, - * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired - * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known - * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left - * #TALER_EC_GENERIC_DB_START_FAILED on hard DB errors - * #TALER_EC_GENERIC_DB_FETCH_FAILED on hard DB errors - * #TALER_EC_GENERIC_DB_STORE_FAILED on hard DB errors - * #TALER_EC_GENERIC_DB_INVARIANT_FAILURE on hard DB errors - * #TALER_EC_GENERIC_DB_SOFT_FAILURE on soft DB errors (client should retry) - * #TALER_EC_NONE upon success - */ - enum TALER_ErrorCode - (*authorize_reward)(void *cls, - const char *instance_id, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - const char *justification, - const char *next_url, - struct TALER_RewardIdentifierP *reward_id, - struct GNUNET_TIME_Timestamp *expiration); - - - /** - * Lookup pickup details for pickup @a pickup_id. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup reward details for - * @param reward_id which reward should we lookup details on - * @param pickup_id which pickup should we lookup details on - * @param[out] exchange_url which exchange is the reward withdrawn from - * @param[out] reserve_priv private key the reward is withdrawn from (set if still available!) - * @param sigs_length length of the @a sigs array - * @param[out] sigs set to the (blind) signatures we have for this @a pickup_id, - * those that are unavailable are left at NULL - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_pickup)(void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - const struct TALER_PickupIdentifierP *pickup_id, - char **exchange_url, - struct TALER_ReservePrivateKeyP *reserve_priv, - unsigned int sigs_length, - struct TALER_BlindedDenominationSignature sigs[]); - - - /** - * Lookup reward details for reward @a reward_id. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup reward details for - * @param reward_id which reward should we lookup details on - * @param[out] total_authorized amount how high is the reward (with fees) - * @param[out] total_picked_up how much of the reward was so far picked up (with fees) - * @param[out] expiration set to when the reward expires - * @param[out] exchange_url set to the exchange URL where the reserve is - * @param[out] next_url set to the URL where the wallet should navigate to after getting the reward - * @param[out] reserve_priv set to private key of reserve to be debited - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_reward)(void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - struct TALER_Amount *total_authorized, - struct TALER_Amount *total_picked_up, - struct GNUNET_TIME_Timestamp *expiration, - char **exchange_url, - char **next_url, - struct TALER_ReservePrivateKeyP *reserve_priv); - - - /** - * Lookup rewards - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup rewards for - * @param expired should we include expired rewards? - * @param limit maximum number of results to return, positive for - * ascending row id, negative for descending - * @param offset row id to start returning results from - * @param cb function to call with reward data - * @param cb_cls closure for @a cb - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_rewards)(void *cls, - const char *instance_id, - enum TALER_EXCHANGE_YesNoAll expired, - int64_t limit, - uint64_t offset, - TALER_MERCHANTDB_RewardsCallback cb, - void *cb_cls); - - - /** - * Lookup reward details for reward @a reward_id. - * - * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup reward details for - * @param reward_id which reward should we lookup details on - * @param fpu should we fetch details about individual pickups - * @param[out] total_authorized amount how high is the reward (with fees) - * @param[out] total_picked_up how much of the reward was so far picked up (with fees) - * @param[out] justification why was the reward approved - * @param[out] expiration set to when the reward expires - * @param[out] reserve_pub set to which reserve is debited - * @param[out] pickups_length set to the length of @e pickups - * @param[out] pickups if @a fpu is true, set to details about the pickup operations - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_reward_details)(void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - bool fpu, - struct TALER_Amount *total_authorized, - struct TALER_Amount *total_picked_up, - char **justification, - struct GNUNET_TIME_Timestamp *expiration, - struct TALER_ReservePublicKeyP *reserve_pub, - unsigned int *pickups_length, - struct TALER_MERCHANTDB_PickupDetails **pickups); - - - /** - * Insert details about a reward pickup operation. The @a total_picked_up - * UPDATES the total amount under the @a reward_id, while the @a total_requested - * is the amount to be associated with this @a pickup_id. - * While there is usually only one pickup event that picks up the entire - * amount, our schema allows for wallets to pick up the amount incrementally - * over mulrewardle pick up operations. - * - * @param cls closure, typically a connection to the db - * @param reward_id the unique ID for the reward - * @param total_picked_up how much was picked up overall at this - * point (includes @a total_requested) - * @param pickup_id unique ID for the operation - * @param total_requested how much is being picked up in this operation - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known - */ - enum GNUNET_DB_QueryStatus - (*insert_pickup)(void *cls, - const char *instance_id, - const struct TALER_RewardIdentifierP *reward_id, - const struct TALER_Amount *total_picked_up, - const struct TALER_PickupIdentifierP *pickup_id, - const struct TALER_Amount *total_requested); - - - /** - * Insert blind signature obtained from the exchange during a - * reward pickup operation. - * - * @param cls closure, typically a connection to the db - * @param pickup_id unique ID for the operation - * @param offset offset of the blind signature for the pickup - * @param blind_sig the blind signature - * @return transaction status, usually - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success - * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known - */ - enum GNUNET_DB_QueryStatus - (*insert_pickup_blind_signature)( - void *cls, - const struct TALER_PickupIdentifierP *pickup_id, - uint32_t offset, - const struct TALER_BlindedDenominationSignature *blind_sig); - - - /** * Lookup all of the templates the given instance has configured. * * @param cls closure |