summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-03-05 20:11:51 +0100
committerChristian Grothoff <christian@grothoff.org>2017-03-05 20:11:51 +0100
commit09b01a179daf0de4ad2a14d22f584c105d7de22c (patch)
tree74548bdbd5dc19f3fa2033e908fc4f7552f90bc3
parent2b78ff4482e5e25bc1880dd08ed4acc6182f134c (diff)
downloadmerchant-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.c10
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.c337
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.h4
-rw-r--r--src/backend/taler-merchant-httpd_pay.c121
-rw-r--r--src/backend/taler-merchant-httpd_track-transaction.c3
-rw-r--r--src/backend/taler-merchant-httpd_track-transfer.c3
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