From cbcc3727de347a2426ad6616ef577f0138b7d7e9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 11 Jan 2020 23:06:10 +0100 Subject: add separate transfer and admin/add/incoming commands --- src/bank-lib/Makefile.am | 4 +- src/bank-lib/bank_api_transaction.c | 368 ------------ src/bank-lib/bank_api_transfer.c | 368 ++++++++++++ src/bank-lib/fakebank_history.c | 182 ------ src/bank-lib/test_bank_api.c | 137 ++--- src/bank-lib/testing_api_cmd_admin_add_incoming.c | 625 ++++++++++++++++++++ src/bank-lib/testing_api_cmd_history_credit.c | 11 +- src/bank-lib/testing_api_cmd_history_debit.c | 12 +- src/bank-lib/testing_api_cmd_transfer.c | 394 +++++++++++++ src/benchmark/taler-exchange-benchmark.c | 15 +- src/include/Makefile.am | 4 +- src/include/backoff.h | 33 ++ src/include/taler_bank_service.h | 1 - src/include/taler_testing_bank_lib.h | 120 ++++ src/include/taler_testing_lib.h | 112 ---- src/lib/Makefile.am | 2 - src/lib/backoff.h | 38 -- src/lib/test_auditor_api.c | 12 +- src/lib/test_exchange_api.c | 12 +- src/lib/test_exchange_api_revocation.c | 10 +- src/lib/test_exchange_api_twisted.c | 12 +- src/lib/testing_api_cmd_fakebank_transfer.c | 661 ---------------------- 22 files changed, 1640 insertions(+), 1493 deletions(-) delete mode 100644 src/bank-lib/bank_api_transaction.c create mode 100644 src/bank-lib/bank_api_transfer.c delete mode 100644 src/bank-lib/fakebank_history.c create mode 100644 src/bank-lib/testing_api_cmd_admin_add_incoming.c create mode 100644 src/bank-lib/testing_api_cmd_transfer.c create mode 100644 src/include/backoff.h delete mode 100644 src/lib/backoff.h delete mode 100644 src/lib/testing_api_cmd_fakebank_transfer.c (limited to 'src') diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index 371f5e6d6..d7493bde8 100644 --- a/src/bank-lib/Makefile.am +++ b/src/bank-lib/Makefile.am @@ -41,7 +41,7 @@ libtalerbank_la_SOURCES = \ bank_api_common.c bank_api_common.h \ bank_api_credit.c \ bank_api_debit.c \ - bank_api_transaction.c \ + bank_api_transfer.c \ bank_api_parse.c libtalerbank_la_LIBADD = \ $(top_builddir)/src/json/libtalerjson.la \ @@ -70,8 +70,10 @@ libtalerbanktesting_la_LDFLAGS = \ -version-info 0:0:0 \ -no-undefined libtalerbanktesting_la_SOURCES = \ + testing_api_cmd_admin_add_incoming.c \ testing_api_cmd_history_credit.c \ testing_api_cmd_history_debit.c \ + testing_api_cmd_transfer.c \ testing_api_helpers.c libtalerbanktesting_la_LIBADD = \ $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/bank-lib/bank_api_transaction.c b/src/bank-lib/bank_api_transaction.c deleted file mode 100644 index 177328482..000000000 --- a/src/bank-lib/bank_api_transaction.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015--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 - -*/ -/** - * @file bank-lib/bank_api_transaction.c - * @brief Implementation of the /transaction/ requests of the bank's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include "bank_api_common.h" -#include /* just for HTTP status codes */ -#include "taler_signatures.h" -#include "taler_curl_lib.h" -#include "taler_bank_service.h" - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Data structure serialized in the prepare stage. - */ -struct WirePackP -{ - /** - * Random unique identifier for the request. - */ - struct GNUNET_HashCode request_uid; - - /** - * Amount to be transferred. - */ - struct TALER_AmountNBO amount; - - /** - * Wire transfer identifier to use. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /** - * Length of the payto:// URL of the target account, - * including 0-terminator, in network byte order. - */ - uint32_t account_len GNUNET_PACKED; - - /** - * Length of the exchange's base URL, - * including 0-terminator, in network byte order. - */ - uint32_t exchange_url_len GNUNET_PACKED; - -}; - -GNUNET_NETWORK_STRUCT_END - -/** - * Prepare for exeuction of a wire transfer. - * - * @param destination_account_url payto:// URL identifying where to send the money - * @param amount amount to transfer, already rounded - * @param exchange_base_url base URL of this exchange (included in subject - * to facilitate use of tracking API by merchant backend) - * @param wtid wire transfer identifier to use - * @param buf[out] set to transaction data to persist, NULL on error - * @param buf_size[out] set to number of bytes in @a buf, 0 on error - */ -void -TALER_BANK_prepare_wire_transfer (const char *destination_account_url, - const struct TALER_Amount *amount, - const char *exchange_base_url, - const struct - TALER_WireTransferIdentifierRawP *wtid, - void **buf, - size_t *buf_size) -{ - struct WirePackP *wp; - size_t d_len = strlen (destination_account_url) + 1; - size_t u_len = strlen (exchange_base_url) + 1; - char *end; - - *buf_size = sizeof (*wp) + d_len + u_len; - wp = GNUNET_malloc (*buf_size); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, - &wp->request_uid); - TALER_amount_hton (&wp->amount, - amount); - wp->wtid = *wtid; - wp->account_len = htonl ((uint32_t) d_len); - wp->exchange_url_len = htonl ((uint32_t) u_len); - end = (char *) &wp[1]; - memcpy (end, - destination_account_url, - d_len); - memcpy (end + d_len, - exchange_base_url, - u_len); - *buf = (char *) wp; -} - - -/** - * @brief An transaction Handle - */ -struct TALER_BANK_WireExecuteHandle -{ - - /** - * The url for this request. - */ - char *request_url; - - /** - * POST context. - */ - struct TEAH_PostContext post_ctx; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_BANK_ConfirmationCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - -}; - - -/** - * Function called when we're done processing the - * HTTP /transaction request. - * - * @param cls the `struct TALER_BANK_WireExecuteHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_transaction_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_BANK_WireExecuteHandle *weh = cls; - uint64_t row_id = UINT64_MAX; - struct GNUNET_TIME_Absolute timestamp; - enum TALER_ErrorCode ec; - const json_t *j = response; - - weh->job = NULL; - timestamp = GNUNET_TIME_UNIT_FOREVER_ABS; - switch (response_code) - { - case 0: - ec = TALER_EC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_uint64 ("row_id", - &row_id), - GNUNET_JSON_spec_absolute_time ("timestamp", - ×tamp), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - response_code = 0; - ec = TALER_EC_INVALID_RESPONSE; - break; - } - ec = TALER_EC_NONE; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the bank is buggy - (or API version conflict); just pass JSON reply to the application */ - ec = TALER_BANK_parse_ec_ (j); - break; - case MHD_HTTP_FORBIDDEN: - /* Access denied */ - ec = TALER_BANK_parse_ec_ (j); - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, bank says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - ec = TALER_BANK_parse_ec_ (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - ec = TALER_BANK_parse_ec_ (j); - break; - case MHD_HTTP_NOT_ACCEPTABLE: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - ec = TALER_BANK_parse_ec_ (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - ec = TALER_BANK_parse_ec_ (j); - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - (unsigned int) response_code); - GNUNET_break (0); - ec = TALER_BANK_parse_ec_ (j); - response_code = 0; - break; - } - weh->cb (weh->cb_cls, - response_code, - ec, - row_id, - timestamp); - TALER_BANK_execute_wire_transfer_cancel (weh); -} - - -/** - * Execute a wire transfer. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param buf buffer with the prepared execution details - * @param buf_size number of bytes in @a buf - * @param cc function to call upon success - * @param cc_cls closure for @a cc - * @return NULL on error - */ -struct TALER_BANK_WireExecuteHandle * -TALER_BANK_execute_wire_transfer (struct GNUNET_CURL_Context *ctx, - const char *bank_base_url, - const struct - TALER_BANK_AuthenticationData *auth, - const void *buf, - size_t buf_size, - TALER_BANK_ConfirmationCallback cc, - void *cc_cls) -{ - struct TALER_BANK_WireExecuteHandle *weh; - json_t *transaction_obj; - CURL *eh; - const struct WirePackP *wp = buf; - uint32_t d_len; - uint32_t u_len; - const char *destination_account_url; - const char *exchange_base_url; - struct TALER_Amount amount; - - if (sizeof (*wp) > buf_size) - { - GNUNET_break (0); - return NULL; - } - d_len = ntohl (wp->account_len); - u_len = ntohl (wp->exchange_url_len); - if (sizeof (*wp) + d_len + u_len != buf_size) - { - GNUNET_break (0); - return NULL; - } - destination_account_url = (const char *) &wp[1]; - exchange_base_url = destination_account_url + d_len; - if (NULL == bank_base_url) - { - GNUNET_break (0); - return NULL; - } - TALER_amount_ntoh (&amount, - &wp->amount); - transaction_obj = json_pack ("{s:o, s:o, s:s, s:o, s:o, s:s}", - "request_uid", GNUNET_JSON_from_data_auto ( - &wp->request_uid), - "amount", TALER_JSON_from_amount (&amount), - "exchange_url", exchange_base_url, - "wtid", GNUNET_JSON_from_data_auto (&wp->wtid), - "credit_account", destination_account_url); - if (NULL == transaction_obj) - { - GNUNET_break (0); - return NULL; - } - weh = GNUNET_new (struct TALER_BANK_WireExecuteHandle); - weh->cb = cc; - weh->cb_cls = cc_cls; - weh->request_url = TALER_BANK_path_to_url_ (bank_base_url, - "/transaction"); - weh->post_ctx.headers = curl_slist_append - (weh->post_ctx.headers, - "Content-Type: application/json"); - - eh = curl_easy_init (); - if ( (GNUNET_OK != - TALER_BANK_setup_auth_ (eh, - auth)) || - (CURLE_OK != - curl_easy_setopt (eh, - CURLOPT_URL, - weh->request_url)) || - (GNUNET_OK != - TALER_curl_easy_post (&weh->post_ctx, - eh, - transaction_obj)) ) - { - GNUNET_break (0); - TALER_BANK_execute_wire_transfer_cancel (weh); - curl_easy_cleanup (eh); - json_decref (transaction_obj); - return NULL; - } - json_decref (transaction_obj); - - weh->job = GNUNET_CURL_job_add2 (ctx, - eh, - weh->post_ctx.headers, - &handle_transaction_finished, - weh); - return weh; -} - - -/** - * Cancel a wire transfer. This function cannot be used on a request handle - * if a response is already served for it. - * - * @param weh the wire transfer request handle - */ -void -TALER_BANK_execute_wire_transfer_cancel (struct - TALER_BANK_WireExecuteHandle *weh) -{ - if (NULL != weh->job) - { - GNUNET_CURL_job_cancel (weh->job); - weh->job = NULL; - } - TALER_curl_easy_post_finished (&weh->post_ctx); - GNUNET_free (weh->request_url); - GNUNET_free (weh); -} - - -/* end of bank_api_transaction.c */ diff --git a/src/bank-lib/bank_api_transfer.c b/src/bank-lib/bank_api_transfer.c new file mode 100644 index 000000000..93ff7baca --- /dev/null +++ b/src/bank-lib/bank_api_transfer.c @@ -0,0 +1,368 @@ +/* + This file is part of TALER + Copyright (C) 2015--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 + +*/ +/** + * @file bank-lib/bank_api_transfer.c + * @brief Implementation of the /transfer/ requests of the bank's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include "bank_api_common.h" +#include /* just for HTTP status codes */ +#include "taler_signatures.h" +#include "taler_curl_lib.h" +#include "taler_bank_service.h" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Data structure serialized in the prepare stage. + */ +struct WirePackP +{ + /** + * Random unique identifier for the request. + */ + struct GNUNET_HashCode request_uid; + + /** + * Amount to be transferred. + */ + struct TALER_AmountNBO amount; + + /** + * Wire transfer identifier to use. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Length of the payto:// URL of the target account, + * including 0-terminator, in network byte order. + */ + uint32_t account_len GNUNET_PACKED; + + /** + * Length of the exchange's base URL, + * including 0-terminator, in network byte order. + */ + uint32_t exchange_url_len GNUNET_PACKED; + +}; + +GNUNET_NETWORK_STRUCT_END + +/** + * Prepare for exeuction of a wire transfer. + * + * @param destination_account_url payto:// URL identifying where to send the money + * @param amount amount to transfer, already rounded + * @param exchange_base_url base URL of this exchange (included in subject + * to facilitate use of tracking API by merchant backend) + * @param wtid wire transfer identifier to use + * @param buf[out] set to transfer data to persist, NULL on error + * @param buf_size[out] set to number of bytes in @a buf, 0 on error + */ +void +TALER_BANK_prepare_wire_transfer (const char *destination_account_url, + const struct TALER_Amount *amount, + const char *exchange_base_url, + const struct + TALER_WireTransferIdentifierRawP *wtid, + void **buf, + size_t *buf_size) +{ + struct WirePackP *wp; + size_t d_len = strlen (destination_account_url) + 1; + size_t u_len = strlen (exchange_base_url) + 1; + char *end; + + *buf_size = sizeof (*wp) + d_len + u_len; + wp = GNUNET_malloc (*buf_size); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, + &wp->request_uid); + TALER_amount_hton (&wp->amount, + amount); + wp->wtid = *wtid; + wp->account_len = htonl ((uint32_t) d_len); + wp->exchange_url_len = htonl ((uint32_t) u_len); + end = (char *) &wp[1]; + memcpy (end, + destination_account_url, + d_len); + memcpy (end + d_len, + exchange_base_url, + u_len); + *buf = (char *) wp; +} + + +/** + * @brief An transfer Handle + */ +struct TALER_BANK_WireExecuteHandle +{ + + /** + * The url for this request. + */ + char *request_url; + + /** + * POST context. + */ + struct TEAH_PostContext post_ctx; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_BANK_ConfirmationCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + +}; + + +/** + * Function called when we're done processing the + * HTTP /transfer request. + * + * @param cls the `struct TALER_BANK_WireExecuteHandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_transfer_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_BANK_WireExecuteHandle *weh = cls; + uint64_t row_id = UINT64_MAX; + struct GNUNET_TIME_Absolute timestamp; + enum TALER_ErrorCode ec; + const json_t *j = response; + + weh->job = NULL; + timestamp = GNUNET_TIME_UNIT_FOREVER_ABS; + switch (response_code) + { + case 0: + ec = TALER_EC_INVALID_RESPONSE; + break; + case MHD_HTTP_OK: + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint64 ("row_id", + &row_id), + GNUNET_JSON_spec_absolute_time ("timestamp", + ×tamp), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (j, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + response_code = 0; + ec = TALER_EC_INVALID_RESPONSE; + break; + } + ec = TALER_EC_NONE; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the bank is buggy + (or API version conflict); just pass JSON reply to the application */ + ec = TALER_BANK_parse_ec_ (j); + break; + case MHD_HTTP_FORBIDDEN: + /* Access denied */ + ec = TALER_BANK_parse_ec_ (j); + break; + case MHD_HTTP_UNAUTHORIZED: + /* Nothing really to verify, bank says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + ec = TALER_BANK_parse_ec_ (j); + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + ec = TALER_BANK_parse_ec_ (j); + break; + case MHD_HTTP_NOT_ACCEPTABLE: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + ec = TALER_BANK_parse_ec_ (j); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + ec = TALER_BANK_parse_ec_ (j); + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + ec = TALER_BANK_parse_ec_ (j); + response_code = 0; + break; + } + weh->cb (weh->cb_cls, + response_code, + ec, + row_id, + timestamp); + TALER_BANK_execute_wire_transfer_cancel (weh); +} + + +/** + * Execute a wire transfer. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param buf buffer with the prepared execution details + * @param buf_size number of bytes in @a buf + * @param cc function to call upon success + * @param cc_cls closure for @a cc + * @return NULL on error + */ +struct TALER_BANK_WireExecuteHandle * +TALER_BANK_execute_wire_transfer (struct GNUNET_CURL_Context *ctx, + const char *bank_base_url, + const struct + TALER_BANK_AuthenticationData *auth, + const void *buf, + size_t buf_size, + TALER_BANK_ConfirmationCallback cc, + void *cc_cls) +{ + struct TALER_BANK_WireExecuteHandle *weh; + json_t *transfer_obj; + CURL *eh; + const struct WirePackP *wp = buf; + uint32_t d_len; + uint32_t u_len; + const char *destination_account_url; + const char *exchange_base_url; + struct TALER_Amount amount; + + if (sizeof (*wp) > buf_size) + { + GNUNET_break (0); + return NULL; + } + d_len = ntohl (wp->account_len); + u_len = ntohl (wp->exchange_url_len); + if (sizeof (*wp) + d_len + u_len != buf_size) + { + GNUNET_break (0); + return NULL; + } + destination_account_url = (const char *) &wp[1]; + exchange_base_url = destination_account_url + d_len; + if (NULL == bank_base_url) + { + GNUNET_break (0); + return NULL; + } + TALER_amount_ntoh (&amount, + &wp->amount); + transfer_obj = json_pack ("{s:o, s:o, s:s, s:o, s:o, s:s}", + "request_uid", GNUNET_JSON_from_data_auto ( + &wp->request_uid), + "amount", TALER_JSON_from_amount (&amount), + "exchange_url", exchange_base_url, + "wtid", GNUNET_JSON_from_data_auto (&wp->wtid), + "credit_account", destination_account_url); + if (NULL == transfer_obj) + { + GNUNET_break (0); + return NULL; + } + weh = GNUNET_new (struct TALER_BANK_WireExecuteHandle); + weh->cb = cc; + weh->cb_cls = cc_cls; + weh->request_url = TALER_BANK_path_to_url_ (bank_base_url, + "/transfer"); + weh->post_ctx.headers = curl_slist_append + (weh->post_ctx.headers, + "Content-Type: application/json"); + + eh = curl_easy_init (); + if ( (GNUNET_OK != + TALER_BANK_setup_auth_ (eh, + auth)) || + (CURLE_OK != + curl_easy_setopt (eh, + CURLOPT_URL, + weh->request_url)) || + (GNUNET_OK != + TALER_curl_easy_post (&weh->post_ctx, + eh, + transfer_obj)) ) + { + GNUNET_break (0); + TALER_BANK_execute_wire_transfer_cancel (weh); + curl_easy_cleanup (eh); + json_decref (transfer_obj); + return NULL; + } + json_decref (transfer_obj); + + weh->job = GNUNET_CURL_job_add2 (ctx, + eh, + weh->post_ctx.headers, + &handle_transfer_finished, + weh); + return weh; +} + + +/** + * Cancel a wire transfer. This function cannot be used on a request handle + * if a response is already served for it. + * + * @param weh the wire transfer request handle + */ +void +TALER_BANK_execute_wire_transfer_cancel (struct + TALER_BANK_WireExecuteHandle *weh) +{ + if (NULL != weh->job) + { + GNUNET_CURL_job_cancel (weh->job); + weh->job = NULL; + } + TALER_curl_easy_post_finished (&weh->post_ctx); + GNUNET_free (weh->request_url); + GNUNET_free (weh); +} + + +/* end of bank_api_transfer.c */ diff --git a/src/bank-lib/fakebank_history.c b/src/bank-lib/fakebank_history.c deleted file mode 100644 index 2781cdca8..000000000 --- a/src/bank-lib/fakebank_history.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of TALER - (C) 2016-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 -*/ - -/** - * @file bank-lib/fakebank_history.c - * @brief definitions for the "/history" layer. - * @author Marcello Stanisci - */ -#include "platform.h" -#include -#include "taler_json_lib.h" -#include "fakebank.h" - - -int -TFH_build_history_response (struct MHD_Connection *connection, - struct Transaction *pos, - struct HistoryArgs *ha, - Skip skip, - Step step, - CheckAdvance advance) -{ - - struct HistoryElement *history_results_head = NULL; - struct HistoryElement *history_results_tail = NULL; - struct HistoryElement *history_element = NULL; - json_t *history; - json_t *jresponse; - int ret; - - while ( (NULL != pos) && - advance (ha, - pos) ) - { - json_t *trans; - char *subject; - const char *sign; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Found transaction over %s from %llu to %llu\n", - TALER_amount2s (&pos->amount), - (unsigned long long) pos->debit_account, - (unsigned long long) pos->credit_account); - - if ( (! ( ( (ha->account_number == pos->debit_account) && - (0 != (ha->direction & TALER_BANK_DIRECTION_DEBIT)) ) || - ( (ha->account_number == pos->credit_account) && - (0 != (ha->direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) || - ( (0 == (ha->direction & TALER_BANK_DIRECTION_CANCEL)) && - (GNUNET_YES == pos->rejected) ) ) - { - pos = skip (ha, - pos); - continue; - } - - GNUNET_asprintf (&subject, - "%s %s", - pos->subject, - pos->exchange_base_url); - sign = - (ha->account_number == pos->debit_account) - ? (pos->rejected ? "cancel-" : "-") - : (pos->rejected ? "cancel+" : "+"); - trans = json_pack - ("{s:I, s:o, s:o, s:s, s:I, s:s}", - "row_id", (json_int_t) pos->row_id, - "date", GNUNET_JSON_from_time_abs (pos->date), - "amount", TALER_JSON_from_amount (&pos->amount), - "sign", sign, - "counterpart", (json_int_t) - ( (ha->account_number == pos->debit_account) - ? pos->credit_account - : pos->debit_account), - "wt_subject", subject); - GNUNET_assert (NULL != trans); - GNUNET_free (subject); - - history_element = GNUNET_new (struct HistoryElement); - history_element->element = trans; - - - /* XXX: the ordering feature is missing. */ - - GNUNET_CONTAINER_DLL_insert_tail (history_results_head, - history_results_tail, - history_element); - pos = step (ha, pos); - } - - history = json_array (); - if (NULL != history_results_head) - history_element = history_results_head; - - while (NULL != history_element) - { - GNUNET_assert (0 == - json_array_append_new (history, - history_element->element)); - history_element = history_element->next; - if (NULL != history_element) - GNUNET_free_non_null (history_element->prev); - } - GNUNET_free_non_null (history_results_tail); - - if (0 == json_array_size (history)) - { - struct MHD_Response *resp; - - json_decref (history); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Returning empty transaction history\n"); - resp = MHD_create_response_from_buffer - (0, - "", - MHD_RESPMEM_PERSISTENT); - ret = MHD_queue_response (connection, - MHD_HTTP_NO_CONTENT, - resp); - MHD_destroy_response (resp); - return ret; - } - - jresponse = json_pack ("{s:o}", - "data", - history); - if (NULL == jresponse) - { - GNUNET_break (0); - return MHD_NO; - } - - /* Finally build response object */ - { - struct MHD_Response *resp; - void *json_str; - size_t json_len; - - json_str = json_dumps (jresponse, - JSON_INDENT (2)); - json_decref (jresponse); - if (NULL == json_str) - { - GNUNET_break (0); - return MHD_NO; - } - json_len = strlen (json_str); - resp = MHD_create_response_from_buffer (json_len, - json_str, - MHD_RESPMEM_MUST_FREE); - if (NULL == resp) - { - GNUNET_break (0); - free (json_str); - return MHD_NO; - } - (void) MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_TYPE, - "application/json"); - ret = MHD_queue_response (connection, - MHD_HTTP_OK, - resp); - MHD_destroy_response (resp); - } - return ret; -} diff --git a/src/bank-lib/test_bank_api.c b/src/bank-lib/test_bank_api.c index 087e44848..5e7a3a33f 100644 --- a/src/bank-lib/test_bank_api.c +++ b/src/bank-lib/test_bank_api.c @@ -16,7 +16,6 @@ License along with TALER; see the file COPYING. If not, see */ - /** * @file bank/test_bank_api.c * @brief testcase to test bank's HTTP API @@ -24,7 +23,6 @@ * @author Marcello Stanisci * @author Christian Grothoff */ - #include "platform.h" #include "taler_util.h" #include "taler_signatures.h" @@ -44,6 +42,16 @@ */ static char *bank_url; +/** + * Account URL. + */ +static char *account_url; + +/** + * payto://-URL of another account. + */ +static char *payto_url; + /** * Handle to the Py-bank daemon. */ @@ -55,26 +63,6 @@ static struct GNUNET_OS_Process *bankd; */ static int WITH_FAKEBANK; -/** - * Transfer @a amount from @a src account to @a dst using - * @a subject and the @a label for the command. - */ -#define TRANSFER(label,amount,src,dst,subject) \ - TALER_TESTING_cmd_fakebank_transfer_with_subject (label, \ - amount, \ - bank_url, \ - src, \ - dst, \ - AUTHS[src \ - - 1].details.basic. \ - username, \ - AUTHS[src \ - - 1].details.basic. \ - password, \ - subject, \ - "http://exchange.net/") - - /** * Main function that will tell the interpreter what commands to * run. @@ -85,89 +73,54 @@ static void run (void *cls, struct TALER_TESTING_Interpreter *is) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Bank serves at `%s'\n", - bank_url); - extern struct TALER_BANK_AuthenticationData AUTHS[]; struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_bank_history ("history-0", - bank_url, - TALER_TESTING_BANK_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_BOTH, - GNUNET_YES, + TALER_TESTING_cmd_bank_credits ("history-0", + account_url, NULL, 1), - /* WARNING: old API has expected http response code among - * the parameters, although it was always set as '200 OK' */ - TRANSFER ("debit-1", - "KUDOS:5.01", - TALER_TESTING_EXCHANGE_ACCOUNT_NUMBER, - TALER_TESTING_BANK_ACCOUNT_NUMBER, - "subject 1"), - TALER_TESTING_cmd_bank_history ("history-1c", - bank_url, - TALER_TESTING_BANK_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_CREDIT, - GNUNET_YES, - NULL, - 5), - TALER_TESTING_cmd_bank_history ("history-1d", - bank_url, - TALER_TESTING_BANK_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_DEBIT, - GNUNET_YES, + TALER_TESTING_cmd_admin_add_incoming ("debit-1", + "KUDOS:5.01", + account_url, + payto_url, + NULL, + NULL), + TALER_TESTING_cmd_bank_credits ("history-1c", + account_url, NULL, 5), - TRANSFER ("debit-2", - "KUDOS:3.21", - TALER_TESTING_EXCHANGE_ACCOUNT_NUMBER, - TALER_TESTING_USER_ACCOUNT_NUMBER, - "subject 2"), + TALER_TESTING_cmd_bank_debits ("history-1d", + account_url, + NULL, + 5), + TALER_TESTING_cmd_admin_add_incoming ("debit-2", + "KUDOS:3.21", + account_url, + payto_url, + NULL, + NULL), TRANSFER ("credit-2", "KUDOS:3.22", TALER_TESTING_USER_ACCOUNT_NUMBER, TALER_TESTING_EXCHANGE_ACCOUNT_NUMBER, "credit 2"), - TALER_TESTING_cmd_bank_history ("history-2b", - bank_url, - TALER_TESTING_EXCHANGE_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_BOTH, - GNUNET_YES, - NULL, - 5), - TALER_TESTING_cmd_bank_history ("history-2bi", - bank_url, - TALER_TESTING_EXCHANGE_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_BOTH, - GNUNET_YES, - "debit-1", - 5), - TRANSFER ("credit-for-reject-1", - "KUDOS:1.01", - TALER_TESTING_BANK_ACCOUNT_NUMBER, - TALER_TESTING_EXCHANGE_ACCOUNT_NUMBER, - "subject 3"), - TALER_TESTING_cmd_bank_reject ("reject-1", - bank_url, - "credit-for-reject-1"), - TALER_TESTING_cmd_bank_history ("history-r1", - bank_url, - TALER_TESTING_BANK_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_BOTH, - GNUNET_YES, - NULL, - 5), - TALER_TESTING_cmd_bank_history ("history-r1c", - bank_url, - TALER_TESTING_BANK_ACCOUNT_NUMBER, - TALER_BANK_DIRECTION_BOTH - | TALER_BANK_DIRECTION_CANCEL, - GNUNET_YES, - NULL, - 5), + TALER_TESTING_cmd_bank_debits ("history-2b", + account_url, + NULL, + 5), TALER_TESTING_cmd_end () }; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Bank serves at `%s'\n", + bank_url); + GNUNET_asprintf (&account_url, + "%s/%s", + base_url, + "alice"); + GNUNET_asprintf (&payto_url, + "payto://x-taler-bank/%s/%s", + base_url, + "bob"); if (GNUNET_YES == WITH_FAKEBANK) TALER_TESTING_run_with_fakebank (is, commands, diff --git a/src/bank-lib/testing_api_cmd_admin_add_incoming.c b/src/bank-lib/testing_api_cmd_admin_add_incoming.c new file mode 100644 index 000000000..b7b18374a --- /dev/null +++ b/src/bank-lib/testing_api_cmd_admin_add_incoming.c @@ -0,0 +1,625 @@ +/* + This file is part of TALER + Copyright (C) 2018-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 + +*/ +/** + * @file exchange-lib/testing_api_cmd_admin_add_incoming.c + * @brief implementation of a bank /admin/add-incoming command + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "backoff.h" +#include "taler_json_lib.h" +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_signatures.h" +#include "taler_testing_lib.h" +#include "taler_testing_bank_lib.h" + + +/** + * State for a "fakebank transfer" CMD. + */ +struct AdminAddIncomingState +{ + + /** + * Label of any command that can trait-offer a reserve priv. + */ + const char *reserve_reference; + + /** + * Wire transfer amount. + */ + struct TALER_Amount amount; + + /** + * Base URL of the debit account. + */ + const char *debit_url; + + /** + * Money receiver account URL. + */ + const char *payto_credit_account; + + /** + * Username to use for authentication. + */ + struct TALER_BANK_AuthenticationData auth; + + /** + * Set (by the interpreter) to the reserve's private key + * we used to make a wire transfer subject line with. + */ + struct TALER_ReservePrivateKeyP reserve_priv; + + /** + * Reserve public key matching @e reserve_priv. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Handle to the pending request at the fakebank. + */ + struct TALER_BANK_AdminAddIncomingHandle *aih; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Set to the wire transfer's unique ID. + */ + uint64_t serial_id; + + /** + * Timestamp of the transaction (as returned from the bank). + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Merchant instance. Sometimes used to get the tip reserve + * private key by reading the appropriate config section. + */ + const char *instance; + + /** + * Configuration filename. Used to get the tip reserve key + * filename (used to obtain a public key to write in the + * transfer subject). + */ + const char *config_filename; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Was this command modified via + * #TALER_TESTING_cmd_admin_add_incoming_with_retry to + * enable retries? + */ + int do_retry; +}; + + +/** + * Run the "fakebank transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +fakebank_transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #fakebank_transfer_run. + * + * @param cls a `struct AdminAddIncomingState` + */ +static void +do_retry (void *cls) +{ + struct AdminAddIncomingState *fts = cls; + + fts->retry_task = NULL; + fakebank_transfer_run (fts, + NULL, + fts->is); +} + + +/** + * This callback will process the fakebank response to the wire + * transfer. It just checks whether the HTTP response code is + * acceptable. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for + * successful status request; 0 if the exchange's reply is + * bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success + * @param serial_id unique ID of the wire transfer + * @param timestamp time stamp of the transaction made. + * @param json raw response + */ +static void +confirmation_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + struct GNUNET_TIME_Absolute timestamp, + const json_t *json) +{ + struct AdminAddIncomingState *fts = cls; + struct TALER_TESTING_Interpreter *is = fts->is; + + fts->aih = NULL; + if (MHD_HTTP_OK != http_status) + { + if (GNUNET_YES == fts->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log + (GNUNET_ERROR_TYPE_INFO, + "Retrying fakebank transfer failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + fts->backoff = GNUNET_TIME_UNIT_ZERO; + else + fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); + fts->retry_task = GNUNET_SCHEDULER_add_delayed + (fts->backoff, + &do_retry, + fts); + return; + } + } + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fakebank returned HTTP status %u/%d\n", + http_status, + (int) ec); + TALER_TESTING_interpreter_fail (is); + return; + } + + fts->serial_id = serial_id; + fts->timestamp = timestamp; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the "fakebank transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +fakebank_transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AdminAddIncomingState *fts = cls; + + /* Use reserve public key as subject */ + if (NULL != fts->reserve_reference) + { + const struct TALER_TESTING_Command *ref; + const struct TALER_ReservePrivateKeyP *reserve_priv; + + ref = TALER_TESTING_interpreter_lookup_command + (is, fts->reserve_reference); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (ref, + 0, + &reserve_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv; + } + else + { + if (NULL != fts->instance) + { + char *section; + char *keys; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct GNUNET_CONFIGURATION_Handle *cfg; + + GNUNET_assert (NULL != fts->config_filename); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, + fts->config_filename)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_asprintf (§ion, + "instance-%s", + fts->instance); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename + (cfg, + section, + "TIP_RESERVE_PRIV_FILENAME", + &keys)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Configuration fails to specify reserve" + " private key filename in section %s\n", + section); + GNUNET_free (section); + TALER_TESTING_interpreter_fail (is); + return; + } + priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys); + GNUNET_free (keys); + if (NULL == priv) + { + GNUNET_log_config_invalid + (GNUNET_ERROR_TYPE_ERROR, + section, + "TIP_RESERVE_PRIV_FILENAME", + "Failed to read private key"); + GNUNET_free (section); + TALER_TESTING_interpreter_fail (is); + return; + } + fts->reserve_priv.eddsa_priv = *priv; + GNUNET_free (section); + GNUNET_free (priv); + GNUNET_CONFIGURATION_destroy (cfg); + } + else + { + /* No referenced reserve, no instance to take priv + * from, no explicit subject given: create new key! */ + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + + priv = GNUNET_CRYPTO_eddsa_key_create (); + fts->reserve_priv.eddsa_priv = *priv; + GNUNET_free (priv); + } + } + GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv, + &fts->reserve_pub.eddsa_pub); + fts->is = is; + fts->aih + = TALER_BANK_admin_add_incoming + (TALER_TESTING_interpreter_get_context (is), + fts->debit_url, + &fts->auth, + &fts->reserve_pub, + &fts->amount, + fts->payto_credit_account, + &confirmation_cb, + fts); + if (NULL == fts->aih) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "fakebank transfer" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure + * @param cmd current CMD being cleaned up. + */ +static void +fakebank_transfer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AdminAddIncomingState *fts = cls; + + if (NULL != fts->aih) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %s did not complete\n", + cmd->label); + TALER_BANK_admin_add_incoming_cancel (fts->aih); + fts->aih = NULL; + } + if (NULL != fts->retry_task) + { + GNUNET_SCHEDULER_cancel (fts->retry_task); + fts->retry_task = NULL; + } + GNUNET_free (fts); +} + + +/** + * Offer internal data from a "fakebank transfer" CMD to other + * commands. + * + * @param cls closure. + * @param ret[out] result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +fakebank_transfer_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AdminAddIncomingState *fts = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_url (1, fts->debit_url), + TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id), + TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT (fts->payto_credit_account), + TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT (fts->debit_url), + TALER_TESTING_make_trait_amount_obj (0, &fts->amount), + TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), + TALER_TESTING_make_trait_reserve_priv (0, + &fts->reserve_priv), + TALER_TESTING_make_trait_reserve_pub (0, + &fts->reserve_pub), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create fakebank_transfer command, the subject line will be + * derived from a randomly created reserve priv. Note that that + * reserve priv will then be offered as trait. + * + * @param label command label. + * @param amount amount to transfer. + * @param account_base_url base URL of the account that implements this + * wire transer (which account gives money). + * @param payto_credit_account which account receives money. + * @param auth_username username identifying the @a + * debit_account_no at the bank. + * @param auth_password password for @a auth_username. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming + (const char *label, + const char *amount, + const char *account_base_url, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_credit_account) +{ + struct AdminAddIncomingState *fts; + + fts = GNUNET_new (struct AdminAddIncomingState); + fts->debit_url = account_base_url; + fts->payto_credit_account = payto_credit_account; + fts->auth = *auth; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &fts->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + + { + struct TALER_TESTING_Command cmd = { + .cls = fts, + .label = label, + .run = &fakebank_transfer_run, + .cleanup = &fakebank_transfer_cleanup, + .traits = &fakebank_transfer_traits + }; + + return cmd; + } +} + + +/** + * Create "fakebank transfer" CMD, letting the caller specify + * a reference to a command that can offer a reserve private key. + * This private key will then be used to construct the subject line + * of the wire transfer. + * + * @param label command label. + * @param amount the amount to transfer. + * @param bank_url base URL of the bank running the transfer. + * @param debit_account_no which account (expressed as a number) + * gives money. + * @param credit_account_no which account (expressed as a number) + * receives money. + * @param auth_username username identifying the @a + * debit_account_no at the bank. + * @param auth_password password for @a auth_username. + * @param ref reference to a command that can offer a reserve + * private key. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_with_ref + (const char *label, + const char *amount, + const char *account_base_url, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_credit_account, + const char *ref) +{ + struct AdminAddIncomingState *fts; + + fts = GNUNET_new (struct AdminAddIncomingState); + fts->debit_url = account_base_url; + fts->payto_credit_account = payto_credit_account; + fts->auth = *auth; + fts->reserve_reference = ref; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &fts->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + { + struct TALER_TESTING_Command cmd = { + .cls = fts, + .label = label, + .run = &fakebank_transfer_run, + .cleanup = &fakebank_transfer_cleanup, + .traits = &fakebank_transfer_traits + }; + + return cmd; + } +} + + +/** + * Create "fakebank transfer" CMD, letting the caller specifying + * the merchant instance. This version is useful when a tip + * reserve should be topped up, in fact the interpreter will need + * the "tipping instance" in order to get the instance public key + * and make a wire transfer subject out of it. + * + * @param label command label. + * @param amount amount to transfer. + * @param bank_url base URL of the bank that implements this + * wire transer. For simplicity, both credit and debit + * bank account exist at the same bank. + * @param debit_account_no which account (expressed as a number) + * gives money. + * @param credit_account_no which account (expressed as a number) + * receives money. + * + * @param auth_username username identifying the @a + * debit_account_no at the bank. + * @param auth_password password for @a auth_username. + * @param instance the instance that runs the tipping. Under this + * instance, the configuration file will provide the private + * key of the tipping reserve. This data will then used to + * construct the wire transfer subject line. + * @param config_filename configuration file to use. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_with_instance + (const char *label, + const char *amount, + const char *account_base_url, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_credit_account, + const char *instance, + const char *config_filename) +{ + struct AdminAddIncomingState *fts; + + fts = GNUNET_new (struct AdminAddIncomingState); + fts->debit_url = account_base_url; + fts->payto_credit_account = payto_credit_account; + fts->auth = *auth; + fts->instance = instance; + fts->config_filename = config_filename; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &fts->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + { + struct TALER_TESTING_Command cmd = { + .cls = fts, + .label = label, + .run = &fakebank_transfer_run, + .cleanup = &fakebank_transfer_cleanup, + .traits = &fakebank_transfer_traits + }; + + return cmd; + } +} + + +/** + * Modify a fakebank transfer command to enable retries when the + * reserve is not yet full or we get other transient errors from the + * fakebank. + * + * @param cmd a fakebank transfer command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_retry (struct TALER_TESTING_Command cmd) +{ + struct AdminAddIncomingState *fts; + + GNUNET_assert (&fakebank_transfer_run == cmd.run); + fts = cmd.cls; + fts->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_api_cmd_admin_add_incoming.c */ diff --git a/src/bank-lib/testing_api_cmd_history_credit.c b/src/bank-lib/testing_api_cmd_history_credit.c index 5c2b34d06..fefb2dda7 100644 --- a/src/bank-lib/testing_api_cmd_history_credit.c +++ b/src/bank-lib/testing_api_cmd_history_credit.c @@ -59,6 +59,11 @@ struct HistoryState */ struct TALER_BANK_CreditHistoryHandle *hh; + /** + * Authentication data for the operation. + */ + struct TALER_BANK_AuthenticationData auth; + /** * Expected number of results (= rows). */ @@ -683,7 +688,7 @@ history_run (void *cls, hs->hh = TALER_BANK_credit_history (is->ctx, hs->account_url, - NULL, + &hs->auth, row_id, hs->num_results, &history_cb, @@ -731,6 +736,8 @@ history_cleanup (void *cls, struct TALER_TESTING_Command TALER_TESTING_cmd_bank_credits (const char *label, const char *account_url, + const struct + TALER_BANK_AuthenticationData *auth, const char *start_row_reference, long long num_results) { @@ -740,7 +747,7 @@ TALER_TESTING_cmd_bank_credits (const char *label, hs->account_url = GNUNET_strdup (account_url); hs->start_row_reference = start_row_reference; hs->num_results = num_results; - + hs->auth = *auth; { struct TALER_TESTING_Command cmd = { .label = label, diff --git a/src/bank-lib/testing_api_cmd_history_debit.c b/src/bank-lib/testing_api_cmd_history_debit.c index 93f84da01..96f989c04 100644 --- a/src/bank-lib/testing_api_cmd_history_debit.c +++ b/src/bank-lib/testing_api_cmd_history_debit.c @@ -56,6 +56,11 @@ struct HistoryState */ long long num_results; + /** + * Login data to use to authenticate. + */ + struct TALER_BANK_AuthenticationData auth; + /** * Handle to a pending "history" operation. */ @@ -67,7 +72,7 @@ struct HistoryState uint64_t results_obtained; /** - * Set to GNUNET_YES if the callback detects something + * Set to #GNUNET_YES if the callback detects something * unexpected. */ int failed; @@ -684,7 +689,7 @@ history_run (void *cls, hs->hh = TALER_BANK_debit_history (is->ctx, hs->account_url, - NULL, + &hs->auth, row_id, hs->num_results, &history_cb, @@ -722,6 +727,7 @@ history_cleanup (void *cls, * @param label command label. * @param account_url base URL of the account offering the "history" * operation. + * @param auth login data to use * @param start_row_reference reference to a command that can * offer a row identifier, to be used as the starting row * to accept in the result. @@ -731,6 +737,7 @@ history_cleanup (void *cls, struct TALER_TESTING_Command TALER_TESTING_cmd_bank_debits (const char *label, const char *account_url, + const struct TALER_BANK_AuthenticationData *auth, const char *start_row_reference, long long num_results) { @@ -740,6 +747,7 @@ TALER_TESTING_cmd_bank_debits (const char *label, hs->account_url = account_url; hs->start_row_reference = start_row_reference; hs->num_results = num_results; + hs->auth = *auth; { struct TALER_TESTING_Command cmd = { diff --git a/src/bank-lib/testing_api_cmd_transfer.c b/src/bank-lib/testing_api_cmd_transfer.c new file mode 100644 index 000000000..d5a3872ed --- /dev/null +++ b/src/bank-lib/testing_api_cmd_transfer.c @@ -0,0 +1,394 @@ +/* + This file is part of TALER + Copyright (C) 2018-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 + +*/ +/** + * @file exchange-lib/testing_api_cmd_transfer.c + * @brief implementation of a bank /transfer command + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "backoff.h" +#include "taler_json_lib.h" +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_signatures.h" +#include "taler_testing_lib.h" +#include "taler_testing_bank_lib.h" + + +/** + * State for a "transfer" CMD. + */ +struct TransferState +{ + + /** + * Wire transfer amount. + */ + struct TALER_Amount amount; + + /** + * Base URL of the debit account. + */ + const char *account_debit_url; + + /** + * Money receiver account URL. + */ + const char *payto_credit_account; + + /** + * Username to use for authentication. + */ + struct TALER_BANK_AuthenticationData auth; + + /** + * Base URL of the exchange. + */ + const char *exchange_base_url; + + /** + * Wire transfer identifier to use. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Handle to the pending request at the fakebank. + */ + struct TALER_BANK_WireExecuteHandle *weh; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Set to the wire transfer's unique ID. + */ + uint64_t serial_id; + + /** + * Timestamp of the transaction (as returned from the bank). + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Configuration filename. Used to get the tip reserve key + * filename (used to obtain a public key to write in the + * transfer subject). + */ + const char *config_filename; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Was this command modified via + * #TALER_TESTING_cmd_admin_add_incoming_with_retry to + * enable retries? + */ + int do_retry; +}; + + +/** + * Run the "transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #transfer_run. + * + * @param cls a `struct TransferState` + */ +static void +do_retry (void *cls) +{ + struct TransferState *fts = cls; + + fts->retry_task = NULL; + transfer_run (fts, + NULL, + fts->is); +} + + +/** + * This callback will process the fakebank response to the wire + * transfer. It just checks whether the HTTP response code is + * acceptable. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for + * successful status request; 0 if the exchange's reply is + * bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success + * @param serial_id unique ID of the wire transfer + * @param timestamp time stamp of the transaction made. + */ +static void +confirmation_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + struct GNUNET_TIME_Absolute timestamp) +{ + struct TransferState *fts = cls; + struct TALER_TESTING_Interpreter *is = fts->is; + + fts->weh = NULL; + if (MHD_HTTP_OK != http_status) + { + if (GNUNET_YES == fts->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying transfer failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + fts->backoff = GNUNET_TIME_UNIT_ZERO; + else + fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); + fts->retry_task = GNUNET_SCHEDULER_add_delayed + (fts->backoff, + &do_retry, + fts); + return; + } + } + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fakebank returned HTTP status %u/%d\n", + http_status, + (int) ec); + TALER_TESTING_interpreter_fail (is); + return; + } + + fts->serial_id = serial_id; + fts->timestamp = timestamp; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the "transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct TransferState *fts = cls; + void *buf; + size_t buf_size; + + TALER_BANK_prepare_wire_transfer (fts->payto_credit_account, + &fts->amount, + fts->exchange_base_url, + &fts->wtid, + &buf, + &buf_size); + fts->is = is; + fts->weh + = TALER_BANK_execute_wire_transfer + (TALER_TESTING_interpreter_get_context (is), + fts->account_debit_url, + &fts->auth, + buf, + buf_size, + &confirmation_cb, + fts); + GNUNET_free (buf); + if (NULL == fts->weh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "fakebank transfer" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure + * @param cmd current CMD being cleaned up. + */ +static void +transfer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct TransferState *fts = cls; + + if (NULL != fts->weh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %s did not complete\n", + cmd->label); + TALER_BANK_execute_wire_transfer_cancel (fts->weh); + fts->weh = NULL; + } + if (NULL != fts->retry_task) + { + GNUNET_SCHEDULER_cancel (fts->retry_task); + fts->retry_task = NULL; + } + GNUNET_free (fts); +} + + +/** + * Offer internal data from a "fakebank transfer" CMD to other + * commands. + * + * @param cls closure. + * @param ret[out] result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +transfer_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct TransferState *fts = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_url (1, fts->account_debit_url), + TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id), + TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT (fts->payto_credit_account), + TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT (fts->account_debit_url), + TALER_TESTING_make_trait_amount_obj (0, &fts->amount), + TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), + TALER_TESTING_make_trait_wtid (0, + &fts->wtid), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create transfer command. + * + * @param label command label. + * @param amount amount to transfer. + * @param account_base_url base URL of the account that implements this + * wire transer (which account gives money). + * @param auth authentication data to use + * @param payto_credit_account which account receives money. + * @param wtid wire transfer identifier to use + * @param exchange_base_url exchange URL to use + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_transfer + (const char *label, + const char *amount, + const char *account_base_url, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_credit_account, + const struct TALER_WireTransferIdentifierRawP *wtid, + const char *exchange_base_url) +{ + struct TransferState *fts; + + fts = GNUNET_new (struct TransferState); + fts->account_debit_url = account_base_url; + fts->exchange_base_url = exchange_base_url; + fts->payto_credit_account = payto_credit_account; + fts->auth = *auth; + fts->wtid = *wtid; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &fts->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + + { + struct TALER_TESTING_Command cmd = { + .cls = fts, + .label = label, + .run = &transfer_run, + .cleanup = &transfer_cleanup, + .traits = &transfer_traits + }; + + return cmd; + } +} + + +/** + * Modify a transfer command to enable retries when the reserve is not yet + * full or we get other transient errors from the bank. + * + * @param cmd a fakebank transfer command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd) +{ + struct TransferState *fts; + + GNUNET_assert (&transfer_run == cmd.run); + fts = cmd.cls; + fts->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_api_cmd_transfer.c */ diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index b931c3c90..eff8f5c44 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -59,14 +59,13 @@ enum BenchmarkError #define FIRST_INSTRUCTION -1 #define CMD_TRANSFER_TO_EXCHANGE(label, amount) \ - TALER_TESTING_cmd_fakebank_transfer_retry \ - (TALER_TESTING_cmd_fakebank_transfer (label, amount, \ - user_bank_account.details. \ - x_taler_bank.account_base_url, \ - exchange_payto_url, \ - "dummy_user", \ - "dummy_password", \ - "http://example.com/")) + TALER_TESTING_cmd_admin_add_incoming_retry \ + (TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + user_bank_account.details. \ + x_taler_bank.account_base_url, \ + exchange_payto_url, \ + "dummy_user", \ + "dummy_password")) /** diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 25bc67b25..ed42006f0 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -35,4 +35,6 @@ talerinclude_HEADERS = \ endif -EXTRA_DIST = gauger.h +EXTRA_DIST = \ + backoff.h \ + gauger.h diff --git a/src/include/backoff.h b/src/include/backoff.h new file mode 100644 index 000000000..0fd5683a9 --- /dev/null +++ b/src/include/backoff.h @@ -0,0 +1,33 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 GNUnet e.V. + + 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 + +*/ + +/** + * @file lib/backoff.h + * @brief backoff computation for the exchange lib + * @author Florian Dold + */ +#ifndef _TALER_BACKOFF_H +#define _TALER_BACKOFF_H + +/** + * Random exponential backoff used in the exchange lib. + */ +#define EXCHANGE_LIB_BACKOFF(r) GNUNET_TIME_randomized_backoff ( \ + (r), \ + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)); + +#endif diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h index a2eec49aa..08b29ed11 100644 --- a/src/include/taler_bank_service.h +++ b/src/include/taler_bank_service.h @@ -204,7 +204,6 @@ typedef void /** - * Execute a wire transfer. * * @param ctx context for HTTP interaction diff --git a/src/include/taler_testing_bank_lib.h b/src/include/taler_testing_bank_lib.h index 43d12d336..79712bac9 100644 --- a/src/include/taler_testing_bank_lib.h +++ b/src/include/taler_testing_bank_lib.h @@ -108,6 +108,7 @@ TALER_TESTING_has_in_name (const char *prog, * @param label command label. * @param account_url base URL of the account offering the "history" * operation. + * @param auth login data to use * @param start_row_reference reference to a command that can * offer a row identifier, to be used as the starting row * to accept in the result. @@ -118,6 +119,8 @@ TALER_TESTING_has_in_name (const char *prog, struct TALER_TESTING_Command TALER_TESTING_cmd_bank_credits (const char *label, const char *account_url, + const struct + TALER_BANK_AuthenticationData *auth, const char *start_row_reference, long long num_results); @@ -128,6 +131,7 @@ TALER_TESTING_cmd_bank_credits (const char *label, * @param label command label. * @param account_url base URL of the account offering the "history" * operation. + * @param auth authentication data * @param start_row_reference reference to a command that can * offer a row identifier, to be used as the starting row * to accept in the result. @@ -137,8 +141,124 @@ TALER_TESTING_cmd_bank_credits (const char *label, struct TALER_TESTING_Command TALER_TESTING_cmd_bank_debits (const char *label, const char *account_url, + const struct TALER_BANK_AuthenticationData *auth, const char *start_row_reference, long long num_results); +/** + * Create transfer command. + * + * @param label command label. + * @param amount amount to transfer. + * @param account_base_url base URL of the account that implements this + * wire transer (which account gives money). + * @param auth authentication data to use + * @param payto_credit_account which account receives money. + * @param wtid wire transfer identifier to use + * @param exchange_base_url exchange URL to use + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_transfer (const char *label, + const char *amount, + const char *account_base_url, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_credit_account, + const struct TALER_WireTransferIdentifierRawP *wtid, + const char *exchange_base_url); + + +/** + * Create /admin/add-incoming command. + * + * @param label command label. + * @param amount amount to transfer. + * @param account_base_url base URL of the account that implements this + * wire transer (which account gives money). + * @param payto_credit_account which account receives money. + * @param auth authentication data + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming (const char *label, + const char *amount, + const char *account_base_url, + const struct + TALER_BANK_AuthenticationData *auth, + const char *payto_credit_account); + + +/** + * Create "fakebank transfer" CMD, letting the caller specify + * a reference to a command that can offer a reserve private key. + * This private key will then be used to construct the subject line + * of the wire transfer. + * + * @param label command label. + * @param amount the amount to transfer. + * @param account_base_url base URL of the account that implements this + * wire transer (which account gives money). + * @param payto_credit_account which account receives money. + * @param auth authentication data + * @param ref reference to a command that can offer a reserve + * private key. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_with_ref (const char *label, + const char *amount, + const char *account_base_url, + const struct + TALER_BANK_AuthenticationData * + auth, + const char *payto_credit_account, + const char *ref); + + +/** + * Create "fakebank transfer" CMD, letting the caller specifying + * the merchant instance. This version is useful when a tip + * reserve should be topped up, in fact the interpreter will need + * the "tipping instance" in order to get the instance public key + * and make a wire transfer subject out of it. + * + * @param label command label. + * @param amount amount to transfer. + * @param account_base_url base URL of the account that implements this + * wire transer (which account gives money). + * @param payto_credit_account which account receives money. + * @param auth authentication data + * @param instance the instance that runs the tipping. Under this + * instance, the configuration file will provide the private + * key of the tipping reserve. This data will then used to + * construct the wire transfer subject line. + * @param config_filename configuration file to use. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_with_instance (const char *label, + const char *amount, + const char *account_base_url, + const struct + TALER_BANK_AuthenticationData + *auth, + const char * + payto_credit_account, + const char *instance, + const char *config_filename); + + +/** + * Modify a fakebank transfer command to enable retries when the + * reserve is not yet full or we get other transient errors from + * the fakebank. + * + * @param cmd a fakebank transfer command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_retry (struct TALER_TESTING_Command cmd); + + #endif diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 33f070701..af122abde 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -709,118 +709,6 @@ TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb, /* ************** Specific interpreter commands ************ */ -/** - * Create fakebank_transfer command, the subject line will be - * derived from a randomly created reserve priv. Note that that - * reserve priv will then be offered as trait. - * - * @param label command label. - * @param amount amount to transfer. - * @param account_base_url base URL of the account that implements this - * wire transer (which account gives money). - * @param payto_credit_account which account receives money. - * @param auth_username username identifying the @a - * debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param exchange_url which exchange is involved in this transfer. - * This data is used for tracking purposes (FIXME: explain - * _how_). - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer (const char *label, - const char *amount, - const char *account_base_url, - const char *payto_credit_account, - const char *auth_username, - const char *auth_password, - const char *exchange_url); - - -/** - * Create "fakebank transfer" CMD, letting the caller specify - * a reference to a command that can offer a reserve private key. - * This private key will then be used to construct the subject line - * of the wire transfer. - * - * @param label command label. - * @param amount the amount to transfer. - * @param account_base_url base URL of the account that implements this - * wire transer (which account gives money). - * @param payto_credit_account which account receives money. - * @param auth_username username identifying the @a - * debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param ref reference to a command that can offer a reserve - * private key. - * @param exchange_url the exchage involved in the transfer, - * tipically receiving the money in order to fuel a reserve. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label, - const char *amount, - const char *account_base_url, - const char *payto_credit_account, - - const char *auth_username, - const char *auth_password, - const char *ref, - const char *exchange_url); - - -/** - * Create "fakebank transfer" CMD, letting the caller specifying - * the merchant instance. This version is useful when a tip - * reserve should be topped up, in fact the interpreter will need - * the "tipping instance" in order to get the instance public key - * and make a wire transfer subject out of it. - * - * @param label command label. - * @param amount amount to transfer. - * @param account_base_url base URL of the account that implements this - * wire transer (which account gives money). - * @param payto_credit_account which account receives money. - * @param auth_username username identifying the @a - * debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param instance the instance that runs the tipping. Under this - * instance, the configuration file will provide the private - * key of the tipping reserve. This data will then used to - * construct the wire transfer subject line. - * @param exchange_url which exchange is involved in this transfer. - * This data is used for tracking purposes (FIXME: explain - * _how_). - * @param config_filename configuration file to use. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_with_instance (const char *label, - const char *amount, - const char *account_base_url, - const char * - payto_credit_account, - const char *auth_username, - const char *auth_password, - const char *instance, - const char *exchange_url, - const char *config_filename); - - -/** - * Modify a fakebank transfer command to enable retries when the - * reserve is not yet full or we get other transient errors from - * the fakebank. - * - * @param cmd a fakebank transfer command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_retry (struct TALER_TESTING_Command cmd); - /** * Make a "wirewatch" CMD. diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ee8389f60..729d54ba5 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -16,7 +16,6 @@ libtalerexchange_la_LDFLAGS = \ -version-info 4:0:0 \ -no-undefined libtalerexchange_la_SOURCES = \ - backoff.h \ exchange_api_curl_defaults.c exchange_api_curl_defaults.h \ exchange_api_common.c \ exchange_api_handle.c exchange_api_handle.h \ @@ -77,7 +76,6 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_exec_wirewatch.c \ testing_api_cmd_exec_keyup.c \ testing_api_cmd_exec_auditor-sign.c \ - testing_api_cmd_fakebank_transfer.c \ testing_api_cmd_withdraw.c \ testing_api_cmd_wire.c \ testing_api_cmd_refund.c \ diff --git a/src/lib/backoff.h b/src/lib/backoff.h deleted file mode 100644 index e62e1d90f..000000000 --- a/src/lib/backoff.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 GNUnet e.V. - - 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 - -*/ - -/** - * @file lib/backoff.h - * @brief backoff computation for the exchange lib - * @author Florian Dold - */ - - -#ifndef _TALER_BACKOFF_H -#define _TALER_BACKOFF_H - -#include "platform.h" -#include - -/** - * Random exponential backoff used in the exchange lib. - */ -#define EXCHANGE_LIB_BACKOFF(r) GNUNET_TIME_randomized_backoff ( \ - (r), \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)); - -#endif diff --git a/src/lib/test_auditor_api.c b/src/lib/test_auditor_api.c index 85983277e..da6f65962 100644 --- a/src/lib/test_auditor_api.c +++ b/src/lib/test_auditor_api.c @@ -111,11 +111,11 @@ static char *exchange_url; * @param amount amount to transfer, i.e. "EUR:1" */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ - TALER_TESTING_cmd_fakebank_transfer (label, amount, \ - fakebank_url, USER_ACCOUNT_NO, \ - EXCHANGE_ACCOUNT_NO, \ - USER_LOGIN_NAME, USER_LOGIN_PASS, \ - exchange_url) + TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + fakebank_url, USER_ACCOUNT_NO, \ + EXCHANGE_ACCOUNT_NO, \ + USER_LOGIN_NAME, USER_LOGIN_PASS, \ + exchange_url) /** * Run wire transfer of funds from some user's account to the @@ -125,7 +125,7 @@ static char *exchange_url; * @param amount amount to transfer, i.e. "EUR:1" */ #define CMD_TRANSFER_TO_EXCHANGE_SUBJECT(label,amount,subject) \ - TALER_TESTING_cmd_fakebank_transfer_with_subject \ + TALER_TESTING_cmd_admin_add_incoming_with_subject \ (label, amount, fakebank_url, USER_ACCOUNT_NO, \ EXCHANGE_ACCOUNT_NO, USER_LOGIN_NAME, USER_LOGIN_PASS, \ subject, exchange_url) diff --git a/src/lib/test_exchange_api.c b/src/lib/test_exchange_api.c index 600e4c678..b95b060f5 100644 --- a/src/lib/test_exchange_api.c +++ b/src/lib/test_exchange_api.c @@ -111,11 +111,11 @@ static char *auditor_url; * @param amount amount to transfer, i.e. "EUR:1" */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ - TALER_TESTING_cmd_fakebank_transfer (label, amount, \ - fakebank_url, USER_ACCOUNT_NO, \ - EXCHANGE_ACCOUNT_NO, \ - USER_LOGIN_NAME, USER_LOGIN_PASS, \ - exchange_url) + TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + fakebank_url, USER_ACCOUNT_NO, \ + EXCHANGE_ACCOUNT_NO, \ + USER_LOGIN_NAME, USER_LOGIN_PASS, \ + exchange_url) /** * Run wire transfer of funds from some user's account to the @@ -125,7 +125,7 @@ static char *auditor_url; * @param amount amount to transfer, i.e. "EUR:1" */ #define CMD_TRANSFER_TO_EXCHANGE_SUBJECT(label,amount,subject) \ - TALER_TESTING_cmd_fakebank_transfer_with_subject \ + TALER_TESTING_cmd_admin_add_incoming_with_subject \ (label, amount, fakebank_url, USER_ACCOUNT_NO, \ EXCHANGE_ACCOUNT_NO, USER_LOGIN_NAME, USER_LOGIN_PASS, \ subject, exchange_url) diff --git a/src/lib/test_exchange_api_revocation.c b/src/lib/test_exchange_api_revocation.c index dfe185450..d98326d4a 100644 --- a/src/lib/test_exchange_api_revocation.c +++ b/src/lib/test_exchange_api_revocation.c @@ -98,11 +98,11 @@ static char *auditor_url; * @param amount amount to transfer, i.e. "EUR:1" */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ - TALER_TESTING_cmd_fakebank_transfer (label, amount, \ - fakebank_url, USER_ACCOUNT_NO, \ - EXCHANGE_ACCOUNT_NO, \ - USER_LOGIN_NAME, USER_LOGIN_PASS, \ - exchange_url) + TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + fakebank_url, USER_ACCOUNT_NO, \ + EXCHANGE_ACCOUNT_NO, \ + USER_LOGIN_NAME, USER_LOGIN_PASS, \ + exchange_url) /** * Main function that will tell the interpreter what commands to diff --git a/src/lib/test_exchange_api_twisted.c b/src/lib/test_exchange_api_twisted.c index f648b871d..80f32c921 100644 --- a/src/lib/test_exchange_api_twisted.c +++ b/src/lib/test_exchange_api_twisted.c @@ -116,11 +116,11 @@ static struct GNUNET_OS_Process *twisterd; * @param url exchange_url */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ - TALER_TESTING_cmd_fakebank_transfer (label, amount, \ - fakebank_url, USER_ACCOUNT_NO, \ - EXCHANGE_ACCOUNT_NO, \ - USER_LOGIN_NAME, USER_LOGIN_PASS, \ - exchange_url) + TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + fakebank_url, USER_ACCOUNT_NO, \ + EXCHANGE_ACCOUNT_NO, \ + USER_LOGIN_NAME, USER_LOGIN_PASS, \ + exchange_url) /** * Run wire transfer of funds from some user's account to the @@ -130,7 +130,7 @@ static struct GNUNET_OS_Process *twisterd; * @param amount amount to transfer, i.e. "EUR:1" */ #define CMD_TRANSFER_TO_EXCHANGE_SUBJECT(label,amount,subject) \ - TALER_TESTING_cmd_fakebank_transfer_with_subject \ + TALER_TESTING_cmd_admin_add_incoming_with_subject \ (label, amount, fakebank_url, USER_ACCOUNT_NO, \ EXCHANGE_ACCOUNT_NO, USER_LOGIN_NAME, USER_LOGIN_PASS, \ subject) diff --git a/src/lib/testing_api_cmd_fakebank_transfer.c b/src/lib/testing_api_cmd_fakebank_transfer.c deleted file mode 100644 index e212fd31f..000000000 --- a/src/lib/testing_api_cmd_fakebank_transfer.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-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 - -*/ - -/** - * @file exchange-lib/testing_api_cmd_fakebank_transfer.c - * @brief implementation of a fakebank wire transfer command - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" -#include "taler_testing_bank_lib.h" -#include "backoff.h" - -/** - * State for a "fakebank transfer" CMD. - */ -struct FakebankTransferState -{ - - /** - * Label of any command that can trait-offer a reserve priv. - */ - const char *reserve_reference; - - /** - * Wire transfer amount. - */ - struct TALER_Amount amount; - - /** - * Base URL of the debit account. - */ - const char *debit_url; - - /** - * Money receiver account URL. - */ - const char *payto_credit_account; - - /** - * Username to use for authentication. - */ - const char *auth_username; - - /** - * Password to use for authentication. - */ - const char *auth_password; - - /** - * Set (by the interpreter) to the reserve's private key - * we used to make a wire transfer subject line with. - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * Reserve public key matching @e reserve_priv. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Handle to the pending request at the fakebank. - */ - struct TALER_BANK_AdminAddIncomingHandle *aih; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Set to the wire transfer's unique ID. - */ - uint64_t serial_id; - - /** - * Timestamp of the transaction (as returned from the bank). - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Exchange URL. This value is fed to the bank when requesting - * the wire transfer; note: the bank needs it because a merchant - * might want to know which exchange performed a wire transfer to - * them, just by looking at bank records. - */ - const char *exchange_url; - - /** - * Merchant instance. Sometimes used to get the tip reserve - * private key by reading the appropriate config section. - */ - const char *instance; - - /** - * Configuration filename. Used to get the tip reserve key - * filename (used to obtain a public key to write in the - * transfer subject). - */ - const char *config_filename; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Was this command modified via - * #TALER_TESTING_cmd_fakebank_transfer_with_retry to - * enable retries? - */ - int do_retry; -}; - - -/** - * Run the "fakebank transfer" CMD. - * - * @param cls closure. - * @param cmd CMD being run. - * @param is interpreter state. - */ -static void -fakebank_transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #fakebank_transfer_run. - * - * @param cls a `struct FakebankTransferState` - */ -static void -do_retry (void *cls) -{ - struct FakebankTransferState *fts = cls; - - fts->retry_task = NULL; - fakebank_transfer_run (fts, - NULL, - fts->is); -} - - -/** - * This callback will process the fakebank response to the wire - * transfer. It just checks whether the HTTP response code is - * acceptable. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for - * successful status request; 0 if the exchange's reply is - * bogus (fails to follow the protocol) - * @param ec taler-specific error code, #TALER_EC_NONE on success - * @param serial_id unique ID of the wire transfer - * @param timestamp time stamp of the transaction made. - * @param json raw response - */ -static void -confirmation_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - struct GNUNET_TIME_Absolute timestamp, - const json_t *json) -{ - struct FakebankTransferState *fts = cls; - struct TALER_TESTING_Interpreter *is = fts->is; - - fts->aih = NULL; - if (MHD_HTTP_OK != http_status) - { - if (GNUNET_YES == fts->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log - (GNUNET_ERROR_TYPE_INFO, - "Retrying fakebank transfer failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - fts->backoff = GNUNET_TIME_UNIT_ZERO; - else - fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); - fts->retry_task = GNUNET_SCHEDULER_add_delayed - (fts->backoff, - &do_retry, - fts); - return; - } - } - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Fakebank returned HTTP status %u/%d\n", - http_status, - (int) ec); - TALER_TESTING_interpreter_fail (is); - return; - } - - fts->serial_id = serial_id; - fts->timestamp = timestamp; - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the "fakebank transfer" CMD. - * - * @param cls closure. - * @param cmd CMD being run. - * @param is interpreter state. - */ -static void -fakebank_transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct FakebankTransferState *fts = cls; - struct TALER_BANK_AuthenticationData auth; - - /* Use reserve public key as subject */ - if (NULL != fts->reserve_reference) - { - const struct TALER_TESTING_Command *ref; - const struct TALER_ReservePrivateKeyP *reserve_priv; - - ref = TALER_TESTING_interpreter_lookup_command - (is, fts->reserve_reference); - if (NULL == ref) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_priv (ref, - 0, - &reserve_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv; - } - else - { - if (NULL != fts->instance) - { - char *section; - char *keys; - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - struct GNUNET_CONFIGURATION_Handle *cfg; - - GNUNET_assert (NULL != fts->config_filename); - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, - fts->config_filename)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_asprintf (§ion, - "instance-%s", - fts->instance); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename - (cfg, - section, - "TIP_RESERVE_PRIV_FILENAME", - &keys)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Configuration fails to specify reserve" - " private key filename in section %s\n", - section); - GNUNET_free (section); - TALER_TESTING_interpreter_fail (is); - return; - } - priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys); - GNUNET_free (keys); - if (NULL == priv) - { - GNUNET_log_config_invalid - (GNUNET_ERROR_TYPE_ERROR, - section, - "TIP_RESERVE_PRIV_FILENAME", - "Failed to read private key"); - GNUNET_free (section); - TALER_TESTING_interpreter_fail (is); - return; - } - fts->reserve_priv.eddsa_priv = *priv; - GNUNET_free (section); - GNUNET_free (priv); - GNUNET_CONFIGURATION_destroy (cfg); - } - else - { - /* No referenced reserve, no instance to take priv - * from, no explicit subject given: create new key! */ - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - priv = GNUNET_CRYPTO_eddsa_key_create (); - fts->reserve_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - } - GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv, - &fts->reserve_pub.eddsa_pub); - auth.method = TALER_BANK_AUTH_BASIC; - auth.details.basic.username = (char *) fts->auth_username; - auth.details.basic.password = (char *) fts->auth_password; - fts->is = is; - fts->aih = TALER_BANK_admin_add_incoming - (TALER_TESTING_interpreter_get_context (is), - fts->debit_url, - &auth, - &fts->reserve_pub, - &fts->amount, - fts->payto_credit_account, - &confirmation_cb, - fts); - if (NULL == fts->aih) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } -} - - -/** - * Free the state of a "fakebank transfer" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure - * @param cmd current CMD being cleaned up. - */ -static void -fakebank_transfer_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct FakebankTransferState *fts = cls; - - if (NULL != fts->aih) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); - TALER_BANK_admin_add_incoming_cancel (fts->aih); - fts->aih = NULL; - } - if (NULL != fts->retry_task) - { - GNUNET_SCHEDULER_cancel (fts->retry_task); - fts->retry_task = NULL; - } - GNUNET_free (fts); -} - - -/** - * Offer internal data from a "fakebank transfer" CMD to other - * commands. - * - * @param cls closure. - * @param ret[out] result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -fakebank_transfer_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct FakebankTransferState *fts = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_url (0, fts->exchange_url), - TALER_TESTING_make_trait_url (1, fts->debit_url), - TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id), - TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT (fts->payto_credit_account), - TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT (fts->debit_url), - TALER_TESTING_make_trait_amount_obj (0, &fts->amount), - TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), - TALER_TESTING_make_trait_reserve_priv (0, - &fts->reserve_priv), - TALER_TESTING_make_trait_reserve_pub (0, - &fts->reserve_pub), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Create fakebank_transfer command, the subject line will be - * derived from a randomly created reserve priv. Note that that - * reserve priv will then be offered as trait. - * - * @param label command label. - * @param amount amount to transfer. - * @param account_base_url base URL of the account that implements this - * wire transer (which account gives money). - * @param payto_credit_account which account receives money. - * @param auth_username username identifying the @a - * debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param exchange_url which exchange is involved in this transfer. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer - (const char *label, - const char *amount, - const char *account_base_url, - const char *payto_credit_account, - const char *auth_username, - const char *auth_password, - const char *exchange_url) -{ - struct FakebankTransferState *fts; - - fts = GNUNET_new (struct FakebankTransferState); - fts->debit_url = account_base_url; - fts->payto_credit_account = payto_credit_account; - fts->auth_username = auth_username; - fts->auth_password = auth_password; - fts->exchange_url = exchange_url; - if (GNUNET_OK != - TALER_string_to_amount (amount, - &fts->amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %s\n", - amount, - label); - GNUNET_assert (0); - } - - { - struct TALER_TESTING_Command cmd = { - .cls = fts, - .label = label, - .run = &fakebank_transfer_run, - .cleanup = &fakebank_transfer_cleanup, - .traits = &fakebank_transfer_traits - }; - - return cmd; - } -} - - -/** - * Create "fakebank transfer" CMD, letting the caller specify - * a reference to a command that can offer a reserve private key. - * This private key will then be used to construct the subject line - * of the wire transfer. - * - * @param label command label. - * @param amount the amount to transfer. - * @param bank_url base URL of the bank running the transfer. - * @param debit_account_no which account (expressed as a number) - * gives money. - * @param credit_account_no which account (expressed as a number) - * receives money. - * @param auth_username username identifying the @a - * debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param ref reference to a command that can offer a reserve - * private key. - * @param exchange_url the exchage involved in the transfer, - * tipically receiving the money in order to fuel a reserve. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_with_ref - (const char *label, - const char *amount, - const char *account_base_url, - const char *payto_credit_account, - const char *auth_username, - const char *auth_password, - const char *ref, - const char *exchange_url) -{ - struct FakebankTransferState *fts; - - fts = GNUNET_new (struct FakebankTransferState); - fts->debit_url = account_base_url; - fts->payto_credit_account = payto_credit_account; - fts->auth_username = auth_username; - fts->auth_password = auth_password; - fts->reserve_reference = ref; - fts->exchange_url = exchange_url; - if (GNUNET_OK != - TALER_string_to_amount (amount, - &fts->amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %s\n", - amount, - label); - GNUNET_assert (0); - } - { - struct TALER_TESTING_Command cmd = { - .cls = fts, - .label = label, - .run = &fakebank_transfer_run, - .cleanup = &fakebank_transfer_cleanup, - .traits = &fakebank_transfer_traits - }; - - return cmd; - } -} - - -/** - * Create "fakebank transfer" CMD, letting the caller specifying - * the merchant instance. This version is useful when a tip - * reserve should be topped up, in fact the interpreter will need - * the "tipping instance" in order to get the instance public key - * and make a wire transfer subject out of it. - * - * @param label command label. - * @param amount amount to transfer. - * @param bank_url base URL of the bank that implements this - * wire transer. For simplicity, both credit and debit - * bank account exist at the same bank. - * @param debit_account_no which account (expressed as a number) - * gives money. - * @param credit_account_no which account (expressed as a number) - * receives money. - * - * @param auth_username username identifying the @a - * debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param instance the instance that runs the tipping. Under this - * instance, the configuration file will provide the private - * key of the tipping reserve. This data will then used to - * construct the wire transfer subject line. - * @param exchange_url which exchange is involved in this transfer. - * @param config_filename configuration file to use. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_with_instance - (const char *label, - const char *amount, - const char *account_base_url, - const char *payto_credit_account, - const char *auth_username, - const char *auth_password, - const char *instance, - const char *exchange_url, - const char *config_filename) -{ - struct FakebankTransferState *fts; - - fts = GNUNET_new (struct FakebankTransferState); - fts->debit_url = account_base_url; - fts->payto_credit_account = payto_credit_account; - fts->auth_username = auth_username; - fts->auth_password = auth_password; - fts->instance = instance; - fts->exchange_url = exchange_url; - fts->config_filename = config_filename; - if (GNUNET_OK != - TALER_string_to_amount (amount, - &fts->amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %s\n", - amount, - label); - GNUNET_assert (0); - } - { - struct TALER_TESTING_Command cmd = { - .cls = fts, - .label = label, - .run = &fakebank_transfer_run, - .cleanup = &fakebank_transfer_cleanup, - .traits = &fakebank_transfer_traits - }; - - return cmd; - } -} - - -/** - * Modify a fakebank transfer command to enable retries when the - * reserve is not yet full or we get other transient errors from the - * fakebank. - * - * @param cmd a fakebank transfer command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_retry (struct TALER_TESTING_Command cmd) -{ - struct FakebankTransferState *fts; - - GNUNET_assert (&fakebank_transfer_run == cmd.run); - fts = cmd.cls; - fts->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_api_cmd_fakebank_transfer.c */ -- cgit v1.2.3