diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-05-09 12:43:41 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-05-09 12:43:41 +0200 |
commit | a3a2ebccce82c5378c3c096eee8e8fc3c4239f20 (patch) | |
tree | eea27f9d7ea0fa41c08ebeaad39099f21de86201 | |
parent | c21919263c07c871d33478edc5b2430619870df0 (diff) | |
download | merchant-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.c | 115 |
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 ( |