diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | doc/manual.texi | 4 | ||||
-rw-r--r-- | src/backend/merchant.conf | 10 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 81 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.h | 16 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.c | 129 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_pay.c | 131 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_proposal.c | 51 | ||||
-rw-r--r-- | src/lib/test_merchant_api.conf | 1 |
9 files changed, 338 insertions, 90 deletions
@@ -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", + ¤cy)) + { + 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 |