From f01c986a881b36a49c243f165426624173ed566e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 27 Dec 2017 11:21:21 +0100 Subject: fix wire fee calculation logic for multi-exchange /pay --- src/backend/taler-merchant-httpd_pay.c | 66 +++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c index 829c006a..7d13366a 100644 --- a/src/backend/taler-merchant-httpd_pay.c +++ b/src/backend/taler-merchant-httpd_pay.c @@ -230,16 +230,6 @@ struct PayContext */ struct GNUNET_HashCode h_wire; - /** - * Total wire fees charged by all exchanges involved. Note: there - * is a sublte issue with this value not being correctly calculated - * if /pay is called a second time, as then some deposits that are - * already in the DB are no longer mapped to an exchange (and thus - * no fee is looked up). Fixing this would be rather complicated, - * and is likely simply no worth it. - */ - struct TALER_Amount total_wire_fee; - /** * Maximum fee the merchant is willing to pay, from @e root. * Note that IF the total fee of the exchange is higher, that is @@ -592,9 +582,11 @@ check_payment_sufficient (struct PayContext *pc) struct TALER_Amount acc_amount; struct TALER_Amount wire_fee_delta; struct TALER_Amount wire_fee_customer_contribution; + struct TALER_Amount total_wire_fee; GNUNET_assert (0 != pc->coins_cnt); acc_fee = pc->dc[0].deposit_fee; + total_wire_fee = pc->dc[0].wire_fee; acc_amount = pc->dc[0].amount_with_fee; for (unsigned int i=1;icoins_cnt;i++) { @@ -622,12 +614,38 @@ check_payment_sufficient (struct PayContext *pc) /* fee higher than residual coin value, makes no sense. */ return TALER_EC_PAY_FEES_EXCEED_PAYMENT; } + + /* If exchange differs, add wire fee */ + { + int new_exchange = GNUNET_YES; + + for (unsigned int j=0;jexchange_url, + pc->dc[j].exchange_url)) + { + new_exchange = GNUNET_NO; + break; + } + if (GNUNET_YES == new_exchange) + { + if (GNUNET_OK != + TALER_amount_add (&total_wire_fee, + &total_wire_fee, + &dc->wire_fee)) + { + GNUNET_break_op (0); + return TALER_EC_PAY_EXCHANGE_REJECTED; + } + } + } } + + /* Now compare exchange wire fee compared to what we are willing to pay */ if (GNUNET_YES != - TALER_amount_cmp_currency (&pc->total_wire_fee, + TALER_amount_cmp_currency (&total_wire_fee, &pc->max_wire_fee)) { GNUNET_break (0); @@ -636,7 +654,7 @@ check_payment_sufficient (struct PayContext *pc) if (GNUNET_OK == TALER_amount_subtract (&wire_fee_delta, - &pc->total_wire_fee, + &total_wire_fee, &pc->max_wire_fee)) { /* Actual wire fee is indeed higher than our maximum, compute @@ -648,7 +666,7 @@ check_payment_sufficient (struct PayContext *pc) else { GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (pc->total_wire_fee.currency, + TALER_amount_get_zero (total_wire_fee.currency, &wire_fee_customer_contribution)); } @@ -780,6 +798,12 @@ generate_error_response (struct PayContext *pc, ec, "wire_fee currency does not match"); break; + case TALER_EC_PAY_EXCHANGE_REJECTED: + resume_pay_with_error (pc, + MHD_HTTP_PRECONDITION_FAILED, + ec, + "exchange charges incompatible wire fee"); + break; default: resume_pay_with_error (pc, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -956,18 +980,6 @@ process_pay_with_exchange (void *cls, "exchange not supported"); return; } - if (GNUNET_OK != - TALER_amount_add (&pc->total_wire_fee, - &pc->total_wire_fee, - wire_fee)) - { - GNUNET_break_op (0); - resume_pay_with_error (pc, - MHD_HTTP_PRECONDITION_FAILED, - TALER_EC_PAY_EXCHANGE_REJECTED, - "exchange charges incompatible wire fee"); - return; - } pc->mh = mh; keys = TALER_EXCHANGE_get_keys (mh); if (NULL == keys) @@ -1427,10 +1439,6 @@ parse_pay (struct MHD_Connection *connection, TALER_amount_get_zero (pc->max_fee.currency, &pc->max_wire_fee)); } - /* Initialize wire fee total */ - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (pc->max_fee.currency, - &pc->total_wire_fee)); if (NULL != json_object_get (pc->contract_terms, "wire_fee_amortization")) { -- cgit v1.2.3