From 12cff1b4439ab5dcc26fcf79e19518ae1bdce069 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 18 Sep 2023 18:59:53 +0200 Subject: remove coin and reserve histories from exchange replies --- contrib/gana | 2 +- src/auditor/taler-helper-auditor-reserves.c | 80 -- src/exchange/Makefile.am | 1 - src/exchange/taler-exchange-httpd.c | 6 +- src/exchange/taler-exchange-httpd_coins_get.c | 490 ++++++++++- src/exchange/taler-exchange-httpd_reserves_get.c | 2 +- .../taler-exchange-httpd_reserves_history.c | 429 +++++++--- .../taler-exchange-httpd_reserves_history.h | 5 +- .../taler-exchange-httpd_reserves_status.c | 243 ------ .../taler-exchange-httpd_reserves_status.h | 43 - src/exchange/taler-exchange-httpd_responses.c | 911 +-------------------- src/exchange/taler-exchange-httpd_responses.h | 24 - src/exchangedb/Makefile.am | 2 - src/exchangedb/exchange_do_history_request.sql | 101 --- src/exchangedb/pg_get_reserve_history.c | 360 +------- src/exchangedb/pg_get_reserve_history.h | 32 +- src/exchangedb/pg_insert_history_request.c | 67 -- src/exchangedb/pg_insert_history_request.h | 53 -- .../pg_select_history_requests_above_serial_id.c | 156 ---- .../pg_select_history_requests_above_serial_id.h | 44 - src/exchangedb/plugin_exchangedb_postgres.c | 8 - src/exchangedb/procedures.sql.in | 1 - src/exchangedb/test_exchangedb.c | 1 + src/include/taler_crypto_lib.h | 46 +- src/include/taler_exchange_service.h | 182 +--- src/include/taler_exchangedb_plugin.h | 91 +- src/include/taler_testing_lib.h | 16 - src/lib/Makefile.am | 1 - src/lib/exchange_api_batch_deposit.c | 39 +- src/lib/exchange_api_common.c | 210 +---- src/lib/exchange_api_common.h | 2 - src/lib/exchange_api_melt.c | 16 - src/lib/exchange_api_purse_create_with_deposit.c | 105 +-- src/lib/exchange_api_purse_deposit.c | 111 +-- src/lib/exchange_api_recoup.c | 14 - src/lib/exchange_api_recoup_refresh.c | 33 +- src/lib/exchange_api_refund.c | 314 ------- src/lib/exchange_api_reserves_history.c | 65 +- src/lib/exchange_api_reserves_open.c | 28 +- src/lib/exchange_api_reserves_status.c | 336 -------- src/lib/exchange_api_withdraw2.c | 109 --- src/testing/Makefile.am | 1 - src/testing/test_exchange_api.c | 6 +- src/testing/test_exchange_p2p.c | 4 +- src/testing/test_kyc_api.c | 4 +- src/testing/testing_api_cmd_common.c | 13 - src/testing/testing_api_cmd_reserve_history.c | 31 +- src/testing/testing_api_cmd_reserve_status.c | 397 --------- src/util/wallet_signatures.c | 76 +- 49 files changed, 984 insertions(+), 4327 deletions(-) delete mode 100644 src/exchange/taler-exchange-httpd_reserves_status.c delete mode 100644 src/exchange/taler-exchange-httpd_reserves_status.h delete mode 100644 src/exchangedb/exchange_do_history_request.sql delete mode 100644 src/exchangedb/pg_insert_history_request.c delete mode 100644 src/exchangedb/pg_insert_history_request.h delete mode 100644 src/exchangedb/pg_select_history_requests_above_serial_id.c delete mode 100644 src/exchangedb/pg_select_history_requests_above_serial_id.h delete mode 100644 src/lib/exchange_api_reserves_status.c delete mode 100644 src/testing/testing_api_cmd_reserve_status.c diff --git a/contrib/gana b/contrib/gana index 45da80720..5980339e7 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 45da8072036c16d1f7cd39f85d8e293069ab6482 +Subproject commit 5980339e7bf797e0cc90fb65bd1a78a442d253f3 diff --git a/src/auditor/taler-helper-auditor-reserves.c b/src/auditor/taler-helper-auditor-reserves.c index 9f8c75c2b..eca3c42aa 100644 --- a/src/auditor/taler-helper-auditor-reserves.c +++ b/src/auditor/taler-helper-auditor-reserves.c @@ -1260,75 +1260,6 @@ purse_decision_cb (void *cls, } -/** - * Function called with details about - * history requests that have been made, with - * the goal of auditing the history request execution. - * - * @param cls closure - * @param rowid unique serial ID for the deposit in our DB - * @param history_fee fee paid for the request - * @param ts timestamp of the request - * @param reserve_pub reserve history was requested for - * @param reserve_sig signature approving the @a history_fee - * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop - */ -static enum GNUNET_GenericReturnValue -handle_history_request ( - void *cls, - uint64_t rowid, - const struct TALER_Amount *history_fee, - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig) -{ - struct ReserveContext *rc = cls; - struct ReserveSummary *rs; - - /* should be monotonically increasing */ - GNUNET_assert (rowid >= ppr.last_history_requests_serial_id); - ppr.last_history_requests_serial_id = rowid + 1; - if (GNUNET_OK != - TALER_wallet_reserve_history_verify (ts, - history_fee, - reserve_pub, - reserve_sig)) - { - TALER_ARL_report (report_bad_sig_losses, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("operation", - "account-history"), - GNUNET_JSON_pack_uint64 ("row", - rowid), - TALER_JSON_pack_amount ("loss", - history_fee), - GNUNET_JSON_pack_data_auto ("key_pub", - reserve_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - history_fee); - return GNUNET_OK; - } - rs = setup_reserve (rc, - reserve_pub); - if (NULL == rs) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - TALER_ARL_amount_add (&balance.history_fee_balance, - &balance.history_fee_balance, - history_fee); - TALER_ARL_amount_add (&rs->curr_balance.history_fee_balance, - &rs->curr_balance.history_fee_balance, - history_fee); - TALER_ARL_amount_add (&rs->total_out, - &rs->total_out, - history_fee); - return GNUNET_OK; -} - - /** * Check that the reserve summary matches what the exchange database * thinks about the reserve, and update our own state of the reserve. @@ -1773,17 +1704,6 @@ analyze_reserves (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - /* Charge history fee! */ - qs = TALER_ARL_edb->select_history_requests_above_serial_id ( - TALER_ARL_edb->cls, - ppr.last_history_requests_serial_id, - &handle_history_request, - &rc); - if (qs < 0) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; - } GNUNET_CONTAINER_multihashmap_iterate (rc.reserves, &verify_reserve_balance, &rc); diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index dded2b1f0..86829edda 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -180,7 +180,6 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_reserves_history.c taler-exchange-httpd_reserves_history.h \ taler-exchange-httpd_reserves_open.c taler-exchange-httpd_reserves_open.h \ taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h \ - taler-exchange-httpd_reserves_status.c taler-exchange-httpd_reserves_status.h \ taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \ taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \ taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index ad4b50d23..d059e7430 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -67,7 +67,6 @@ #include "taler-exchange-httpd_reserves_history.h" #include "taler-exchange-httpd_reserves_open.h" #include "taler-exchange-httpd_reserves_purse.h" -#include "taler-exchange-httpd_reserves_status.h" #include "taler-exchange-httpd_terms.h" #include "taler-exchange-httpd_transfers_get.h" #include "taler-exchange-httpd_withdraw.h" @@ -732,10 +731,7 @@ handle_post_reserves (struct TEH_RequestContext *rc, .op = "withdraw", .handler = &TEH_handler_withdraw }, - { - .op = "status", - .handler = &TEH_handler_reserves_status - }, + // FIXME: change to GET! { .op = "history", .handler = &TEH_handler_reserves_history diff --git a/src/exchange/taler-exchange-httpd_coins_get.c b/src/exchange/taler-exchange-httpd_coins_get.c index 9f61b38f6..c5cf6ba56 100644 --- a/src/exchange/taler-exchange-httpd_coins_get.c +++ b/src/exchange/taler-exchange-httpd_coins_get.c @@ -48,6 +48,492 @@ add_response_headers (void *cls, } +/** + * Compile the transaction history of a coin into a JSON object. + * + * @param coin_pub public key of the coin + * @param tl transaction history to JSON-ify + * @return json representation of the @a rh, NULL on error + */ +static json_t * +compile_transaction_history ( + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_EXCHANGEDB_TransactionList *tl) +{ + json_t *history; + + history = json_array (); + if (NULL == history) + { + GNUNET_break (0); /* out of memory!? */ + return NULL; + } + for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl; + NULL != pos; + pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_TT_DEPOSIT: + { + const struct TALER_EXCHANGEDB_DepositListEntry *deposit = + pos->details.deposit; + struct TALER_MerchantWireHashP h_wire; + + TALER_merchant_wire_signature_hash (deposit->receiver_wire_account, + &deposit->wire_salt, + &h_wire); +#if ENABLE_SANITY_CHECKS + /* internal sanity check before we hand out a bogus sig... */ + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (GNUNET_OK != + TALER_wallet_deposit_verify ( + &deposit->amount_with_fee, + &deposit->deposit_fee, + &h_wire, + &deposit->h_contract_terms, + deposit->no_wallet_data_hash + ? NULL + : &deposit->wallet_data_hash, + deposit->no_age_commitment + ? NULL + : &deposit->h_age_commitment, + &deposit->h_policy, + &deposit->h_denom_pub, + deposit->timestamp, + &deposit->merchant_pub, + deposit->refund_deadline, + coin_pub, + &deposit->csig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } +#endif + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + // FIXME: offset missing! (here and in all other cases!) + GNUNET_JSON_pack_string ("type", + "DEPOSIT"), + TALER_JSON_pack_amount ("amount", + &deposit->amount_with_fee), + TALER_JSON_pack_amount ("deposit_fee", + &deposit->deposit_fee), + GNUNET_JSON_pack_timestamp ("timestamp", + deposit->timestamp), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_timestamp ("refund_deadline", + deposit->refund_deadline)), + GNUNET_JSON_pack_data_auto ("merchant_pub", + &deposit->merchant_pub), + GNUNET_JSON_pack_data_auto ("h_contract_terms", + &deposit->h_contract_terms), + GNUNET_JSON_pack_data_auto ("h_wire", + &h_wire), + GNUNET_JSON_pack_allow_null ( + deposit->no_age_commitment ? + GNUNET_JSON_pack_string ( + "h_age_commitment", NULL) : + GNUNET_JSON_pack_data_auto ("h_age_commitment", + &deposit->h_age_commitment)), + GNUNET_JSON_pack_data_auto ("coin_sig", + &deposit->csig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + case TALER_EXCHANGEDB_TT_MELT: + { + const struct TALER_EXCHANGEDB_MeltListEntry *melt = + pos->details.melt; + const struct TALER_AgeCommitmentHash *phac = NULL; + +#if ENABLE_SANITY_CHECKS + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (GNUNET_OK != + TALER_wallet_melt_verify ( + &melt->amount_with_fee, + &melt->melt_fee, + &melt->rc, + &melt->h_denom_pub, + &melt->h_age_commitment, + coin_pub, + &melt->coin_sig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } +#endif + + /* Age restriction is optional. We communicate a NULL value to + * JSON_PACK below */ + if (! melt->no_age_commitment) + phac = &melt->h_age_commitment; + + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "MELT"), + TALER_JSON_pack_amount ("amount", + &melt->amount_with_fee), + TALER_JSON_pack_amount ("melt_fee", + &melt->melt_fee), + GNUNET_JSON_pack_data_auto ("rc", + &melt->rc), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_data_auto ("h_age_commitment", + phac)), + GNUNET_JSON_pack_data_auto ("coin_sig", + &melt->coin_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_TT_REFUND: + { + const struct TALER_EXCHANGEDB_RefundListEntry *refund = + pos->details.refund; + struct TALER_Amount value; + +#if ENABLE_SANITY_CHECKS + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (GNUNET_OK != + TALER_merchant_refund_verify ( + coin_pub, + &refund->h_contract_terms, + refund->rtransaction_id, + &refund->refund_amount, + &refund->merchant_pub, + &refund->merchant_sig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } +#endif + if (0 > + TALER_amount_subtract (&value, + &refund->refund_amount, + &refund->refund_fee)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "REFUND"), + TALER_JSON_pack_amount ("amount", + &value), + TALER_JSON_pack_amount ("refund_fee", + &refund->refund_fee), + GNUNET_JSON_pack_data_auto ("h_contract_terms", + &refund->h_contract_terms), + GNUNET_JSON_pack_data_auto ("merchant_pub", + &refund->merchant_pub), + GNUNET_JSON_pack_uint64 ("rtransaction_id", + refund->rtransaction_id), + GNUNET_JSON_pack_data_auto ("merchant_sig", + &refund->merchant_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP: + { + struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr = + pos->details.old_coin_recoup; + struct TALER_ExchangePublicKeyP epub; + struct TALER_ExchangeSignatureP esig; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_refresh_sign ( + &TEH_keys_exchange_sign_, + pr->timestamp, + &pr->value, + &pr->coin.coin_pub, + &pr->old_coin_pub, + &epub, + &esig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + /* NOTE: we could also provide coin_pub's coin_sig, denomination key hash and + the denomination key's RSA signature over coin_pub, but as the + wallet should really already have this information (and cannot + check or do anything with it anyway if it doesn't), it seems + strictly unnecessary. */ + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "OLD-COIN-RECOUP"), + TALER_JSON_pack_amount ("amount", + &pr->value), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &esig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &epub), + GNUNET_JSON_pack_data_auto ("coin_pub", + &pr->coin.coin_pub), + GNUNET_JSON_pack_timestamp ("timestamp", + pr->timestamp)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + case TALER_EXCHANGEDB_TT_RECOUP: + { + const struct TALER_EXCHANGEDB_RecoupListEntry *recoup = + pos->details.recoup; + struct TALER_ExchangePublicKeyP epub; + struct TALER_ExchangeSignatureP esig; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_sign ( + &TEH_keys_exchange_sign_, + recoup->timestamp, + &recoup->value, + coin_pub, + &recoup->reserve_pub, + &epub, + &esig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "RECOUP"), + TALER_JSON_pack_amount ("amount", + &recoup->value), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &esig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &epub), + GNUNET_JSON_pack_data_auto ("reserve_pub", + &recoup->reserve_pub), + GNUNET_JSON_pack_data_auto ("coin_sig", + &recoup->coin_sig), + GNUNET_JSON_pack_data_auto ("coin_blind", + &recoup->coin_blind), + GNUNET_JSON_pack_data_auto ("reserve_pub", + &recoup->reserve_pub), + GNUNET_JSON_pack_timestamp ("timestamp", + recoup->timestamp)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_TT_RECOUP_REFRESH: + { + struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr = + pos->details.recoup_refresh; + struct TALER_ExchangePublicKeyP epub; + struct TALER_ExchangeSignatureP esig; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_refresh_sign ( + &TEH_keys_exchange_sign_, + pr->timestamp, + &pr->value, + coin_pub, + &pr->old_coin_pub, + &epub, + &esig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + /* NOTE: we could also provide coin_pub's coin_sig, denomination key + hash and the denomination key's RSA signature over coin_pub, but as + the wallet should really already have this information (and cannot + check or do anything with it anyway if it doesn't), it seems + strictly unnecessary. */ + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "RECOUP-REFRESH"), + TALER_JSON_pack_amount ("amount", + &pr->value), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &esig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &epub), + GNUNET_JSON_pack_data_auto ("old_coin_pub", + &pr->old_coin_pub), + GNUNET_JSON_pack_data_auto ("coin_sig", + &pr->coin_sig), + GNUNET_JSON_pack_data_auto ("coin_blind", + &pr->coin_blind), + GNUNET_JSON_pack_timestamp ("timestamp", + pr->timestamp)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + + case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: + { + struct TALER_EXCHANGEDB_PurseDepositListEntry *pd + = pos->details.purse_deposit; + const struct TALER_AgeCommitmentHash *phac = NULL; + + if (! pd->no_age_commitment) + phac = &pd->h_age_commitment; + + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "PURSE-DEPOSIT"), + TALER_JSON_pack_amount ("amount", + &pd->amount), + GNUNET_JSON_pack_string ("exchange_base_url", + NULL == pd->exchange_base_url + ? TEH_base_url + : pd->exchange_base_url), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_data_auto ("h_age_commitment", + phac)), + GNUNET_JSON_pack_data_auto ("purse_pub", + &pd->purse_pub), + GNUNET_JSON_pack_bool ("refunded", + pd->refunded), + GNUNET_JSON_pack_data_auto ("coin_sig", + &pd->coin_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + + case TALER_EXCHANGEDB_TT_PURSE_REFUND: + { + const struct TALER_EXCHANGEDB_PurseRefundListEntry *prefund = + pos->details.purse_refund; + struct TALER_Amount value; + enum TALER_ErrorCode ec; + struct TALER_ExchangePublicKeyP epub; + struct TALER_ExchangeSignatureP esig; + + if (0 > + TALER_amount_subtract (&value, + &prefund->refund_amount, + &prefund->refund_fee)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + ec = TALER_exchange_online_purse_refund_sign ( + &TEH_keys_exchange_sign_, + &value, + &prefund->refund_fee, + coin_pub, + &prefund->purse_pub, + &epub, + &esig); + if (TALER_EC_NONE != ec) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "PURSE-REFUND"), + TALER_JSON_pack_amount ("amount", + &value), + TALER_JSON_pack_amount ("refund_fee", + &prefund->refund_fee), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &esig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &epub), + GNUNET_JSON_pack_data_auto ("purse_pub", + &prefund->purse_pub)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + } + break; + + case TALER_EXCHANGEDB_TT_RESERVE_OPEN: + { + struct TALER_EXCHANGEDB_ReserveOpenListEntry *role + = pos->details.reserve_open; + + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "RESERVE-OPEN-DEPOSIT"), + TALER_JSON_pack_amount ("coin_contribution", + &role->coin_contribution), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &role->reserve_sig), + GNUNET_JSON_pack_data_auto ("coin_sig", + &role->coin_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + } + } + return history; +} + + MHD_RESULT TEH_handler_coins_get (struct TEH_RequestContext *rc, const struct TALER_CoinSpendPublicKeyP *coin_pub) @@ -118,8 +604,8 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc, sizeof (etagp), "\"%llu\"", (unsigned long long) etag); - history = TEH_RESPONSE_compile_transaction_history (coin_pub, - tl); + history = compile_transaction_history (coin_pub, + tl); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); tl = NULL; diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index bbaac8535..a46886ef4 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -253,7 +253,7 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, { return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, + TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, args[0]); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, diff --git a/src/exchange/taler-exchange-httpd_reserves_history.c b/src/exchange/taler-exchange-httpd_reserves_history.c index ffdc6eaa4..1bf73cb25 100644 --- a/src/exchange/taler-exchange-httpd_reserves_history.c +++ b/src/exchange/taler-exchange-httpd_reserves_history.c @@ -15,7 +15,7 @@ */ /** * @file taler-exchange-httpd_reserves_history.c - * @brief Handle /reserves/$RESERVE_PUB/history requests + * @brief Handle /reserves/$RESERVE_PUB HISTORY requests * @author Florian Dold * @author Benedikt Mueller * @author Christian Grothoff @@ -30,7 +30,6 @@ #include "taler-exchange-httpd_reserves_history.h" #include "taler-exchange-httpd_responses.h" - /** * How far do we allow a client's time to be off when * checking the request timestamp? @@ -49,26 +48,11 @@ struct ReserveHistoryContext */ const struct TALER_ReservePublicKeyP *reserve_pub; - /** - * Timestamp of the request. - */ - struct GNUNET_TIME_Timestamp timestamp; - - /** - * Client signature approving the request. - */ - struct TALER_ReserveSignatureP reserve_sig; - /** * History of the reserve, set in the callback. */ struct TALER_EXCHANGEDB_ReserveHistory *rh; - /** - * Global fees applying to the request. - */ - const struct TEH_GlobalFee *gf; - /** * Current reserve balance. */ @@ -76,6 +60,305 @@ struct ReserveHistoryContext }; +/** + * Compile the history of a reserve into a JSON object. + * + * @param rh reserve history to JSON-ify + * @return json representation of the @a rh, NULL on error + */ +static json_t * +compile_reserve_history ( + const struct TALER_EXCHANGEDB_ReserveHistory *rh) +{ + json_t *json_history; + + json_history = json_array (); + GNUNET_assert (NULL != json_history); + for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh; + NULL != pos; + pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + { + const struct TALER_EXCHANGEDB_BankTransfer *bank = + pos->details.bank; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "CREDIT"), + // FIXME: offset missing! (here and in all other cases!) + GNUNET_JSON_pack_timestamp ("timestamp", + bank->execution_date), + GNUNET_JSON_pack_string ("sender_account_url", + bank->sender_account_details), + GNUNET_JSON_pack_uint64 ("wire_reference", + bank->wire_reference), + TALER_JSON_pack_amount ("amount", + &bank->amount)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + break; + } + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + { + const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw + = pos->details.withdraw; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "WITHDRAW"), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &withdraw->reserve_sig), + GNUNET_JSON_pack_data_auto ("h_coin_envelope", + &withdraw->h_coin_envelope), + GNUNET_JSON_pack_data_auto ("h_denom_pub", + &withdraw->denom_pub_hash), + TALER_JSON_pack_amount ("withdraw_fee", + &withdraw->withdraw_fee), + TALER_JSON_pack_amount ("amount", + &withdraw->amount_with_fee)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_RO_RECOUP_COIN: + { + const struct TALER_EXCHANGEDB_Recoup *recoup + = pos->details.recoup; + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_sign ( + &TEH_keys_exchange_sign_, + recoup->timestamp, + &recoup->value, + &recoup->coin.coin_pub, + &recoup->reserve_pub, + &pub, + &sig)) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "RECOUP"), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &pub), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &sig), + GNUNET_JSON_pack_timestamp ("timestamp", + recoup->timestamp), + TALER_JSON_pack_amount ("amount", + &recoup->value), + GNUNET_JSON_pack_data_auto ("coin_pub", + &recoup->coin.coin_pub)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK: + { + const struct TALER_EXCHANGEDB_ClosingTransfer *closing = + pos->details.closing; + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + + if (TALER_EC_NONE != + TALER_exchange_online_reserve_closed_sign ( + &TEH_keys_exchange_sign_, + closing->execution_date, + &closing->amount, + &closing->closing_fee, + closing->receiver_account_details, + &closing->wtid, + &pos->details.closing->reserve_pub, + &pub, + &sig)) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "CLOSING"), + GNUNET_JSON_pack_string ("receiver_account_details", + closing->receiver_account_details), + GNUNET_JSON_pack_data_auto ("wtid", + &closing->wtid), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &pub), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &sig), + GNUNET_JSON_pack_timestamp ("timestamp", + closing->execution_date), + TALER_JSON_pack_amount ("amount", + &closing->amount), + TALER_JSON_pack_amount ("closing_fee", + &closing->closing_fee)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_RO_PURSE_MERGE: + { + const struct TALER_EXCHANGEDB_PurseMerge *merge = + pos->details.merge; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "MERGE"), + GNUNET_JSON_pack_data_auto ("h_contract_terms", + &merge->h_contract_terms), + GNUNET_JSON_pack_data_auto ("merge_pub", + &merge->merge_pub), + GNUNET_JSON_pack_uint64 ("min_age", + merge->min_age), + GNUNET_JSON_pack_uint64 ("flags", + merge->flags), + GNUNET_JSON_pack_data_auto ("purse_pub", + &merge->purse_pub), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &merge->reserve_sig), + GNUNET_JSON_pack_timestamp ("merge_timestamp", + merge->merge_timestamp), + GNUNET_JSON_pack_timestamp ("purse_expiration", + merge->purse_expiration), + TALER_JSON_pack_amount ("purse_fee", + &merge->purse_fee), + TALER_JSON_pack_amount ("amount", + &merge->amount_with_fee), + GNUNET_JSON_pack_bool ("merged", + merge->merged)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_RO_HISTORY_REQUEST: + { + const struct TALER_EXCHANGEDB_HistoryRequest *history = + pos->details.history; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "HISTORY"), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &history->reserve_sig), + GNUNET_JSON_pack_timestamp ("request_timestamp", + history->request_timestamp), + TALER_JSON_pack_amount ("amount", + &history->history_fee)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + + case TALER_EXCHANGEDB_RO_OPEN_REQUEST: + { + const struct TALER_EXCHANGEDB_OpenRequest *orq = + pos->details.open_request; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "OPEN"), + GNUNET_JSON_pack_uint64 ("requested_min_purses", + orq->purse_limit), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &orq->reserve_sig), + GNUNET_JSON_pack_timestamp ("request_timestamp", + orq->request_timestamp), + GNUNET_JSON_pack_timestamp ("requested_expiration", + orq->reserve_expiration), + TALER_JSON_pack_amount ("open_fee", + &orq->open_fee)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + + case TALER_EXCHANGEDB_RO_CLOSE_REQUEST: + { + const struct TALER_EXCHANGEDB_CloseRequest *crq = + pos->details.close_request; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "CLOSE"), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &crq->reserve_sig), + GNUNET_is_zero (&crq->target_account_h_payto) + ? GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("h_payto", + NULL)) + : GNUNET_JSON_pack_data_auto ("h_payto", + &crq->target_account_h_payto), + GNUNET_JSON_pack_timestamp ("request_timestamp", + crq->request_timestamp)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + } + } + + return json_history; +} + + /** * Send reserve history to client. * @@ -90,7 +373,7 @@ reply_reserve_history_success (struct MHD_Connection *connection, const struct TALER_EXCHANGEDB_ReserveHistory *rh = rhc->rh; json_t *json_history; - json_history = TEH_RESPONSE_compile_reserve_history (rh); + json_history = compile_reserve_history (rh); if (NULL == json_history) return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -107,19 +390,20 @@ reply_reserve_history_success (struct MHD_Connection *connection, /** - * Function implementing /reserves/$RID/history transaction. Given the public - * key of a reserve, return the associated transaction history. Runs the - * transaction logic; IF it returns a non-error code, the transaction logic - * MUST NOT queue a MHD response. IF it returns an hard error, the - * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it - * returns the soft error code, the function MAY be called again to retry and - * MUST not queue a MHD response. + * Function implementing /reserves/ HISTORY transaction. + * Execute a /reserves/ HISTORY. Given the public key of a reserve, + * return the associated transaction history. Runs the + * transaction logic; IF it returns a non-error code, the transaction + * logic MUST NOT queue a MHD response. IF it returns an hard error, + * the transaction logic MUST queue a MHD response and set @a mhd_ret. + * IF it returns the soft error code, the function MAY be called again + * to retry and MUST not queue a MHD response. * * @param cls a `struct ReserveHistoryContext *` * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, + * @param[out] mhd_ret set to MHD response history for @a connection, * if transaction failed (!); unused - * @return transaction status + * @return transaction history */ static enum GNUNET_DB_QueryStatus reserve_history_transaction (void *cls, @@ -129,47 +413,9 @@ reserve_history_transaction (void *cls, struct ReserveHistoryContext *rsc = cls; enum GNUNET_DB_QueryStatus qs; - if (! TALER_amount_is_zero (&rsc->gf->fees.history)) - { - bool balance_ok = false; - bool idempotent = true; - - qs = TEH_plugin->insert_history_request (TEH_plugin->cls, - rsc->reserve_pub, - &rsc->reserve_sig, - rsc->timestamp, - &rsc->gf->fees.history, - &balance_ok, - &idempotent); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_history"); - } - if (qs <= 0) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; - } - if (! balance_ok) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_EXCHANGE_GET_RESERVE_HISTORY_ERROR_INSUFFICIENT_BALANCE, - NULL); - } - if (idempotent) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Idempotent /reserves/history request observed. Is caching working?\n"); - } - } qs = TEH_plugin->get_reserve_history (TEH_plugin->cls, rsc->reserve_pub, + 0, &rsc->balance, &rsc->rh); if (GNUNET_DB_STATUS_HARD_ERROR == qs) @@ -192,14 +438,13 @@ TEH_handler_reserves_history (struct TEH_RequestContext *rc, { struct ReserveHistoryContext rsc; MHD_RESULT mhd_ret; + uint64_t start_off = 0; + struct TALER_ReserveSignatureP reserve_sig; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("request_timestamp", - &rsc.timestamp), GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &rsc.reserve_sig), + &reserve_sig), GNUNET_JSON_spec_end () }; - struct GNUNET_TIME_Timestamp now; rsc.reserve_pub = reserve_pub; { @@ -219,51 +464,15 @@ TEH_handler_reserves_history (struct TEH_RequestContext *rc, return MHD_YES; /* failure */ } } - now = GNUNET_TIME_timestamp_get (); - if (! GNUNET_TIME_absolute_approx_eq (now.abs_time, - rsc.timestamp.abs_time, - TIMESTAMP_TOLERANCE)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW, - NULL); - } - { - struct TEH_KeyStateHandle *keys; - - keys = TEH_keys_get_state (); - if (NULL == keys) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, - NULL); - } - rsc.gf = TEH_keys_global_fee_by_time (keys, - rsc.timestamp); - } - if (NULL == rsc.gf) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, - NULL); - } if (GNUNET_OK != - TALER_wallet_reserve_history_verify (rsc.timestamp, - &rsc.gf->fees.history, + TALER_wallet_reserve_history_verify (start_off, reserve_pub, - &rsc.reserve_sig)) + &reserve_sig)) { GNUNET_break_op (0); return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_FORBIDDEN, - TALER_EC_EXCHANGE_RESERVES_HISTORY_BAD_SIGNATURE, + TALER_EC_EXCHANGE_RESERVE_HISTORY_BAD_SIGNATURE, NULL); } rsc.rh = NULL; @@ -281,7 +490,7 @@ TEH_handler_reserves_history (struct TEH_RequestContext *rc, { return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, + TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, NULL); } mhd_ret = reply_reserve_history_success (rc->connection, diff --git a/src/exchange/taler-exchange-httpd_reserves_history.h b/src/exchange/taler-exchange-httpd_reserves_history.h index e02cb4d9b..9a2a93782 100644 --- a/src/exchange/taler-exchange-httpd_reserves_history.h +++ b/src/exchange/taler-exchange-httpd_reserves_history.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2020 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -15,8 +15,9 @@ */ /** * @file taler-exchange-httpd_reserves_history.h - * @brief Handle /reserves/$RESERVE_PUB/history requests + * @brief Handle /reserves/$RESERVE_PUB HISTORY requests * @author Florian Dold + * @author Benedikt Mueller * @author Christian Grothoff */ #ifndef TALER_EXCHANGE_HTTPD_RESERVES_HISTORY_H diff --git a/src/exchange/taler-exchange-httpd_reserves_status.c b/src/exchange/taler-exchange-httpd_reserves_status.c deleted file mode 100644 index 4e7b4f47c..000000000 --- a/src/exchange/taler-exchange-httpd_reserves_status.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see -*/ -/** - * @file taler-exchange-httpd_reserves_status.c - * @brief Handle /reserves/$RESERVE_PUB STATUS requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include -#include "taler_mhd_lib.h" -#include "taler_json_lib.h" -#include "taler_dbevents.h" -#include "taler-exchange-httpd_keys.h" -#include "taler-exchange-httpd_reserves_status.h" -#include "taler-exchange-httpd_responses.h" - -/** - * How far do we allow a client's time to be off when - * checking the request timestamp? - */ -#define TIMESTAMP_TOLERANCE \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) - - -/** - * Closure for #reserve_status_transaction. - */ -struct ReserveStatusContext -{ - /** - * Public key of the reserve the inquiry is about. - */ - const struct TALER_ReservePublicKeyP *reserve_pub; - - /** - * History of the reserve, set in the callback. - */ - struct TALER_EXCHANGEDB_ReserveHistory *rh; - - /** - * Sum of incoming transactions within the returned history. - * (currently not used). - */ - struct TALER_Amount balance_in; - - /** - * Sum of outgoing transactions within the returned history. - * (currently not used). - */ - struct TALER_Amount balance_out; - - /** - * Current reserve balance. - */ - struct TALER_Amount balance; -}; - - -/** - * Send reserve status to client. - * - * @param connection connection to the client - * @param rhc reserve history to return - * @return MHD result code - */ -static MHD_RESULT -reply_reserve_status_success (struct MHD_Connection *connection, - const struct ReserveStatusContext *rhc) -{ - const struct TALER_EXCHANGEDB_ReserveHistory *rh = rhc->rh; - json_t *json_history; - - json_history = TEH_RESPONSE_compile_reserve_history (rh); - if (NULL == json_history) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, - NULL); - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("balance", - &rhc->balance), - GNUNET_JSON_pack_array_steal ("history", - json_history)); -} - - -/** - * Function implementing /reserves/ STATUS transaction. - * Execute a /reserves/ STATUS. Given the public key of a reserve, - * return the associated transaction history. Runs the - * transaction logic; IF it returns a non-error code, the transaction - * logic MUST NOT queue a MHD response. IF it returns an hard error, - * the transaction logic MUST queue a MHD response and set @a mhd_ret. - * IF it returns the soft error code, the function MAY be called again - * to retry and MUST not queue a MHD response. - * - * @param cls a `struct ReserveStatusContext *` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!); unused - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -reserve_status_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct ReserveStatusContext *rsc = cls; - enum GNUNET_DB_QueryStatus qs; - - qs = TEH_plugin->get_reserve_status (TEH_plugin->cls, - rsc->reserve_pub, - &rsc->balance_in, - &rsc->balance_out, - &rsc->rh); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_status"); - } - qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, - rsc->reserve_pub, - &rsc->balance); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_balance"); - } - return qs; -} - - -MHD_RESULT -TEH_handler_reserves_status (struct TEH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root) -{ - struct ReserveStatusContext rsc; - MHD_RESULT mhd_ret; - struct GNUNET_TIME_Timestamp timestamp; - struct TALER_ReserveSignatureP reserve_sig; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("request_timestamp", - ×tamp), - GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &reserve_sig), - GNUNET_JSON_spec_end () - }; - struct GNUNET_TIME_Timestamp now; - - rsc.reserve_pub = reserve_pub; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (rc->connection, - root, - spec); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return MHD_NO; /* hard failure */ - } - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - } - now = GNUNET_TIME_timestamp_get (); - if (! GNUNET_TIME_absolute_approx_eq (now.abs_time, - timestamp.abs_time, - TIMESTAMP_TOLERANCE)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW, - NULL); - } - if (GNUNET_OK != - TALER_wallet_reserve_status_verify (timestamp, - reserve_pub, - &reserve_sig)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_EXCHANGE_RESERVES_STATUS_BAD_SIGNATURE, - NULL); - } - rsc.rh = NULL; - if (GNUNET_OK != - TEH_DB_run_transaction (rc->connection, - "get reserve status", - TEH_MT_REQUEST_OTHER, - &mhd_ret, - &reserve_status_transaction, - &rsc)) - { - return mhd_ret; - } - if (NULL == rsc.rh) - { - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, - NULL); - } - mhd_ret = reply_reserve_status_success (rc->connection, - &rsc); - TEH_plugin->free_reserve_history (TEH_plugin->cls, - rsc.rh); - return mhd_ret; -} - - -/* end of taler-exchange-httpd_reserves_status.c */ diff --git a/src/exchange/taler-exchange-httpd_reserves_status.h b/src/exchange/taler-exchange-httpd_reserves_status.h deleted file mode 100644 index 831b270f7..000000000 --- a/src/exchange/taler-exchange-httpd_reserves_status.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see -*/ -/** - * @file taler-exchange-httpd_reserves_status.h - * @brief Handle /reserves/$RESERVE_PUB STATUS requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_EXCHANGE_HTTPD_RESERVES_STATUS_H -#define TALER_EXCHANGE_HTTPD_RESERVES_STATUS_H - -#include -#include "taler-exchange-httpd.h" - - -/** - * Handle a POST "/reserves/$RID/status" request. - * - * @param rc request context - * @param reserve_pub public key of the reserve - * @param root uploaded body from the client - * @return MHD result code - */ -MHD_RESULT -TEH_handler_reserves_status (struct TEH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root); - -#endif diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 13c654e60..4c8b385bf 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -32,491 +32,6 @@ #include "taler-exchange-httpd_keys.h" -/** - * Compile the transaction history of a coin into a JSON object. - * - * @param coin_pub public key of the coin - * @param tl transaction history to JSON-ify - * @return json representation of the @a rh, NULL on error - */ -json_t * -TEH_RESPONSE_compile_transaction_history ( - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_EXCHANGEDB_TransactionList *tl) -{ - json_t *history; - - history = json_array (); - if (NULL == history) - { - GNUNET_break (0); /* out of memory!? */ - return NULL; - } - for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl; - NULL != pos; - pos = pos->next) - { - switch (pos->type) - { - case TALER_EXCHANGEDB_TT_DEPOSIT: - { - const struct TALER_EXCHANGEDB_DepositListEntry *deposit = - pos->details.deposit; - struct TALER_MerchantWireHashP h_wire; - - TALER_merchant_wire_signature_hash (deposit->receiver_wire_account, - &deposit->wire_salt, - &h_wire); -#if ENABLE_SANITY_CHECKS - /* internal sanity check before we hand out a bogus sig... */ - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; - if (GNUNET_OK != - TALER_wallet_deposit_verify ( - &deposit->amount_with_fee, - &deposit->deposit_fee, - &h_wire, - &deposit->h_contract_terms, - deposit->no_wallet_data_hash - ? NULL - : &deposit->wallet_data_hash, - deposit->no_age_commitment - ? NULL - : &deposit->h_age_commitment, - &deposit->h_policy, - &deposit->h_denom_pub, - deposit->timestamp, - &deposit->merchant_pub, - deposit->refund_deadline, - coin_pub, - &deposit->csig)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } -#endif - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "DEPOSIT"), - TALER_JSON_pack_amount ("amount", - &deposit->amount_with_fee), - TALER_JSON_pack_amount ("deposit_fee", - &deposit->deposit_fee), - GNUNET_JSON_pack_timestamp ("timestamp", - deposit->timestamp), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_timestamp ("refund_deadline", - deposit->refund_deadline)), - GNUNET_JSON_pack_data_auto ("merchant_pub", - &deposit->merchant_pub), - GNUNET_JSON_pack_data_auto ("h_contract_terms", - &deposit->h_contract_terms), - GNUNET_JSON_pack_data_auto ("h_wire", - &h_wire), - GNUNET_JSON_pack_allow_null ( - deposit->no_age_commitment ? - GNUNET_JSON_pack_string ( - "h_age_commitment", NULL) : - GNUNET_JSON_pack_data_auto ("h_age_commitment", - &deposit->h_age_commitment)), - GNUNET_JSON_pack_data_auto ("coin_sig", - &deposit->csig)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - break; - } - case TALER_EXCHANGEDB_TT_MELT: - { - const struct TALER_EXCHANGEDB_MeltListEntry *melt = - pos->details.melt; - const struct TALER_AgeCommitmentHash *phac = NULL; - -#if ENABLE_SANITY_CHECKS - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; - if (GNUNET_OK != - TALER_wallet_melt_verify ( - &melt->amount_with_fee, - &melt->melt_fee, - &melt->rc, - &melt->h_denom_pub, - &melt->h_age_commitment, - coin_pub, - &melt->coin_sig)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } -#endif - - /* Age restriction is optional. We communicate a NULL value to - * JSON_PACK below */ - if (! melt->no_age_commitment) - phac = &melt->h_age_commitment; - - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "MELT"), - TALER_JSON_pack_amount ("amount", - &melt->amount_with_fee), - TALER_JSON_pack_amount ("melt_fee", - &melt->melt_fee), - GNUNET_JSON_pack_data_auto ("rc", - &melt->rc), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_data_auto ("h_age_commitment", - phac)), - GNUNET_JSON_pack_data_auto ("coin_sig", - &melt->coin_sig)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_TT_REFUND: - { - const struct TALER_EXCHANGEDB_RefundListEntry *refund = - pos->details.refund; - struct TALER_Amount value; - -#if ENABLE_SANITY_CHECKS - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; - if (GNUNET_OK != - TALER_merchant_refund_verify ( - coin_pub, - &refund->h_contract_terms, - refund->rtransaction_id, - &refund->refund_amount, - &refund->merchant_pub, - &refund->merchant_sig)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } -#endif - if (0 > - TALER_amount_subtract (&value, - &refund->refund_amount, - &refund->refund_fee)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "REFUND"), - TALER_JSON_pack_amount ("amount", - &value), - TALER_JSON_pack_amount ("refund_fee", - &refund->refund_fee), - GNUNET_JSON_pack_data_auto ("h_contract_terms", - &refund->h_contract_terms), - GNUNET_JSON_pack_data_auto ("merchant_pub", - &refund->merchant_pub), - GNUNET_JSON_pack_uint64 ("rtransaction_id", - refund->rtransaction_id), - GNUNET_JSON_pack_data_auto ("merchant_sig", - &refund->merchant_sig)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP: - { - struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr = - pos->details.old_coin_recoup; - struct TALER_ExchangePublicKeyP epub; - struct TALER_ExchangeSignatureP esig; - - if (TALER_EC_NONE != - TALER_exchange_online_confirm_recoup_refresh_sign ( - &TEH_keys_exchange_sign_, - pr->timestamp, - &pr->value, - &pr->coin.coin_pub, - &pr->old_coin_pub, - &epub, - &esig)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - /* NOTE: we could also provide coin_pub's coin_sig, denomination key hash and - the denomination key's RSA signature over coin_pub, but as the - wallet should really already have this information (and cannot - check or do anything with it anyway if it doesn't), it seems - strictly unnecessary. */ - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "OLD-COIN-RECOUP"), - TALER_JSON_pack_amount ("amount", - &pr->value), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &esig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &epub), - GNUNET_JSON_pack_data_auto ("coin_pub", - &pr->coin.coin_pub), - GNUNET_JSON_pack_timestamp ("timestamp", - pr->timestamp)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - break; - } - case TALER_EXCHANGEDB_TT_RECOUP: - { - const struct TALER_EXCHANGEDB_RecoupListEntry *recoup = - pos->details.recoup; - struct TALER_ExchangePublicKeyP epub; - struct TALER_ExchangeSignatureP esig; - - if (TALER_EC_NONE != - TALER_exchange_online_confirm_recoup_sign ( - &TEH_keys_exchange_sign_, - recoup->timestamp, - &recoup->value, - coin_pub, - &recoup->reserve_pub, - &epub, - &esig)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "RECOUP"), - TALER_JSON_pack_amount ("amount", - &recoup->value), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &esig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &epub), - GNUNET_JSON_pack_data_auto ("reserve_pub", - &recoup->reserve_pub), - GNUNET_JSON_pack_data_auto ("coin_sig", - &recoup->coin_sig), - GNUNET_JSON_pack_data_auto ("coin_blind", - &recoup->coin_blind), - GNUNET_JSON_pack_data_auto ("reserve_pub", - &recoup->reserve_pub), - GNUNET_JSON_pack_timestamp ("timestamp", - recoup->timestamp)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_TT_RECOUP_REFRESH: - { - struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr = - pos->details.recoup_refresh; - struct TALER_ExchangePublicKeyP epub; - struct TALER_ExchangeSignatureP esig; - - if (TALER_EC_NONE != - TALER_exchange_online_confirm_recoup_refresh_sign ( - &TEH_keys_exchange_sign_, - pr->timestamp, - &pr->value, - coin_pub, - &pr->old_coin_pub, - &epub, - &esig)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - /* NOTE: we could also provide coin_pub's coin_sig, denomination key - hash and the denomination key's RSA signature over coin_pub, but as - the wallet should really already have this information (and cannot - check or do anything with it anyway if it doesn't), it seems - strictly unnecessary. */ - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "RECOUP-REFRESH"), - TALER_JSON_pack_amount ("amount", - &pr->value), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &esig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &epub), - GNUNET_JSON_pack_data_auto ("old_coin_pub", - &pr->old_coin_pub), - GNUNET_JSON_pack_data_auto ("coin_sig", - &pr->coin_sig), - GNUNET_JSON_pack_data_auto ("coin_blind", - &pr->coin_blind), - GNUNET_JSON_pack_timestamp ("timestamp", - pr->timestamp)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - break; - } - - case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: - { - struct TALER_EXCHANGEDB_PurseDepositListEntry *pd - = pos->details.purse_deposit; - const struct TALER_AgeCommitmentHash *phac = NULL; - - if (! pd->no_age_commitment) - phac = &pd->h_age_commitment; - - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "PURSE-DEPOSIT"), - TALER_JSON_pack_amount ("amount", - &pd->amount), - GNUNET_JSON_pack_string ("exchange_base_url", - NULL == pd->exchange_base_url - ? TEH_base_url - : pd->exchange_base_url), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_data_auto ("h_age_commitment", - phac)), - GNUNET_JSON_pack_data_auto ("purse_pub", - &pd->purse_pub), - GNUNET_JSON_pack_bool ("refunded", - pd->refunded), - GNUNET_JSON_pack_data_auto ("coin_sig", - &pd->coin_sig)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - break; - } - - case TALER_EXCHANGEDB_TT_PURSE_REFUND: - { - const struct TALER_EXCHANGEDB_PurseRefundListEntry *prefund = - pos->details.purse_refund; - struct TALER_Amount value; - enum TALER_ErrorCode ec; - struct TALER_ExchangePublicKeyP epub; - struct TALER_ExchangeSignatureP esig; - - if (0 > - TALER_amount_subtract (&value, - &prefund->refund_amount, - &prefund->refund_fee)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - ec = TALER_exchange_online_purse_refund_sign ( - &TEH_keys_exchange_sign_, - &value, - &prefund->refund_fee, - coin_pub, - &prefund->purse_pub, - &epub, - &esig); - if (TALER_EC_NONE != ec) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "PURSE-REFUND"), - TALER_JSON_pack_amount ("amount", - &value), - TALER_JSON_pack_amount ("refund_fee", - &prefund->refund_fee), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &esig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &epub), - GNUNET_JSON_pack_data_auto ("purse_pub", - &prefund->purse_pub)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - } - break; - - case TALER_EXCHANGEDB_TT_RESERVE_OPEN: - { - struct TALER_EXCHANGEDB_ReserveOpenListEntry *role - = pos->details.reserve_open; - - if (0 != - json_array_append_new ( - history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "RESERVE-OPEN-DEPOSIT"), - TALER_JSON_pack_amount ("coin_contribution", - &role->coin_contribution), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &role->reserve_sig), - GNUNET_JSON_pack_data_auto ("coin_sig", - &role->coin_sig)))) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - break; - } - } - } - return history; -} - - MHD_RESULT TEH_RESPONSE_reply_unknown_denom_pub_hash ( struct MHD_Connection *connection, @@ -650,48 +165,6 @@ TEH_RESPONSE_reply_coin_insufficient_funds ( const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub) { - struct TALER_EXCHANGEDB_TransactionList *tl; - enum GNUNET_DB_QueryStatus qs; - json_t *history; - uint64_t etag = 0; - - TEH_plugin->rollback (TEH_plugin->cls); - if (GNUNET_OK != - TEH_plugin->start_read_only (TEH_plugin->cls, - "get_coin_transactions")) - { - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, - NULL); - } - qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls, - coin_pub, - &etag, - &tl); - TEH_plugin->rollback (TEH_plugin->cls); - if (0 > qs) - { - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - NULL); - } - - history = TEH_RESPONSE_compile_transaction_history (coin_pub, - tl); - TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, - tl); - if (NULL == history) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, - "Failed to generated proof of insufficient funds"); - } return TALER_MHD_REPLY_JSON_PACK ( connection, TALER_ErrorCode_get_http_status_safe (ec), @@ -700,347 +173,7 @@ TEH_RESPONSE_reply_coin_insufficient_funds ( coin_pub), // FIXME: to be kept only for some of the error types! GNUNET_JSON_pack_data_auto ("h_denom_pub", - h_denom_pub), - // FIXME: to be removed! - GNUNET_JSON_pack_array_steal ("history", - history)); -} - - -json_t * -TEH_RESPONSE_compile_reserve_history ( - const struct TALER_EXCHANGEDB_ReserveHistory *rh) -{ - json_t *json_history; - - json_history = json_array (); - GNUNET_assert (NULL != json_history); - for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh; - NULL != pos; - pos = pos->next) - { - switch (pos->type) - { - case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: - { - const struct TALER_EXCHANGEDB_BankTransfer *bank = - pos->details.bank; - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "CREDIT"), - GNUNET_JSON_pack_timestamp ("timestamp", - bank->execution_date), - GNUNET_JSON_pack_string ("sender_account_url", - bank->sender_account_details), - GNUNET_JSON_pack_uint64 ("wire_reference", - bank->wire_reference), - TALER_JSON_pack_amount ("amount", - &bank->amount)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - break; - } - case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: - { - const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw - = pos->details.withdraw; - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "WITHDRAW"), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &withdraw->reserve_sig), - GNUNET_JSON_pack_data_auto ("h_coin_envelope", - &withdraw->h_coin_envelope), - GNUNET_JSON_pack_data_auto ("h_denom_pub", - &withdraw->denom_pub_hash), - TALER_JSON_pack_amount ("withdraw_fee", - &withdraw->withdraw_fee), - TALER_JSON_pack_amount ("amount", - &withdraw->amount_with_fee)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_RO_RECOUP_COIN: - { - const struct TALER_EXCHANGEDB_Recoup *recoup - = pos->details.recoup; - struct TALER_ExchangePublicKeyP pub; - struct TALER_ExchangeSignatureP sig; - - if (TALER_EC_NONE != - TALER_exchange_online_confirm_recoup_sign ( - &TEH_keys_exchange_sign_, - recoup->timestamp, - &recoup->value, - &recoup->coin.coin_pub, - &recoup->reserve_pub, - &pub, - &sig)) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "RECOUP"), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &pub), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &sig), - GNUNET_JSON_pack_timestamp ("timestamp", - recoup->timestamp), - TALER_JSON_pack_amount ("amount", - &recoup->value), - GNUNET_JSON_pack_data_auto ("coin_pub", - &recoup->coin.coin_pub)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK: - { - const struct TALER_EXCHANGEDB_ClosingTransfer *closing = - pos->details.closing; - struct TALER_ExchangePublicKeyP pub; - struct TALER_ExchangeSignatureP sig; - - if (TALER_EC_NONE != - TALER_exchange_online_reserve_closed_sign ( - &TEH_keys_exchange_sign_, - closing->execution_date, - &closing->amount, - &closing->closing_fee, - closing->receiver_account_details, - &closing->wtid, - &pos->details.closing->reserve_pub, - &pub, - &sig)) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "CLOSING"), - GNUNET_JSON_pack_string ("receiver_account_details", - closing->receiver_account_details), - GNUNET_JSON_pack_data_auto ("wtid", - &closing->wtid), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &pub), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &sig), - GNUNET_JSON_pack_timestamp ("timestamp", - closing->execution_date), - TALER_JSON_pack_amount ("amount", - &closing->amount), - TALER_JSON_pack_amount ("closing_fee", - &closing->closing_fee)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_RO_PURSE_MERGE: - { - const struct TALER_EXCHANGEDB_PurseMerge *merge = - pos->details.merge; - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "MERGE"), - GNUNET_JSON_pack_data_auto ("h_contract_terms", - &merge->h_contract_terms), - GNUNET_JSON_pack_data_auto ("merge_pub", - &merge->merge_pub), - GNUNET_JSON_pack_uint64 ("min_age", - merge->min_age), - GNUNET_JSON_pack_uint64 ("flags", - merge->flags), - GNUNET_JSON_pack_data_auto ("purse_pub", - &merge->purse_pub), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &merge->reserve_sig), - GNUNET_JSON_pack_timestamp ("merge_timestamp", - merge->merge_timestamp), - GNUNET_JSON_pack_timestamp ("purse_expiration", - merge->purse_expiration), - TALER_JSON_pack_amount ("purse_fee", - &merge->purse_fee), - TALER_JSON_pack_amount ("amount", - &merge->amount_with_fee), - GNUNET_JSON_pack_bool ("merged", - merge->merged)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - case TALER_EXCHANGEDB_RO_HISTORY_REQUEST: - { - const struct TALER_EXCHANGEDB_HistoryRequest *history = - pos->details.history; - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "HISTORY"), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &history->reserve_sig), - GNUNET_JSON_pack_timestamp ("request_timestamp", - history->request_timestamp), - TALER_JSON_pack_amount ("amount", - &history->history_fee)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - - case TALER_EXCHANGEDB_RO_OPEN_REQUEST: - { - const struct TALER_EXCHANGEDB_OpenRequest *orq = - pos->details.open_request; - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "OPEN"), - GNUNET_JSON_pack_uint64 ("requested_min_purses", - orq->purse_limit), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &orq->reserve_sig), - GNUNET_JSON_pack_timestamp ("request_timestamp", - orq->request_timestamp), - GNUNET_JSON_pack_timestamp ("requested_expiration", - orq->reserve_expiration), - TALER_JSON_pack_amount ("open_fee", - &orq->open_fee)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - - case TALER_EXCHANGEDB_RO_CLOSE_REQUEST: - { - const struct TALER_EXCHANGEDB_CloseRequest *crq = - pos->details.close_request; - - if (0 != - json_array_append_new ( - json_history, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("type", - "CLOSE"), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &crq->reserve_sig), - GNUNET_is_zero (&crq->target_account_h_payto) - ? GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("h_payto", - NULL)) - : GNUNET_JSON_pack_data_auto ("h_payto", - &crq->target_account_h_payto), - GNUNET_JSON_pack_timestamp ("request_timestamp", - crq->request_timestamp)))) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - } - break; - } - } - - return json_history; -} - - -/** - * Send reserve history information to client with the - * message that we have insufficient funds for the - * requested withdraw operation. - * - * @param connection connection to the client - * @param ec error code to return - * @param ebalance expected balance based on our database - * @param withdraw_amount amount that the client requested to withdraw - * @param rh reserve history to return - * @return MHD result code - */ -static MHD_RESULT -reply_reserve_insufficient_funds ( - struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const struct TALER_Amount *ebalance, - const struct TALER_Amount *withdraw_amount, - const struct TALER_EXCHANGEDB_ReserveHistory *rh) -{ - json_t *json_history; - - json_history = TEH_RESPONSE_compile_reserve_history (rh); - if (NULL == json_history) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to compile reserve history\n"); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_RESERVE_HISTORY_ERROR_INSUFFICIENT_FUNDS, - NULL); - } - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_CONFLICT, - TALER_JSON_pack_ec (ec), - TALER_JSON_pack_amount ("balance", - ebalance), - TALER_JSON_pack_amount ("requested_amount", - withdraw_amount), - GNUNET_JSON_pack_array_steal ("history", - json_history)); + h_denom_pub)); } @@ -1051,46 +184,30 @@ TEH_RESPONSE_reply_reserve_insufficient_balance ( const struct TALER_Amount *balance_required, const struct TALER_ReservePublicKeyP *reserve_pub) { - struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL; struct TALER_Amount balance; enum GNUNET_DB_QueryStatus qs; - MHD_RESULT mhd_ret; - if (GNUNET_OK != - TEH_plugin->start_read_only (TEH_plugin->cls, - "get_reserve_history on insufficient balance")) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, - NULL); - } - /* The reserve does not have the required amount (actual - * amount + withdraw fee) */ - qs = TEH_plugin->get_reserve_history (TEH_plugin->cls, + // FIXME: pass balance as argument to this function, + // instead of getting it in another transaction! + qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, reserve_pub, - &balance, - &rh); - TEH_plugin->rollback (TEH_plugin->cls); - if ( (qs < 0) || - (NULL == rh) ) + &balance); + if (qs < 0) { GNUNET_break (0); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, - "reserve history"); + "reserve balance"); } - mhd_ret = reply_reserve_insufficient_funds ( + return TALER_MHD_REPLY_JSON_PACK ( connection, - ec, - &balance, - balance_required, - rh); - TEH_plugin->free_reserve_history (TEH_plugin->cls, - rh); - return mhd_ret; + MHD_HTTP_CONFLICT, + TALER_JSON_pack_ec (ec), + TALER_JSON_pack_amount ("balance", + &balance), + TALER_JSON_pack_amount ("requested_amount", + balance_required)); } diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index 9b525929b..3e55f0b07 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -33,17 +33,6 @@ #include -/** - * Compile the history of a reserve into a JSON object. - * - * @param rh reserve history to JSON-ify - * @return json representation of the @a rh, NULL on error - */ -json_t * -TEH_RESPONSE_compile_reserve_history ( - const struct TALER_EXCHANGEDB_ReserveHistory *rh); - - /** * Send assertion that the given denomination key hash * is unknown to us at this time. @@ -213,19 +202,6 @@ TEH_RESPONSE_reply_purse_created ( const struct TEH_PurseDetails *pd); -/** - * Compile the transaction history of a coin into a JSON object. - * - * @param coin_pub public key of the coin - * @param tl transaction history to JSON-ify - * @return json representation of the @a rh, NULL on error - */ -json_t * -TEH_RESPONSE_compile_transaction_history ( - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_EXCHANGEDB_TransactionList *tl); - - /** * Callback used to set headers in a response. * diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 50f9e768a..3a4120afc 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -164,7 +164,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_store_wire_transfer_out.h pg_store_wire_transfer_out.c \ pg_gc.h pg_gc.c \ pg_select_coin_deposits_above_serial_id.h pg_select_coin_deposits_above_serial_id.c \ - pg_select_history_requests_above_serial_id.h pg_select_history_requests_above_serial_id.c \ pg_select_purse_decisions_above_serial_id.h pg_select_purse_decisions_above_serial_id.c \ pg_select_purse_deposits_by_purse.h pg_select_purse_deposits_by_purse.c \ pg_select_refreshes_above_serial_id.h pg_select_refreshes_above_serial_id.c \ @@ -215,7 +214,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_update_auditor.h pg_update_auditor.c \ pg_begin_revolving_shard.h pg_begin_revolving_shard.c \ pg_get_extension_manifest.h pg_get_extension_manifest.c \ - pg_insert_history_request.h pg_insert_history_request.c \ pg_do_purse_merge.h pg_do_purse_merge.c \ pg_start_read_committed.h pg_start_read_committed.c \ pg_start_read_only.h pg_start_read_only.c \ diff --git a/src/exchangedb/exchange_do_history_request.sql b/src/exchangedb/exchange_do_history_request.sql deleted file mode 100644 index 726c853fb..000000000 --- a/src/exchangedb/exchange_do_history_request.sql +++ /dev/null @@ -1,101 +0,0 @@ --- --- This file is part of TALER --- Copyright (C) 2014--2022 Taler Systems SA --- --- TALER is free software; you can redistribute it and/or modify it under the --- terms of the GNU General Public License as published by the Free Software --- Foundation; either version 3, or (at your option) any later version. --- --- TALER is distributed in the hope that it will be useful, but WITHOUT ANY --- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR --- A PARTICULAR PURPOSE. See the GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License along with --- TALER; see the file COPYING. If not, see --- - - -CREATE OR REPLACE FUNCTION exchange_do_history_request( - IN in_reserve_pub BYTEA, - IN in_reserve_sig BYTEA, - IN in_request_timestamp INT8, - IN in_history_fee taler_amount, - OUT out_balance_ok BOOLEAN, - OUT out_idempotent BOOLEAN) -LANGUAGE plpgsql -AS $$ -DECLARE - reserve RECORD; - balance taler_amount; - new_balance taler_amount; -BEGIN - - -- Insert and check for idempotency. - INSERT INTO exchange.history_requests - (reserve_pub - ,request_timestamp - ,reserve_sig - ,history_fee) - VALUES - (in_reserve_pub - ,in_request_timestamp - ,in_reserve_sig - ,in_history_fee) - ON CONFLICT DO NOTHING; - - IF NOT FOUND - THEN - out_balance_ok=TRUE; - out_idempotent=TRUE; - RETURN; - END IF; - - out_idempotent=FALSE; - - SELECT * - INTO reserve - FROM exchange.reserves - WHERE reserve_pub=in_reserve_pub; - - IF NOT FOUND - THEN - -- Reserve does not exist, we treat it the same here - -- as balance insufficient. - out_balance_ok=FALSE; - RETURN; - END IF; - - balance = reserve.current_balance; - - -- check balance - IF ( (balance.val <= in_history_fee.val) AND - ( (balance.frac < in_history_fee.frac) OR - (balance.val < in_history_fee.val) ) ) - THEN - out_balance_ok=FALSE; - RETURN; - END IF; - - new_balance.frac=balance.frac-in_history_fee.frac - + CASE - WHEN balance.frac < in_history_fee.frac - THEN 100000000 - ELSE 0 - END; - new_balance.val=balance.val-in_history_fee.val - - CASE - WHEN balance.frac < in_history_fee.frac - THEN 1 - ELSE 0 - END; - - -- Update reserve balance. - UPDATE exchange.reserves - SET current_balance=new_balance - WHERE reserve_pub=in_reserve_pub; - - ASSERT FOUND, 'reserve suddenly disappeared'; - - out_balance_ok=TRUE; - -END $$; diff --git a/src/exchangedb/pg_get_reserve_history.c b/src/exchangedb/pg_get_reserve_history.c index c0cb08f59..ba1db2a16 100644 --- a/src/exchangedb/pg_get_reserve_history.c +++ b/src/exchangedb/pg_get_reserve_history.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -424,62 +424,6 @@ add_p2p_merge (void *cls, } -/** - * Add paid for history requests to result set for - * #TEH_PG_get_reserve_history. - * - * @param cls a `struct ReserveHistoryContext *` - * @param result SQL result - * @param num_results number of rows in @a result - */ -static void -add_history_requests (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct ReserveHistoryContext *rhc = cls; - struct PostgresClosure *pg = rhc->pg; - - while (0 < num_results) - { - struct TALER_EXCHANGEDB_HistoryRequest *history; - struct TALER_EXCHANGEDB_ReserveHistory *tail; - - history = GNUNET_new (struct TALER_EXCHANGEDB_HistoryRequest); - { - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee", - &history->history_fee), - GNUNET_PQ_result_spec_timestamp ("request_timestamp", - &history->request_timestamp), - GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", - &history->reserve_sig), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - --num_results)) - { - GNUNET_break (0); - GNUNET_free (history); - rhc->status = GNUNET_SYSERR; - return; - } - } - GNUNET_assert (0 <= - TALER_amount_add (&rhc->balance_out, - &rhc->balance_out, - &history->history_fee)); - history->reserve_pub = *rhc->reserve_pub; - tail = append_rh (rhc); - tail->type = TALER_EXCHANGEDB_RO_HISTORY_REQUEST; - tail->details.history = history; - } -} - - /** * Add paid for history requests to result set for * #TEH_PG_get_reserve_history. @@ -598,6 +542,7 @@ add_close_requests (void *cls, enum GNUNET_DB_QueryStatus TEH_PG_get_reserve_history (void *cls, const struct TALER_ReservePublicKeyP *reserve_pub, + uint64_t start_off, struct TALER_Amount *balance, struct TALER_EXCHANGEDB_ReserveHistory **rhp) { @@ -629,9 +574,6 @@ TEH_PG_get_reserve_history (void *cls, /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */ { "merge_by_reserve", &add_p2p_merge }, - /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */ - { "history_by_reserve", - &add_history_requests }, /** #TALER_EXCHANGEDB_RO_OPEN_REQUEST */ { "open_request_by_reserve", &add_open_requests }, @@ -792,14 +734,6 @@ TEH_PG_get_reserve_history (void *cls, " WHERE pm.reserve_pub=$1" " AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */ " AND NOT COALESCE (pdes.refunded, FALSE);"); - PREPARE (pg, // done - "history_by_reserve", - "SELECT" - " history_fee" - ",request_timestamp" - ",reserve_sig" - " FROM history_requests" - " WHERE reserve_pub=$1;"); PREPARE (pg, // done "open_request_by_reserve", "SELECT" @@ -866,293 +800,3 @@ TEH_PG_get_reserve_history (void *cls, &rhc.balance_out)); return qs; } - - -enum GNUNET_DB_QueryStatus -TEH_PG_get_reserve_status (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct TALER_Amount *balance_in, - struct TALER_Amount *balance_out, - struct TALER_EXCHANGEDB_ReserveHistory **rhp) -{ - struct PostgresClosure *pg = cls; - struct ReserveHistoryContext rhc; - struct - { - /** - * Name of the prepared statement to run. - */ - const char *statement; - /** - * Function to use to process the results. - */ - GNUNET_PQ_PostgresResultHandler cb; - } work[] = { - /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */ - { "reserves_in_get_transactions_truncated", - add_bank_to_exchange }, - /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */ - { "get_reserves_out_truncated", - &add_withdraw_coin }, - /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */ - { "recoup_by_reserve_truncated", - &add_recoup }, - /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */ - { "close_by_reserve_truncated", - &add_exchange_to_bank }, - /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */ - { "merge_by_reserve_truncated", - &add_p2p_merge }, - /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */ - { "history_by_reserve_truncated", - &add_history_requests }, - /** #TALER_EXCHANGEDB_RO_OPEN_REQUEST */ - { "open_request_by_reserve_truncated", - &add_open_requests }, - /** #TALER_EXCHANGEDB_RO_CLOSE_REQUEST */ - { "close_request_by_reserve_truncated", - &add_close_requests }, - /* List terminator */ - { NULL, - NULL } - }; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_TIME_Absolute timelimit; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_absolute_time (&timelimit), - GNUNET_PQ_query_param_end - }; - - PREPARE (pg, - "reserves_in_get_transactions_truncated", - /* - "SELECT" - " wire_reference" - ",credit" - ",execution_date" - ",payto_uri AS sender_account_details" - " FROM reserves_in" - " JOIN wire_targets" - " ON (wire_source_h_payto = wire_target_h_payto)" - " WHERE reserve_pub=$1" - " AND execution_date>=$2;", - */ - "WITH ri AS MATERIALIZED ( " - " SELECT * " - " FROM reserves_in " - " WHERE reserve_pub = $1 " - ") " - "SELECT " - " wire_reference" - " ,credit" - " ,execution_date" - " ,payto_uri AS sender_account_details" - " FROM wire_targets" - " JOIN ri" - " ON (wire_target_h_payto = wire_source_h_payto)" - " WHERE execution_date >= $2" - " AND wire_target_h_payto = ( " - " SELECT wire_source_h_payto FROM ri " - "); "); - PREPARE (pg, - "get_reserves_out_truncated", - /* - "SELECT" - " ro.h_blind_ev" - ",denom.denom_pub_hash" - ",ro.denom_sig" - ",ro.reserve_sig" - ",ro.execution_date" - ",ro.amount_with_fee" - ",denom.fee_withdraw" - " FROM reserves res" - " JOIN reserves_out_by_reserve ror" - " ON (res.reserve_uuid = ror.reserve_uuid)" - " JOIN reserves_out ro" - " ON (ro.h_blind_ev = ror.h_blind_ev)" - " JOIN denominations denom" - " ON (ro.denominations_serial = denom.denominations_serial)" - " WHERE res.reserve_pub=$1" - " AND execution_date>=$2;", - */ - "WITH robr AS MATERIALIZED ( " - " SELECT h_blind_ev " - " FROM reserves_out_by_reserve " - " WHERE reserve_uuid= ( " - " SELECT reserve_uuid " - " FROM reserves " - " WHERE reserve_pub = $1 " - " ) " - ") SELECT " - " ro.h_blind_ev" - " ,denom.denom_pub_hash" - " ,ro.denom_sig" - " ,ro.reserve_sig" - " ,ro.execution_date" - " ,ro.amount_with_fee" - " ,denom.fee_withdraw" - " FROM robr" - " JOIN reserves_out ro" - " ON (ro.h_blind_ev = robr.h_blind_ev)" - " JOIN denominations denom" - " ON (ro.denominations_serial = denom.denominations_serial)" - " WHERE ro.execution_date>=$2;"); - PREPARE (pg, - "recoup_by_reserve_truncated", - /* - "SELECT" - " recoup.coin_pub" - ",recoup.coin_sig" - ",recoup.coin_blind" - ",recoup.amount" - ",recoup.recoup_timestamp" - ",denominations.denom_pub_hash" - ",known_coins.denom_sig" - " FROM denominations" - " JOIN (known_coins" - " JOIN recoup " - " ON (recoup.coin_pub = known_coins.coin_pub))" - " ON (known_coins.denominations_serial = denominations.denominations_serial)" - " WHERE recoup_timestamp>=$2" - " AND recoup.coin_pub" - " IN (SELECT coin_pub" - " FROM recoup_by_reserve" - " JOIN (reserves_out" - " JOIN (reserves_out_by_reserve" - " JOIN reserves" - " ON (reserves.reserve_uuid = reserves_out_by_reserve.reserve_uuid))" - " ON (reserves_out_by_reserve.h_blind_ev = reserves_out.h_blind_ev))" - " ON (recoup_by_reserve.reserve_out_serial_id = reserves_out.reserve_out_serial_id)" - " WHERE reserves.reserve_pub=$1);", - */ - "SELECT robr.coin_pub " - " ,robr.coin_sig " - " ,robr.coin_blind " - " ,robr.amount" - " ,robr.recoup_timestamp " - " ,denominations.denom_pub_hash " - " ,robr.denom_sig " - "FROM denominations " - " JOIN exchange_do_recoup_by_reserve($1) robr" - " USING (denominations_serial)" - " WHERE recoup_timestamp>=$2;"); - PREPARE (pg, - "close_by_reserve_truncated", - "SELECT" - " amount" - ",closing_fee" - ",execution_date" - ",payto_uri AS receiver_account" - ",wtid" - " FROM reserves_close" - " JOIN wire_targets" - " USING (wire_target_h_payto)" - " WHERE reserve_pub=$1" - " AND execution_date>=$2;"); - PREPARE (pg, - "merge_by_reserve_truncated", - "SELECT" - " pr.amount_with_fee" - ",pr.balance" - ",pr.purse_fee" - ",pr.h_contract_terms" - ",pr.merge_pub" - ",am.reserve_sig" - ",pm.purse_pub" - ",pm.merge_timestamp" - ",pr.purse_expiration" - ",pr.age_limit" - ",pr.flags" - " FROM purse_merges pm" - " JOIN purse_requests pr" - " USING (purse_pub)" - " JOIN purse_decision pdes" - " USING (purse_pub)" - " JOIN account_merges am" - " ON (am.purse_pub = pm.purse_pub AND" - " am.reserve_pub = pm.reserve_pub)" - " WHERE pm.reserve_pub=$1" - " AND pm.merge_timestamp >= $2" - " AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */ - " AND NOT pdes.refunded;"); - PREPARE (pg, - "history_by_reserve_truncated", - "SELECT" - " history_fee" - ",request_timestamp" - ",reserve_sig" - " FROM history_requests" - " WHERE reserve_pub=$1" - " AND request_timestamp>=$2;"); - PREPARE (pg, - "open_request_by_reserve_truncated", - "SELECT" - " reserve_payment" - ",request_timestamp" - ",expiration_date" - ",requested_purse_limit" - ",reserve_sig" - " FROM reserves_open_requests" - " WHERE reserve_pub=$1" - " AND request_timestamp>=$2;"); - - PREPARE (pg, - "close_request_by_reserve_truncated", - "SELECT" - " close_timestamp" - ",payto_uri" - ",reserve_sig" - " FROM close_requests" - " WHERE reserve_pub=$1" - " AND close_timestamp>=$2;"); - - timelimit = GNUNET_TIME_absolute_subtract ( - GNUNET_TIME_absolute_get (), - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS, - 5)); - rhc.reserve_pub = reserve_pub; - rhc.rh = NULL; - rhc.rh_tail = NULL; - rhc.pg = pg; - rhc.status = GNUNET_OK; - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (pg->currency, - &rhc.balance_in)); - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (pg->currency, - &rhc.balance_out)); - qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */ - for (unsigned int i = 0; NULL != work[i].cb; i++) - { - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - work[i].statement, - params, - work[i].cb, - &rhc); - if ( (0 > qs) || - (GNUNET_OK != rhc.status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Query %s failed\n", - work[i].statement); - break; - } - } - if ( (qs < 0) || - (rhc.status != GNUNET_OK) ) - { - TEH_COMMON_free_reserve_history (cls, - rhc.rh); - rhc.rh = NULL; - if (qs >= 0) - { - /* status == SYSERR is a very hard error... */ - qs = GNUNET_DB_STATUS_HARD_ERROR; - } - } - *rhp = rhc.rh; - *balance_in = rhc.balance_in; - *balance_out = rhc.balance_out; - return qs; -} diff --git a/src/exchangedb/pg_get_reserve_history.h b/src/exchangedb/pg_get_reserve_history.h index ee47996b2..ca6740c6c 100644 --- a/src/exchangedb/pg_get_reserve_history.h +++ b/src/exchangedb/pg_get_reserve_history.h @@ -32,36 +32,18 @@ * * @param cls the `struct PostgresClosure` with the plugin-specific state * @param reserve_pub public key of the reserve + * @param start_off maximum starting offset in history to exclude from returning * @param[out] balance set to the reserve balance * @param[out] rhp set to known transaction history (NULL if reserve is unknown) * @return transaction status */ enum GNUNET_DB_QueryStatus -TEH_PG_get_reserve_history (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct TALER_Amount *balance, - struct TALER_EXCHANGEDB_ReserveHistory **rhp); - - -/** - * Get a truncated transaction history associated with the specified - * reserve. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param reserve_pub public key of the reserve - * @param[out] balance_in set to the total of inbound - * transactions in the returned history - * @param[out] balance_out set to the total of outbound - * transactions in the returned history - * @param[out] rhp set to known transaction history (NULL if reserve is unknown) - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -TEH_PG_get_reserve_status (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct TALER_Amount *balance_in, - struct TALER_Amount *balance_out, - struct TALER_EXCHANGEDB_ReserveHistory **rhp); +TEH_PG_get_reserve_history ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + uint64_t start_off, + struct TALER_Amount *balance, + struct TALER_EXCHANGEDB_ReserveHistory **rhp); #endif diff --git a/src/exchangedb/pg_insert_history_request.c b/src/exchangedb/pg_insert_history_request.c deleted file mode 100644 index b13066b5c..000000000 --- a/src/exchangedb/pg_insert_history_request.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - */ -/** - * @file exchangedb/pg_insert_history_request.c - * @brief Implementation of the insert_history_request function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_insert_history_request.h" -#include "pg_helper.h" - - -enum GNUNET_DB_QueryStatus -TEH_PG_insert_history_request ( - void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig, - struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *history_fee, - bool *balance_ok, - bool *idempotent) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_auto_from_type (reserve_sig), - GNUNET_PQ_query_param_timestamp (&request_timestamp), - TALER_PQ_query_param_amount (pg->conn, - history_fee), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("balance_ok", - balance_ok), - GNUNET_PQ_result_spec_bool ("idempotent", - idempotent), - GNUNET_PQ_result_spec_end - }; - /* Used in #postgres_insert_history_request() */ - PREPARE (pg, - "call_history_request", - "SELECT" - " out_balance_ok AS balance_ok" - " ,out_idempotent AS idempotent" - " FROM exchange_do_history_request" - " ($1, $2, $3, $4)"); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "call_history_request", - params, - rs); -} diff --git a/src/exchangedb/pg_insert_history_request.h b/src/exchangedb/pg_insert_history_request.h deleted file mode 100644 index 75004a7e4..000000000 --- a/src/exchangedb/pg_insert_history_request.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - */ -/** - * @file exchangedb/pg_insert_history_request.h - * @brief implementation of the insert_history_request function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_INSERT_HISTORY_REQUEST_H -#define PG_INSERT_HISTORY_REQUEST_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" -/** - * Function called to persist a signature that - * prove that the client requested an - * account history. Debits the @a history_fee from - * the reserve (if possible). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param reserve_pub account that the history was requested for - * @param reserve_sig signature affirming the request - * @param request_timestamp when was the request made - * @param history_fee how much should the @a reserve_pub be charged for the request - * @param[out] balance_ok set to TRUE if the reserve balance - * was sufficient - * @param[out] idempotent set to TRUE if the request is already in the DB - * @return transaction status code - */ -enum GNUNET_DB_QueryStatus -TEH_PG_insert_history_request ( - void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig, - struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *history_fee, - bool *balance_ok, - bool *idempotent); - -#endif diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.c b/src/exchangedb/pg_select_history_requests_above_serial_id.c deleted file mode 100644 index 2ff2f989c..000000000 --- a/src/exchangedb/pg_select_history_requests_above_serial_id.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - */ -/** - * @file exchangedb/pg_select_history_requests_above_serial_id.c - * @brief Implementation of the select_history_requests_above_serial_id function for Postgres - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_select_history_requests_above_serial_id.h" -#include "pg_helper.h" - -/** - * Closure for #purse_deposit_serial_helper_cb(). - */ -struct HistoryRequestSerialContext -{ - - /** - * Callback to call. - */ - TALER_EXCHANGEDB_HistoryRequestCallback cb; - - /** - * Closure for @e cb. - */ - void *cb_cls; - - /** - * Plugin context. - */ - struct PostgresClosure *pg; - - /** - * Status code, set to #GNUNET_SYSERR on hard errors. - */ - enum GNUNET_GenericReturnValue status; -}; - - -/** - * Helper function to be called with the results of a SELECT statement - * that has returned @a num_results results. - * - * @param cls closure of type `struct HistoryRequestSerialContext` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -history_request_serial_helper_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct HistoryRequestSerialContext *dsc = cls; - struct PostgresClosure *pg = dsc->pg; - - for (unsigned int i = 0; istatus = GNUNET_SYSERR; - return; - } - ret = dsc->cb (dsc->cb_cls, - rowid, - &history_fee, - ts, - &reserve_pub, - &reserve_sig); - GNUNET_PQ_cleanup_result (rs); - if (GNUNET_OK != ret) - break; - } -} - - -enum GNUNET_DB_QueryStatus -TEH_PG_select_history_requests_above_serial_id ( - void *cls, - uint64_t serial_id, - TALER_EXCHANGEDB_HistoryRequestCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&serial_id), - GNUNET_PQ_query_param_end - }; - struct HistoryRequestSerialContext dsc = { - .cb = cb, - .cb_cls = cb_cls, - .pg = pg, - .status = GNUNET_OK - }; - enum GNUNET_DB_QueryStatus qs; - PREPARE (pg, - "audit_get_history_requests_incr", - "SELECT" - " history_request_serial_id" - ",history_fee" - ",request_timestamp" - ",reserve_pub" - ",reserve_sig" - " FROM history_requests" - " WHERE (" - " (history_request_serial_id>=$1)" - " )" - " ORDER BY history_request_serial_id ASC;"); - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "audit_get_history_requests_incr", - params, - &history_request_serial_helper_cb, - &dsc); - if (GNUNET_OK != dsc.status) - return GNUNET_DB_STATUS_HARD_ERROR; - return qs; -} diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.h b/src/exchangedb/pg_select_history_requests_above_serial_id.h deleted file mode 100644 index b16efdce1..000000000 --- a/src/exchangedb/pg_select_history_requests_above_serial_id.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - */ -/** - * @file exchangedb/pg_select_history_requests_above_serial_id.h - * @brief implementation of the select_history_requests_above_serial_id function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_SELECT_HISTORY_REQUESTS_ABOVE_SERIAL_ID_H -#define PG_SELECT_HISTORY_REQUESTS_ABOVE_SERIAL_ID_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" -/** - * Select history requests above @a serial_id in monotonically increasing - * order. - * - * @param cls closure - * @param serial_id highest serial ID to exclude (select strictly larger) - * @param cb function to call on each result - * @param cb_cls closure for @a cb - * @return transaction status code - */ -enum GNUNET_DB_QueryStatus -TEH_PG_select_history_requests_above_serial_id ( - void *cls, - uint64_t serial_id, - TALER_EXCHANGEDB_HistoryRequestCallback cb, - void *cb_cls); - -#endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index c6e55d017..aacc29681 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -92,7 +92,6 @@ #include "pg_update_auditor.h" #include "pg_begin_revolving_shard.h" #include "pg_get_extension_manifest.h" -#include "pg_insert_history_request.h" #include "pg_do_purse_delete.h" #include "pg_do_purse_merge.h" #include "pg_start_read_committed.h" @@ -160,7 +159,6 @@ #include "pg_store_wire_transfer_out.h" #include "pg_gc.h" #include "pg_select_coin_deposits_above_serial_id.h" -#include "pg_select_history_requests_above_serial_id.h" #include "pg_select_purse_decisions_above_serial_id.h" #include "pg_select_purse_deposits_by_purse.h" #include "pg_select_refreshes_above_serial_id.h" @@ -429,8 +427,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_get_purse_request; plugin->get_reserve_history = &TEH_PG_get_reserve_history; - plugin->get_reserve_status - = &TEH_PG_get_reserve_status; plugin->get_unfinished_close_requests = &TEH_PG_get_unfinished_close_requests; plugin->insert_records_by_table @@ -531,8 +527,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_begin_revolving_shard; plugin->get_extension_manifest = &TEH_PG_get_extension_manifest; - plugin->insert_history_request - = &TEH_PG_insert_history_request; plugin->do_purse_merge = &TEH_PG_do_purse_merge; plugin->do_purse_delete @@ -667,8 +661,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_gc; plugin->select_coin_deposits_above_serial_id = &TEH_PG_select_coin_deposits_above_serial_id; - plugin->select_history_requests_above_serial_id - = &TEH_PG_select_history_requests_above_serial_id; plugin->select_purse_decisions_above_serial_id = &TEH_PG_select_purse_decisions_above_serial_id; plugin->select_purse_deposits_by_purse diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in index b963900c9..998c2c160 100644 --- a/src/exchangedb/procedures.sql.in +++ b/src/exchangedb/procedures.sql.in @@ -37,7 +37,6 @@ SET search_path TO exchange; #include "exchange_do_purse_merge.sql" #include "exchange_do_reserve_purse.sql" #include "exchange_do_expire_purse.sql" -#include "exchange_do_history_request.sql" #include "exchange_do_reserve_open_deposit.sql" #include "exchange_do_reserve_open.sql" #include "exchange_do_insert_or_update_policy_details.sql" diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 217df2bb4..9a30a1895 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1863,6 +1863,7 @@ run (void *cls) qs = plugin->get_reserve_history (plugin->cls, &reserve_pub, + 0, &balance, &rh); } diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 67e5ff713..dfce91cdb 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -3854,63 +3854,59 @@ TALER_wallet_recoup_refresh_sign ( /** * Verify reserve history request signature. * - * @param ts timestamp used - * @param history_fee how much did the wallet say it would pay + * @param start_off start of the requested range * @param reserve_pub reserve the history request was for * @param reserve_sig resulting signature * @return #GNUNET_OK if the signature is valid */ enum GNUNET_GenericReturnValue TALER_wallet_reserve_history_verify ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_Amount *history_fee, + uint64_t start_off, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig); /** - * Create reserve history request signature. + * Create reserve status request signature. * - * @param ts timestamp used - * @param history_fee how much do we expect to pay + * @param start_off start of the requested range * @param reserve_priv private key of the reserve the history request is for * @param[out] reserve_sig resulting signature */ void TALER_wallet_reserve_history_sign ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_Amount *history_fee, + uint64_t start_off, const struct TALER_ReservePrivateKeyP *reserve_priv, struct TALER_ReserveSignatureP *reserve_sig); /** - * Verify reserve status request signature. + * Verify coin history request signature. * - * @param ts timestamp used - * @param reserve_pub reserve the status request was for - * @param reserve_sig resulting signature + * @param start_off start of the requested range + * @param coin_pub coin the history request was for + * @param coin_sig resulting signature * @return #GNUNET_OK if the signature is valid */ enum GNUNET_GenericReturnValue -TALER_wallet_reserve_status_verify ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig); +TALER_wallet_coin_history_verify ( + uint64_t start_off, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig); /** - * Create reserve status request signature. + * Create coin status request signature. * - * @param ts timestamp used - * @param reserve_priv private key of the reserve the status request is for - * @param[out] reserve_sig resulting signature + * @param start_off start of the requested range + * @param coin_priv private key of the coin the history request is for + * @param[out] coin_sig resulting signature */ void -TALER_wallet_reserve_status_sign ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePrivateKeyP *reserve_priv, - struct TALER_ReserveSignatureP *reserve_sig); +TALER_wallet_coin_history_sign ( + uint64_t start_off, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig); /* ********************* merchant signing ************************** */ diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 730451d12..77d4f2bad 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1171,8 +1171,11 @@ struct TALER_EXCHANGE_BatchDepositResult */ struct { - /* FIXME: returning full details is not implemented */ - // Should have 'coin_pub' here! + /** + * The coin that had a conflict. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + } conflict; } details; @@ -1611,11 +1614,6 @@ enum TALER_EXCHANGE_ReserveTransactionType */ TALER_EXCHANGE_RTT_CLOSING, - /** - * Reserve history request. - */ - TALER_EXCHANGE_RTT_HISTORY, - /** * Reserve purse merge operation. */ @@ -1650,6 +1648,13 @@ struct TALER_EXCHANGE_ReserveHistoryEntry */ struct TALER_Amount amount; + /** + * Index of this entry in the reserve history. + * Useful to filter requests by starting offset. + * Offsets are not necessarily contiguous. + */ + uint64_t entry_off; + /** * Details depending on @e type. */ @@ -1787,25 +1792,6 @@ struct TALER_EXCHANGE_ReserveHistoryEntry } close_details; - /** - * Information about a history operation of the reserve. - * @e type is #TALER_EXCHANGE_RTT_HISTORY. - */ - struct - { - - /** - * When was the request made. - */ - struct GNUNET_TIME_Timestamp request_timestamp; - - /** - * Signature by the reserve approving the history request. - */ - struct TALER_ReserveSignatureP reserve_sig; - - } history_details; - /** * Information about a merge operation on the reserve. * @e type is #TALER_EXCHANGE_RTT_MERGE. @@ -2031,115 +2017,6 @@ TALER_EXCHANGE_reserves_get_cancel ( struct TALER_EXCHANGE_ReservesGetHandle *rgh); -/** - * @brief A /reserves/$RID/status Handle - */ -struct TALER_EXCHANGE_ReservesStatusHandle; - - -/** - * @brief Reserve status details. - */ -struct TALER_EXCHANGE_ReserveStatus -{ - - /** - * High-level HTTP response details. - */ - struct TALER_EXCHANGE_HttpResponse hr; - - /** - * Details depending on @e hr.http_status. - */ - union - { - - /** - * Information returned on success, if - * @e hr.http_status is #MHD_HTTP_OK - */ - struct - { - - /** - * Current reserve balance. May not be the difference between - * @e total_in and @e total_out because the @e may be truncated. - */ - struct TALER_Amount balance; - - /** - * Total of all inbound transactions in @e history. - */ - struct TALER_Amount total_in; - - /** - * Total of all outbound transactions in @e history. - */ - struct TALER_Amount total_out; - - /** - * Reserve history. - */ - const struct TALER_EXCHANGE_ReserveHistoryEntry *history; - - /** - * Length of the @e history array. - */ - unsigned int history_len; - - } ok; - - } details; - -}; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * reserve status request to a exchange. - * - * @param cls closure - * @param rs HTTP response data - */ -typedef void -(*TALER_EXCHANGE_ReservesStatusCallback) ( - void *cls, - const struct TALER_EXCHANGE_ReserveStatus *rs); - - -/** - * Submit a request to obtain the reserve status. - * - * @param ctx curl context - * @param url exchange base URL - * @param keys exchange keys - * @param reserve_priv private key of the reserve to inspect - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @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_ReservesStatusHandle * -TALER_EXCHANGE_reserves_status ( - struct GNUNET_CURL_Context *ctx, - const char *url, - struct TALER_EXCHANGE_Keys *keys, - const struct TALER_ReservePrivateKeyP *reserve_priv, - TALER_EXCHANGE_ReservesStatusCallback cb, - void *cb_cls); - - -/** - * Cancel a reserve status request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param rsh the reserve request handle - */ -void -TALER_EXCHANGE_reserves_status_cancel ( - struct TALER_EXCHANGE_ReservesStatusHandle *rsh); - - /** * @brief A /reserves/$RID/history Handle */ @@ -2158,34 +2035,21 @@ struct TALER_EXCHANGE_ReserveHistory struct TALER_EXCHANGE_HttpResponse hr; /** - * Timestamp of when we made the history request - * (client-side). - */ - struct GNUNET_TIME_Timestamp ts; - - /** - * Reserve signature affirming the history request - * (generated as part of the request). - */ - const struct TALER_ReserveSignatureP *reserve_sig; - - /** - * Details depending on @e hr.http_status. + * Details depending on @e hr.http_history. */ union { /** * Information returned on success, if - * @e hr.http_status is #MHD_HTTP_OK + * @e hr.http_history is #MHD_HTTP_OK */ struct { /** - * Reserve balance. May not be the difference between - * @e total_in and @e total_out because the @e may be truncated - * due to expiration. + * Current reserve balance. May not be the difference between + * @e total_in and @e total_out because the @e may be truncated. */ struct TALER_Amount balance; @@ -2236,6 +2100,7 @@ typedef void * @param url exchange base URL * @param keys exchange keys * @param reserve_priv private key of the reserve to inspect + * @param start_off offset of the oldest history entry to exclude from the response * @param cb the callback to call when a reply for this request is available * @param cb_cls closure for the above callback * @return a handle for this request; NULL if the inputs are invalid (i.e. @@ -2247,6 +2112,7 @@ TALER_EXCHANGE_reserves_history ( const char *url, struct TALER_EXCHANGE_Keys *keys, const struct TALER_ReservePrivateKeyP *reserve_priv, + uint64_t start_off, TALER_EXCHANGE_ReservesHistoryCallback cb, void *cb_cls); @@ -6866,6 +6732,18 @@ struct TALER_EXCHANGE_ReserveOpenResult } payment_required; + /** + * Information returned if status is + * #MHD_HTTP_CONFLICT. + */ + struct + { + /** + * Public key of the coin that caused the conflict. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + } conflict; /** * Information returned if KYC is required to proceed, set if diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 8fd9ce19f..cc71f7770 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -2739,29 +2739,6 @@ typedef enum GNUNET_GenericReturnValue struct GNUNET_TIME_Timestamp merge_timestamp); -/** - * Function called with details about - * history requests that have been made, with - * the goal of auditing the history request execution. - * - * @param cls closure - * @param rowid unique serial ID for the deposit in our DB - * @param history_fee fee paid for the request - * @param ts timestamp of the request - * @param reserve_pub reserve history was requested for - * @param reserve_sig signature approving the @a history_fee - * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop - */ -typedef enum GNUNET_GenericReturnValue -(*TALER_EXCHANGEDB_HistoryRequestCallback)( - void *cls, - uint64_t rowid, - const struct TALER_Amount *history_fee, - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig); - - /** * Function called with details about purse decisions that have been made, with * the goal of auditing the purse's execution. @@ -4249,6 +4226,7 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls the @e cls of this struct with the plugin-specific state * @param reserve_pub public key of the reserve + * @param start_off maximum starting offset in history to exclude from returning * @param[out] balance set to the reserve balance * @param[out] rhp set to known transaction history (NULL if reserve is unknown) * @return transaction status @@ -4256,31 +4234,11 @@ struct TALER_EXCHANGEDB_Plugin enum GNUNET_DB_QueryStatus (*get_reserve_history)(void *cls, const struct TALER_ReservePublicKeyP *reserve_pub, + uint64_t start_off, struct TALER_Amount *balance, struct TALER_EXCHANGEDB_ReserveHistory **rhp); - /** - * Get truncated transaction history associated with the specified - * reserve. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param reserve_pub public key of the reserve - * @param[out] balance_in set to the total of inbound - * transactions in the returned history - * @param[out] balance_out set to the total of outbound - * transactions in the returned history - * @param[out] rhp set to known transaction history (NULL if reserve is unknown) - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*get_reserve_status)(void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct TALER_Amount *balance_in, - struct TALER_Amount *balance_out, - struct TALER_EXCHANGEDB_ReserveHistory **rhp); - - /** * The current reserve balance of the specified reserve. * @@ -5252,24 +5210,6 @@ struct TALER_EXCHANGEDB_Plugin void *cb_cls); - /** - * Select history requests above @a serial_id in monotonically increasing - * order. - * - * @param cls closure - * @param serial_id highest serial ID to exclude (select strictly larger) - * @param cb function to call on each result - * @param cb_cls closure for @a cb - * @return transaction status code - */ - enum GNUNET_DB_QueryStatus - (*select_history_requests_above_serial_id)( - void *cls, - uint64_t serial_id, - TALER_EXCHANGEDB_HistoryRequestCallback cb, - void *cb_cls); - - /** * Select purse refunds above @a serial_id in monotonically increasing * order. @@ -6589,33 +6529,6 @@ struct TALER_EXCHANGEDB_Plugin struct TALER_ReservePublicKeyP *reserve_pub); - /** - * Function called to persist a signature that - * prove that the client requested an - * account history. Debits the @a history_fee from - * the reserve (if possible). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param reserve_pub account that the history was requested for - * @param reserve_sig signature affirming the request - * @param request_timestamp when was the request made - * @param history_fee how much should the @a reserve_pub be charged for the request - * @param[out] balance_ok set to TRUE if the reserve balance - * was sufficient - * @param[out] idempotent set to TRUE if the request is already in the DB - * @return transaction status code - */ - enum GNUNET_DB_QueryStatus - (*insert_history_request)( - void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig, - struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *history_fee, - bool *balance_ok, - bool *idempotent); - - /** * Function called to initiate closure of an account. * diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 367b54bba..5506f025c 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -1289,22 +1289,6 @@ TALER_TESTING_cmd_reserve_history (const char *label, unsigned int expected_response_code); -/** - * Create a POST "/reserves/$RID/status" command. - * - * @param label the command label. - * @param reserve_reference reference to the reserve to check. - * @param expected_balance expected balance for the reserve. - * @param expected_response_code expected HTTP response code. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_reserve_status (const char *label, - const char *reserve_reference, - const char *expected_balance, - unsigned int expected_response_code); - - /** * Create a POST "/reserves/$RID/open" command. * diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 6ff8e2371..ff5d3b801 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -73,7 +73,6 @@ libtalerexchange_la_SOURCES = \ exchange_api_reserves_get_attestable.c \ exchange_api_reserves_history.c \ exchange_api_reserves_open.c \ - exchange_api_reserves_status.c \ exchange_api_stefan.c \ exchange_api_transfers_get.c \ exchange_api_withdraw.c \ diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c index 3aea22b64..273b25e85 100644 --- a/src/lib/exchange_api_batch_deposit.c +++ b/src/lib/exchange_api_batch_deposit.c @@ -464,14 +464,11 @@ handle_deposit_finished (void *cls, break; case MHD_HTTP_CONFLICT: { - struct TALER_CoinSpendPublicKeyP coin_pub; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("coin_pub", - &coin_pub), + &dr->details.conflict.coin_pub), GNUNET_JSON_spec_end () }; - const struct TALER_EXCHANGE_DenomPublicKey *dki; - bool found = false; if (GNUNET_OK != GNUNET_JSON_parse (j, @@ -483,40 +480,6 @@ handle_deposit_finished (void *cls, dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - for (unsigned int i = 0; inum_cdds; i++) - { - if (0 != - GNUNET_memcmp (&coin_pub, - &dh->cdds[i].coin_pub)) - continue; - 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_ ( - dh->keys, - j, - dki, - &dh->cdds[i].coin_pub, - &dh->cdds[i].coin_sig, - &dh->cdds[i].amount)) - { - GNUNET_break_op (0); - dr->hr.http_status = 0; - dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - found = true; - break; - } - if (! found) - { - GNUNET_break_op (0); - 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); } diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 609a2f7ef..3ad880171 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -478,59 +478,6 @@ parse_merge (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, } -/** - * Parse "history" reserve history entry. - * - * @param[in,out] rh entry to parse - * @param uc our context - * @param transaction the transaction to parse - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -parse_history (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, - struct HistoryParseContext *uc, - const json_t *transaction) -{ - struct GNUNET_JSON_Specification history_spec[] = { - GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &rh->details.history_details.reserve_sig), - GNUNET_JSON_spec_timestamp ("request_timestamp", - &rh->details.history_details.request_timestamp), - GNUNET_JSON_spec_end () - }; - - rh->type = TALER_EXCHANGE_RTT_HISTORY; - if (GNUNET_OK != - GNUNET_JSON_parse (transaction, - history_spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_wallet_reserve_history_verify ( - rh->details.history_details.request_timestamp, - &rh->amount, - uc->reserve_pub, - &rh->details.history_details.reserve_sig)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 > - TALER_amount_add (uc->total_out, - uc->total_out, - &rh->amount)) - { - /* overflow in history already!? inconceivable! Bad exchange! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - /** * Parse "open" reserve open entry. * @@ -666,7 +613,6 @@ TALER_EXCHANGE_parse_reserve_history ( { "RECOUP", &parse_recoup }, { "MERGE", &parse_merge }, { "CLOSING", &parse_closing }, - { "HISTORY", &parse_history }, { "OPEN", &parse_open }, { "CLOSE", &parse_close }, { NULL, NULL } @@ -771,8 +717,6 @@ TALER_EXCHANGE_free_reserve_history ( break; case TALER_EXCHANGE_RTT_CLOSING: break; - case TALER_EXCHANGE_RTT_HISTORY: - break; case TALER_EXCHANGE_RTT_MERGE: break; case TALER_EXCHANGE_RTT_OPEN: @@ -1867,66 +1811,6 @@ TALER_EXCHANGE_check_purse_econtract_conflict_ ( } -enum GNUNET_GenericReturnValue -TALER_EXCHANGE_check_coin_amount_conflict_ ( - const struct TALER_EXCHANGE_Keys *keys, - const json_t *proof, - struct TALER_CoinSpendPublicKeyP *coin_pub, - struct TALER_Amount *remaining) -{ - const json_t *history; - struct TALER_Amount total; - struct TALER_DenominationHashP h_denom_pub; - const struct TALER_EXCHANGE_DenomPublicKey *dki; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("coin_pub", - coin_pub), - GNUNET_JSON_spec_fixed_auto ("h_denom_pub", - &h_denom_pub), - GNUNET_JSON_spec_array_const ("history", - &history), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (proof, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - dki = TALER_EXCHANGE_get_denomination_key_by_hash ( - keys, - &h_denom_pub); - if (NULL == dki) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_EXCHANGE_verify_coin_history (dki, - coin_pub, - history, - &total)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 > - TALER_amount_subtract (remaining, - &dki->value, - &total)) - { - /* Strange 'proof': coin was double-spent - before our transaction?! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - /** * Verify that @a coin_sig does NOT appear in * the history of @a proof and thus whatever transaction @@ -1937,6 +1821,7 @@ TALER_EXCHANGE_check_coin_amount_conflict_ ( * @param coin_sig signature that must not be in @a proof * @return #GNUNET_OK if @a coin_sig is not in @a proof */ +// FIXME: move to exchange_api_coin_history.c! enum GNUNET_GenericReturnValue TALER_EXCHANGE_check_coin_signature_conflict_ ( const json_t *proof, @@ -2011,13 +1896,25 @@ TALER_EXCHANGE_check_coin_denomination_conflict_ ( } +/** + * Check that the provided @a proof indeeds indicates + * a conflict for @a coin_pub. + * + * @param keys exchange keys + * @param proof provided conflict proof + * @param dk denomination of @a coin_pub that the client + * used + * @param coin_pub public key of the coin + * @param required balance required on the coin for the operation + * @return #GNUNET_OK if @a proof holds + */ +// FIXME: move to exchange_api_coin_history.c! enum GNUNET_GenericReturnValue TALER_EXCHANGE_check_coin_conflict_ ( const struct TALER_EXCHANGE_Keys *keys, const json_t *proof, const struct TALER_EXCHANGE_DenomPublicKey *dk, const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *required) { enum TALER_ErrorCode ec; @@ -2026,81 +1923,12 @@ TALER_EXCHANGE_check_coin_conflict_ ( switch (ec) { case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: - { - struct TALER_Amount left; - struct TALER_CoinSpendPublicKeyP pcoin_pub; - - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_amount_conflict_ ( - keys, - proof, - &pcoin_pub, - &left)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 != - GNUNET_memcmp (&pcoin_pub, - coin_pub)) - { - /* conflict is for a different coin! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (-1 != - TALER_amount_cmp (&left, - required)) - { - /* Balance was sufficient after all; recoup MAY have still been possible */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_signature_conflict_ ( - proof, - coin_sig)) - { - /* Not a conflicting transaction: ours is included! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - break; - } + /* Nothing to check anymore here, proof needs to be + checked in the GET /coins/$COIN_PUB handler */ + break; case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: - { - struct TALER_Amount left; - struct TALER_CoinSpendPublicKeyP pcoin_pub; - - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_amount_conflict_ ( - keys, - proof, - &pcoin_pub, - &left)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 != - GNUNET_memcmp (&pcoin_pub, - coin_pub)) - { - /* conflict is for a different coin! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_denomination_conflict_ ( - proof, - &dk->h_key)) - { - /* Eh, same denomination, hence no conflict */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - break; - } + // FIXME: write check! + break; default: GNUNET_break_op (0); return GNUNET_SYSERR; diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h index 1b9ddce34..0fcaac3f3 100644 --- a/src/lib/exchange_api_common.h +++ b/src/lib/exchange_api_common.h @@ -170,7 +170,6 @@ TALER_EXCHANGE_check_coin_signature_conflict_ ( * @param dk denomination of @a coin_pub that the client * used * @param coin_pub public key of the coin - * @param coin_sig signature over operation that conflicted * @param required balance required on the coin for the operation * @return #GNUNET_OK if @a proof holds */ @@ -180,7 +179,6 @@ TALER_EXCHANGE_check_coin_conflict_ ( const json_t *proof, const struct TALER_EXCHANGE_DenomPublicKey *dk, const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *required); diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c index 7fbd2114c..ba4241dab 100644 --- a/src/lib/exchange_api_melt.c +++ b/src/lib/exchange_api_melt.c @@ -218,10 +218,8 @@ handle_melt_finished (void *cls, .hr.reply = j, .hr.http_status = (unsigned int) response_code }; - const struct TALER_EXCHANGE_Keys *keys; mh->job = NULL; - keys = mh->keys; switch (response_code) { case 0: @@ -254,20 +252,6 @@ handle_melt_finished (void *cls, case MHD_HTTP_CONFLICT: mr.hr.ec = TALER_JSON_get_error_code (j); mr.hr.hint = TALER_JSON_get_error_hint (j); - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_conflict_ ( - keys, - j, - mh->dki, - &mh->coin_pub, - &mh->coin_sig, - &mh->md.melted_coin.melt_amount_with_fee)) - { - GNUNET_break_op (0); - mr.hr.http_status = 0; - mr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } break; case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c index 13874678a..c64beedec 100644 --- a/src/lib/exchange_api_purse_create_with_deposit.c +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -277,107 +277,12 @@ handle_purse_create_deposit_finished (void *cls, } break; case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: - { - struct TALER_Amount left; - struct TALER_CoinSpendPublicKeyP pcoin_pub; - bool found = false; - - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_amount_conflict_ ( - keys, - j, - &pcoin_pub, - &left)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - for (unsigned int i = 0; inum_deposits; i++) - { - struct Deposit *deposit = &pch->deposits[i]; - - if (0 != GNUNET_memcmp (&pcoin_pub, - &deposit->coin_pub)) - continue; - if (-1 != - TALER_amount_cmp (&left, - &deposit->contribution)) - { - /* Balance was sufficient after all; operation MAY have still been possible */ - GNUNET_break_op (0); - continue; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_signature_conflict_ ( - j, - &deposit->coin_sig)) - { - GNUNET_break_op (0); - continue; - } - found = true; - break; - } - if (! found) - { - /* conflict is for a different coin! */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - break; - } + /* Nothing to check anymore here, proof needs to be + checked in the GET /coins/$COIN_PUB handler */ + break; case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: - { - struct TALER_Amount left; - struct TALER_CoinSpendPublicKeyP pcoin_pub; - bool found = false; - - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_amount_conflict_ ( - keys, - j, - &pcoin_pub, - &left)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - for (unsigned int i = 0; inum_deposits; i++) - { - struct Deposit *deposit = &pch->deposits[i]; - - if (0 != - GNUNET_memcmp (&pcoin_pub, - &deposit->coin_pub)) - continue; - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_denomination_conflict_ ( - j, - &deposit->h_denom_pub)) - { - /* Eh, same denomination, hence no conflict */ - GNUNET_break_op (0); - continue; - } - found = true; - } - if (! found) - { - /* conflict is for a different coin! */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - /* meta data conflict is real! */ - break; - } + // FIXME: write check (add to exchange_api_common! */ + break; case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA: { struct TALER_CoinSpendPublicKeyP coin_pub; diff --git a/src/lib/exchange_api_purse_deposit.c b/src/lib/exchange_api_purse_deposit.c index 7bb3b9517..7db2f34c7 100644 --- a/src/lib/exchange_api_purse_deposit.c +++ b/src/lib/exchange_api_purse_deposit.c @@ -297,114 +297,11 @@ handle_purse_deposit_finished (void *cls, break; } case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: - { - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_Amount remaining; - bool found = false; - const struct Coin *my_coin; - - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_amount_conflict_ ( - keys, - j, - &coin_pub, - &remaining)) - { - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - for (unsigned int i = 0; inum_deposits; i++) - { - if (0 == GNUNET_memcmp (&coin_pub, - &pch->coins[i].coin_pub)) - { - found = true; - my_coin = &pch->coins[i]; - break; - } - } - if (! found) - { - /* proof is about a coin we did not even deposit */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - if (1 == TALER_amount_cmp (&remaining, - &my_coin->contribution)) - { - /* transaction should have still fit */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_signature_conflict_ ( - j, - &my_coin->coin_sig)) - { - /* THIS transaction must not be in the conflicting history */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - /* everything OK, proof of double-spending was provided */ - break; - } + /* Nothing to check anymore here, proof needs to be + checked in the GET /coins/$COIN_PUB handler */ + break; case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: - { - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_Amount remaining; - bool found = false; - const struct Coin *my_coin; - - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_amount_conflict_ ( - keys, - j, - &coin_pub, - &remaining)) - { - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - for (unsigned int i = 0; inum_deposits; i++) - { - if (0 == GNUNET_memcmp (&coin_pub, - &pch->coins[i].coin_pub)) - { - found = true; - my_coin = &pch->coins[i]; - break; - } - } - if (! found) - { - /* proof is about a coin we did not even deposit */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_denomination_conflict_ ( - j, - &my_coin->h_denom_pub)) - { - /* no conflicting denomination detected */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - /* everything OK, proof of conflicting denomination was provided */ - break; - } + break; default: GNUNET_break_op (0); dr.hr.http_status = 0; diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c index e7daff165..cfd265f04 100644 --- a/src/lib/exchange_api_recoup.c +++ b/src/lib/exchange_api_recoup.c @@ -183,20 +183,6 @@ handle_recoup_finished (void *cls, rr.hr.http_status = 0; break; } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_conflict_ ( - ph->keys, - j, - &ph->pk, - &ph->coin_pub, - &ph->coin_sig, - &min_key)) - { - GNUNET_break (0); - rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - rr.hr.http_status = 0; - break; - } break; } case MHD_HTTP_FORBIDDEN: diff --git a/src/lib/exchange_api_recoup_refresh.c b/src/lib/exchange_api_recoup_refresh.c index f5745deb0..0bcd44dec 100644 --- a/src/lib/exchange_api_recoup_refresh.c +++ b/src/lib/exchange_api_recoup_refresh.c @@ -183,36 +183,9 @@ handle_recoup_refresh_finished (void *cls, rrr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: - { - struct TALER_Amount min_key; - - rrr.hr.ec = TALER_JSON_get_error_code (j); - rrr.hr.hint = TALER_JSON_get_error_hint (j); - if (GNUNET_OK != - TALER_EXCHANGE_get_min_denomination_ (ph->keys, - &min_key)) - { - GNUNET_break (0); - rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - rrr.hr.http_status = 0; - break; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_conflict_ ( - ph->keys, - j, - &ph->pk, - &ph->coin_pub, - &ph->coin_sig, - &min_key)) - { - GNUNET_break (0); - rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - rrr.hr.http_status = 0; - break; - } - break; - } + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); + break; case MHD_HTTP_GONE: /* Kind of normal: the money was already sent to the merchant (it was too late for the refund). */ diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c index 3f12f28d6..7401bfe4f 100644 --- a/src/lib/exchange_api_refund.c +++ b/src/lib/exchange_api_refund.c @@ -157,307 +157,6 @@ verify_refund_signature_ok (struct TALER_EXCHANGE_RefundHandle *rh, } -/** - * Verify that the information in the "409 Conflict" response - * from the exchange is valid and indeed shows that the refund - * amount requested is too high. - * - * @param[in,out] rh refund handle (refund fee added) - * @param json json reply with the coin transaction history - * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not - */ -static enum GNUNET_GenericReturnValue -verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh, - const json_t *json) -{ - const json_t *history; - struct TALER_DenominationHashP h_denom_pub; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("history", - &history), - GNUNET_JSON_spec_fixed_auto ("h_denom_pub", - &h_denom_pub), - GNUNET_JSON_spec_end () - }; - size_t len; - struct TALER_Amount dtotal; - bool have_deposit; - struct TALER_Amount rtotal; - bool have_refund; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - len = json_array_size (history); - if (0 == len) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - have_deposit = false; - have_refund = false; - for (size_t off = 0; offcoin_pub, - &sig)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if ( (0 != GNUNET_memcmp (&rh->h_contract_terms, - &h_contract_terms)) || - (0 != GNUNET_memcmp (&rh->merchant, - &merchant_pub)) ) - { - /* deposit information is about a different merchant/contract */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (have_deposit) - { - /* this cannot really happen, but we conservatively support it anyway */ - if (GNUNET_YES != - TALER_amount_cmp_currency (&amount, - &dtotal)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_break (0 <= - TALER_amount_add (&dtotal, - &dtotal, - &amount)); - } - else - { - dtotal = amount; - have_deposit = true; - } - } - else if (0 == strcasecmp (type, - "REFUND")) - { - struct TALER_MerchantSignatureP sig; - struct TALER_Amount refund_fee; - struct TALER_Amount sig_amount; - struct TALER_PrivateContractHashP h_contract_terms; - uint64_t rtransaction_id; - struct TALER_MerchantPublicKeyP merchant_pub; - struct GNUNET_JSON_Specification ispec[] = { - TALER_JSON_spec_amount_any ("refund_fee", - &refund_fee), - GNUNET_JSON_spec_fixed_auto ("merchant_sig", - &sig), - GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &h_contract_terms), - GNUNET_JSON_spec_fixed_auto ("merchant_pub", - &merchant_pub), - GNUNET_JSON_spec_uint64 ("rtransaction_id", - &rtransaction_id), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (transaction, - ispec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 > - TALER_amount_add (&sig_amount, - &refund_fee, - &amount)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_merchant_refund_verify (&rh->coin_pub, - &h_contract_terms, - rtransaction_id, - &sig_amount, - &merchant_pub, - &sig)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if ( (0 != GNUNET_memcmp (&rh->h_contract_terms, - &h_contract_terms)) || - (0 != GNUNET_memcmp (&rh->merchant, - &merchant_pub)) ) - { - /* refund is about a different merchant/contract */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (rtransaction_id == rh->rtransaction_id) - { - /* Eh, this shows either a dependency failure or idempotency, - but must not happen in a conflict reply. Fail! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - if (have_refund) - { - if (GNUNET_YES != - TALER_amount_cmp_currency (&amount, - &rtotal)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_break (0 <= - TALER_amount_add (&rtotal, - &rtotal, - &amount)); - } - else - { - rtotal = amount; - have_refund = true; - } - } - else - { - /* unexpected type, new version on server? */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected type `%s' in response for exchange refund\n", - type); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - } - - if (have_refund) - { - if (0 > - TALER_amount_add (&rtotal, - &rtotal, - &rh->refund_amount)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - } - else - { - rtotal = rh->refund_amount; - have_refund = true; - } - if (! have_deposit) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (-1 != TALER_amount_cmp (&dtotal, - &rtotal)) - { - /* rtotal <= dtotal is fine, no conflict! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* dtotal < rtotal: that's a conflict! */ - return GNUNET_OK; -} - - /** * Verify that the information on the "412 Dependency Failed" response * from the exchange is valid and indeed shows that there is a refund @@ -615,19 +314,6 @@ handle_refund_finished (void *cls, break; case MHD_HTTP_CONFLICT: /* Requested total refunds exceed deposited amount */ - if (GNUNET_OK != - verify_conflict_history_ok (rh, - j)) - { - GNUNET_break (0); - json_dumpf (j, - stderr, - JSON_INDENT (2)); - rr.hr.http_status = 0; - rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; - rr.hr.hint = "conflict information provided by exchange is invalid"; - break; - } rr.hr.ec = TALER_JSON_get_error_code (j); rr.hr.hint = TALER_JSON_get_error_hint (j); break; diff --git a/src/lib/exchange_api_reserves_history.c b/src/lib/exchange_api_reserves_history.c index d4366eb37..c92fad5e8 100644 --- a/src/lib/exchange_api_reserves_history.c +++ b/src/lib/exchange_api_reserves_history.c @@ -64,25 +64,15 @@ struct TALER_EXCHANGE_ReservesHistoryHandle */ TALER_EXCHANGE_ReservesHistoryCallback cb; - /** - * Closure for @a cb. - */ - void *cb_cls; - /** * Public key of the reserve we are querying. */ struct TALER_ReservePublicKeyP reserve_pub; /** - * Our signature. - */ - struct TALER_ReserveSignatureP reserve_sig; - - /** - * When did we make the request. + * Closure for @a cb. */ - struct GNUNET_TIME_Timestamp ts; + void *cb_cls; }; @@ -103,9 +93,7 @@ handle_reserves_history_ok (struct TALER_EXCHANGE_ReservesHistoryHandle *rsh, unsigned int len; struct TALER_EXCHANGE_ReserveHistory rs = { .hr.reply = j, - .hr.http_status = MHD_HTTP_OK, - .ts = rsh->ts, - .reserve_sig = &rsh->reserve_sig + .hr.http_status = MHD_HTTP_OK }; struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount_any ("balance", @@ -143,6 +131,7 @@ handle_reserves_history_ok (struct TALER_EXCHANGE_ReservesHistoryHandle *rsh, GNUNET_break_op (0); TALER_EXCHANGE_free_reserve_history (len, rhistory); + GNUNET_JSON_parse_free (spec); return GNUNET_SYSERR; } if (NULL != rsh->cb) @@ -191,7 +180,6 @@ handle_reserves_history_finished (void *cls, handle_reserves_history_ok (rsh, j)) { - GNUNET_break_op (0); rs.hr.http_status = 0; rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; } @@ -216,11 +204,6 @@ handle_reserves_history_finished (void *cls, rs.hr.ec = TALER_JSON_get_error_code (j); rs.hr.hint = TALER_JSON_get_error_hint (j); break; - case MHD_HTTP_CONFLICT: - /* Insufficient balance to inquire for reserve history */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ @@ -254,18 +237,18 @@ TALER_EXCHANGE_reserves_history ( const char *url, struct TALER_EXCHANGE_Keys *keys, const struct TALER_ReservePrivateKeyP *reserve_priv, + uint64_t start_off, TALER_EXCHANGE_ReservesHistoryCallback cb, void *cb_cls) { struct TALER_EXCHANGE_ReservesHistoryHandle *rsh; CURL *eh; - char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; - const struct TALER_EXCHANGE_GlobalFee *gf; + char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 64]; + struct TALER_ReserveSignatureP reserve_sig; rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesHistoryHandle); rsh->cb = cb; rsh->cb_cls = cb_cls; - rsh->ts = GNUNET_TIME_timestamp_get (); GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, &rsh->reserve_pub.eddsa_pub); { @@ -278,10 +261,17 @@ TALER_EXCHANGE_reserves_history ( pub_str, sizeof (pub_str)); *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s/history", - pub_str); + if (0 != start_off) + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "reserves/%s/history?start=%llu", + pub_str, + (unsigned long long) start_off); + else + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "reserves/%s/history", + pub_str); } rsh->url = TALER_url_join (url, arg_str, @@ -299,26 +289,13 @@ TALER_EXCHANGE_reserves_history ( GNUNET_free (rsh); return NULL; } - gf = TALER_EXCHANGE_get_global_fee (keys, - rsh->ts); - if (NULL == gf) - { - GNUNET_break_op (0); - curl_easy_cleanup (eh); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - TALER_wallet_reserve_history_sign (rsh->ts, - &gf->fees.history, + TALER_wallet_reserve_history_sign (start_off, reserve_priv, - &rsh->reserve_sig); + &reserve_sig); { json_t *history_obj = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_timestamp ("request_timestamp", - rsh->ts), GNUNET_JSON_pack_data_auto ("reserve_sig", - &rsh->reserve_sig)); + &reserve_sig)); if (GNUNET_OK != TALER_curl_easy_post (&rsh->post_ctx, diff --git a/src/lib/exchange_api_reserves_open.c b/src/lib/exchange_api_reserves_open.c index 536efdb10..36e435685 100644 --- a/src/lib/exchange_api_reserves_open.c +++ b/src/lib/exchange_api_reserves_open.c @@ -322,11 +322,9 @@ handle_reserves_open_finished (void *cls, case MHD_HTTP_CONFLICT: { const struct CoinData *cd = NULL; - struct TALER_CoinSpendPublicKeyP coin_pub; - const struct TALER_EXCHANGE_DenomPublicKey *dk; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("coin_pub", - &coin_pub), + &rs.details.conflict.coin_pub), GNUNET_JSON_spec_end () }; @@ -345,7 +343,7 @@ handle_reserves_open_finished (void *cls, { const struct CoinData *cdi = &roh->coins[i]; - if (0 == GNUNET_memcmp (&coin_pub, + if (0 == GNUNET_memcmp (&rs.details.conflict.coin_pub, &cdi->coin_pub)) { cd = cdi; @@ -359,28 +357,6 @@ handle_reserves_open_finished (void *cls, rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - dk = TALER_EXCHANGE_get_denomination_key_by_hash (roh->keys, - &cd->h_denom_pub); - if (NULL == dk) - { - GNUNET_break_op (0); - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR; - break; - } - if (GNUNET_OK != - TALER_EXCHANGE_check_coin_conflict_ (roh->keys, - j, - dk, - &coin_pub, - &cd->coin_sig, - &cd->contribution)) - { - GNUNET_break_op (0); - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } rs.hr.ec = TALER_JSON_get_error_code (j); rs.hr.hint = TALER_JSON_get_error_hint (j); break; diff --git a/src/lib/exchange_api_reserves_status.c b/src/lib/exchange_api_reserves_status.c deleted file mode 100644 index 2ea64e8aa..000000000 --- a/src/lib/exchange_api_reserves_status.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/exchange_api_reserves_status.c - * @brief Implementation of the POST /reserves/$RESERVE_PUB/status requests - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include /* just for HTTP status codes */ -#include -#include -#include -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "exchange_api_curl_defaults.h" - - -/** - * @brief A /reserves/$RID/status Handle - */ -struct TALER_EXCHANGE_ReservesStatusHandle -{ - - /** - * The keys of the exchange this request handle will use - */ - struct TALER_EXCHANGE_Keys *keys; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Context for #TEH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; - - /** - * Function to call with the result. - */ - TALER_EXCHANGE_ReservesStatusCallback cb; - - /** - * Public key of the reserve we are querying. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Closure for @a cb. - */ - void *cb_cls; - -}; - - -/** - * We received an #MHD_HTTP_OK status code. Handle the JSON - * response. - * - * @param rsh handle of the request - * @param j JSON response - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -handle_reserves_status_ok (struct TALER_EXCHANGE_ReservesStatusHandle *rsh, - const json_t *j) -{ - const json_t *history; - unsigned int len; - struct TALER_EXCHANGE_ReserveStatus rs = { - .hr.reply = j, - .hr.http_status = MHD_HTTP_OK - }; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("balance", - &rs.details.ok.balance), - GNUNET_JSON_spec_array_const ("history", - &history), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - len = json_array_size (history); - { - struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory; - - rhistory = GNUNET_new_array (len, - struct TALER_EXCHANGE_ReserveHistoryEntry); - if (GNUNET_OK != - TALER_EXCHANGE_parse_reserve_history (rsh->keys, - history, - &rsh->reserve_pub, - rs.details.ok.balance.currency, - &rs.details.ok.total_in, - &rs.details.ok.total_out, - len, - rhistory)) - { - GNUNET_break_op (0); - TALER_EXCHANGE_free_reserve_history (len, - rhistory); - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; - } - if (NULL != rsh->cb) - { - rs.details.ok.history = rhistory; - rs.details.ok.history_len = len; - rsh->cb (rsh->cb_cls, - &rs); - rsh->cb = NULL; - } - TALER_EXCHANGE_free_reserve_history (len, - rhistory); - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserves/$RID/status request. - * - * @param cls the `struct TALER_EXCHANGE_ReservesStatusHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_reserves_status_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_EXCHANGE_ReservesStatusHandle *rsh = cls; - const json_t *j = response; - struct TALER_EXCHANGE_ReserveStatus rs = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - - rsh->job = NULL; - switch (response_code) - { - case 0: - rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - handle_reserves_status_ok (rsh, - j)) - { - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - 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 */ - GNUNET_break (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_FORBIDDEN: - /* This should never happen, either us or the exchange is buggy - (or API version conflict); just pass JSON reply to the application */ - GNUNET_break (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for reserves status\n", - (unsigned int) response_code, - (int) rs.hr.ec); - break; - } - if (NULL != rsh->cb) - { - rsh->cb (rsh->cb_cls, - &rs); - rsh->cb = NULL; - } - TALER_EXCHANGE_reserves_status_cancel (rsh); -} - - -struct TALER_EXCHANGE_ReservesStatusHandle * -TALER_EXCHANGE_reserves_status ( - struct GNUNET_CURL_Context *ctx, - const char *url, - struct TALER_EXCHANGE_Keys *keys, - const struct TALER_ReservePrivateKeyP *reserve_priv, - TALER_EXCHANGE_ReservesStatusCallback cb, - void *cb_cls) -{ - struct TALER_EXCHANGE_ReservesStatusHandle *rsh; - CURL *eh; - char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; - struct TALER_ReserveSignatureP reserve_sig; - struct GNUNET_TIME_Timestamp ts - = GNUNET_TIME_timestamp_get (); - - rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesStatusHandle); - rsh->cb = cb; - rsh->cb_cls = cb_cls; - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, - &rsh->reserve_pub.eddsa_pub); - { - char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; - char *end; - - end = GNUNET_STRINGS_data_to_string ( - &rsh->reserve_pub, - sizeof (rsh->reserve_pub), - pub_str, - sizeof (pub_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s/status", - pub_str); - } - rsh->url = TALER_url_join (url, - arg_str, - NULL); - if (NULL == rsh->url) - { - GNUNET_free (rsh); - return NULL; - } - eh = TALER_EXCHANGE_curl_easy_get_ (rsh->url); - if (NULL == eh) - { - GNUNET_break (0); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - TALER_wallet_reserve_status_sign (ts, - reserve_priv, - &reserve_sig); - { - json_t *status_obj = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_timestamp ("request_timestamp", - ts), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &reserve_sig)); - - if (GNUNET_OK != - TALER_curl_easy_post (&rsh->post_ctx, - eh, - status_obj)) - { - GNUNET_break (0); - curl_easy_cleanup (eh); - json_decref (status_obj); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - json_decref (status_obj); - } - rsh->keys = TALER_EXCHANGE_keys_incref (keys); - rsh->job = GNUNET_CURL_job_add2 (ctx, - eh, - rsh->post_ctx.headers, - &handle_reserves_status_finished, - rsh); - return rsh; -} - - -void -TALER_EXCHANGE_reserves_status_cancel ( - struct TALER_EXCHANGE_ReservesStatusHandle *rsh) -{ - if (NULL != rsh->job) - { - GNUNET_CURL_job_cancel (rsh->job); - rsh->job = NULL; - } - TALER_curl_easy_post_finished (&rsh->post_ctx); - GNUNET_free (rsh->url); - TALER_EXCHANGE_keys_decref (rsh->keys); - GNUNET_free (rsh); -} - - -/* end of exchange_api_reserves_status.c */ diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c index 6de7adccb..53a5934d8 100644 --- a/src/lib/exchange_api_withdraw2.c +++ b/src/lib/exchange_api_withdraw2.c @@ -128,101 +128,6 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh, } -/** - * We got a 409 CONFLICT response for the /reserves/$RESERVE_PUB/withdraw operation. - * Check the signatures on the withdraw transactions in the provided - * history and that the balances add up. We don't do anything directly - * with the information, as the JSON will be returned to the application. - * However, our job is ensuring that the exchange followed the protocol, and - * this in particular means checking all of the signatures in the history. - * - * @param wh operation handle - * @param json reply from the exchange - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static enum GNUNET_GenericReturnValue -reserve_withdraw_payment_required ( - struct TALER_EXCHANGE_Withdraw2Handle *wh, - const json_t *json) -{ - struct TALER_Amount balance; - struct TALER_Amount total_in_from_history; - struct TALER_Amount total_out_from_history; - json_t *history; - size_t len; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("balance", - &balance), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - history = json_object_get (json, - "history"); - if (NULL == history) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* go over transaction history and compute - total incoming and outgoing amounts */ - len = json_array_size (history); - { - struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory; - - /* Use heap allocation as "len" may be very big and thus this may - not fit on the stack. Use "GNUNET_malloc_large" as a malicious - exchange may theoretically try to crash us by giving a history - that does not fit into our memory. */ - rhistory = GNUNET_malloc_large ( - sizeof (struct TALER_EXCHANGE_ReserveHistoryEntry) - * len); - if (NULL == rhistory) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - TALER_EXCHANGE_parse_reserve_history (wh->keys, - history, - &wh->reserve_pub, - balance.currency, - &total_in_from_history, - &total_out_from_history, - len, - rhistory)) - { - GNUNET_break_op (0); - TALER_EXCHANGE_free_reserve_history (len, - rhistory); - return GNUNET_SYSERR; - } - TALER_EXCHANGE_free_reserve_history (len, - rhistory); - } - - /* Check that funds were really insufficient */ - if (0 >= TALER_amount_cmp (&wh->requested_amount, - &balance)) - { - /* Requested amount is smaller or equal to reported balance, - so this should not have failed. */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - /** * Function called when we're done processing the * HTTP /reserves/$RESERVE_PUB/withdraw request. @@ -287,20 +192,6 @@ handle_reserve_withdraw_finished (void *cls, case MHD_HTTP_CONFLICT: w2r.hr.ec = TALER_JSON_get_error_code (j); w2r.hr.hint = TALER_JSON_get_error_hint (j); - - if (TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED == w2r.hr.ec) - break; - - /* The exchange says that the reserve has insufficient funds; - check the signatures in the history... */ - if (GNUNET_OK != - reserve_withdraw_payment_required (wh, - j)) - { - GNUNET_break_op (0); - w2r.hr.http_status = 0; - w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } break; case MHD_HTTP_GONE: /* could happen if denomination was revoked */ diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 957f028d9..3a4f06323 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -100,7 +100,6 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_reserve_history.c \ testing_api_cmd_reserve_open.c \ testing_api_cmd_reserve_purse.c \ - testing_api_cmd_reserve_status.c \ testing_api_cmd_revoke.c \ testing_api_cmd_revoke_denom_key.c \ testing_api_cmd_revoke_sign_key.c \ diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c index 41b8301a3..e3ef5a5bb 100644 --- a/src/testing/test_exchange_api.c +++ b/src/testing/test_exchange_api.c @@ -1154,12 +1154,8 @@ run (void *cls, MHD_HTTP_OK), TALER_TESTING_cmd_reserve_history ("history-batch-1", "create-batch-reserve-1", - "EUR:0", + "EUR:0.01", MHD_HTTP_OK), - TALER_TESTING_cmd_status ("status-batch-2", - "create-batch-reserve-1", - "EUR:0.0", - MHD_HTTP_OK), /** * Spend the coins. */ diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c index 2fd7dfb29..6f25dd2b0 100644 --- a/src/testing/test_exchange_p2p.c +++ b/src/testing/test_exchange_p2p.c @@ -202,7 +202,7 @@ run (void *cls, "EUR:1.02", MHD_HTTP_OK), /* POST history doesn't yet support P2P transfers */ - TALER_TESTING_cmd_reserve_status ( + TALER_TESTING_cmd_reserve_history ( "push-check-post-merge-reserve-balance-post", "create-reserve-1", "EUR:1.02", @@ -256,7 +256,7 @@ run (void *cls, "create-reserve-1", "EUR:2.01", MHD_HTTP_OK), - TALER_TESTING_cmd_reserve_status ( + TALER_TESTING_cmd_reserve_history ( "push-check-post-merge-reserve-balance-post", "create-reserve-1", "EUR:2.01", diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c index 5f51b86e8..71f1216a0 100644 --- a/src/testing/test_kyc_api.c +++ b/src/testing/test_kyc_api.c @@ -335,7 +335,7 @@ run (void *cls, "p2p_create-reserve-1", "EUR:1.03", MHD_HTTP_OK), - TALER_TESTING_cmd_reserve_status ( + TALER_TESTING_cmd_reserve_history ( "push-check-post-merge-reserve-balance-post", "p2p_create-reserve-1", "EUR:1.03", @@ -399,7 +399,7 @@ run (void *cls, "p2p_create-reserve-3", "EUR:1.02", MHD_HTTP_OK), - TALER_TESTING_cmd_reserve_status ( + TALER_TESTING_cmd_reserve_history ( "push-check-post-merge-reserve-balance-post", "p2p_create-reserve-3", "EUR:1.02", diff --git a/src/testing/testing_api_cmd_common.c b/src/testing/testing_api_cmd_common.c index 2c29f4ec2..9ed0f16b6 100644 --- a/src/testing/testing_api_cmd_common.c +++ b/src/testing/testing_api_cmd_common.c @@ -97,19 +97,6 @@ TALER_TESTING_history_entry_cmp ( &h2->details.close_details.fee)) ) return 0; return 1; - case TALER_EXCHANGE_RTT_HISTORY: - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (GNUNET_TIME_timestamp_cmp ( - h1->details.history_details.request_timestamp, - ==, - h2->details.history_details.request_timestamp)) && - (0 == - GNUNET_memcmp (&h1->details.history_details.reserve_sig, - &h2->details.history_details.reserve_sig)) ) - return 0; - return 1; case TALER_EXCHANGE_RTT_MERGE: if ( (0 == TALER_amount_cmp (&h1->amount, diff --git a/src/testing/testing_api_cmd_reserve_history.c b/src/testing/testing_api_cmd_reserve_history.c index ff0a8a554..4b08e78e8 100644 --- a/src/testing/testing_api_cmd_reserve_history.c +++ b/src/testing/testing_api_cmd_reserve_history.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -64,12 +64,6 @@ struct HistoryState */ struct TALER_TESTING_Interpreter *is; - /** - * Reserve history entry that corresponds to this operation. - * Will be of type #TALER_EXCHANGE_RTT_HISTORY. - */ - struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history; - /** * Expected HTTP response code. */ @@ -232,21 +226,6 @@ reserve_history_cb (void *cls, struct TALER_Amount eb; ss->rsh = NULL; - if (MHD_HTTP_OK == rs->hr.http_status) - { - struct TALER_EXCHANGE_Keys *keys; - const struct TALER_EXCHANGE_GlobalFee *gf; - - ss->reserve_history.type = TALER_EXCHANGE_RTT_HISTORY; - keys = TALER_TESTING_get_keys (is); - GNUNET_assert (NULL != keys); - gf = TALER_EXCHANGE_get_global_fee (keys, - rs->ts); - GNUNET_assert (NULL != gf); - ss->reserve_history.amount = gf->fees.history; - ss->reserve_history.details.history_details.request_timestamp = rs->ts; - ss->reserve_history.details.history_details.reserve_sig = *rs->reserve_sig; - } if (ss->expected_response_code != rs->hr.http_status) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -366,6 +345,7 @@ history_run (void *cls, TALER_TESTING_get_exchange_url (is), TALER_TESTING_get_keys (is), ss->reserve_priv, + 0, &reserve_history_cb, ss); } @@ -388,16 +368,11 @@ history_traits (void *cls, { struct HistoryState *hs = cls; struct TALER_TESTING_Trait traits[] = { - /* history entry MUST be first due to response code logic below! */ - TALER_TESTING_make_trait_reserve_history (0, - &hs->reserve_history), TALER_TESTING_make_trait_reserve_pub (&hs->reserve_pub), TALER_TESTING_trait_end () }; - return TALER_TESTING_get_trait ((hs->expected_response_code == MHD_HTTP_OK) - ? &traits[0] /* we have reserve history */ - : &traits[1], /* skip reserve history */ + return TALER_TESTING_get_trait (traits, ret, trait, index); diff --git a/src/testing/testing_api_cmd_reserve_status.c b/src/testing/testing_api_cmd_reserve_status.c deleted file mode 100644 index 2438b2c21..000000000 --- a/src/testing/testing_api_cmd_reserve_status.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file testing/testing_api_cmd_reserve_status.c - * @brief Implement the /reserve/$RID/status test command. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_testing_lib.h" - - -/** - * State for a "status" CMD. - */ -struct StatusState -{ - /** - * Label to the command which created the reserve to check, - * needed to resort the reserve key. - */ - const char *reserve_reference; - - /** - * Handle to the "reserve status" operation. - */ - struct TALER_EXCHANGE_ReservesStatusHandle *rsh; - - /** - * Expected reserve balance. - */ - const char *expected_balance; - - /** - * Private key of the reserve being analyzed. - */ - const struct TALER_ReservePrivateKeyP *reserve_priv; - - /** - * Public key of the reserve being analyzed. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - -/** - * Closure for analysis_cb(). - */ -struct AnalysisContext -{ - /** - * Reserve public key we are looking at. - */ - const struct TALER_ReservePublicKeyP *reserve_pub; - - /** - * Length of the @e history array. - */ - unsigned int history_length; - - /** - * Array of history items to match. - */ - const struct TALER_EXCHANGE_ReserveHistoryEntry *history; - - /** - * Array of @e history_length of matched entries. - */ - bool *found; - - /** - * Set to true if an entry could not be found. - */ - bool failure; -}; - - -/** - * Check if @a cmd changed the reserve, if so, find the - * entry in our history and set the respective index in found - * to true. If the entry is not found, set failure. - * - * @param cls our `struct AnalysisContext *` - * @param cmd command to analyze for impact on history - */ -static void -analyze_command (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AnalysisContext *ac = cls; - const struct TALER_ReservePublicKeyP *reserve_pub = ac->reserve_pub; - const struct TALER_EXCHANGE_ReserveHistoryEntry *history = ac->history; - unsigned int history_length = ac->history_length; - bool *found = ac->found; - - if (TALER_TESTING_cmd_is_batch (cmd)) - { - struct TALER_TESTING_Command *cur; - struct TALER_TESTING_Command *bcmd; - - cur = TALER_TESTING_cmd_batch_get_current (cmd); - if (GNUNET_OK != - TALER_TESTING_get_trait_batch_cmds (cmd, - &bcmd)) - { - GNUNET_break (0); - ac->failure = true; - return; - } - for (unsigned int i = 0; NULL != bcmd[i].label; i++) - { - struct TALER_TESTING_Command *step = &bcmd[i]; - - if (step == cur) - break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */ - analyze_command (ac, - step); - if (ac->failure) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Entry for batch step `%s' missing in history\n", - step->label); - return; - } - } - return; - } - - { - const struct TALER_ReservePublicKeyP *rp; - - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (cmd, - &rp)) - return; /* command does nothing for reserves */ - if (0 != - GNUNET_memcmp (rp, - reserve_pub)) - return; /* command affects some _other_ reserve */ - for (unsigned int j = 0; true; j++) - { - const struct TALER_EXCHANGE_ReserveHistoryEntry *he; - bool matched = false; - - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_history (cmd, - j, - &he)) - { - /* NOTE: only for debugging... */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Command `%s' has the reserve_pub trait, but does not reserve history trait\n", - cmd->label); - return; /* command does nothing for reserves */ - } - for (unsigned int i = 0; ilabel, - j); - ac->failure = true; - return; - } - } - } -} - - -/** - * Check that the reserve balance and HTTP response code are - * both acceptable. - * - * @param cls closure. - * @param rs HTTP response details - */ -static void -reserve_status_cb (void *cls, - const struct TALER_EXCHANGE_ReserveStatus *rs) -{ - struct StatusState *ss = cls; - struct TALER_TESTING_Interpreter *is = ss->is; - struct TALER_Amount eb; - - ss->rsh = NULL; - if (ss->expected_response_code != rs->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected HTTP response code: %d in %s:%u\n", - rs->hr.http_status, - __FILE__, - __LINE__); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - if (MHD_HTTP_OK != rs->hr.http_status) - { - TALER_TESTING_interpreter_next (is); - return; - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (ss->expected_balance, - &eb)); - - if (0 != TALER_amount_cmp (&eb, - &rs->details.ok.balance)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected amount in reserve: %s\n", - TALER_amount_to_string (&rs->details.ok.balance)); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected balance of: %s\n", - TALER_amount_to_string (&eb)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - { - bool found[rs->details.ok.history_len]; - struct AnalysisContext ac = { - .reserve_pub = &ss->reserve_pub, - .history = rs->details.ok.history, - .history_length = rs->details.ok.history_len, - .found = found - }; - - memset (found, - 0, - sizeof (found)); - TALER_TESTING_iterate (is, - true, - &analyze_command, - &ac); - if (ac.failure) - { - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - for (unsigned int i = 0; idetails.ok.history_len; i++) - { - if (found[i]) - continue; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "History entry at index %u of type %d not justified by command status\n", - i, - rs->details.ok.history[i].type); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command being executed. - * @param is the interpreter state. - */ -static void -status_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct StatusState *ss = cls; - const struct TALER_TESTING_Command *create_reserve; - - ss->is = is; - create_reserve - = TALER_TESTING_interpreter_lookup_command (is, - ss->reserve_reference); - - if (NULL == create_reserve) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_priv (create_reserve, - &ss->reserve_priv)) - { - GNUNET_break (0); - TALER_LOG_ERROR ("Failed to find reserve_priv for status query\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, - &ss->reserve_pub.eddsa_pub); - ss->rsh = TALER_EXCHANGE_reserves_status ( - TALER_TESTING_interpreter_get_context (is), - TALER_TESTING_get_exchange_url (is), - TALER_TESTING_get_keys (is), - ss->reserve_priv, - &reserve_status_cb, - ss); -} - - -/** - * Cleanup the state from a "reserve status" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -status_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct StatusState *ss = cls; - - if (NULL != ss->rsh) - { - TALER_TESTING_command_incomplete (ss->is, - cmd->label); - TALER_EXCHANGE_reserves_status_cancel (ss->rsh); - ss->rsh = NULL; - } - GNUNET_free (ss); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_reserve_status (const char *label, - const char *reserve_reference, - const char *expected_balance, - unsigned int expected_response_code) -{ - struct StatusState *ss; - - GNUNET_assert (NULL != reserve_reference); - ss = GNUNET_new (struct StatusState); - ss->reserve_reference = reserve_reference; - ss->expected_balance = expected_balance; - ss->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &status_run, - .cleanup = &status_cleanup - }; - - return cmd; - } -} diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index 4b2fab6e4..897f7f986 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -790,9 +790,7 @@ GNUNET_NETWORK_STRUCT_BEGIN /** - * Response by which a wallet requests a full - * reserve history and indicates it is willing - * to pay for it. + * Response by which a wallet requests a reserve history. */ struct TALER_ReserveHistoryRequestPS { @@ -803,36 +801,27 @@ struct TALER_ReserveHistoryRequestPS struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * When did the wallet make the request. + * Which entries to exclude. Only return above this offset. */ - struct GNUNET_TIME_TimestampNBO request_timestamp; - - /** - * How much does the exchange charge for the history? - */ - struct TALER_AmountNBO history_fee; + uint64_t start_off; }; - GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_wallet_reserve_history_verify ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_Amount *history_fee, + uint64_t start_off, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig) { struct TALER_ReserveHistoryRequestPS rhr = { .purpose.size = htonl (sizeof (rhr)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .start_off = GNUNET_htonll (start_off) }; - TALER_amount_hton (&rhr.history_fee, - history_fee); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_WALLET_RESERVE_HISTORY, &rhr, @@ -843,19 +832,16 @@ TALER_wallet_reserve_history_verify ( void TALER_wallet_reserve_history_sign ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_Amount *history_fee, + uint64_t start_off, const struct TALER_ReservePrivateKeyP *reserve_priv, struct TALER_ReserveSignatureP *reserve_sig) { struct TALER_ReserveHistoryRequestPS rhr = { .purpose.size = htonl (sizeof (rhr)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .start_off = GNUNET_htonll (start_off) }; - TALER_amount_hton (&rhr.history_fee, - history_fee); GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, &rhr, &reserve_sig->eddsa_signature); @@ -865,60 +851,60 @@ TALER_wallet_reserve_history_sign ( GNUNET_NETWORK_STRUCT_BEGIN /** - * Response by which a wallet requests an account status. + * Response by which a wallet requests a coin history. */ -struct TALER_ReserveStatusRequestPS +struct TALER_CoinHistoryRequestPS { /** - * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_STATUS + * Purpose is #TALER_SIGNATURE_WALLET_COIN_HISTORY */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * When did the wallet make the request. + * Which entries to exclude. Only return above this offset. */ - struct GNUNET_TIME_TimestampNBO request_timestamp; + uint64_t start_off; }; GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue -TALER_wallet_reserve_status_verify ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig) +TALER_wallet_coin_history_verify ( + uint64_t start_off, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) { - struct TALER_ReserveStatusRequestPS rsr = { + struct TALER_CoinHistoryRequestPS rsr = { .purpose.size = htonl (sizeof (rsr)), - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_STATUS), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY), + .start_off = GNUNET_htonll (start_off) }; return GNUNET_CRYPTO_eddsa_verify ( - TALER_SIGNATURE_WALLET_RESERVE_STATUS, + TALER_SIGNATURE_WALLET_COIN_HISTORY, &rsr, - &reserve_sig->eddsa_signature, - &reserve_pub->eddsa_pub); + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); } void -TALER_wallet_reserve_status_sign ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePrivateKeyP *reserve_priv, - struct TALER_ReserveSignatureP *reserve_sig) +TALER_wallet_coin_history_sign ( + uint64_t start_off, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) { - struct TALER_ReserveStatusRequestPS rsr = { + struct TALER_CoinHistoryRequestPS rsr = { .purpose.size = htonl (sizeof (rsr)), - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_STATUS), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY), + .start_off = GNUNET_htonll (start_off) }; - GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, &rsr, - &reserve_sig->eddsa_signature); + &coin_sig->eddsa_signature); } -- cgit v1.2.3