aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--doc/manual.texi4
-rw-r--r--src/backend/merchant.conf10
-rw-r--r--src/backend/taler-merchant-httpd.c81
-rw-r--r--src/backend/taler-merchant-httpd.h16
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.c129
-rw-r--r--src/backend/taler-merchant-httpd_pay.c131
-rw-r--r--src/backend/taler-merchant-httpd_proposal.c51
-rw-r--r--src/lib/test_merchant_api.conf1
9 files changed, 338 insertions, 90 deletions
diff --git a/ChangeLog b/ChangeLog
index 6ea07385..8ff267ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Mar 6 17:57:51 CET 2017
+ Add support for wire fee calculations to /pay handling (#4935),
+ and adding setting "max_wire_fee" and "wire_fee_amortization"
+ in contract from defaults. -CG
+
Mon Mar 6 00:59:25 CET 2017
Implement BIND_TO option to allow binding backend to a particular
IP address (#4752). Enabling use of dual-stack by default. -CG
diff --git a/doc/manual.texi b/doc/manual.texi
index b97fe4ea..af2dc37d 100644
--- a/doc/manual.texi
+++ b/doc/manual.texi
@@ -507,14 +507,14 @@ Which currency the Web shop deals in, i.e. ``EUR'' or ``USD'', is specified usin
@cindex currency
@cindex KUDOS
@example
-[merchant]/currency
+[taler]/currency
@end example
For testing purposes, the currency MUST match ``KUDOS'' so that tests will work
with the Taler demonstration exchange at @url{https://exchange.demo.taler.net/}:
@example
-$ taler-config -s merchant -o currency -V KUDOS
+$ taler-config -s taler -o currency -V KUDOS
@end example
@item Database
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
index 3723af08..55117874 100644
--- a/src/backend/merchant.conf
+++ b/src/backend/merchant.conf
@@ -24,6 +24,16 @@ UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
UNIXPATH_MODE = 660
+# Maximum wire fee to permit by default. You most certainly want to
+# adjust at least the currency.
+# DEFAULT_MAX_WIRE_FEE = "KUDOS:0.10"
+
+# Which fraction of an exessivly high wire fee is the customer expected
+# to cover? Must be a positive integer representing the expected
+# average number of transactions aggregated by exchanges. 1 is
+# always safe (financially speaking).
+DEFAULT_WIRE_FEE_AMORTIZATION = 1
+
# Where does the backend store the merchant's private key?
KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index b400416e..f3faa303 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -73,6 +73,17 @@ static long long unsigned port;
struct GNUNET_TIME_Relative wire_transfer_delay;
/**
+ * Default maximum wire fee to assume, unless stated differently in the proposal
+ * already.
+ */
+struct TALER_Amount default_max_wire_fee;
+
+/**
+ * Default factor for wire fee amortization.
+ */
+unsigned long long default_wire_fee_amortization;
+
+/**
* Should a "Connection: close" header be added to each HTTP response?
*/
int TMH_merchant_connection_close;
@@ -275,6 +286,10 @@ do_shutdown (void *cls)
GNUNET_SCHEDULER_cancel (mhd_task);
mhd_task = NULL;
}
+ /* FIXME: MHD API requires us to resume all suspended
+ connections before we do this, but /pay currently
+ suspends connections without giving us a way to
+ enumerate / resume them... */
if (NULL != mhd)
{
MHD_stop_daemon (mhd);
@@ -446,13 +461,15 @@ instances_iterator_cb (void *cls,
/* used as hashmap keys */
struct GNUNET_HashCode h_pk;
struct GNUNET_HashCode h_id;
+ json_t *type;
char *emsg;
iic = cls;
substr = strstr (section, "merchant-instance-");
- if ((NULL == substr)
- || (NULL != strstr (section, "merchant-instance-wireformat-")))
+ if ( (NULL == substr) ||
+ (NULL != strstr (section,
+ "merchant-instance-wireformat-")) )
return;
if (substr != section)
@@ -509,11 +526,19 @@ instances_iterator_cb (void *cls,
GNUNET_asprintf (&instance_wiresection,
"merchant-instance-wireformat-%s",
mi->id);
-
mi->j_wire = iic->plugin->get_wire_details (iic->plugin->cls,
iic->config,
instance_wiresection);
GNUNET_free (instance_wiresection);
+ if ( (NULL == (type = json_object_get (mi->j_wire,
+ "type"))) ||
+ (! json_is_string (type)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Malformed wireformat: lacks type\n");
+ iic->ret |= GNUNET_SYSERR;
+ }
+ mi->wire_method = json_string_value (type);
if (TALER_EC_NONE !=
iic->plugin->wire_validate (iic->plugin->cls,
@@ -521,7 +546,6 @@ instances_iterator_cb (void *cls,
NULL,
&emsg))
{
-
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Malformed wireformat: %s\n",
emsg);
@@ -762,6 +786,55 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+
+ if (GNUNET_OK !=
+ TALER_config_get_denom (config,
+ "merchant",
+ "DEFAULT_MAX_WIRE_FEE",
+ &default_max_wire_fee))
+ {
+ char *currency;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (config,
+ "taler",
+ "CURRENCY",
+ &currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler",
+ "CURRENCY");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_get_zero (currency,
+ &default_max_wire_fee))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "taler",
+ "CURRENCY",
+ "Specified value not legal for a Taler currency");
+ GNUNET_SCHEDULER_shutdown ();
+ GNUNET_free (currency);
+ return;
+ }
+ GNUNET_free (currency);
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (config,
+ "merchant",
+ "DEFAULT_WIRE_FEE_AMORTIZATION",
+ &default_wire_fee_amortization))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "merchant",
+ "DEFAULT_WIRE_FEE_AMORTIZATION");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
wireformat = NULL;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (config,
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index ee4a3b25..0526ad20 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -95,6 +95,11 @@ struct MerchantInstance
once we implement #4939 */
/**
+ * Which wire method is @e j_wire using?
+ */
+ const char *wire_method;
+
+ /**
* Wire details for this instance
*/
struct json_t *j_wire;
@@ -220,6 +225,17 @@ struct TM_HandlerContext
extern json_t *j_wire;
/**
+ * Default maximum wire fee to assume, unless stated differently in the proposal
+ * already.
+ */
+extern struct TALER_Amount default_max_wire_fee;
+
+/**
+ * Default factor for wire fee amortization.
+ */
+extern unsigned long long default_wire_fee_amortization;
+
+/**
* Hash of our wire format details as given in #j_wire.
*/
extern struct GNUNET_HashCode h_wire;
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c
index c7e88c7f..daf5550f 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -354,6 +354,40 @@ process_wire_fees (void *cls,
/**
+ * Obtain applicable fees for @a exchange and @a wire_method.
+ *
+ * @param exchange the exchange to query
+ * @param now current time
+ * @param wire_method the wire method we want the fees for
+ * @return NULL if we do not have fees for this method yet
+ */
+static struct TALER_EXCHANGE_WireAggregateFees *
+get_wire_fees (struct Exchange *exchange,
+ struct GNUNET_TIME_Absolute now,
+ const char *wire_method)
+{
+ for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
+ NULL != fbw;
+ fbw = fbw->next)
+ if (0 == strcasecmp (fbw->wire_method,
+ wire_method) )
+ {
+ struct TALER_EXCHANGE_WireAggregateFees *af;
+
+ /* 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);
+ }
+ return af;
+ }
+ return NULL;
+}
+
+
+/**
* Check if we have any remaining pending requests for the
* given @a exchange, and if we have the required data, call
* the callback.
@@ -378,26 +412,12 @@ process_find_operations (struct Exchange *exchange)
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);
- }
+ af = get_wire_fees (exchange,
+ now,
+ fo->wire_method);
if (NULL == af)
{
need_wire = GNUNET_YES;
@@ -479,18 +499,40 @@ handle_wire_data (void *cls,
return;
}
if (GNUNET_OK !=
- TALER_EXCHANGE_wire_get_fees (&exchange->master_pub,
+ TALER_EXCHANGE_wire_get_fees (&TALER_EXCHANGE_get_keys (exchange->conn)->master_pub,
obj,
&process_wire_fees,
exchange))
{
+ /* Report hard failure to all callbacks! */
+ struct TMH_EXCHANGES_FindOperation *fo;
+
GNUNET_break_op (0);
+ while (NULL != (fo = exchange->fo_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
+ exchange->fo_tail,
+ fo);
+ /* TODO: report more precise error, this ultimately generates
+ "exchange not supported" instead of "exchange violated
+ protocol"; we should ideally generate a reply with
+ a specific TALER_EC-code, boxing 'obj' within it. */
+ fo->fc (fo->fc_cls,
+ NULL,
+ NULL,
+ GNUNET_NO);
+ GNUNET_free_non_null (fo->wire_method);
+ GNUNET_free (fo);
+ }
return;
}
if (GNUNET_YES ==
process_find_operations (exchange))
{
/* need to run /wire again, with some delay */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Do not have sufficient wire data. Will re-request /wire in 1 minute\n");
+
GNUNET_assert (NULL == exchange->wire_task);
exchange->wire_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
&wire_task_cb,
@@ -574,7 +616,8 @@ keys_mgmt_cb (void *cls,
delay = RELOAD_DELAY;
else
delay = GNUNET_TIME_absolute_get_remaining (expire);
- exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
+ exchange->retry_delay
+ = GNUNET_TIME_UNIT_ZERO;
exchange->retry_task
= GNUNET_SCHEDULER_add_delayed (delay,
&retry_exchange,
@@ -583,6 +626,8 @@ keys_mgmt_cb (void *cls,
if (GNUNET_YES ==
process_find_operations (exchange))
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got key data, but do not have current wire data. Will request /wire now\n");
GNUNET_assert (NULL == exchange->wire_request);
GNUNET_assert (NULL == exchange->wire_task);
exchange->wire_request = TALER_EXCHANGE_wire (exchange->conn,
@@ -603,18 +648,19 @@ return_result (void *cls)
struct TMH_EXCHANGES_FindOperation *fo = cls;
struct Exchange *exchange = fo->my_exchange;
- fo->at = NULL;
- GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
- exchange->fo_tail,
- fo);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Returning result for exchange %s, trusted=%d\n",
- 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);
+ if ( (GNUNET_YES ==
+ process_find_operations (exchange)) &&
+ (NULL == exchange->wire_request) &&
+ (GNUNET_NO == exchange->pending) &&
+ (NULL != exchange->wire_task) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Do not have current wire data. Will re-request /wire in 1 minute\n");
+ exchange->wire_task
+ = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &wire_task_cb,
+ exchange);
+ }
}
@@ -689,7 +735,11 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
exchange->fo_tail,
fo);
- if (GNUNET_YES != exchange->pending)
+ if ( (GNUNET_YES != exchange->pending) &&
+ ( (NULL == fo->wire_method) ||
+ (NULL != get_wire_fees (exchange,
+ GNUNET_TIME_absolute_get (),
+ fo->wire_method)) ) )
{
/* We are not currently waiting for a reply, immediately
return result */
@@ -702,9 +752,22 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
if ( (NULL == exchange->conn) &&
(GNUNET_YES == exchange->pending) )
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Do not have current key data. Will request /keys now\n");
exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange,
exchange);
}
+ else if ( (GNUNET_NO == exchange->pending) &&
+ (NULL == exchange->wire_task) &&
+ (NULL == exchange->wire_request) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Do not have current wire data. Will re-request /wire now\n");
+ exchange->wire_task = GNUNET_SCHEDULER_add_now (&wire_task_cb,
+ exchange);
+ }
+
+
return fo;
}
@@ -723,7 +786,7 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo)
{
GNUNET_SCHEDULER_cancel (fo->at);
fo->at = NULL;
- }
+ }
GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
exchange->fo_tail,
fo);
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index 54d8efaf..c3203ef6 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -315,28 +315,6 @@ resume_pay_with_response (struct PayContext *pc,
/**
- * Convert denomination key to its base32 representation
- *
- * @param dk denomination key to convert
- * @return 0-terminated base32 encoding of @a dk, to be deallocated
- */
-static char *
-denomination_to_string_alloc (struct TALER_DenominationPublicKey *dk)
-{
- char *buf;
- char *buf2;
- size_t buf_size;
-
- buf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key,
- &buf);
- buf2 = GNUNET_STRINGS_data_to_string_alloc (buf,
- buf_size);
- GNUNET_free (buf);
- return buf2;
-}
-
-
-/**
* Abort all pending /deposit operations.
*
* @param pc pay context to abort
@@ -572,6 +550,8 @@ process_pay_with_exchange (void *cls,
struct PayContext *pc = cls;
struct TALER_Amount acc_fee;
struct TALER_Amount acc_amount;
+ struct TALER_Amount wire_fee_delta;
+ struct TALER_Amount wire_fee_customer_contribution;
const struct TALER_EXCHANGE_Keys *keys;
unsigned int i;
@@ -609,8 +589,6 @@ process_pay_with_exchange (void *cls,
&dc->denom);
if (NULL == denom_details)
{
- char *denom_enc;
-
GNUNET_break_op (0);
resume_pay_with_response (pc,
MHD_HTTP_BAD_REQUEST,
@@ -619,11 +597,6 @@ process_pay_with_exchange (void *cls,
"code", TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND,
"denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key),
"exchange_keys", TALER_EXCHANGE_get_keys_raw (mh)));
- denom_enc = denomination_to_string_alloc (&dc->denom);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "unknown denom to exchange: %s\n",
- denom_enc);
- GNUNET_free (denom_enc);
return;
}
if (GNUNET_OK !=
@@ -631,8 +604,6 @@ process_pay_with_exchange (void *cls,
denom_details,
exchange_trusted))
{
- char *denom_enc;
-
GNUNET_break_op (0);
resume_pay_with_response (pc,
MHD_HTTP_BAD_REQUEST,
@@ -640,11 +611,6 @@ process_pay_with_exchange (void *cls,
"error", "invalid denomination",
"code", (json_int_t) TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE,
"denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key)));
- denom_enc = denomination_to_string_alloc (&dc->denom);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Client offered invalid denomination: %s\n",
- denom_enc);
- GNUNET_free (denom_enc);
return;
}
dc->deposit_fee = denom_details->fee_deposit;
@@ -690,6 +656,38 @@ process_pay_with_exchange (void *cls,
}
}
+ /* Now compare exchange wire fee compared to what we are willing to pay */
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (wire_fee,
+ &pc->max_wire_fee))
+ {
+ GNUNET_break (0);
+ resume_pay_with_response (pc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_internal_error (TALER_EC_PAY_WIRE_FEE_CURRENCY_MISSMATCH,
+ "wire_fee"));
+ return;
+ }
+
+ if (GNUNET_OK ==
+ TALER_amount_subtract (&wire_fee_delta,
+ wire_fee,
+ &pc->max_wire_fee))
+ {
+ /* Actual wire fee is indeed higher than our maximum, compute
+ how much the customer is expected to cover! */
+ TALER_amount_divide (&wire_fee_customer_contribution,
+ &wire_fee_delta,
+ pc->wire_fee_amortization);
+ }
+ else
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (wire_fee->currency,
+ &wire_fee_customer_contribution));
+
+ }
+
/* Now check that the customer paid enough for the full contract */
if (-1 == TALER_amount_cmp (&pc->max_fee,
&acc_fee))
@@ -716,6 +714,12 @@ process_pay_with_exchange (void *cls,
"overflow"));
return;
}
+ /* add wire fee contribution to the total */
+ if (GNUNET_OK ==
+ TALER_amount_add (&total_needed,
+ &total_needed,
+ &wire_fee_customer_contribution))
+
/* check if total payment sufficies */
if (-1 == TALER_amount_cmp (&acc_amount,
&total_needed))
@@ -730,7 +734,40 @@ process_pay_with_exchange (void *cls,
}
else
{
- /* fees are acceptable, we cover them all; let's check the amount */
+ struct TALER_Amount deposit_fee_savings;
+
+ /* Compute how much the customer saved by not going to the
+ limit on the deposit fees, as this amount is counted against
+ what we expect him to cover for the wire fees */
+ GNUNET_assert (GNUNET_SYSERR !=
+ TALER_amount_subtract (&deposit_fee_savings,
+ &pc->max_fee,
+ &acc_fee));
+ /* See how much of wire fee contribution is covered by fee_savings */
+ if (-1 == TALER_amount_cmp (&deposit_fee_savings,
+ &wire_fee_customer_contribution))
+ {
+ /* wire_fee_customer_contribution > deposit_fee_savings */
+ GNUNET_assert (GNUNET_SYSERR !=
+ TALER_amount_subtract (&wire_fee_customer_contribution,
+ &wire_fee_customer_contribution,
+ &deposit_fee_savings));
+ /* subtract remaining wire fees from total contribution */
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&acc_amount,
+ &acc_amount,
+ &wire_fee_customer_contribution))
+ {
+ GNUNET_break_op (0);
+ resume_pay_with_response (pc,
+ MHD_HTTP_METHOD_NOT_ACCEPTABLE,
+ TMH_RESPONSE_make_external_error (TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES,
+ "insufficient funds (including excessive exchange fees to be covered by customer)"));
+ return;
+ }
+ }
+
+ /* fees are acceptable, merchant covers them all; let's check the amount */
if (-1 == TALER_amount_cmp (&acc_amount,
&pc->amount))
{
@@ -746,8 +783,6 @@ process_pay_with_exchange (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Exchange and fee structure OK. Initiating deposit operation for coins\n");
-
-
/* Initiate /deposit operation for all coins */
for (i=0;i<pc->coins_cnt;i++)
{
@@ -1072,7 +1107,7 @@ parse_pay (struct MHD_Connection *connection,
/* NOTE: In the future, iterate over all wire hashes
available to a given instance here! (#4939) */
if (0 != memcmp (&pc->h_wire,
- &mi->h_wire,
+ &pc->mi->h_wire,
sizeof (struct GNUNET_HashCode)))
{
GNUNET_break (0);
@@ -1104,6 +1139,13 @@ parse_pay (struct MHD_Connection *connection,
&pc->max_wire_fee));
}
}
+ else
+ {
+ /* default is we cover no fee */
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (pc->max_fee.currency,
+ &pc->max_wire_fee));
+ }
if (NULL != json_object_get (pc->proposal_data,
"wire_fee_amortization"))
{
@@ -1124,6 +1166,10 @@ parse_pay (struct MHD_Connection *connection,
pc->wire_fee_amortization = 1;
}
}
+ else
+ {
+ pc->wire_fee_amortization = 1;
+ }
pc->coins_cnt = json_array_size (coins);
if (0 == pc->coins_cnt)
@@ -1287,7 +1333,7 @@ handler_pay_json (struct MHD_Connection *connection,
/* Find the responsible exchange, this may take a while... */
pc->fo = TMH_EXCHANGES_find_exchange (pc->chosen_exchange,
- NULL, /* FIXME: wire method! */
+ pc->mi->wire_method,
&process_pay_with_exchange,
pc);
@@ -1378,7 +1424,8 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
GNUNET_break (0);
return TMH_RESPONSE_reply_invalid_json (connection);
}
- if ((GNUNET_NO == res) || (NULL == root))
+ if ( (GNUNET_NO == res) ||
+ (NULL == root) )
return MHD_YES; /* the POST's body has to be further fetched */
res = handler_pay_json (connection,
diff --git a/src/backend/taler-merchant-httpd_proposal.c b/src/backend/taler-merchant-httpd_proposal.c
index 09b221ee..0d96a1f6 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -170,35 +170,67 @@ proposal_put (struct MHD_Connection *connection,
time (&timer);
tm_info = localtime (&timer);
- off = strftime (buf, sizeof (buf), "%H:%M:%S", tm_info);
+ off = strftime (buf,
+ sizeof (buf),
+ "%H:%M:%S",
+ tm_info);
snprintf (buf + off, sizeof (buf) - off,
"-%llX",
- (long long unsigned) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX));
- json_object_set (order, "order_id", json_string (buf));
+ (long long unsigned) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT64_MAX));
+ json_object_set (order,
+ "order_id",
+ json_string (buf));
}
- if (NULL == json_string_value (json_object_get (order, "timestamp")))
+ if (NULL == json_object_get (order,
+ "timestamp"))
{
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+
(void) GNUNET_TIME_round_abs (&now);
- json_object_set (order, "timestamp", GNUNET_JSON_from_time_abs (now));
+ json_object_set (order,
+ "timestamp",
+ GNUNET_JSON_from_time_abs (now));
}
- if (NULL == json_string_value (json_object_get (order, "refund_deadline")))
+ if (NULL == json_object_get (order,
+ "refund_deadline"))
{
struct GNUNET_TIME_Absolute zero = { 0 };
- json_object_set (order, "refund_deadline", GNUNET_JSON_from_time_abs (zero));
+
+ json_object_set (order,
+ "refund_deadline",
+ GNUNET_JSON_from_time_abs (zero));
}
- if (NULL == json_string_value (json_object_get (order, "pay_deadline")))
+ if (NULL == json_object_get (order,
+ "pay_deadline"))
{
struct GNUNET_TIME_Absolute t;
+
/* FIXME: read the delay for pay_deadline from config */
- t = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), GNUNET_TIME_UNIT_HOURS);
+ t = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
(void) GNUNET_TIME_round_abs (&t);
json_object_set (order, "pay_deadline", GNUNET_JSON_from_time_abs (t));
}
+ if (NULL == json_object_get (order,
+ "max_wire_fee"))
+ {
+ json_object_set (order,
+ "max_wire_fee",
+ TALER_JSON_from_amount (&default_max_wire_fee));
+ }
+
+ if (NULL == json_object_get (order,
+ "wire_fee_amortization"))
+ {
+ json_object_set (order,
+ "wire_fee_amortization",
+ json_integer ((json_int_t) default_wire_fee_amortization));
+ }
+
/* extract fields we need to sign separately */
res = TMH_PARSE_json_data (connection, order, spec);
if (GNUNET_NO == res)
@@ -348,6 +380,7 @@ MH_handler_proposal_put (struct TMH_RequestHandler *rh,
return res;
}
+
/**
* Manage a GET /proposal request. Query the db and returns the
* proposal's data related to the transaction id given as the URL's
diff --git a/src/lib/test_merchant_api.conf b/src/lib/test_merchant_api.conf
index dc580e26..8a9b80cf 100644
--- a/src/lib/test_merchant_api.conf
+++ b/src/lib/test_merchant_api.conf
@@ -36,6 +36,7 @@ WIREFORMAT = test
# section like X-wireformat and merchant-instance-X
INSTANCES = tor default
+
[exchange-wire-test]
# Enable 'test' for testing of the actual coin operations.
ENABLE = YES