From 9443c10d7feb0d91323869dd08ec61ca781564f4 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 11 Jan 2020 15:19:56 +0100 Subject: major refactoring, eliminating wire-plugins and moving towards new bank API. main code compiles, testcases known to fail, code sure not to fully work yet --- src/exchange/Makefile.am | 5 + src/exchange/taler-exchange-aggregator.c | 448 +++++++++++-------------- src/exchange/taler-exchange-httpd_deposit.c | 13 - src/exchange/taler-exchange-httpd_validation.c | 142 +------- src/exchange/taler-exchange-wirewatch.c | 271 +++++---------- 5 files changed, 296 insertions(+), 583 deletions(-) (limited to 'src/exchange') diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 3453683ae..b08c85c6f 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -29,9 +29,11 @@ taler_exchange_aggregator_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/wire/libtalerwire.la \ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ -ljansson \ + -lgnunetcurl \ -lgnunetutil taler_exchange_wirewatch_SOURCES = \ @@ -40,9 +42,11 @@ taler_exchange_wirewatch_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/wire/libtalerwire.la \ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ -ljansson \ + -lgnunetcurl \ -lgnunetutil taler_exchange_httpd_SOURCES = \ @@ -66,6 +70,7 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_validation.c taler-exchange-httpd_validation.h taler_exchange_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/wire/libtalerwire.la \ $(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 71a3efd7d..2704f5910 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2016-2018 Taler Systems SA + Copyright (C) 2016-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 @@ -26,6 +26,7 @@ #include "taler_exchangedb_lib.h" #include "taler_exchangedb_plugin.h" #include "taler_json_lib.h" +#include "taler_bank_service.h" #include "taler_wire_lib.h" @@ -45,9 +46,14 @@ struct WireAccount struct WireAccount *prev; /** - * Handle to the plugin. + * Account information. */ - struct TALER_WIRE_Plugin *wire_plugin; + struct TALER_Account account; + + /** + * Authentication data. + */ + struct TALER_BANK_AuthenticationData auth; /** * Wire transfer fee structure. @@ -59,6 +65,11 @@ struct WireAccount */ char *section_name; + /** + * Name of the wire method underlying the account. + */ + char *method; + }; @@ -77,7 +88,7 @@ struct WirePrepareData /** * Wire execution handle. */ - struct TALER_WIRE_ExecuteHandle *eh; + struct TALER_BANK_WireExecuteHandle *eh; /** * Wire plugin used for this preparation. @@ -187,10 +198,6 @@ struct AggregationUnit */ struct CloseTransferContext { - /** - * Handle for preparing the wire transfer. - */ - struct TALER_WIRE_PrepareHandle *ph; /** * Our database session. @@ -262,6 +269,16 @@ static struct WirePrepareData *wpd; */ static struct AggregationUnit *au; +/** + * Handle to the context for interacting with the bank. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Scheduler context for running the @e ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + /** * Value to return from main(). #GNUNET_OK on success, #GNUNET_SYSERR * on serious errors. @@ -339,7 +356,7 @@ update_fees (struct WireAccount *wa, return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* Let's try to load it from disk... */ wa->af = TALER_EXCHANGEDB_fees_read (cfg, - wa->wire_plugin->method); + wa->method); advance_fees (wa, now); for (struct TALER_EXCHANGEDB_AggregateFees *p = wa->af; @@ -348,7 +365,7 @@ update_fees (struct WireAccount *wa, { qs = db_plugin->insert_wire_fee (db_plugin->cls, session, - wa->wire_plugin->method, + wa->method, p->start_date, p->end_date, &p->wire_fee, @@ -365,7 +382,7 @@ update_fees (struct WireAccount *wa, return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to find current wire transfer fees for `%s'\n", - wa->wire_plugin->method); + wa->method); return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } @@ -381,7 +398,7 @@ find_account_by_method (const char *method) { for (struct WireAccount *wa = wa_head; NULL != wa; wa = wa->next) if (0 == strcmp (method, - wa->wire_plugin->method)) + wa->method)) return wa; return NULL; } @@ -431,13 +448,40 @@ add_account_cb (void *cls, if (GNUNET_YES != ai->debit_enabled) return; /* not enabled for us, skip */ wa = GNUNET_new (struct WireAccount); - wa->wire_plugin = TALER_WIRE_plugin_load (cfg, - ai->plugin_name); - if (NULL == wa->wire_plugin) + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + ai->section_name, + "METHOD", + &wa->method)) { - fprintf (stderr, - "Failed to load wire plugin for `%s'\n", - ai->plugin_name); + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + ai->section_name, + "METHOD"); + GNUNET_free (wa); + return; + } + if (GNUNET_OK != + TALER_BANK_auth_parse_cfg (cfg, + ai->section_name, + &wa->auth)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to load account `%s'\n", + ai->section_name); + GNUNET_free (wa->method); + GNUNET_free (wa); + return; + } + if (GNUNET_OK != + TALER_BANK_account_parse_cfg (cfg, + ai->section_name, + &wa->account)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to load account `%s'\n", + ai->section_name); + TALER_BANK_auth_free (&wa->auth); + GNUNET_free (wa->method); GNUNET_free (wa); return; } @@ -476,6 +520,16 @@ static void shutdown_task (void *cls) { (void) cls; + if (NULL != ctx) + { + GNUNET_CURL_fini (ctx); + ctx = NULL; + } + if (NULL != rc) + { + GNUNET_CURL_gnunet_rc_destroy (rc); + rc = NULL; + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running shutdown\n"); if (NULL != task) @@ -487,9 +541,7 @@ shutdown_task (void *cls) { if (NULL != wpd->eh) { - wpd->wa->wire_plugin->execute_wire_transfer_cancel ( - wpd->wa->wire_plugin->cls, - wpd->eh); + TALER_BANK_execute_wire_transfer_cancel (wpd->eh); wpd->eh = NULL; } db_plugin->rollback (db_plugin->cls, @@ -499,23 +551,12 @@ shutdown_task (void *cls) } if (NULL != au) { - if (NULL != au->ph) - { - au->wa->wire_plugin->prepare_wire_transfer_cancel ( - au->wa->wire_plugin->cls, - au->ph); - au->ph = NULL; - } db_plugin->rollback (db_plugin->cls, au->session); cleanup_au (); } if (NULL != ctc) { - ctc->wa->wire_plugin->prepare_wire_transfer_cancel ( - ctc->wa->wire_plugin->cls, - ctc->ph); - ctc->ph = NULL; db_plugin->rollback (db_plugin->cls, ctc->session); GNUNET_free (ctc->method); @@ -532,9 +573,11 @@ shutdown_task (void *cls) GNUNET_CONTAINER_DLL_remove (wa_head, wa_tail, wa); - TALER_WIRE_plugin_unload (wa->wire_plugin); + TALER_WIRE_account_free (&wa->account); + TALER_BANK_auth_free (&wa->auth); TALER_EXCHANGEDB_fees_free (wa->af); GNUNET_free (wa->section_name); + GNUNET_free (wa->method); GNUNET_free (wa); } } @@ -921,20 +964,6 @@ aggregate_cb (void *cls, } -/** - * Function to be called with the prepared transfer data - * when running an aggregation on a merchant. - * - * @param cls closure with the `struct AggregationUnit` - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, - const char *buf, - size_t buf_size); - - /** * Main work function that finds and triggers transfers for reserves * closures. @@ -988,83 +1017,6 @@ commit_or_warn (struct TALER_EXCHANGEDB_Session *session) } -/** - * Function to be called with the prepared transfer data - * when closing a reserve. - * - * @param cls closure with a `struct CloseTransferContext` - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_close_cb (void *cls, - const char *buf, - size_t buf_size) -{ - enum GNUNET_DB_QueryStatus qs; - - GNUNET_assert (cls == ctc); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Prepared for reserve closing\n"); - ctc->ph = NULL; - if (NULL == buf) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - ctc->session); - /* start again */ - GNUNET_free (ctc->method); - GNUNET_free (ctc); - ctc = NULL; - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - NULL); - return; - } - - /* Commit our intention to execute the wire transfer! */ - qs = db_plugin->wire_prepare_data_insert (db_plugin->cls, - ctc->session, - ctc->method, - buf, - buf_size); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - db_plugin->rollback (db_plugin->cls, - ctc->session); - global_ret = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - GNUNET_free (ctc->method); - GNUNET_free (ctc); - ctc = NULL; - return; - } - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - db_plugin->rollback (db_plugin->cls, - ctc->session); - /* start again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - NULL); - GNUNET_free (ctc->method); - GNUNET_free (ctc); - ctc = NULL; - return; - } - - /* finally commit */ - (void) commit_or_warn (ctc->session); - GNUNET_free (ctc->method); - GNUNET_free (ctc); - ctc = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Reserve closure committed, running transfer\n"); - task = GNUNET_SCHEDULER_add_now (&run_transfers, - NULL); -} - - /** * Closure for #expired_reserve_cb(). */ @@ -1113,6 +1065,8 @@ expired_reserve_cb (void *cls, int ret; enum GNUNET_DB_QueryStatus qs; struct WireAccount *wa; + void *buf; + size_t buf_size; /* NOTE: potential optimization: use custom SQL API to not fetch this: */ @@ -1121,7 +1075,7 @@ expired_reserve_cb (void *cls, now = GNUNET_TIME_absolute_get (); (void) GNUNET_TIME_round_abs (&now); - /* lookup wire plugin */ + /* lookup account we should use */ wa = find_account_by_url (account_details); if (NULL == wa) { @@ -1161,6 +1115,18 @@ expired_reserve_cb (void *cls, TALER_amount_get_zero (left->currency, &amount_without_fee)); } + /* round down to enable transfer */ + if (GNUNET_SYSERR == + TALER_WIRE_amount_round (&amount_without_fee)) + { + GNUNET_break (0); + global_ret = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if ( (0 == amount_without_fee.value) && + (0 == amount_without_fee.fraction) ) + ret = GNUNET_NO; /* NOTE: sizeof (*reserve_pub) == sizeof (wtid) right now, but to be future-compatible, we use the memset + min construction */ @@ -1171,61 +1137,23 @@ expired_reserve_cb (void *cls, reserve_pub, GNUNET_MIN (sizeof (wtid), sizeof (*reserve_pub))); - - qs = db_plugin->insert_reserve_closed (db_plugin->cls, - session, - reserve_pub, - now, - account_details, - &wtid, - left, - closing_fee); - + if (GNUNET_SYSERR != ret) + qs = db_plugin->insert_reserve_closed (db_plugin->cls, + session, + reserve_pub, + now, + account_details, + &wtid, + left, + closing_fee); + else + ret = GNUNET_DB_STATUS_HARD_ERROR; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Closing reserve %s over %s (%d, %d)\n", TALER_B2S (reserve_pub), TALER_amount2s (left), ret, qs); - if ( (GNUNET_OK == ret) && - (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) ) - { - /* success, perform wire transfer */ - if (GNUNET_SYSERR == - wa->wire_plugin->amount_round (wa->wire_plugin->cls, - &amount_without_fee)) - { - GNUNET_break (0); - global_ret = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - return GNUNET_DB_STATUS_HARD_ERROR; - } - ctc = GNUNET_new (struct CloseTransferContext); - ctc->wa = wa; - ctc->session = session; - ctc->method = TALER_WIRE_payto_get_method (account_details); - ctc->ph - = wa->wire_plugin->prepare_wire_transfer (wa->wire_plugin->cls, - wa->section_name, - account_details, - &amount_without_fee, - exchange_base_url, - &wtid, - &prepare_close_cb, - ctc); - if (NULL == ctc->ph) - { - GNUNET_break (0); - global_ret = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - GNUNET_free (ctc->method); - GNUNET_free (ctc); - ctc = NULL; - return GNUNET_DB_STATUS_HARD_ERROR; - } - erc->async_cont = GNUNET_YES; - return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - } /* Check for hard failure */ if ( (GNUNET_SYSERR == ret) || (GNUNET_DB_STATUS_HARD_ERROR == qs) ) @@ -1235,10 +1163,59 @@ expired_reserve_cb (void *cls, GNUNET_SCHEDULER_shutdown (); return GNUNET_DB_STATUS_HARD_ERROR; } - /* Reserve balance was almost zero OR soft error */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Reserve was virtually empty, moving on\n"); - return qs; + if ( (GNUNET_OK != ret) || + (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ) + { + /* Reserve balance was almost zero OR soft error */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Reserve was virtually empty, moving on\n"); + (void) commit_or_warn (ctc->session); + GNUNET_free (ctc->method); + GNUNET_free (ctc); + ctc = NULL; + task = GNUNET_SCHEDULER_add_now (&run_transfers, + NULL); + return qs; + } + + /* success, perform wire transfer */ + ctc = GNUNET_new (struct CloseTransferContext); + ctc->wa = wa; + ctc->session = session; + ctc->method = TALER_WIRE_payto_get_method (account_details); + TALER_BANK_prepare_wire_transfer (account_details, + &amount_without_fee, + exchange_base_url, + &wtid, + &buf, + &buf_size); + /* Commit our intention to execute the wire transfer! */ + qs = db_plugin->wire_prepare_data_insert (db_plugin->cls, + ctc->session, + ctc->method, + buf, + buf_size); + GNUNET_free (buf); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); + GNUNET_free (ctc->method); + GNUNET_free (ctc); + ctc = NULL; + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + { + /* start again */ + GNUNET_free (ctc->method); + GNUNET_free (ctc); + ctc = NULL; + return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + } + erc->async_cont = GNUNET_YES; + task = GNUNET_SCHEDULER_add_now (&run_transfers, + NULL); + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; } @@ -1344,6 +1321,8 @@ run_aggregation (void *cls) struct TALER_EXCHANGEDB_Session *session; enum GNUNET_DB_QueryStatus qs; const struct GNUNET_SCHEDULER_TaskContext *tc; + void *buf; + size_t buf_size; (void) cls; task = NULL; @@ -1470,8 +1449,7 @@ run_aggregation (void *cls) &au->total_amount, &au->wire_fee)) || (GNUNET_SYSERR == - au->wa->wire_plugin->amount_round (au->wa->wire_plugin->cls, - &au->final_amount)) || + TALER_WIRE_amount_round (&au->final_amount)) || ( (0 == au->final_amount.value) && (0 == au->final_amount.fraction) ) ) { @@ -1555,70 +1533,26 @@ run_aggregation (void *cls) char *url; url = TALER_JSON_wire_to_payto (au->wire); - au->ph = au->wa->wire_plugin->prepare_wire_transfer ( - au->wa->wire_plugin->cls, - au->wa->section_name, - url, - &au->final_amount, - exchange_base_url, - &au->wtid, - &prepare_cb, - au); + TALER_BANK_prepare_wire_transfer (url, + &au->final_amount, + exchange_base_url, + &au->wtid, + &buf, + &buf_size); GNUNET_free (url); } - if (NULL == au->ph) - { - /* something went very wrong, likely bad configuration, - abort */ - db_plugin->rollback (db_plugin->cls, - session); - cleanup_au (); - GNUNET_SCHEDULER_shutdown (); - return; - } - /* otherwise we continue with #prepare_cb(), see below */ -} - - -/** - * Function to be called with the prepared transfer data. - * - * @param cls NULL - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, - const char *buf, - size_t buf_size) -{ - struct TALER_EXCHANGEDB_Session *session = au->session; - enum GNUNET_DB_QueryStatus qs; - - (void) cls; GNUNET_free_non_null (au->additional_rows); au->additional_rows = NULL; - if (NULL == buf) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - session); - /* start again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - NULL); - cleanup_au (); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing %u bytes of wire prepare data\n", (unsigned int) buf_size); /* Commit our intention to execute the wire transfer! */ qs = db_plugin->wire_prepare_data_insert (db_plugin->cls, session, - au->wa->wire_plugin->method, + au->wa->method, buf, buf_size); + GNUNET_free (buf); /* Commit the WTID data to 'wire_out' to finally satisfy aggregation table constraints */ if (qs >= 0) @@ -1691,29 +1625,30 @@ prepare_cb (void *cls, * Function called with the result from the execute step. * * @param cls NULL - * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure - * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error - * @param emsg NULL on success, otherwise an error message + * @param http_status_code #MHD_HTTP_OK on success + * @param ec taler error code + * @param row_id unique ID of the wire transfer in the bank's records + * @param wire_timestamp when did the transfer happen */ static void wire_confirm_cb (void *cls, - int success, - const void *row_id, - size_t row_id_size, - const char *emsg) + unsigned int http_status_code, + enum TALER_ErrorCode ec, + uint64_t row_id, + struct GNUNET_TIME_Absolute wire_timestamp) { struct TALER_EXCHANGEDB_Session *session = wpd->session; enum GNUNET_DB_QueryStatus qs; (void) cls; (void) row_id; - (void) row_id_size; wpd->eh = NULL; - if (GNUNET_SYSERR == success) + if (MHD_HTTP_OK != http_status_code) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire transaction failed: %s\n", - emsg); + "Wire transaction failed: %u/%d\n", + http_status_code, + ec); db_plugin->rollback (db_plugin->cls, session); global_ret = GNUNET_SYSERR; @@ -1792,6 +1727,8 @@ wire_prepare_cb (void *cls, const char *buf, size_t buf_size) { + struct WireAccount *wa; + (void) cls; wpd->row_id = rowid; GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -1811,12 +1748,15 @@ wire_prepare_cb (void *cls, wpd = NULL; return; } - wpd->eh = wpd->wa->wire_plugin->execute_wire_transfer ( - wpd->wa->wire_plugin->cls, - buf, - buf_size, - &wire_confirm_cb, - NULL); + wa = wpd->wa; + wpd->eh = TALER_BANK_execute_wire_transfer (ctx, + wa->account.details.x_taler_bank. + account_base_url, + &wa->auth, + buf, + buf_size, + &wire_confirm_cb, + NULL); if (NULL == wpd->eh) { GNUNET_break (0); /* why? how to best recover? */ @@ -1927,6 +1867,7 @@ run (void *cls, (void) cls; (void) args; (void) cfgfile; + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "exchange", @@ -1947,6 +1888,15 @@ run (void *cls, global_ret = 1; return; } + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + if (NULL == ctx) + { + GNUNET_break (0); + return; + } + task = GNUNET_SCHEDULER_add_now (&run_transfers, NULL); GNUNET_SCHEDULER_add_shutdown (&shutdown_task, diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 024482389..96e30e437 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -400,7 +400,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, json_t *json; int res; json_t *wire; - char *emsg; enum TALER_ErrorCode ec; unsigned int hc; struct TALER_EXCHANGEDB_Deposit deposit; @@ -460,18 +459,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, "refund_deadline"); } - if (TALER_EC_NONE != - (ec = TEH_json_validate_wireformat (wire, - &emsg))) - { - GNUNET_JSON_parse_free (spec); - res = TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - ec, - emsg); - GNUNET_free (emsg); - return res; - } if (GNUNET_OK != check_timestamp_current (deposit.timestamp)) { diff --git a/src/exchange/taler-exchange-httpd_validation.c b/src/exchange/taler-exchange-httpd_validation.c index 23dbbf249..d0371e930 100644 --- a/src/exchange/taler-exchange-httpd_validation.c +++ b/src/exchange/taler-exchange-httpd_validation.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2016, 2017, 2018 Taler Systems SA + Copyright (C) 2016-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 @@ -29,40 +29,6 @@ #include "taler_wire_lib.h" -/** - * Information we keep for each plugin. - */ -struct Plugin -{ - - /** - * We keep plugins in a DLL. - */ - struct Plugin *next; - - /** - * We keep plugins in a DLL. - */ - struct Plugin *prev; - - /** - * Pointer to the plugin. - */ - struct TALER_WIRE_Plugin *plugin; - -}; - - -/** - * Head of DLL of wire plugins. - */ -static struct Plugin *wire_head; - -/** - * Tail of DLL of wire plugins. - */ -static struct Plugin *wire_tail; - /** * Array of wire methods supported by this exchange. */ @@ -191,9 +157,8 @@ load_account (void *cls, else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fees not specified for `%s', ignoring plugin %s\n", - method, - ai->plugin_name); + "Wire fees not specified for `%s'\n", + method); *ret = GNUNET_SYSERR; } GNUNET_free (method); @@ -201,35 +166,15 @@ load_account (void *cls, if (GNUNET_YES == ai->debit_enabled) { - struct Plugin *p; - - p = GNUNET_new (struct Plugin); - p->plugin = TALER_WIRE_plugin_load (cfg, - ai->plugin_name); - if (NULL == p->plugin) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to load plugin %s\n", - ai->plugin_name); - GNUNET_free (p); - *ret = GNUNET_SYSERR; - return; - } if (GNUNET_OK != - load_fee (p->plugin->method)) + load_fee (ai->method)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Disabling plugin `%s' as wire transfer fees for `%s' are not given correctly\n", - ai->plugin_name, - p->plugin->method); - TALER_WIRE_plugin_unload (p->plugin); - GNUNET_free (p); + "Wire transfer fees for `%s' are not given correctly\n", + ai->method); *ret = GNUNET_SYSERR; return; } - GNUNET_CONTAINER_DLL_insert (wire_head, - wire_tail, - p); } } @@ -251,12 +196,6 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg) TALER_EXCHANGEDB_find_accounts (cfg, &load_account, &ret); - if (NULL == wire_head) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to find properly configured wire transfer method\n"); - ret = GNUNET_SYSERR; - } if (GNUNET_OK != ret) TEH_VALIDATION_done (); return ret; @@ -269,16 +208,6 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg) void TEH_VALIDATION_done () { - struct Plugin *p; - - while (NULL != (p = wire_head)) - { - GNUNET_CONTAINER_DLL_remove (wire_head, - wire_tail, - p); - TALER_WIRE_plugin_unload (p->plugin); - GNUNET_free (p); - } json_decref (wire_fee_object); wire_fee_object = NULL; json_decref (wire_accounts_array); @@ -286,65 +215,6 @@ TEH_VALIDATION_done () } -/** - * Check if the given wire format JSON object is correctly formatted as - * a wire address. - * - * @param wire the JSON wire format object - * @param[out] emsg set to error message if we return an error code - * @return #TALER_EC_NONE if correctly formatted; otherwise error code - */ -enum TALER_ErrorCode -TEH_json_validate_wireformat (const json_t *wire, - char **emsg) -{ - const char *payto_url; - json_error_t error; - char *method; - - *emsg = NULL; - if (0 != json_unpack_ex ((json_t *) wire, - &error, 0, - "{s:s}", - "url", &payto_url)) - { - GNUNET_asprintf (emsg, - "No `url' specified in the wire details\n"); - return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING; - } - method = TALER_WIRE_payto_get_method (payto_url); - if (NULL == method) - { - GNUNET_asprintf (emsg, - "Malformed payto URL `%s'\n", - payto_url); - return TALER_EC_PAYTO_MALFORMED; - } - for (struct Plugin *p = wire_head; NULL != p; p = p->next) - { - if (0 == strcasecmp (p->plugin->method, - method)) - { - enum TALER_ErrorCode ec; - - GNUNET_free (method); - ec = p->plugin->wire_validate (p->plugin->cls, - payto_url); - if (TALER_EC_NONE != ec) - GNUNET_asprintf (emsg, - "Payto URL `%s' rejected by plugin\n", - payto_url); - return ec; - } - } - GNUNET_asprintf (emsg, - "Wire format type `%s' is not supported by this exchange\n", - method); - GNUNET_free (method); - return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED; -} - - /** * Obtain JSON response for /wire * diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 21f62cd82..091f4ba20 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -27,6 +27,7 @@ #include "taler_exchangedb_lib.h" #include "taler_exchangedb_plugin.h" #include "taler_json_lib.h" +#include "taler_bank_service.h" #include "taler_wire_lib.h" /** @@ -36,23 +37,6 @@ #define DELAY GNUNET_TIME_UNIT_SECONDS -/** - * Closure for #reject_cb(). - */ -struct RejectContext -{ - /** - * Wire transfer subject that was illformed. - */ - char *wtid_s; - - /** - * Database session that encountered the problem. - */ - struct TALER_EXCHANGEDB_Session *session; -}; - - /** * Information we keep for each supported account. */ @@ -69,14 +53,19 @@ struct WireAccount struct WireAccount *prev; /** - * Handle to the plugin. + * Name of the section that configures this account. */ - struct TALER_WIRE_Plugin *wire_plugin; + char *section_name; /** - * Name of the section that configures this account. + * Account information. */ - char *section_name; + struct TALER_Account account; + + /** + * Authentication data. + */ + struct TALER_BANK_AuthenticationData auth; /** * Are we running from scratch and should re-process all transactions @@ -107,6 +96,16 @@ static struct WireAccount *wa_tail; */ static struct WireAccount *wa_pos; +/** + * Handle to the context for interacting with the bank. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Scheduler context for running the @e ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + /** * Which currency is used by this exchange? */ @@ -132,23 +131,13 @@ static int global_ret; * Encoded offset in the wire transfer list from where * to start the next query with the bank. */ -static void *last_row_off; - -/** - * Number of bytes in #last_row_off. - */ -static size_t last_row_off_size; +static uint64_t last_row_off; /** * Latest row offset seen in this transaction, becomes * the new #last_row_off upon commit. */ -static void *latest_row_off; - -/** - * Number of bytes in #latest_row_off. - */ -static size_t latest_row_off_size; +static uint64_t latest_row_off; /** * Should we delay the next request to the wire plugin a bit? @@ -183,12 +172,7 @@ static struct GNUNET_SCHEDULER_Task *task; /** * Active request for history. */ -static struct TALER_WIRE_HistoryHandle *hh; - -/** - * Active request to reject a wire transfer. - */ -static struct TALER_WIRE_RejectHandle *rt; +static struct TALER_BANK_CreditHistoryHandle *hh; /** @@ -202,6 +186,16 @@ shutdown_task (void *cls) struct WireAccount *wa; (void) cls; + if (NULL != ctx) + { + GNUNET_CURL_fini (ctx); + ctx = NULL; + } + if (NULL != rc) + { + GNUNET_CURL_gnunet_rc_destroy (rc); + rc = NULL; + } if (NULL != task) { GNUNET_SCHEDULER_cancel (task); @@ -209,20 +203,9 @@ shutdown_task (void *cls) } if (NULL != hh) { - wa_pos->wire_plugin->get_history_cancel (wa_pos->wire_plugin->cls, - hh); + TALER_BANK_credit_history_cancel (hh); hh = NULL; } - if (NULL != rt) - { - char *wtid_s; - - wtid_s = wa_pos->wire_plugin->reject_transfer_cancel ( - wa_pos->wire_plugin->cls, - rt); - rt = NULL; - GNUNET_free (wtid_s); - } TALER_EXCHANGEDB_plugin_unload (db_plugin); db_plugin = NULL; while (NULL != (wa = wa_head)) @@ -230,14 +213,13 @@ shutdown_task (void *cls) GNUNET_CONTAINER_DLL_remove (wa_head, wa_tail, wa); - TALER_WIRE_plugin_unload (wa->wire_plugin); + TALER_WIRE_account_free (&wa->account); + TALER_BANK_auth_free (&wa->auth); GNUNET_free (wa->section_name); GNUNET_free (wa); } wa_pos = NULL; - GNUNET_free_non_null (last_row_off); - last_row_off = NULL; - last_row_off_size = 0; + last_row_off = 0; } @@ -259,13 +241,26 @@ add_account_cb (void *cls, return; /* not enabled for us, skip */ wa = GNUNET_new (struct WireAccount); wa->reset_mode = reset_mode; - wa->wire_plugin = TALER_WIRE_plugin_load (cfg, - ai->plugin_name); - if (NULL == wa->wire_plugin) + if (GNUNET_OK != + TALER_BANK_auth_parse_cfg (cfg, + ai->section_name, + &wa->auth)) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Failed to load wire plugin for `%s'\n", - ai->plugin_name); + "Failed to load account `%s'\n", + ai->section_name); + GNUNET_free (wa); + return; + } + if (GNUNET_OK != + TALER_BANK_account_parse_cfg (cfg, + ai->section_name, + &wa->account)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to load account `%s'\n", + ai->section_name); + TALER_BANK_auth_free (&wa->auth); GNUNET_free (wa); return; } @@ -335,71 +330,29 @@ static void find_transfers (void *cls); -/** - * Function called upon completion of the rejection of a wire transfer. - * - * @param cls closure with the `struct RejectContext` - * @param ec error code for the operation - */ -static void -reject_cb (void *cls, - enum TALER_ErrorCode ec) -{ - struct RejectContext *rtc = cls; - enum GNUNET_DB_QueryStatus qs; - - rt = NULL; - if (TALER_EC_NONE != ec) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to wire back transfer `%s': %d\n", - rtc->wtid_s, - ec); - GNUNET_free (rtc->wtid_s); - db_plugin->rollback (db_plugin->cls, - rtc->session); - GNUNET_free (rtc); - GNUNET_SCHEDULER_shutdown (); - return; - } - GNUNET_free (rtc->wtid_s); - qs = db_plugin->commit (db_plugin->cls, - rtc->session); - GNUNET_break (0 <= qs); - GNUNET_free (rtc); - task = GNUNET_SCHEDULER_add_now (&find_transfers, - NULL); -} - - /** * Callbacks of this type are used to serve the result of asking * the bank for the transaction history. * * @param cls closure with the `struct TALER_EXCHANGEDB_Session *` * @param ec taler error code - * @param dir direction of the transfer - * @param row_off identification of the position at which we are querying - * @param row_off_size number of bytes in @a row_off + * @param serial_id identification of the position at which we are querying * @param details details about the wire transfer + * @param json raw JSON response * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration */ static int history_cb (void *cls, + unsigned int http_status, enum TALER_ErrorCode ec, - enum TALER_BANK_Direction dir, - const void *row_off, - size_t row_off_size, - const struct TALER_WIRE_TransferDetails *details) + uint64_t serial_id, + const struct TALER_BANK_CreditDetails *details, + const json_t *json) { struct TALER_EXCHANGEDB_Session *session = cls; enum GNUNET_DB_QueryStatus qs; - struct TALER_ReservePublicKeyP reserve_pub; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got history callback, direction %u!\n", - (unsigned int) dir); - if (TALER_BANK_DIRECTION_NONE == dir) + if (NULL == details) { hh = NULL; if (TALER_EC_NONE != ec) @@ -428,11 +381,8 @@ history_cb (void *cls, if (0 < qs) { /* transaction success, update #last_row_off */ - GNUNET_free_non_null (last_row_off); last_row_off = latest_row_off; - last_row_off_size = latest_row_off_size; - latest_row_off = NULL; - latest_row_off_size = 0; + latest_row_off = 0; /* if successful at limit, try increasing transaction batch size (AIMD) */ if (current_batch_size == batch_size) @@ -462,49 +412,10 @@ history_cb (void *cls, NULL); return GNUNET_OK; /* will be ignored anyway */ } - if (NULL != details->wtid_s) - { - struct RejectContext *rtc; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Wire transfer over %s has invalid subject `%s', sending it back!\n", - TALER_amount2s (&details->amount), - details->wtid_s); - GNUNET_break (0 != row_off_size); - if (latest_row_off_size != row_off_size) - { - GNUNET_free_non_null (latest_row_off); - latest_row_off = GNUNET_malloc (row_off_size); - latest_row_off_size = row_off_size; - } - memcpy (latest_row_off, - row_off, - row_off_size); - rtc = GNUNET_new (struct RejectContext); - rtc->session = session; - rtc->wtid_s = GNUNET_strdup (details->wtid_s); - rt = wa_pos->wire_plugin->reject_transfer (wa_pos->wire_plugin->cls, - wa_pos->section_name, - row_off, - row_off_size, - &reject_cb, - rtc); - if (NULL == rt) - { - GNUNET_break (0); - db_plugin->rollback (db_plugin->cls, - session); - GNUNET_assert (NULL == task); - task = GNUNET_SCHEDULER_add_now (&find_transfers, - NULL); - } - return GNUNET_SYSERR; /* will continue later... */ - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Adding wire transfer over %s with (hashed) subject `%s'\n", TALER_amount2s (&details->amount), - TALER_B2S (&details->wtid)); + TALER_B2S (&details->reserve_pub)); /** * Debug block. @@ -515,8 +426,8 @@ history_cb (void *cls, char wtid_s[PUBSIZE]; GNUNET_break - (NULL != GNUNET_STRINGS_data_to_string (&details->wtid, - sizeof (details->wtid), + (NULL != GNUNET_STRINGS_data_to_string (&details->reserve_pub, + sizeof (details->reserve_pub), &wtid_s[0], PUBSIZE)); GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -525,20 +436,14 @@ history_cb (void *cls, } current_batch_size++; - /* Wire transfer identifier == reserve public key */ - GNUNET_assert (sizeof (reserve_pub) == sizeof (details->wtid)); - memcpy (&reserve_pub, - &details->wtid, - sizeof (reserve_pub)); qs = db_plugin->reserves_in_insert (db_plugin->cls, session, - &reserve_pub, + &details->reserve_pub, &details->amount, details->execution_date, details->account_url, wa_pos->section_name, - row_off, - row_off_size); + serial_id); if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); @@ -560,15 +465,7 @@ history_cb (void *cls, return GNUNET_SYSERR; } - if (latest_row_off_size != row_off_size) - { - GNUNET_free_non_null (latest_row_off); - latest_row_off = GNUNET_malloc (row_off_size); - latest_row_off_size = row_off_size; - } - memcpy (latest_row_off, - row_off, - row_off_size); + latest_row_off = serial_id; return GNUNET_OK; } @@ -615,8 +512,7 @@ find_transfers (void *cls) qs = db_plugin->get_latest_reserve_in_reference (db_plugin->cls, session, wa_pos->section_name, - &last_row_off, - &last_row_off_size); + &last_row_off); if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -638,20 +534,17 @@ find_transfers (void *cls) } } wa_pos->reset_mode = GNUNET_NO; - GNUNET_assert ( (NULL == last_row_off) || - ( (NULL != last_row_off) && - (0 != last_row_off_size) ) ); delay = GNUNET_YES; current_batch_size = 0; - hh = wa_pos->wire_plugin->get_history (wa_pos->wire_plugin->cls, - wa_pos->section_name, - TALER_BANK_DIRECTION_CREDIT, - last_row_off, - last_row_off_size, - batch_size, - &history_cb, - session); + hh = TALER_BANK_credit_history (ctx, + wa_pos->account.details.x_taler_bank. + account_base_url, + &wa_pos->auth, + last_row_off, + batch_size, + &history_cb, + session); if (NULL == hh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -695,6 +588,14 @@ run (void *cls, NULL); GNUNET_SCHEDULER_add_shutdown (&shutdown_task, cls); + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + if (NULL == ctx) + { + GNUNET_break (0); + return; + } } -- cgit v1.2.3