diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-03-05 20:11:51 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-03-05 20:11:51 +0100 |
commit | 09b01a179daf0de4ad2a14d22f584c105d7de22c (patch) | |
tree | 74548bdbd5dc19f3fa2033e908fc4f7552f90bc3 | |
parent | 2b78ff4482e5e25bc1880dd08ed4acc6182f134c (diff) | |
download | merchant-09b01a179daf0de4ad2a14d22f584c105d7de22c.tar.gz merchant-09b01a179daf0de4ad2a14d22f584c105d7de22c.tar.bz2 merchant-09b01a179daf0de4ad2a14d22f584c105d7de22c.zip |
towards implementing #4935: make sure all of the fee data is available for the /pay handler (but not yet checked)
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 10 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.c | 337 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.h | 4 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_pay.c | 121 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_track-transaction.c | 3 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_track-transfer.c | 3 |
6 files changed, 414 insertions, 64 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index f13b8911..cb083017 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -632,7 +632,7 @@ get_instance (struct json_t *json) * @param config configuration handle * @param allowed which wire format is allowed/expected? * @return #GNUNET_OK if successful, #GNUNET_SYSERR upon errors - * (for example, if no "defaul" instance is defined) + * (for example, if no "default" instance is defined) */ static unsigned int iterate_instances (const struct GNUNET_CONFIGURATION_Handle *config, @@ -716,7 +716,6 @@ run (void *cls, char *wireformat; int fh; - wireformat = NULL; result = GNUNET_SYSERR; GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); @@ -763,6 +762,7 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } + wireformat = NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (config, "merchant", @@ -775,10 +775,10 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } - - iterate_instances (config, wireformat); - + iterate_instances (config, + wireformat); GNUNET_free (wireformat); + if (NULL == (db = TALER_MERCHANTDB_plugin_load (config))) { diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c index 176c8ad6..c7e88c7f 100644 --- a/src/backend/taler-merchant-httpd_exchanges.c +++ b/src/backend/taler-merchant-httpd_exchanges.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2014, 2015, 2016 INRIA + (C) 2014-2017 INRIA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -84,6 +84,11 @@ struct TMH_EXCHANGES_FindOperation struct Exchange *my_exchange; /** + * Wire method we care about for fees. + */ + char *wire_method; + + /** * Task scheduled to asynchronously return the result to * the find continuation. */ @@ -93,6 +98,35 @@ struct TMH_EXCHANGES_FindOperation /** + * Information about wire transfer fees of an exchange, by wire method. + */ +struct FeesByWireMethod +{ + + /** + * Kept in a DLL. + */ + struct FeesByWireMethod *next; + + /** + * Kept in a DLL. + */ + struct FeesByWireMethod *prev; + + /** + * Wire method these fees are for. + */ + char *wire_method; + + /** + * Applicable fees, NULL if unknown/error. + */ + struct TALER_EXCHANGE_WireAggregateFees *af; + +}; + + +/** * Exchange */ struct Exchange @@ -129,6 +163,26 @@ struct Exchange struct TALER_EXCHANGE_Handle *conn; /** + * Active /wire request to the exchange, or NULL. + */ + struct TALER_EXCHANGE_WireHandle *wire_request; + + /** + * Task to re-run /wire after some delay. + */ + struct GNUNET_SCHEDULER_Task *wire_task; + + /** + * Head of wire fees from /wire request. + */ + struct FeesByWireMethod *wire_fees_head; + + /** + * Tail of wire fees from /wire request. + */ + struct FeesByWireMethod *wire_fees_tail; + + /** * Master public key, guaranteed to be set ONLY for * trusted exchanges. */ @@ -239,6 +293,237 @@ retry_exchange (void *cls) /** + * Function called with information about the wire fees + * for each wire method. Stores the wire fees with the + * exchange for laster use. + * + * @param cls closure + * @param wire_method name of the wire method (i.e. "sepa") + * @param fees fee structure for this method + */ +static void +process_wire_fees (void *cls, + const char *wire_method, + const struct TALER_EXCHANGE_WireAggregateFees *fees) +{ + struct Exchange *exchange = cls; + struct FeesByWireMethod *f; + struct TALER_EXCHANGE_WireAggregateFees *endp; + struct TALER_EXCHANGE_WireAggregateFees *af; + + for (f = exchange->wire_fees_head; NULL != f; f = f->next) + if (0 == strcasecmp (wire_method, + f->wire_method)) + break; + if (NULL == f) + { + f = GNUNET_new (struct FeesByWireMethod); + f->wire_method = GNUNET_strdup (wire_method); + GNUNET_CONTAINER_DLL_insert (exchange->wire_fees_head, + exchange->wire_fees_tail, + f); + } + endp = f->af; + while ( (NULL != endp) && + (NULL != endp->next) ) + endp = endp->next; + while ( (NULL != endp) && + (fees->start_date.abs_value_us < endp->end_date.abs_value_us) ) + fees = fees->next; + if ( (NULL != endp) && + (fees->start_date.abs_value_us != endp->end_date.abs_value_us) ) + { + /* Hole in the fee structure, not allowed! */ + GNUNET_break_op (0); + return; + } + while (NULL != fees) + { + af = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees); + *af = *fees; + af->next = NULL; + if (NULL == endp) + f->af = af; + else + endp->next = af; + endp = af; + // FIXME: also preserve `fees` in backend DB (under wire method + exchange master pub!) + fees = fees->next; + } +} + + +/** + * Check if we have any remaining pending requests for the + * given @a exchange, and if we have the required data, call + * the callback. + * + * @param exchange the exchange to check for pending find operations + * @return #GNUNET_YES if we need /wire data from @a exchange + */ +static int +process_find_operations (struct Exchange *exchange) +{ + struct TMH_EXCHANGES_FindOperation *fo; + struct TMH_EXCHANGES_FindOperation *fn; + struct GNUNET_TIME_Absolute now; + int need_wire; + + now = GNUNET_TIME_absolute_get (); + need_wire = GNUNET_NO; + for (fo = exchange->fo_head; NULL != fo; fo = fn) + { + const struct TALER_Amount *wire_fee; + + fn = fo->next; + if (NULL != fo->wire_method) + { + struct FeesByWireMethod *fbw; + struct TALER_EXCHANGE_WireAggregateFees *af; + + /* Find fee structure for our wire method */ + for (fbw = exchange->wire_fees_head; NULL != fbw; fbw = fbw->next) + if (0 == strcasecmp (fbw->wire_method, + fo->wire_method) ) + break; + if (NULL == fbw) + { + need_wire = GNUNET_YES; + continue; + } + /* Advance through list up to current time */ + while ( (NULL != (af = fbw->af)) && + (now.abs_value_us >= af->end_date.abs_value_us) ) + { + fbw->af = af->next; + GNUNET_free (af); + } + if (NULL == af) + { + need_wire = GNUNET_YES; + continue; + } + if (af->start_date.abs_value_us > now.abs_value_us) + { + /* Disagreement on the current time */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Exchange's earliest fee is %s adhead of our time. Clock skew issue?\n", + GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (af->start_date), + GNUNET_YES)); + continue; + } + /* found fee, great! */ + wire_fee = &af->wire_fee; + } + else + { + /* no wire transfer method given, so we yield no fee */ + wire_fee = NULL; + } + GNUNET_CONTAINER_DLL_remove (exchange->fo_head, + exchange->fo_tail, + fo); + fo->fc (fo->fc_cls, + exchange->conn, + wire_fee, + exchange->trusted); + GNUNET_free_non_null (fo->wire_method); + GNUNET_free (fo); + } + return need_wire; +} + + +/** + * Check if we have any remaining pending requests for the + * given @a exchange, and if we have the required data, call + * the callback. If requests without /wire data remain, + * retry the /wire request after some delay. + * + * @param cls a `struct Exchange` to check + */ +static void +wire_task_cb (void *cls); + + +/** + * Callbacks of this type are used to serve the result of submitting a + * wire format inquiry request to a exchange. + * + * If the request fails to generate a valid response from the + * exchange, @a http_status will also be zero. + * + * @param cls closure, a `struct Exchange` + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 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 obj the received JSON reply, if successful this should be the wire + * format details as provided by /wire, or NULL if the + * reply was not in JSON format. + */ +static void +handle_wire_data (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const json_t *obj) +{ + struct Exchange *exchange = cls; + + exchange->wire_request = NULL; + if (MHD_HTTP_OK != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to obtain /wire details from `%s': %d\n", + exchange->uri, + ec); + return; + } + if (GNUNET_OK != + TALER_EXCHANGE_wire_get_fees (&exchange->master_pub, + obj, + &process_wire_fees, + exchange)) + { + GNUNET_break_op (0); + return; + } + if (GNUNET_YES == + process_find_operations (exchange)) + { + /* need to run /wire again, with some delay */ + GNUNET_assert (NULL == exchange->wire_task); + exchange->wire_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &wire_task_cb, + exchange); + } +} + + +/** + * Check if we have any remaining pending requests for the + * given @a exchange, and if we have the required data, call + * the callback. If requests without /wire data remain, + * retry the /wire request after some delay. + * + * @param cls a `struct Exchange` to check + */ +static void +wire_task_cb (void *cls) +{ + struct Exchange *exchange = cls; + + exchange->wire_task = NULL; + if (GNUNET_YES != + process_find_operations (exchange)) + return; /* no more need */ + GNUNET_assert (NULL == exchange->wire_request); + exchange->wire_request = TALER_EXCHANGE_wire (exchange->conn, + &handle_wire_data, + exchange); +} + + +/** * Function called with information about who is auditing * a particular exchange and what key the exchange is using. * @@ -257,13 +542,22 @@ keys_mgmt_cb (void *cls, const struct TALER_EXCHANGE_Keys *keys) { struct Exchange *exchange = cls; - struct TMH_EXCHANGES_FindOperation *fo; struct GNUNET_TIME_Absolute expire; struct GNUNET_TIME_Relative delay; if (NULL == keys) { exchange->pending = GNUNET_YES; + if (NULL != exchange->wire_request) + { + TALER_EXCHANGE_wire_cancel (exchange->wire_request); + exchange->wire_request = NULL; + } + if (NULL != exchange->wire_task) + { + GNUNET_SCHEDULER_cancel (exchange->wire_task); + exchange->wire_task = NULL; + } exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to fetch /keys from `%s', retrying in %s\n", @@ -286,15 +580,14 @@ keys_mgmt_cb (void *cls, &retry_exchange, exchange); exchange->pending = GNUNET_NO; - while (NULL != (fo = exchange->fo_head)) + if (GNUNET_YES == + process_find_operations (exchange)) { - GNUNET_CONTAINER_DLL_remove (exchange->fo_head, - exchange->fo_tail, - fo); - fo->fc (fo->fc_cls, - exchange->conn, - exchange->trusted); - GNUNET_free (fo); + GNUNET_assert (NULL == exchange->wire_request); + GNUNET_assert (NULL == exchange->wire_task); + exchange->wire_request = TALER_EXCHANGE_wire (exchange->conn, + &handle_wire_data, + exchange); } } @@ -319,6 +612,7 @@ return_result (void *cls) exchange->uri, exchange->trusted); fo->fc (fo->fc_cls, (GNUNET_SYSERR == exchange->pending) ? NULL : exchange->conn, + NULL, /* FIXME: pass fees! */ exchange->trusted); GNUNET_free (fo); } @@ -330,12 +624,14 @@ return_result (void *cls) * NULL for the exchange. * * @param chosen_exchange URI of the exchange we would like to talk to + * @param wire_method the wire method we will use with @a chosen_exchange, NULL for none * @param fc function to call with the handles for the exchange * @param fc_cls closure for @a fc * @return NULL on error */ struct TMH_EXCHANGES_FindOperation * TMH_EXCHANGES_find_exchange (const char *chosen_exchange, + const char *wire_method, TMH_EXCHANGES_FindContinuation fc, void *fc_cls) { @@ -387,6 +683,8 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, fo->fc = fc; fo->fc_cls = fc_cls; fo->my_exchange = exchange; + if (NULL != wire_method) + fo->wire_method = GNUNET_strdup (wire_method); GNUNET_CONTAINER_DLL_insert (exchange->fo_head, exchange->fo_tail, fo); @@ -429,6 +727,7 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo) GNUNET_CONTAINER_DLL_remove (exchange->fo_head, exchange->fo_tail, fo); + GNUNET_free_non_null (fo->wire_method); GNUNET_free (fo); } @@ -443,7 +742,7 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo) */ static void accept_exchanges (void *cls, - const char *section) + const char *section) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; char *uri; @@ -561,10 +860,26 @@ TMH_EXCHANGES_done () GNUNET_CONTAINER_DLL_remove (exchange_head, exchange_tail, exchange); + if (NULL != exchange->wire_request) + { + TALER_EXCHANGE_wire_cancel (exchange->wire_request); + exchange->wire_request = NULL; + } + if (NULL != exchange->wire_task) + { + GNUNET_SCHEDULER_cancel (exchange->wire_task); + exchange->wire_task = NULL; + } if (NULL != exchange->conn) + { TALER_EXCHANGE_disconnect (exchange->conn); + exchange->conn = NULL; + } if (NULL != exchange->retry_task) + { GNUNET_SCHEDULER_cancel (exchange->retry_task); + exchange->retry_task = NULL; + } GNUNET_free (exchange->uri); GNUNET_free (exchange); } diff --git a/src/backend/taler-merchant-httpd_exchanges.h b/src/backend/taler-merchant-httpd_exchanges.h index 0e705a41..6b763aeb 100644 --- a/src/backend/taler-merchant-httpd_exchanges.h +++ b/src/backend/taler-merchant-httpd_exchanges.h @@ -60,11 +60,13 @@ TMH_EXCHANGES_done (void); * * @param cls closure * @param eh handle to the exchange context + * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if not available * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config */ typedef void (*TMH_EXCHANGES_FindContinuation)(void *cls, struct TALER_EXCHANGE_Handle *eh, + const struct TALER_Amount *wire_fee, int exchange_trusted); @@ -80,11 +82,13 @@ struct TMH_EXCHANGES_FindOperation; * NULL for the exchange. * * @param chosen_exchange URI of the exchange we would like to talk to + * @param wire_method the wire method we will use with @a chosen_exchange, NULL for none * @param fc function to call with the handles for the exchange * @param fc_cls closure for @a fc */ struct TMH_EXCHANGES_FindOperation * TMH_EXCHANGES_find_exchange (const char *chosen_exchange, + const char *wire_method, TMH_EXCHANGES_FindContinuation fc, void *fc_cls); diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c index 91860ca2..090ae144 100644 --- a/src/backend/taler-merchant-httpd_pay.c +++ b/src/backend/taler-merchant-httpd_pay.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2014, 2015, 2016 GNUnet e.V. and INRIA + (C) 2014, 2015, 2016, 2017 GNUnet e.V. and INRIA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -165,6 +165,34 @@ struct PayContext struct TALER_Amount max_fee; /** + * Maximum wire fee the merchant is willing to pay, from @e root. + * Note that IF the total fee of the exchange is higher, that is + * acceptable to the merchant if the customer is willing to + * pay the amorized difference. Wire fees are charged over an + * aggregate of several translations, hence unlike the deposit + * fees, they are amortized over several customer's transactions. + * The contract specifies under @e wire_fee_amortization how many + * customer's transactions he expects the wire fees to be amortized + * over on average. Thus, if the wire fees are larger than + * @e max_wire_fee, each customer is expected to contribute + * $\frac{actual-wire-fee - max_wire_fee}{wire_fee_amortization}$. + * The customer's contribution may be further reduced by the + * difference between @e max_fee and the sum of the deposit fees. + * + * Default is that the merchant is unwilling to pay any wire fees. + */ + struct TALER_Amount max_wire_fee; + + /** + * Number of transactions that the wire fees are expected to be + * amortized over. Never zero, defaults (conservateively) to 1. + * May be higher if merchants expect many small transactions to + * be aggregated and thus wire fees to be reasonably amortized + * due to aggregation. + */ + uint32_t wire_fee_amortization; + + /** * Amount from @e root. This is the amount the merchant expects * to make, minus @e max_fee. */ @@ -526,11 +554,13 @@ pay_context_cleanup (struct TM_HandlerContext *hc) * * @param cls the `struct PayContext` * @param mh NULL if exchange was not found to be acceptable + * @param wire_fee current applicable fee for dealing with @a mh, NULL if not available * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config */ static void process_pay_with_exchange (void *cls, struct TALER_EXCHANGE_Handle *mh, + const struct TALER_Amount *wire_fee, int exchange_trusted) { struct PayContext *pc = cls; @@ -552,7 +582,6 @@ process_pay_with_exchange (void *cls, return; } pc->mh = mh; - keys = TALER_EXCHANGE_get_keys (mh); if (NULL == keys) { @@ -874,40 +903,13 @@ check_transaction_exists (void *cls, } } + +// FIXME: declare in proper header! extern struct MerchantInstance * get_instance (struct json_t *json); /** - * Just a stub used to double-check if a transaction - * has been correctly inserted into db. - * - * @param cls closure - * @param transaction_id of the contract - * @param merchant's public key - * @param exchange_uri URI of the exchange - * @param h_contract hash of the contract - * @param h_wire hash of our wire details - * @param timestamp time of the confirmation - * @param refund refund deadline - * @param total_amount total amount we receive for the contract after fees - */ -static void -transaction_double_check (void *cls, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const char *exchange_uri, - const struct GNUNET_HashCode *h_proposal_data, - const struct GNUNET_HashCode *h_wire, - struct GNUNET_TIME_Absolute timestamp, - struct GNUNET_TIME_Absolute refund, - const struct TALER_Amount *total_amount) -{ - return; -} - - - -/** * Try to parse the pay request into the given pay context. * * Schedules an error response in the connection on failure. @@ -968,7 +970,7 @@ parse_pay (struct MHD_Connection *connection, GNUNET_JSON_parse_free (spec); if (MHD_YES != TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, + TALER_EC_PAY_FAILED_COMPUTE_PROPOSAL_HASH, "Can not hash proposal")) { GNUNET_break (0); @@ -984,10 +986,9 @@ parse_pay (struct MHD_Connection *connection, GNUNET_JSON_parse_free (spec); /* invalid contract */ GNUNET_break (0); - // FIXME: define proper EC for this! if (MHD_YES != TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, + TALER_EC_PAY_MERCHANT_FIELD_MISSING, "No merchant field in contract")) { GNUNET_break (0); @@ -1015,12 +1016,10 @@ parse_pay (struct MHD_Connection *connection, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "/pay: picked instance %s with key %s\n", pc->mi->id, - GNUNET_STRINGS_data_to_string_alloc (&pc->mi->pubkey, sizeof (pc->mi->pubkey))); + GNUNET_STRINGS_data_to_string_alloc (&pc->mi->pubkey, + sizeof (pc->mi->pubkey))); pc->chosen_exchange = GNUNET_strdup (chosen_exchange); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Parsed JSON for /pay.\n"); - { struct GNUNET_JSON_Specification espec[] = { GNUNET_JSON_spec_absolute_time ("refund_deadline", @@ -1060,9 +1059,42 @@ parse_pay (struct MHD_Connection *connection, } } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "parsed timestamps\n"); + /* parse optional details */ + { + struct GNUNET_JSON_Specification espec[] = { + TALER_JSON_spec_amount ("max_wire_fee", + &pc->max_wire_fee), + GNUNET_JSON_spec_end() + }; + + res = TMH_PARSE_json_data (connection, + pc->proposal_data, + espec); + if (GNUNET_YES != res) + { + /* default is we cover no fee */ + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (pc->max_fee.currency, + &pc->max_wire_fee)); + } + } + { + struct GNUNET_JSON_Specification espec[] = { + GNUNET_JSON_spec_uint32 ("wire_fee_amortization", + &pc->wire_fee_amortization), + GNUNET_JSON_spec_end() + }; + res = TMH_PARSE_json_data (connection, + pc->proposal_data, + espec); + if ( (GNUNET_YES != res) || + (0 == pc->wire_fee_amortization) ) + { + /* default is no amortization */ + pc->wire_fee_amortization = 1; + } + } pc->coins_cnt = json_array_size (coins); if (0 == pc->coins_cnt) @@ -1140,8 +1172,6 @@ handler_pay_json (struct MHD_Connection *connection, if (GNUNET_OK != ret) return ret; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "parsed '/pay' body\n"); - /* Check if this payment attempt has already succeeded */ if (GNUNET_SYSERR == db->find_payments (db->cls, @@ -1232,18 +1262,13 @@ handler_pay_json (struct MHD_Connection *connection, TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR, "Merchant database error"); } - if (GNUNET_OK != db->find_transaction (db->cls, - &pc->h_proposal_data, - &pc->mi->pubkey, - &transaction_double_check, - NULL)) - GNUNET_break (0); } MHD_suspend_connection (connection); /* Find the responsible exchange, this may take a while... */ pc->fo = TMH_EXCHANGES_find_exchange (pc->chosen_exchange, + NULL, /* FIXME: wire method! */ &process_pay_with_exchange, pc); diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c index b0dffaff..7eeadd0c 100644 --- a/src/backend/taler-merchant-httpd_track-transaction.c +++ b/src/backend/taler-merchant-httpd_track-transaction.c @@ -679,11 +679,13 @@ trace_coins (struct TrackTransactionContext *tctx) * * @param cls the `struct TrackTransactionContext` * @param eh NULL if exchange was not found to be acceptable + * @param wire_fee NULL (we did not specify a wire method) * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config */ static void process_track_transaction_with_exchange (void *cls, struct TALER_EXCHANGE_Handle *eh, + const struct TALER_Amount *wire_fee, int exchange_trusted) { struct TrackTransactionContext *tctx = cls; @@ -987,6 +989,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, "Suspending /track/transaction handling while working with the exchange\n"); MHD_suspend_connection (connection); tctx->fo = TMH_EXCHANGES_find_exchange (tctx->exchange_uri, + NULL, &process_track_transaction_with_exchange, tctx); diff --git a/src/backend/taler-merchant-httpd_track-transfer.c b/src/backend/taler-merchant-httpd_track-transfer.c index 029eec52..3635c1d4 100644 --- a/src/backend/taler-merchant-httpd_track-transfer.c +++ b/src/backend/taler-merchant-httpd_track-transfer.c @@ -415,11 +415,13 @@ wire_transfer_cb (void *cls, * * @param cls the `struct TrackTransferContext` * @param eh NULL if exchange was not found to be acceptable + * @param wire_fee NULL (we did not specify a wire method) * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config */ static void process_track_transfer_with_exchange (void *cls, struct TALER_EXCHANGE_Handle *eh, + const struct TALER_Amount *wire_fee, int exchange_trusted) { struct TrackTransferContext *rctx = cls; @@ -623,6 +625,7 @@ MH_handler_track_transfer (struct TMH_RequestHandler *rh, "Suspending /track/transfer handling while working with the exchange\n"); MHD_suspend_connection (connection); rctx->fo = TMH_EXCHANGES_find_exchange (uri, + NULL, &process_track_transfer_with_exchange, rctx); rctx->timeout_task |