diff options
Diffstat (limited to 'src/exchange')
-rw-r--r-- | src/exchange/Makefile.am | 1 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 6 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_coins_get.c | 490 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_get.c | 2 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_history.c | 429 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_history.h | 5 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_status.c | 243 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_status.h | 43 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 911 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.h | 24 |
10 files changed, 826 insertions, 1328 deletions
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? @@ -50,26 +49,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. */ struct TALER_Amount balance; @@ -77,6 +61,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. * * @param connection connection to the 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 <http://www.gnu.org/licenses/> -*/ -/** - * @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 <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#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 <http://www.gnu.org/licenses/> -*/ -/** - * @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 <microhttpd.h> -#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 @@ -34,17 +34,6 @@ /** - * 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. * @@ -214,19 +203,6 @@ TEH_RESPONSE_reply_purse_created ( /** - * 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. * * @param cls closure |