summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-05-09 12:43:41 +0200
committerChristian Grothoff <christian@grothoff.org>2021-05-09 12:43:41 +0200
commita3a2ebccce82c5378c3c096eee8e8fc3c4239f20 (patch)
treeeea27f9d7ea0fa41c08ebeaad39099f21de86201
parentc21919263c07c871d33478edc5b2430619870df0 (diff)
downloadmerchant-a3a2ebccce82c5378c3c096eee8e8fc3c4239f20.tar.gz
merchant-a3a2ebccce82c5378c3c096eee8e8fc3c4239f20.tar.bz2
merchant-a3a2ebccce82c5378c3c096eee8e8fc3c4239f20.zip
more work on #6854
-rw-r--r--src/backend/taler-merchant-httpd_private-post-transfers.c115
1 files changed, 79 insertions, 36 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.c b/src/backend/taler-merchant-httpd_private-post-transfers.c
index 9a425e9c..4c844c8f 100644
--- a/src/backend/taler-merchant-httpd_private-post-transfers.c
+++ b/src/backend/taler-merchant-httpd_private-post-transfers.c
@@ -140,6 +140,12 @@ struct PostTransfersContext
* Should we retry the transaction due to a serialization error?
*/
bool soft_retry;
+
+ /**
+ * Did we just download the exchange reply?
+ */
+ bool downloaded;
+
};
@@ -390,8 +396,18 @@ check_wire_fee (struct PostTransfersContext *ptc,
&start_date,
&end_date,
&master_sig);
- if (0 >= qs)
+ switch (qs)
{
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ptc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ptc->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "lookup_wire_fee");
+ return GNUNET_SYSERR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ ptc->soft_retry = true;
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to find wire fee for `%s' and method `%s' at %s in DB, accepting blindly that the fee is %s\n",
TALER_B2S (&ptc->master_pub),
@@ -400,6 +416,8 @@ check_wire_fee (struct PostTransfersContext *ptc,
TALER_amount2s (wire_fee));
GNUNET_free (wire_method);
return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
}
if (0 <= TALER_amount_cmp (&expected_fee,
wire_fee))
@@ -639,8 +657,9 @@ verify_exchange_claim_cb (void *cls,
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
- if (GNUNET_NO == ptc->check_transfer_result)
+ switch (ptc->check_transfer_result)
{
+ case GNUNET_NO:
/* Internal error: how can we have called #check_transfer()
but still have no result? */
GNUNET_break (0);
@@ -649,13 +668,13 @@ verify_exchange_claim_cb (void *cls,
TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
"check_transfer_result must not be NULL");
return;
- }
- if (GNUNET_SYSERR == ptc->check_transfer_result)
- {
+ case GNUNET_SYSERR:
/* #check_transfer() failed, report conflict! */
GNUNET_break_op (0);
GNUNET_assert (NULL != ptc->response);
return;
+ case GNUNET_OK:
+ break;
}
}
@@ -750,9 +769,9 @@ transfer_summary_cb (void *cls,
* #GNUNET_NO otherwise.
*/
static int
-hashmap_free (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
+hashmap_update_and_free (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
{
json_t *ja = cls;
struct Entry *entry = value;
@@ -835,6 +854,33 @@ queue (struct PostTransfersContext *ptc)
}
+/**
+ * Download transfer data from the exchange.
+ *
+ * @param ptc request context
+ */
+static void
+download (struct PostTransfersContext *ptc)
+{
+ ptc->downloaded = true;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Suspending POST /private/transfers handling while working with exchange\n");
+ MHD_suspend_connection (ptc->connection);
+ GNUNET_CONTAINER_DLL_insert (ptc_head,
+ ptc_tail,
+ ptc);
+ ptc->fo = TMH_EXCHANGES_find_exchange (ptc->exchange_url,
+ NULL,
+ GNUNET_NO,
+ &process_transfer_with_exchange,
+ ptc);
+ ptc->timeout_task
+ = GNUNET_SCHEDULER_add_delayed (TRANSFER_GENERIC_TIMEOUT,
+ &handle_transfer_timeout,
+ ptc);
+}
+
+
MHD_RESULT
TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
@@ -856,7 +902,7 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
if ( (NULL != ptc->fo) ||
(NULL != ptc->wdh) )
{
- /* likely old MHD version */
+ /* likely old MHD version causing spurious wake-up */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Not sure why we are here, should be suspended\n");
return MHD_YES; /* still work in progress */
@@ -886,7 +932,7 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
: MHD_NO;
}
- /* Check if transfer data is in database! */
+ /* Check if transfer data is in database, if not, add it. */
for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
{
struct GNUNET_TIME_Absolute execution_time;
@@ -926,13 +972,11 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
TMH_db->rollback (TMH_db->cls);
continue;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* Transfer unknown */
+ /* Transfer so far unknown */
{
uint64_t account_serial;
- /* Either the record already exists (we should ignore this), or
- the INSERT failed because we did not find the account based on
- the given payto-URI and the instance. */
+ /* Make sure the bank account is configured. */
qs = TMH_db->lookup_account (TMH_db->cls,
ptc->hc->instance->settings.id,
ptc->payto_uri,
@@ -1006,30 +1050,22 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Suspending POST /private/transfers handling while working with exchange\n");
- MHD_suspend_connection (connection);
- GNUNET_CONTAINER_DLL_insert (ptc_head,
- ptc_tail,
- ptc);
- ptc->fo = TMH_EXCHANGES_find_exchange (ptc->exchange_url,
- NULL,
- GNUNET_NO,
- &process_transfer_with_exchange,
- ptc);
- ptc->timeout_task
- = GNUNET_SCHEDULER_add_delayed (TRANSFER_GENERIC_TIMEOUT,
- &handle_transfer_timeout,
- ptc);
+ download (ptc);
return MHD_YES;
-
}
- break;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
/* Transfer exists */
if (! verified)
{
+ if (! ptc->downloaded)
+ {
+ /* We may have previously attempted and failed to
+ download the exchange data, do it again! */
+ TMH_db->rollback (TMH_db->cls);
+ download (ptc);
+ return MHD_YES;
+ }
+ /* verify */
if (GNUNET_SYSERR ==
check_wire_fee (ptc,
execution_time,
@@ -1038,6 +1074,13 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
TMH_db->rollback (TMH_db->cls);
return queue (ptc); /* generate error */
}
+ if (ptc->soft_retry)
+ {
+ /* DB serialization failure */
+ ptc->soft_retry = false;
+ TMH_db->rollback (TMH_db->cls);
+ continue;
+ }
qs = TMH_db->lookup_transfer_details (TMH_db->cls,
ptc->exchange_url,
&ptc->wtid,
@@ -1096,7 +1139,8 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
}
} /* end of 'if (! verified)' */
- /* Short version: we already verified, generate the summary response */
+ /* Short version: we verified that the exchange reply and
+ our own accounting match; generate the summary response */
GNUNET_assert (verified);
{
struct GNUNET_CONTAINER_MultiHashMap *map;
@@ -1118,7 +1162,7 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
GNUNET_break (0);
TMH_db->rollback (TMH_db->cls);
GNUNET_CONTAINER_multihashmap_iterate (map,
- &hashmap_free,
+ &hashmap_update_and_free,
NULL);
GNUNET_CONTAINER_multihashmap_destroy (map);
return TALER_MHD_reply_with_error (connection,
@@ -1131,11 +1175,10 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
break;
}
-
deposit_sums = json_array ();
GNUNET_assert (NULL != deposit_sums);
GNUNET_CONTAINER_multihashmap_iterate (map,
- &hashmap_free,
+ &hashmap_update_and_free,
deposit_sums);
GNUNET_CONTAINER_multihashmap_destroy (map);
return TALER_MHD_reply_json_pack (