summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-09-24 19:03:37 +0200
committerChristian Grothoff <christian@grothoff.org>2023-09-24 19:03:37 +0200
commit08b2623684a09bf5bb1e30282b1fd314df02b3e7 (patch)
tree17459816875abcfb42b6d79d8ff18767a2148b24 /src/backend/taler-merchant-httpd_post-orders-ID-pay.c
parentcc15874189dcfb4336921559ce94f4234daa3ca2 (diff)
downloadmerchant-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.c235
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,