diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-09-24 19:03:37 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-09-24 19:03:37 +0200 |
commit | 08b2623684a09bf5bb1e30282b1fd314df02b3e7 (patch) | |
tree | 17459816875abcfb42b6d79d8ff18767a2148b24 /src/backend/taler-merchant-httpd_post-orders-ID-pay.c | |
parent | cc15874189dcfb4336921559ce94f4234daa3ca2 (diff) | |
download | merchant-08b2623684a09bf5bb1e30282b1fd314df02b3e7.tar.gz merchant-08b2623684a09bf5bb1e30282b1fd314df02b3e7.tar.bz2 merchant-08b2623684a09bf5bb1e30282b1fd314df02b3e7.zip |
combine deposit confirmation signatures into one big signature
Diffstat (limited to 'src/backend/taler-merchant-httpd_post-orders-ID-pay.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-pay.c | 235 |
1 files changed, 141 insertions, 94 deletions
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c index fd17f029..c99a6c64 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -90,11 +90,6 @@ struct DepositConfirmation struct TALER_Amount refund_fee; /** - * Wire fee charged by the exchange of this coin. - */ - struct TALER_Amount wire_fee; - - /** * If a minimum age was required (i. e. pc->minimum_age is large enough), * this is the signature of the minimum age (as a single uint8_t), using the * private key to the corresponding age group. Might be all zeroes for no @@ -902,6 +897,107 @@ check_kyc (struct PayContext *pc, /** + * Do database transaction for a completed batch deposit. + * + * @param eg group that completed + * @param dr response from the server + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +batch_deposit_transaction (const struct ExchangeGroup *eg, + const struct TALER_EXCHANGE_BatchDepositResult *dr) +{ + const struct PayContext *pc = eg->pc; + enum GNUNET_DB_QueryStatus qs; + struct TALER_Amount total_without_fees = { 0 }; + uint64_t b_dep_serial; + uint32_t off = 0; + bool found = false; + + for (unsigned int i = 0; i<pc->coins_cnt; i++) + { + struct DepositConfirmation *dc = &pc->dc[i]; + struct TALER_Amount amount_without_fees; + + /* might want to group deposits by batch more explicitly ... */ + if (0 != strcmp (eg->exchange_url, + dc->exchange_url)) + continue; + if (dc->found_in_db) + continue; + GNUNET_assert (0 <= + TALER_amount_subtract (&amount_without_fees, + &dc->cdd.amount, + &dc->deposit_fee)); + if (! found) + { + found = true; + total_without_fees = amount_without_fees; + } + else + { + GNUNET_assert ( + 0 <= + TALER_amount_add (&total_without_fees, + &total_without_fees, + &amount_without_fees)); + } + } + qs = TMH_db->insert_deposit_confirmation ( + TMH_db->cls, + pc->hc->instance->settings.id, + dr->details.ok.deposit_timestamp, + &pc->h_contract_terms, + eg->exchange_url, + &total_without_fees, + &eg->wire_fee, + &pc->wm->h_wire, + dr->details.ok.exchange_sig, + dr->details.ok.exchange_pub, + &b_dep_serial); + if (qs <= 0) + return qs; /* Entire batch already known or failure, we're done */ + + if (! found) + { + /* All coins already done, but the batch was not? Invariant violation! */ + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + for (unsigned int i = 0; i<pc->coins_cnt; i++) + { + struct DepositConfirmation *dc = &pc->dc[i]; + + /* might want to group deposits by batch more explicitly ... */ + if (0 != strcmp (eg->exchange_url, + dc->exchange_url)) + continue; + if (dc->found_in_db) + continue; + /* NOTE: We might want to check if the order was fully paid concurrently + by some other wallet here, and if so, issue an auto-refund. Right now, + it is possible to over-pay if two wallets literally make a concurrent + payment, as the earlier check for 'paid' is not in the same transaction + scope as this 'insert' operation. */ + qs = TMH_db->insert_deposit ( + TMH_db->cls, + off++, /* might want to group deposits by batch more explicitly ... */ + b_dep_serial, + &dc->cdd.coin_pub, + &dc->cdd.coin_sig, + &dc->cdd.amount, + &dc->deposit_fee, + &dc->refund_fee); + if (qs < 0) + return qs; + GNUNET_break (qs > 0); + } + return qs; +} + + +/** * Handle case where the batch deposit completed * with a status of #MHD_HTTP_OK. * @@ -924,8 +1020,6 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, pc->hc->instance->settings.id); for (unsigned int r = 0; r<MAX_RETRIES; r++) { - unsigned int j = 0; - TMH_db->preflight (TMH_db->cls); if (GNUNET_OK != TMH_db->start (TMH_db->cls, @@ -940,50 +1034,19 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, TMH_pack_exchange_reply (&dr->hr))); return; } - for (unsigned int i = 0; i<pc->coins_cnt; i++) + qs = batch_deposit_transaction (eg, + dr); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { - struct DepositConfirmation *dc = &pc->dc[i]; - - if (0 != strcmp (eg->exchange_url, - pc->dc[i].exchange_url)) - continue; - if (dc->found_in_db) - continue; - /* NOTE: We might want to check if the order was fully paid concurrently - by some other wallet here, and if so, issue an auto-refund. Right now, - it is possible to over-pay if two wallets literally make a concurrent - payment, as the earlier check for 'paid' is not in the same transaction - scope as this 'insert' operation. */ - GNUNET_assert (j < dr->details.ok.num_signatures); - qs = TMH_db->insert_deposit ( - TMH_db->cls, - pc->hc->instance->settings.id, - dr->details.ok.deposit_timestamp, - &pc->h_contract_terms, - &dc->cdd.coin_pub, - dc->exchange_url, - &dc->cdd.amount, - &dc->deposit_fee, - &dc->refund_fee, - &dc->wire_fee, - &pc->wm->h_wire, - &dr->details.ok.exchange_sigs[j++], - dr->details.ok.exchange_pub); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_db->rollback (TMH_db->cls); - break; - } - if (0 > qs) - { - /* Always report on hard error as well to enable diagnostics */ - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); - /* Forward error including 'proof' for the body */ - resume_pay_with_error (pc, - TALER_EC_GENERIC_DB_STORE_FAILED, - "insert_deposit"); - return; - } + TMH_db->rollback (TMH_db->cls); + continue; + } + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); + resume_pay_with_error (pc, + TALER_EC_GENERIC_DB_COMMIT_FAILED, + "batch_deposit_transaction"); } qs = TMH_db->commit (TMH_db->cls); if (GNUNET_DB_STATUS_SOFT_ERROR == qs) @@ -999,7 +1062,7 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, "insert_deposit"); } break; /* DB transaction succeeded */ - } /* FOR DB retries */ + } if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { resume_pay_with_error (pc, @@ -1387,7 +1450,6 @@ AGE_FAIL: eg->exchange_url)) continue; cdds[i] = dc->cdd; - dc->wire_fee = eg->wire_fee; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Initiating batch deposit with %u coins\n", @@ -1509,7 +1571,6 @@ start_batch_deposits (struct PayContext *pc) * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param refund_fee fee the exchange will charge for refunding this coin - * @param wire_fee wire fee the exchange of this coin charges */ static void check_coin_paid (void *cls, @@ -1517,8 +1578,7 @@ check_coin_paid (void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee) + const struct TALER_Amount *refund_fee) { struct PayContext *pc = cls; @@ -1551,7 +1611,6 @@ check_coin_paid (void *cls, deposit_fee)); dc->deposit_fee = *deposit_fee; dc->refund_fee = *refund_fee; - dc->wire_fee = *wire_fee; dc->cdd.amount = *amount_with_fee; dc->found_in_db = true; pc->pending--; @@ -1623,8 +1682,33 @@ check_payment_sufficient (struct PayContext *pc) (0 == pc->amount.fraction)); } + total_wire_fee = pc->egs[0]->wire_fee; + for (unsigned int i = 1; i < pc->num_exchanges; i++) + { + if (GNUNET_OK != + TALER_amount_cmp_currency (&total_wire_fee, + &pc->egs[i]->wire_fee)) + { + GNUNET_break_op (0); + resume_pay_with_error (pc, + TALER_EC_GENERIC_CURRENCY_MISMATCH, + total_wire_fee.currency); + return false; + } + if (0 > + TALER_amount_add (&total_wire_fee, + &total_wire_fee, + &pc->egs[i]->wire_fee)) + { + GNUNET_break (0); + resume_pay_with_error (pc, + TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, + "could not add exchange wire fee to total"); + return false; + } + } + acc_fee = pc->dc[0].deposit_fee; - total_wire_fee = pc->dc[0].wire_fee; acc_amount = pc->dc[0].cdd.amount; /** @@ -1663,43 +1747,6 @@ check_payment_sufficient (struct PayContext *pc) return false; } - /* If exchange differs, add wire fee */ - { - bool new_exchange = true; - - for (unsigned int j = 0; j<i; j++) - if (0 == strcasecmp (dc->exchange_url, - pc->dc[j].exchange_url)) - { - new_exchange = false; - break; - } - - if (! new_exchange) - continue; - - if (GNUNET_OK != - TALER_amount_cmp_currency (&total_wire_fee, - &dc->wire_fee)) - { - GNUNET_break_op (0); - resume_pay_with_error (pc, - TALER_EC_GENERIC_CURRENCY_MISMATCH, - total_wire_fee.currency); - return false; - } - if (0 > - TALER_amount_add (&total_wire_fee, - &total_wire_fee, - &dc->wire_fee)) - { - GNUNET_break (0); - resume_pay_with_error (pc, - TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, - "could not add exchange wire fee to total"); - return false; - } - } } /* deposit loop */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |