From 75733ee00efc6d5342ed8b4fccd637efaebdce06 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 25 Jun 2023 13:59:47 +0200 Subject: more work on atomizing exchange API: deposit --- src/auditor/taler-auditor-httpd.c | 2 + src/include/taler_exchange_service.h | 159 +++--------- src/include/taler_testing_lib.h | 12 + src/lib/Makefile.am | 1 - src/lib/exchange_api_batch_deposit.c | 267 +++++++++++++++------ src/lib/exchange_api_handle.c | 93 ++----- src/lib/exchange_api_handle.h | 46 +--- src/testing/test_exchange_api.conf | 2 +- .../taler/auditor/offline-keys/auditor.priv | 1 + src/testing/testing_api_cmd_batch_deposit.c | 26 +- src/testing/testing_api_cmd_deposit.c | 34 ++- src/testing/testing_api_cmd_get_exchange.c | 3 +- src/testing/testing_api_traits.c | 28 +++ 13 files changed, 326 insertions(+), 348 deletions(-) create mode 100644 src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv (limited to 'src') diff --git a/src/auditor/taler-auditor-httpd.c b/src/auditor/taler-auditor-httpd.c index 68316082f..a59ce3de0 100644 --- a/src/auditor/taler-auditor-httpd.c +++ b/src/auditor/taler-auditor-httpd.c @@ -157,6 +157,8 @@ handle_config (struct TAH_RequestHandler *rh, if (NULL == ver) { ver = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("name", + "taler-auditor"), GNUNET_JSON_pack_string ("version", AUDITOR_PROTOCOL_VERSION), GNUNET_JSON_pack_string ("currency", diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 065c2dcde..9cb5f083f 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -573,10 +573,30 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange); * @param exchange the exchange handle * @return the exchange's key set */ -const struct TALER_EXCHANGE_Keys * +struct TALER_EXCHANGE_Keys * TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange); +/** + * Increment reference counter for @a keys + * + * @param[in,out] keys object to increment reference counter for + * @return keys, with incremented reference counter + */ +struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys); + + +/** + * Deccrement reference counter for @a keys. + * Frees @a keys if reference counter becomes zero. + * + * @param[in,out] keys object to decrement reference counter for + */ +void +TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys); + + /** * Let the user set the last valid denomination time manually. * @@ -1151,135 +1171,6 @@ struct TALER_EXCHANGE_DepositContractDetail }; -/** - * @brief A Deposit Handle - */ -struct TALER_EXCHANGE_DepositHandle; - - -/** - * Structure with information about a deposit - * operation's result. - */ -struct TALER_EXCHANGE_DepositResult -{ - /** - * HTTP response data - */ - struct TALER_EXCHANGE_HttpResponse hr; - - union - { - - /** - * Information returned if the HTTP status is - * #MHD_HTTP_OK. - */ - struct - { - /** - * Time when the exchange generated the deposit confirmation - */ - struct GNUNET_TIME_Timestamp deposit_timestamp; - - /** - * signature provided by the exchange - */ - const struct TALER_ExchangeSignatureP *exchange_sig; - - /** - * exchange key used to sign @a exchange_sig. - */ - const struct TALER_ExchangePublicKeyP *exchange_pub; - - /** - * Base URL for looking up wire transfers, or - * NULL to use the default base URL. - */ - const char *transaction_base_url; - - } ok; - - /** - * Information returned if the HTTP status is - * #MHD_HTTP_CONFLICT. - */ - struct - { - /* TODO: returning full details is not implemented */ - } conflict; - - } details; -}; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * deposit permission request to a exchange. - * - * @param cls closure - * @param dr deposit response details - */ -typedef void -(*TALER_EXCHANGE_DepositResultCallback) ( - void *cls, - const struct TALER_EXCHANGE_DepositResult *dr); - - -/** - * Submit a deposit permission to the exchange and get the exchange's - * response. This API is typically used by a merchant. Note that - * while we return the response verbatim to the caller for further - * processing, we do already verify that the response is well-formed - * (i.e. that signatures included in the response are all valid). If - * the exchange's reply is not well-formed, we return an HTTP status code - * of zero to @a cb. - * - * We also verify that the @a cdd.coin_sig is valid for this deposit - * request, and that the @a cdd.ub_sig is a valid signature for @a - * coin_pub. Also, the @a exchange must be ready to operate (i.e. have - * finished processing the /keys reply). If either check fails, we do - * NOT initiate the transaction with the exchange and instead return NULL. - * - * @param exchange the exchange handle; the exchange must be ready to operate - * @param dcd details about the contract the deposit is for - * @param cdd details about the coin to be deposited - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @param[out] ec if NULL is returned, set to the error code explaining why the operation failed - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ -struct TALER_EXCHANGE_DepositHandle * -TALER_EXCHANGE_deposit ( - struct TALER_EXCHANGE_Handle *exchange, - const struct TALER_EXCHANGE_DepositContractDetail *dcd, - const struct TALER_EXCHANGE_CoinDepositDetail *cdd, - TALER_EXCHANGE_DepositResultCallback cb, - void *cb_cls, - enum TALER_ErrorCode *ec); - - -/** - * Change the chance that our deposit confirmation will be given to the - * auditor to 100%. - * - * @param deposit the deposit permission request handle - */ -void -TALER_EXCHANGE_deposit_force_dc (struct TALER_EXCHANGE_DepositHandle *deposit); - - -/** - * Cancel a deposit permission request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param deposit the deposit permission request handle - */ -void -TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit); - - /** * @brief A Batch Deposit Handle */ @@ -1374,7 +1265,9 @@ typedef void * finished processing the /keys reply). If either check fails, we do * NOT initiate the transaction with the exchange and instead return NULL. * - * @param exchange the exchange handle; the exchange must be ready to operate + * @param ctx curl context + * @param url exchange base URL + * @param keys exchange keys * @param dcd details about the contract the deposit is for * @param num_cdds length of the @a cdds array * @param cdds array with details about the coins to be deposited @@ -1386,7 +1279,9 @@ typedef void */ struct TALER_EXCHANGE_BatchDepositHandle * TALER_EXCHANGE_batch_deposit ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, + struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_DepositContractDetail *dcd, unsigned int num_cdds, const struct TALER_EXCHANGE_CoinDepositDetail *cdds, diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 6554bc95e..2ef7ef602 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -2694,6 +2694,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, op (relative_time, const struct GNUNET_TIME_Relative) \ op (exchange, struct TALER_EXCHANGE_Handle) \ op (fakebank, struct TALER_FAKEBANK_Handle) \ + op (keys, struct TALER_EXCHANGE_Keys) \ op (process, struct GNUNET_OS_Process *) @@ -2751,4 +2752,15 @@ TALER_TESTING_get_exchange_url ( struct TALER_TESTING_Interpreter *is); +/** + * Get exchange keys from interpreter. Convenience function. + * + * @param is interpreter state. + * @return the exchange keys, or NULL on error + */ +struct TALER_EXCHANGE_Keys * +TALER_TESTING_get_keys ( + struct TALER_TESTING_Interpreter *is); + + #endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2c9031428..53190bc5b 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -32,7 +32,6 @@ libtalerexchange_la_SOURCES = \ exchange_api_csr_melt.c \ exchange_api_csr_withdraw.c \ exchange_api_handle.c exchange_api_handle.h \ - exchange_api_deposit.c \ exchange_api_deposits_get.c \ exchange_api_kyc_check.c \ exchange_api_kyc_proof.c \ diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c index bb17737fa..22ae2d58d 100644 --- a/src/lib/exchange_api_batch_deposit.c +++ b/src/lib/exchange_api_batch_deposit.c @@ -44,6 +44,39 @@ */ #define AUDITOR_CHANCE 20 + +/** + * Entry in list of ongoing interactions with an auditor. + */ +struct TEAH_AuditorInteractionEntry +{ + /** + * DLL entry. + */ + struct TEAH_AuditorInteractionEntry *next; + + /** + * DLL entry. + */ + struct TEAH_AuditorInteractionEntry *prev; + + /** + * URL of our auditor. For logging. + */ + const char *auditor_url; + + /** + * Interaction state. + */ + struct TALER_AUDITOR_DepositConfirmationHandle *dch; + + /** + * Batch deposit this is for. + */ + struct TALER_EXCHANGE_BatchDepositHandle *dh; +}; + + /** * @brief A Deposit Handle */ @@ -51,9 +84,9 @@ struct TALER_EXCHANGE_BatchDepositHandle { /** - * The connection to exchange this request handle will use + * The keys of the exchange. */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_Keys *keys; /** * Context for our curl request(s). @@ -117,11 +150,31 @@ struct TALER_EXCHANGE_BatchDepositHandle */ struct TALER_ExchangeSignatureP *exchange_sigs; + /** + * Head of DLL of interactions with this auditor. + */ + struct TEAH_AuditorInteractionEntry *ai_head; + + /** + * Tail of DLL of interactions with this auditor. + */ + struct TEAH_AuditorInteractionEntry *ai_tail; + + /** + * Result to return to the application once @e ai_head is empty. + */ + struct TALER_EXCHANGE_BatchDepositResult dr; + /** * Exchange signing public key, set for #auditor_cb. */ struct TALER_ExchangePublicKeyP exchange_pub; + /** + * Response object to free at the end. + */ + json_t *response; + /** * Chance that we will inform the auditor about the deposit * is 1:n, where the value of this field is "n". @@ -136,6 +189,52 @@ struct TALER_EXCHANGE_BatchDepositHandle }; +/** + * Finish batch deposit operation by calling the callback. + * + * @param[in] dh handle to finished batch deposit operation + */ +static void +finish_dh (struct TALER_EXCHANGE_BatchDepositHandle *dh) +{ + dh->cb (dh->cb_cls, + &dh->dr); + TALER_EXCHANGE_batch_deposit_cancel (dh); +} + + +/** + * Function called with the result from our call to the + * auditor's /deposit-confirmation handler. + * + * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` + * @param dcr response + */ +static void +acc_confirmation_cb ( + void *cls, + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) +{ + struct TEAH_AuditorInteractionEntry *aie = cls; + struct TALER_EXCHANGE_BatchDepositHandle *dh = aie->dh; + + if (MHD_HTTP_OK != dcr->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n", + aie->auditor_url, + dcr->hr.http_status, + dcr->hr.ec); + } + GNUNET_CONTAINER_DLL_remove (dh->ai_head, + dh->ai_tail, + aie); + GNUNET_free (aie); + if (NULL == dh->ai_head) + finish_dh (dh); +} + + /** * Function called for each auditor to give us a chance to possibly * launch a deposit confirmation interaction. @@ -143,15 +242,13 @@ struct TALER_EXCHANGE_BatchDepositHandle * @param cls closure * @param auditor_url base URL of the auditor * @param auditor_pub public key of the auditor - * @return NULL if no deposit confirmation interaction was launched */ -static struct TEAH_AuditorInteractionEntry * +static void auditor_cb (void *cls, const char *auditor_url, const struct TALER_AuditorPublicKeyP *auditor_pub) { struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; - const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_SigningPublicKey *spk; struct TEAH_AuditorInteractionEntry *aie; struct TALER_Amount amount_without_fee; @@ -164,29 +261,30 @@ auditor_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Not providing deposit confirmation to auditor\n"); - return NULL; + return; } coin = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, dh->num_cdds); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Will provide deposit confirmation to auditor `%s'\n", TALER_B2S (auditor_pub)); - key_state = TALER_EXCHANGE_get_keys (dh->exchange); - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys, &dh->cdds[coin].h_denom_pub); GNUNET_assert (NULL != dki); - spk = TALER_EXCHANGE_get_signing_key_info (key_state, + spk = TALER_EXCHANGE_get_signing_key_info (dh->keys, &dh->exchange_pub); if (NULL == spk) { GNUNET_break_op (0); - return NULL; + return; } GNUNET_assert (0 <= TALER_amount_subtract (&amount_without_fee, &dh->cdds[coin].amount, &dki->fees.deposit)); aie = GNUNET_new (struct TEAH_AuditorInteractionEntry); + aie->dh = dh; + aie->auditor_url = auditor_url; aie->dch = TALER_AUDITOR_deposit_confirmation ( dh->ctx, auditor_url, @@ -201,14 +299,16 @@ auditor_cb (void *cls, &dh->dcd.merchant_pub, &dh->exchange_pub, &dh->exchange_sigs[coin], - &key_state->master_pub, + &dh->keys->master_pub, spk->valid_from, spk->valid_until, spk->valid_legal, &spk->master_sig, - &TEAH_acc_confirmation_cb, + &acc_confirmation_cb, aie); - return aie; + GNUNET_CONTAINER_DLL_insert (dh->ai_head, + dh->ai_tail, + aie); } @@ -227,22 +327,19 @@ handle_deposit_finished (void *cls, { struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; const json_t *j = response; - struct TALER_EXCHANGE_BatchDepositResult dr = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - const struct TALER_EXCHANGE_Keys *keys; + struct TALER_EXCHANGE_BatchDepositResult *dr = &dh->dr; dh->job = NULL; - keys = TALER_EXCHANGE_get_keys (dh->exchange); + dh->response = json_incref ((json_t*) j); + dr->hr.reply = dh->response; + dr->hr.http_status = (unsigned int) response_code; switch (response_code) { case 0: - dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + dr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: { - const struct TALER_EXCHANGE_Keys *key_state; const json_t *sigs; json_t *sig; unsigned int idx; @@ -253,7 +350,7 @@ handle_deposit_finished (void *cls, &dh->exchange_pub), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("transaction_base_url", - &dr.details.ok.transaction_base_url), + &dr->details.ok.transaction_base_url), NULL), GNUNET_JSON_spec_timestamp ("exchange_timestamp", &dh->exchange_timestamp), @@ -266,27 +363,26 @@ handle_deposit_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } if (json_array_size (sigs) != dh->num_cdds) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } dh->exchange_sigs = GNUNET_new_array (dh->num_cdds, struct TALER_ExchangeSignatureP); - key_state = TALER_EXCHANGE_get_keys (dh->exchange); if (GNUNET_OK != - TALER_EXCHANGE_test_signing_key (key_state, + TALER_EXCHANGE_test_signing_key (dh->keys, &dh->exchange_pub)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; break; } json_array_foreach (sigs, idx, sig) @@ -305,11 +401,11 @@ handle_deposit_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys, &dh->cdds[idx]. h_denom_pub); GNUNET_assert (NULL != dki); @@ -333,42 +429,41 @@ handle_deposit_finished (void *cls, &dh->exchange_sigs[idx])) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; break; } } - TEAH_get_auditors_for_dc (dh->exchange, + TEAH_get_auditors_for_dc (dh->keys, &auditor_cb, dh); } - dr.details.ok.exchange_sigs = dh->exchange_sigs; - dr.details.ok.exchange_pub = &dh->exchange_pub; - dr.details.ok.deposit_timestamp = dh->exchange_timestamp; - dr.details.ok.num_signatures = dh->num_cdds; + dr->details.ok.exchange_sigs = dh->exchange_sigs; + dr->details.ok.exchange_pub = &dh->exchange_pub; + dr->details.ok.deposit_timestamp = dh->exchange_timestamp; + dr->details.ok.num_signatures = dh->num_cdds; break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_NOT_FOUND: - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_CONFLICT: { - const struct TALER_EXCHANGE_Keys *key_state; struct TALER_CoinSpendPublicKeyP coin_pub; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("coin_pub", @@ -384,8 +479,8 @@ handle_deposit_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } for (unsigned int i = 0; inum_cdds; i++) @@ -394,14 +489,13 @@ handle_deposit_finished (void *cls, GNUNET_memcmp (&coin_pub, &dh->cdds[i].coin_pub)) continue; - key_state = TALER_EXCHANGE_get_keys (dh->exchange); - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys, &dh->cdds[i]. h_denom_pub); GNUNET_assert (NULL != dki); if (GNUNET_OK != TALER_EXCHANGE_check_coin_conflict_ ( - keys, + dh->keys, j, dki, &dh->cdds[i].coin_pub, @@ -409,8 +503,8 @@ handle_deposit_finished (void *cls, &dh->cdds[i].amount)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } found = true; @@ -419,12 +513,12 @@ handle_deposit_finished (void *cls, if (! found) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); } break; case MHD_HTTP_GONE: @@ -432,35 +526,37 @@ handle_deposit_finished (void *cls, /* Note: one might want to check /keys for revocation signature here, alas tricky in case our /keys is outdated => left to clients */ - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); /* Server had an internal issue; we should retry, but this API leaves this to the application */ break; default: /* unexpected response code */ - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange deposit\n", (unsigned int) response_code, - dr.hr.ec); + dr->hr.ec); GNUNET_break_op (0); break; } - dh->cb (dh->cb_cls, - &dr); - TALER_EXCHANGE_batch_deposit_cancel (dh); + if (NULL != dh->ai_head) + return; + finish_dh (dh); } struct TALER_EXCHANGE_BatchDepositHandle * TALER_EXCHANGE_batch_deposit ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, + struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_DepositContractDetail *dcd, unsigned int num_cdds, const struct TALER_EXCHANGE_CoinDepositDetail *cdds, @@ -468,15 +564,12 @@ TALER_EXCHANGE_batch_deposit ( void *cb_cls, enum TALER_ErrorCode *ec) { - const struct TALER_EXCHANGE_Keys *key_state; struct TALER_EXCHANGE_BatchDepositHandle *dh; json_t *deposit_obj; json_t *deposits; CURL *eh; struct TALER_Amount amount_without_fee; - GNUNET_assert (GNUNET_YES == - TEAH_handle_is_ready (exchange)); if (GNUNET_TIME_timestamp_cmp (dcd->refund_deadline, >, dcd->wire_deadline)) @@ -485,10 +578,8 @@ TALER_EXCHANGE_batch_deposit ( *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE; return NULL; } - key_state = TALER_EXCHANGE_get_keys (exchange); dh = GNUNET_new (struct TALER_EXCHANGE_BatchDepositHandle); dh->auditor_chance = AUDITOR_CHANCE; - dh->exchange = exchange; dh->cb = cb; dh->cb_cls = cb_cls; dh->cdds = GNUNET_memdup (cdds, @@ -509,7 +600,7 @@ TALER_EXCHANGE_batch_deposit ( const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i]; const struct TALER_EXCHANGE_DenomPublicKey *dki; - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (keys, &cdd->h_denom_pub); if (NULL == dki) { @@ -568,8 +659,9 @@ TALER_EXCHANGE_batch_deposit ( &cdd->coin_sig) ))); } - dh->url = TEAH_path_to_url (exchange, - "/batch-deposit"); + dh->url = TALER_url_join (url, + "batch-deposit", + NULL); if (NULL == dh->url) { GNUNET_break (0); @@ -623,8 +715,9 @@ TALER_EXCHANGE_batch_deposit ( GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URL for deposit: `%s'\n", dh->url); - dh->ctx = TEAH_handle_to_context (exchange); - dh->job = GNUNET_CURL_job_add2 (dh->ctx, + dh->ctx = ctx; + dh->keys = TALER_EXCHANGE_keys_incref (keys); + dh->job = GNUNET_CURL_job_add2 (ctx, eh, dh->post_ctx.headers, &handle_deposit_finished, @@ -645,15 +738,31 @@ void TALER_EXCHANGE_batch_deposit_cancel ( struct TALER_EXCHANGE_BatchDepositHandle *deposit) { + struct TEAH_AuditorInteractionEntry *aie; + + while (NULL != (aie = deposit->ai_head)) + { + GNUNET_assert (aie->dh == deposit); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Not sending deposit confirmation to auditor `%s' due to cancellation\n", + aie->auditor_url); + TALER_AUDITOR_deposit_confirmation_cancel (aie->dch); + GNUNET_CONTAINER_DLL_remove (deposit->ai_head, + deposit->ai_tail, + aie); + GNUNET_free (aie); + } if (NULL != deposit->job) { GNUNET_CURL_job_cancel (deposit->job); deposit->job = NULL; } + TALER_EXCHANGE_keys_decref (deposit->keys); GNUNET_free (deposit->url); GNUNET_free (deposit->cdds); GNUNET_free (deposit->exchange_sigs); TALER_curl_easy_post_finished (&deposit->post_ctx); + json_decref (deposit->response); GNUNET_free (deposit); } diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 4d245b077..7e3021129 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -112,16 +112,6 @@ struct TEAH_AuditorListEntry */ struct TALER_AUDITOR_GetConfigHandle *ah; - /** - * Head of DLL of interactions with this auditor. - */ - struct TEAH_AuditorInteractionEntry *ai_head; - - /** - * Tail of DLL of interactions with this auditor. - */ - struct TEAH_AuditorInteractionEntry *ai_tail; - /** * Public key of the auditor. */ @@ -168,58 +158,24 @@ struct KeysRequest void -TEAH_acc_confirmation_cb ( - void *cls, - const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) -{ - struct TEAH_AuditorInteractionEntry *aie = cls; - struct TEAH_AuditorListEntry *ale = aie->ale; - - if (MHD_HTTP_OK != dcr->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n", - ale->auditor_url, - dcr->hr.http_status, - dcr->hr.ec); - } - GNUNET_CONTAINER_DLL_remove (ale->ai_head, - ale->ai_tail, - aie); - GNUNET_free (aie); -} - - -void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h, +TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, TEAH_AuditorCallback ac, void *ac_cls) { - if (NULL == h->auditors_head) + if (0 == keys->num_auditors) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "No auditor available for exchange `%s'. Not submitting deposit confirmations.\n", - h->url); + "No auditor available. Not submitting deposit confirmations.\n"); return; } - for (struct TEAH_AuditorListEntry *ale = h->auditors_head; - NULL != ale; - ale = ale->next) + for (unsigned int i = 0; inum_auditors; i++) { - struct TEAH_AuditorInteractionEntry *aie; + const struct TALER_EXCHANGE_AuditorInformation *auditor + = &keys->auditors[i]; - if (! ale->is_up) - continue; - aie = ac (ac_cls, - ale->auditor_url, - &ale->auditor_pub); - if (NULL != aie) - { - aie->ale = ale; - GNUNET_CONTAINER_DLL_insert (ale->ai_head, - ale->ai_tail, - aie); - } + ac (ac_cls, + auditor->auditor_url, + &auditor->auditor_pub); } } @@ -2121,20 +2077,6 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) while (NULL != (ale = exchange->auditors_head)) { - struct TEAH_AuditorInteractionEntry *aie; - - while (NULL != (aie = ale->ai_head)) - { - GNUNET_assert (aie->ale == ale); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not sending deposit confirmation to auditor `%s' due to exchange disconnect\n", - ale->auditor_url); - TALER_AUDITOR_deposit_confirmation_cancel (aie->dch); - GNUNET_CONTAINER_DLL_remove (ale->ai_head, - ale->ai_tail, - aie); - GNUNET_free (aie); - } GNUNET_CONTAINER_DLL_remove (exchange->auditors_head, exchange->auditors_tail, ale); @@ -2275,7 +2217,7 @@ TALER_EXCHANGE_get_denomination_key_by_hash ( } -const struct TALER_EXCHANGE_Keys * +struct TALER_EXCHANGE_Keys * TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange) { (void) TALER_EXCHANGE_check_keys_current (exchange, @@ -2297,4 +2239,19 @@ TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange) } +struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys) +{ + // FIXME + return keys; +} + + +void +TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys) +{ + // FIXME +} + + /* end of exchange_api_handle.c */ diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h index 8e3b10654..6b96e21eb 100644 --- a/src/lib/exchange_api_handle.h +++ b/src/lib/exchange_api_handle.h @@ -34,32 +34,6 @@ struct TEAH_AuditorListEntry; -/** - * Entry in list of ongoing interactions with an auditor. - */ -struct TEAH_AuditorInteractionEntry -{ - /** - * DLL entry. - */ - struct TEAH_AuditorInteractionEntry *next; - - /** - * DLL entry. - */ - struct TEAH_AuditorInteractionEntry *prev; - - /** - * Which auditor is this action associated with? - */ - struct TEAH_AuditorListEntry *ale; - - /** - * Interaction state. - */ - struct TALER_AUDITOR_DepositConfirmationHandle *dch; -}; - /** * Stages of initialization for the `struct TALER_EXCHANGE_Handle` */ @@ -180,38 +154,24 @@ struct TALER_EXCHANGE_Handle * @param cls closure * @param auditor_url base URL of the auditor * @param auditor_pub public key of the auditor - * @return NULL if no deposit confirmation interaction was launched */ -typedef struct TEAH_AuditorInteractionEntry * +typedef void (*TEAH_AuditorCallback)(void *cls, const char *auditor_url, const struct TALER_AuditorPublicKeyP *auditor_pub); -/** - * Signature of functions called with the result from our call to the - * auditor's /deposit-confirmation handler. - * - * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` - * @param dcr response - */ -void -TEAH_acc_confirmation_cb ( - void *cls, - const struct TALER_AUDITOR_DepositConfirmationResponse *dcr); - - /** * Iterate over all available auditors for @a h, calling * @a ac and giving it a chance to start a deposit * confirmation interaction. * - * @param h exchange to go over auditors for + * @param keys the keys to go over auditors for * @param ac function to call per auditor * @param ac_cls closure for @a ac */ void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h, +TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, TEAH_AuditorCallback ac, void *ac_cls); diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf index 9ed12412e..b7f8c5c60 100644 --- a/src/testing/test_exchange_api.conf +++ b/src/testing/test_exchange_api.conf @@ -11,7 +11,7 @@ CURRENCY_ROUND_UNIT = EUR:0.01 [auditor] BASE_URL = "http://localhost:8083/" PORT = 8083 -PUBLIC_KEY = SA7JVMCW3MMN7SYAWJ9AB0BGJDX6MP3PNN2JWQ3T8233MDSQC7Z0 +PUBLIC_KEY = T0XJ9QZ59YDN7QG3RE40SB2HY7W0ASR1EKF4WZDGZ1G159RSQC80 TINY_AMOUNT = EUR:0.01 [auditordb-postgres] diff --git a/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv new file mode 100644 index 000000000..7e712e483 --- /dev/null +++ b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv @@ -0,0 +1 @@ +G,U{~#r-H  \ No newline at end of file diff --git a/src/testing/testing_api_cmd_batch_deposit.c b/src/testing/testing_api_cmd_batch_deposit.c index 6a05071af..0a4fbd251 100644 --- a/src/testing/testing_api_cmd_batch_deposit.c +++ b/src/testing/testing_api_cmd_batch_deposit.c @@ -251,12 +251,15 @@ batch_deposit_run (void *cls, &wire_salt), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); (void) cmd; - if (NULL == exchange) + if (NULL == exchange_url) + { + GNUNET_break (0); return; + } memset (cdds, 0, sizeof (cdds)); @@ -383,13 +386,16 @@ batch_deposit_run (void *cls, .refund_deadline = ds->refund_deadline }; - ds->dh = TALER_EXCHANGE_batch_deposit (exchange, - &dcd, - ds->num_coins, - cdds, - &batch_deposit_cb, - ds, - &ec); + ds->dh = TALER_EXCHANGE_batch_deposit ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + &dcd, + ds->num_coins, + cdds, + &batch_deposit_cb, + ds, + &ec); } if (NULL == ds->dh) { diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c index 3d5c00abd..f2a3a2698 100644 --- a/src/testing/testing_api_cmd_deposit.c +++ b/src/testing/testing_api_cmd_deposit.c @@ -98,7 +98,7 @@ struct DepositState /** * Deposit handle while operation is running. */ - struct TALER_EXCHANGE_DepositHandle *dh; + struct TALER_EXCHANGE_BatchDepositHandle *dh; /** * Timestamp of the /deposit operation in the wallet (contract signing time). @@ -215,7 +215,7 @@ do_retry (void *cls) */ static void deposit_cb (void *cls, - const struct TALER_EXCHANGE_DepositResult *dr) + const struct TALER_EXCHANGE_BatchDepositResult *dr) { struct DepositState *ds = cls; @@ -254,10 +254,11 @@ deposit_cb (void *cls, } if (MHD_HTTP_OK == dr->hr.http_status) { + GNUNET_assert (1 == dr->details.ok.num_signatures); ds->deposit_succeeded = GNUNET_YES; ds->exchange_timestamp = dr->details.ok.deposit_timestamp; ds->exchange_pub = *dr->details.ok.exchange_pub; - ds->exchange_sig = *dr->details.ok.exchange_sig; + ds->exchange_sig = dr->details.ok.exchange_sigs[0]; } TALER_TESTING_interpreter_next (ds->is); } @@ -296,12 +297,15 @@ deposit_run (void *cls, &wire_salt), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); (void) cmd; - if (NULL == exchange) + if (NULL == exchange_url) + { + GNUNET_break (0); return; + } ds->is = is; if (NULL != ds->deposit_reference) { @@ -469,12 +473,16 @@ deposit_run (void *cls, .refund_deadline = ds->refund_deadline }; - ds->dh = TALER_EXCHANGE_deposit (exchange, - &dcd, - &cdd, - &deposit_cb, - ds, - &ec); + ds->dh = TALER_EXCHANGE_batch_deposit ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + &dcd, + 1, + &cdd, + &deposit_cb, + ds, + &ec); } if (NULL == ds->dh) { @@ -505,7 +513,7 @@ deposit_cleanup (void *cls, { TALER_TESTING_command_incomplete (ds->is, cmd->label); - TALER_EXCHANGE_deposit_cancel (ds->dh); + TALER_EXCHANGE_batch_deposit_cancel (ds->dh); ds->dh = NULL; } if (NULL != ds->retry_task) diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c index 2fc8ba77e..2822616c0 100644 --- a/src/testing/testing_api_cmd_get_exchange.c +++ b/src/testing/testing_api_cmd_get_exchange.c @@ -189,7 +189,7 @@ get_exchange_traits (void *cls, { struct GetExchangeState *ges = cls; unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; - const struct TALER_EXCHANGE_Keys *keys + struct TALER_EXCHANGE_Keys *keys = TALER_EXCHANGE_get_keys (ges->exchange); if (NULL != keys) @@ -198,6 +198,7 @@ get_exchange_traits (void *cls, TALER_TESTING_make_trait_master_priv (&ges->master_priv), TALER_TESTING_make_trait_master_pub (&keys->master_pub), TALER_TESTING_make_trait_exchange (ges->exchange), + TALER_TESTING_make_trait_keys (keys), TALER_TESTING_make_trait_exchange_url (ges->exchange_url), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c index 27eef5a5b..d00a8d8ca 100644 --- a/src/testing/testing_api_traits.c +++ b/src/testing/testing_api_traits.c @@ -129,4 +129,32 @@ TALER_TESTING_get_exchange_url (struct TALER_TESTING_Interpreter *is) } +struct TALER_EXCHANGE_Keys * +TALER_TESTING_get_keys ( + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_EXCHANGE_Keys *keys; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd + = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_keys (exchange_cmd, + &keys)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + return keys; +} + + /* end of testing_api_traits.c */ -- cgit v1.2.3