From d61c2e400ac07574fc326c8d2be6f51be7c2a25c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 16 Jan 2020 23:49:34 +0100 Subject: kill another FIXME --- src/auditor/taler-auditor.c | 51 ++--- src/exchange/taler-exchange-httpd_deposit.c | 2 + src/exchange/taler-exchange-httpd_payback.c | 1 + src/exchange/taler-exchange-httpd_refresh_melt.c | 3 +- src/exchange/taler-exchange-httpd_refund.c | 118 ++++++++---- src/exchange/taler-exchange-httpd_responses.c | 53 +++-- src/exchange/taler-exchange-httpd_responses.h | 8 +- src/exchangedb/exchangedb_transactions.c | 7 +- src/exchangedb/plugin_exchangedb_common.c | 12 -- src/exchangedb/plugin_exchangedb_postgres.c | 140 +++++--------- src/exchangedb/test_exchangedb.c | 65 +++---- src/include/taler_exchangedb_plugin.h | 235 ++++++++++++++++++++--- 12 files changed, 435 insertions(+), 260 deletions(-) diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 42724efba..a3f6eae21 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -2274,7 +2274,7 @@ check_transaction_history_for_deposit (const struct } break; case TALER_EXCHANGEDB_TT_REFRESH_MELT: - amount_with_fee = &tl->details.melt->session.amount_with_fee; + amount_with_fee = &tl->details.melt->amount_with_fee; fee = &tl->details.melt->melt_fee; fee_dki = &issue->fee_refresh; if (GNUNET_OK != @@ -2489,7 +2489,7 @@ wire_transfer_information_cb (void *cls, struct TALER_Amount computed_value; struct TALER_Amount coin_value_without_fee; struct TALER_EXCHANGEDB_TransactionList *tl; - const struct TALER_CoinPublicInfo *coin; + struct TALER_CoinPublicInfo coin; enum GNUNET_DB_QueryStatus qs; struct GNUNET_HashCode hw; @@ -2525,36 +2525,26 @@ wire_transfer_information_cb (void *cls, "no transaction history for coin claimed in aggregation"); return; } + qs = edb->get_known_coin (edb->cls, + esession, + coin_pub, + &coin); + if (qs < 0) + { + GNUNET_break (0); /* this should be a foreign key violation at this point! */ + wcc->qs = qs; + report_row_inconsistency ("aggregation", + rowid, + "could not get coin details for coin claimed in aggregation"); + return; + } - /* Obtain general denomination information about the coin */ - coin = NULL; - switch (tl->type) - { - case TALER_EXCHANGEDB_TT_DEPOSIT: - coin = &tl->details.deposit->coin; - break; - case TALER_EXCHANGEDB_TT_REFRESH_MELT: - coin = &tl->details.melt->session.coin; - break; - case TALER_EXCHANGEDB_TT_REFUND: - coin = &tl->details.refund->coin; - break; - case TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK: - coin = &tl->details.payback_refresh->coin; - break; - case TALER_EXCHANGEDB_TT_PAYBACK: - coin = &tl->details.payback->coin; - break; - case TALER_EXCHANGEDB_TT_PAYBACK_REFRESH: - coin = &tl->details.payback_refresh->coin; - break; - } - GNUNET_assert (NULL != coin); /* hard check that switch worked */ - qs = get_denomination_info_by_hash (&coin->denom_pub_hash, + qs = get_denomination_info_by_hash (&coin.denom_pub_hash, &issue); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature); edb->free_coin_transaction_list (edb->cls, tl); wcc->qs = qs; @@ -2564,7 +2554,7 @@ wire_transfer_information_cb (void *cls, return; } if (GNUNET_OK != - TALER_test_coin_valid (coin, + TALER_test_coin_valid (&coin, denom_pub)) { report (report_bad_sig_losses, @@ -2578,7 +2568,7 @@ wire_transfer_information_cb (void *cls, TALER_amount_add (&total_bad_sig_loss, &total_bad_sig_loss, coin_value)); - + GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature); edb->free_coin_transaction_list (edb->cls, tl); wcc->qs = GNUNET_DB_STATUS_HARD_ERROR; @@ -2587,7 +2577,8 @@ wire_transfer_information_cb (void *cls, "coin denomination signature invalid"); return; } - + GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature); + coin.denom_sig.rsa_signature = NULL; /* just to be sure */ GNUNET_assert (NULL != issue); /* mostly to help static analysis */ /* Check transaction history to see if it supports aggregate valuation */ diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 11f579abc..38cc43074 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -214,6 +214,8 @@ deposit_transaction (void *cls, "Deposited coin has insufficient funds left!\n"); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection, TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS, + &deposit->coin. + coin_pub, tl); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c index a05045b24..bfd0f4133 100644 --- a/src/exchange/taler-exchange-httpd_payback.c +++ b/src/exchange/taler-exchange-httpd_payback.c @@ -346,6 +346,7 @@ payback_transaction (void *cls, session); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection, TALER_EC_PAYBACK_COIN_BALANCE_ZERO, + &pc->coin->coin_pub, tl); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c b/src/exchange/taler-exchange-httpd_refresh_melt.c index 4f429012c..e0a4d8360 100644 --- a/src/exchange/taler-exchange-httpd_refresh_melt.c +++ b/src/exchange/taler-exchange-httpd_refresh_melt.c @@ -59,7 +59,8 @@ reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, { json_t *history; - history = TEH_RESPONSE_compile_transaction_history (tl); + history = TEH_RESPONSE_compile_transaction_history (coin_pub, + tl); if (NULL == history) return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c index 6a96ff982..cb0a0f15f 100644 --- a/src/exchange/taler-exchange-httpd_refund.c +++ b/src/exchange/taler-exchange-httpd_refund.c @@ -40,12 +40,14 @@ * Generate successful refund confirmation message. * * @param connection connection to the client + * @param coin_pub public key of the coin * @param refund details about the successful refund * @return MHD result code */ static int reply_refund_success (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_Refund *refund) + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_EXCHANGEDB_RefundListEntry *refund) { struct TALER_RefundConfirmationPS rc; struct TALER_ExchangePublicKeyP pub; @@ -54,7 +56,7 @@ reply_refund_success (struct MHD_Connection *connection, rc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND); rc.purpose.size = htonl (sizeof (struct TALER_RefundConfirmationPS)); rc.h_contract_terms = refund->h_contract_terms; - rc.coin_pub = refund->coin.coin_pub; + rc.coin_pub = *coin_pub; rc.merchant = refund->merchant_pub; rc.rtransaction_id = GNUNET_htonll (refund->rtransaction_id); TALER_amount_hton (&rc.refund_amount, @@ -107,11 +109,13 @@ reply_refund_failure (struct MHD_Connection *connection, * transaction list @a tl with the details about the conflict. * * @param connection connection to the client + * @param coin_pub public key this is about * @param tl transaction list showing the conflict * @return MHD result code */ static int reply_refund_conflict (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_EXCHANGEDB_TransactionList *tl) { return TALER_MHD_reply_json_pack (connection, @@ -122,6 +126,7 @@ reply_refund_conflict (struct MHD_Connection *connection, (json_int_t) TALER_EC_REFUND_CONFLICT, "history", TEH_RESPONSE_compile_transaction_history ( + coin_pub, tl)); } @@ -152,8 +157,8 @@ refund_transaction (void *cls, { const struct TALER_EXCHANGEDB_Refund *refund = cls; struct TALER_EXCHANGEDB_TransactionList *tl; - const struct TALER_EXCHANGEDB_Deposit *dep; - const struct TALER_EXCHANGEDB_Refund *ref; + const struct TALER_EXCHANGEDB_DepositListEntry *dep; + const struct TALER_EXCHANGEDB_RefundListEntry *ref; struct TEH_KS_StateHandle *mks; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; struct TALER_Amount expect_fee; @@ -163,6 +168,7 @@ refund_transaction (void *cls, int fee_cmp; unsigned int hc; enum TALER_ErrorCode ec; + struct TALER_CoinPublicInfo coin_info; dep = NULL; ref = NULL; @@ -192,10 +198,10 @@ refund_transaction (void *cls, if (GNUNET_NO == deposit_found) { if ( (0 == memcmp (&tlp->details.deposit->merchant_pub, - &refund->merchant_pub, + &refund->details.merchant_pub, sizeof (struct TALER_MerchantPublicKeyP))) && (0 == memcmp (&tlp->details.deposit->h_contract_terms, - &refund->h_contract_terms, + &refund->details.h_contract_terms, sizeof (struct GNUNET_HashCode))) ) { dep = tlp->details.deposit; @@ -212,12 +218,13 @@ refund_transaction (void *cls, { /* First, check if existing refund request is identical */ if ( (0 == memcmp (&tlp->details.refund->merchant_pub, - &refund->merchant_pub, + &refund->details.merchant_pub, sizeof (struct TALER_MerchantPublicKeyP))) && (0 == memcmp (&tlp->details.refund->h_contract_terms, - &refund->h_contract_terms, + &refund->details.h_contract_terms, sizeof (struct GNUNET_HashCode))) && - (tlp->details.refund->rtransaction_id == refund->rtransaction_id) ) + (tlp->details.refund->rtransaction_id == + refund->details.rtransaction_id) ) { ref = tlp->details.refund; refund_found = GNUNET_YES; @@ -225,12 +232,13 @@ refund_transaction (void *cls, } /* Second, check if existing refund request conflicts */ if ( (0 == memcmp (&tlp->details.refund->merchant_pub, - &refund->merchant_pub, + &refund->details.merchant_pub, sizeof (struct TALER_MerchantPublicKeyP))) && (0 == memcmp (&tlp->details.refund->h_contract_terms, - &refund->h_contract_terms, + &refund->details.h_contract_terms, sizeof (struct GNUNET_HashCode))) && - (tlp->details.refund->rtransaction_id != refund->rtransaction_id) ) + (tlp->details.refund->rtransaction_id != + refund->details.rtransaction_id) ) { GNUNET_break_op (0); /* conflicting refund found */ refund_found = GNUNET_SYSERR; @@ -269,6 +277,7 @@ refund_transaction (void *cls, if (GNUNET_SYSERR == refund_found) { *mhd_ret = reply_refund_conflict (connection, + &refund->coin.coin_pub, tl); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); @@ -279,6 +288,7 @@ refund_transaction (void *cls, { /* /refund already done, simply re-transmit confirmation */ *mhd_ret = reply_refund_success (connection, + &refund->coin.coin_pub, ref); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); @@ -287,10 +297,10 @@ refund_transaction (void *cls, /* check currency is compatible */ if ( (GNUNET_YES != - TALER_amount_cmp_currency (&refund->refund_amount, + TALER_amount_cmp_currency (&refund->details.refund_amount, &dep->amount_with_fee)) || (GNUNET_YES != - TALER_amount_cmp_currency (&refund->refund_fee, + TALER_amount_cmp_currency (&refund->details.refund_fee, &dep->deposit_fee)) ) { GNUNET_break_op (0); /* currency missmatch */ @@ -303,7 +313,10 @@ refund_transaction (void *cls, /* check if we already send the money for the /deposit */ qs = TEH_plugin->test_deposit_done (TEH_plugin->cls, session, - dep); + &refund->coin.coin_pub, + &dep->merchant_pub, + &dep->h_contract_terms, + &dep->h_wire); if (GNUNET_DB_STATUS_HARD_ERROR == qs) { /* Internal error, we first had the deposit in the history, @@ -332,7 +345,7 @@ refund_transaction (void *cls, } /* check refund amount is sufficiently low */ - if (1 == TALER_amount_cmp (&refund->refund_amount, + if (1 == TALER_amount_cmp (&refund->details.refund_amount, &dep->amount_with_fee) ) { GNUNET_break_op (0); /* cannot refund more than original value */ @@ -343,7 +356,25 @@ refund_transaction (void *cls, TALER_EC_REFUND_INSUFFICIENT_FUNDS); return GNUNET_DB_STATUS_HARD_ERROR; } - + qs = TEH_plugin->get_known_coin (TEH_plugin->cls, + session, + &refund->coin.coin_pub, + &coin_info); + if (0 > qs) + { + TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, + tl); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); /* should be impossible by foreign key constraint! */ + *mhd_ret = reply_refund_failure (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_REFUND_COIN_NOT_FOUND); + } + return qs; + } + GNUNET_CRYPTO_rsa_signature_free (coin_info.denom_sig.rsa_signature); + coin_info.denom_sig.rsa_signature = NULL; /* just to be safe */ // FIXME: do this outside of transaction function? /* Check refund fee matches fee of denomination key! */ mks = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); @@ -359,7 +390,7 @@ refund_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } dki = TEH_KS_denomination_key_lookup_by_hash (mks, - &dep->coin.denom_pub_hash, + &coin_info.denom_pub_hash, TEH_KS_DKU_DEPOSIT, &ec, &hc); @@ -379,7 +410,7 @@ refund_transaction (void *cls, } TALER_amount_ntoh (&expect_fee, &dki->issue.properties.fee_refund); - fee_cmp = TALER_amount_cmp (&refund->refund_fee, + fee_cmp = TALER_amount_cmp (&refund->details.refund_fee, &expect_fee); TEH_KS_release (mks); @@ -436,19 +467,9 @@ verify_and_execute_refund (struct MHD_Connection *connection, struct TALER_RefundRequestPS rr; int mhd_ret; - rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); - rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); - rr.h_contract_terms = refund->h_contract_terms; - rr.coin_pub = refund->coin.coin_pub; - rr.merchant = refund->merchant_pub; - rr.rtransaction_id = GNUNET_htonll (refund->rtransaction_id); - TALER_amount_hton (&rr.refund_amount, - &refund->refund_amount); - TALER_amount_hton (&rr.refund_fee, - &refund->refund_fee); if (GNUNET_YES != - TALER_amount_cmp_currency (&refund->refund_amount, - &refund->refund_fee) ) + TALER_amount_cmp_currency (&refund->details.refund_amount, + &refund->details.refund_fee) ) { GNUNET_break_op (0); return TALER_MHD_reply_with_error (connection, @@ -456,8 +477,8 @@ verify_and_execute_refund (struct MHD_Connection *connection, TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH, "refund_fee"); } - if (-1 == TALER_amount_cmp (&refund->refund_amount, - &refund->refund_fee) ) + if (-1 == TALER_amount_cmp (&refund->details.refund_amount, + &refund->details.refund_fee) ) { GNUNET_break_op (0); return TALER_MHD_reply_with_error (connection, @@ -465,11 +486,21 @@ verify_and_execute_refund (struct MHD_Connection *connection, TALER_EC_REFUND_FEE_ABOVE_AMOUNT, "refund_amount"); } + rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); + rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); + rr.h_contract_terms = refund->details.h_contract_terms; + rr.coin_pub = refund->coin.coin_pub; + rr.merchant = refund->details.merchant_pub; + rr.rtransaction_id = GNUNET_htonll (refund->details.rtransaction_id); + TALER_amount_hton (&rr.refund_amount, + &refund->details.refund_amount); + TALER_amount_hton (&rr.refund_fee, + &refund->details.refund_fee); if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, &rr.purpose, - &refund->merchant_sig.eddsa_sig, - &refund->merchant_pub.eddsa_pub)) + &refund->details.merchant_sig.eddsa_sig, + &refund->details.merchant_pub.eddsa_pub)) { TALER_LOG_WARNING ("Invalid signature on /refund request\n"); return TALER_MHD_reply_with_error (connection, @@ -485,7 +516,8 @@ verify_and_execute_refund (struct MHD_Connection *connection, (void *) refund)) return mhd_ret; return reply_refund_success (connection, - refund); + &refund->coin.coin_pub, + &refund->details); } @@ -514,13 +546,15 @@ TEH_REFUND_handler_refund (struct TEH_RequestHandler *rh, int res; struct TALER_EXCHANGEDB_Refund refund; struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount ("refund_amount", &refund.refund_amount), - TALER_JSON_spec_amount ("refund_fee", &refund.refund_fee), - GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &refund.h_contract_terms), + TALER_JSON_spec_amount ("refund_amount", &refund.details.refund_amount), + TALER_JSON_spec_amount ("refund_fee", &refund.details.refund_fee), + GNUNET_JSON_spec_fixed_auto ("h_contract_terms", + &refund.details.h_contract_terms), GNUNET_JSON_spec_fixed_auto ("coin_pub", &refund.coin.coin_pub), - GNUNET_JSON_spec_fixed_auto ("merchant_pub", &refund.merchant_pub), - GNUNET_JSON_spec_uint64 ("rtransaction_id", &refund.rtransaction_id), - GNUNET_JSON_spec_fixed_auto ("merchant_sig", &refund.merchant_sig), + GNUNET_JSON_spec_fixed_auto ("merchant_pub", &refund.details.merchant_pub), + GNUNET_JSON_spec_uint64 ("rtransaction_id", + &refund.details.rtransaction_id), + GNUNET_JSON_spec_fixed_auto ("merchant_sig", &refund.details.merchant_sig), GNUNET_JSON_spec_end () }; diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 4ef0f2d15..d6e5c32aa 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -42,11 +42,14 @@ /** * 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; @@ -66,7 +69,8 @@ TEH_RESPONSE_compile_transaction_history (const struct case TALER_EXCHANGEDB_TT_DEPOSIT: { struct TALER_DepositRequestPS dr; - const struct TALER_EXCHANGEDB_Deposit *deposit = pos->details.deposit; + const struct TALER_EXCHANGEDB_DepositListEntry *deposit = + pos->details.deposit; dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); @@ -80,14 +84,14 @@ TEH_RESPONSE_compile_transaction_history (const struct TALER_amount_hton (&dr.deposit_fee, &deposit->deposit_fee); dr.merchant = deposit->merchant_pub; - dr.coin_pub = deposit->coin.coin_pub; + dr.coin_pub = *coin_pub; #if SANITY_CHECKS_ON /* internal sanity check before we hand out a bogus sig... */ if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, &dr.purpose, &deposit->csig.eddsa_signature, - &deposit->coin.coin_pub.eddsa_pub)) + &coin_pub->eddsa_pub)) { GNUNET_break (0); json_decref (history); @@ -132,24 +136,25 @@ TEH_RESPONSE_compile_transaction_history (const struct case TALER_EXCHANGEDB_TT_REFRESH_MELT: { struct TALER_RefreshMeltCoinAffirmationPS ms; - const struct TALER_EXCHANGEDB_RefreshMelt *melt = pos->details.melt; + const struct TALER_EXCHANGEDB_RefreshMeltListEntry *melt = + pos->details.melt; ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - ms.rc = melt->session.rc; + ms.rc = melt->rc; TALER_amount_hton (&ms.amount_with_fee, - &melt->session.amount_with_fee); + &melt->amount_with_fee); TALER_amount_hton (&ms.melt_fee, &melt->melt_fee); - ms.coin_pub = melt->session.coin.coin_pub; + ms.coin_pub = *coin_pub; #if SANITY_CHECKS_ON /* internal sanity check before we hand out a bogus sig... */ if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, &ms.purpose, - &melt->session.coin_sig.eddsa_signature, - &melt->session.coin.coin_pub.eddsa_pub)) + &melt->coin_sig.eddsa_signature, + &coin_pub->eddsa_pub)) { GNUNET_break (0); json_decref (history); @@ -161,15 +166,15 @@ TEH_RESPONSE_compile_transaction_history (const struct json_pack ("{s:s, s:o, s:o, s:o, s:o}", "type", "MELT", "amount", TALER_JSON_from_amount ( - &melt->session.amount_with_fee), + &melt->amount_with_fee), "melt_fee", TALER_JSON_from_amount ( &melt->melt_fee), "rc", GNUNET_JSON_from_data_auto ( - &melt->session.rc), + &melt->rc), "coin_sig", GNUNET_JSON_from_data_auto ( - &melt->session.coin_sig)))) + &melt->coin_sig)))) { GNUNET_break (0); json_decref (history); @@ -180,7 +185,8 @@ TEH_RESPONSE_compile_transaction_history (const struct case TALER_EXCHANGEDB_TT_REFUND: { struct TALER_RefundRequestPS rr; - const struct TALER_EXCHANGEDB_Refund *refund = pos->details.refund; + const struct TALER_EXCHANGEDB_RefundListEntry *refund = + pos->details.refund; struct TALER_Amount value; if (GNUNET_OK != @@ -195,7 +201,7 @@ TEH_RESPONSE_compile_transaction_history (const struct rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); rr.h_contract_terms = refund->h_contract_terms; - rr.coin_pub = refund->coin.coin_pub; + rr.coin_pub = *coin_pub; rr.merchant = refund->merchant_pub; rr.rtransaction_id = GNUNET_htonll (refund->rtransaction_id); TALER_amount_hton (&rr.refund_amount, @@ -245,7 +251,7 @@ TEH_RESPONSE_compile_transaction_history (const struct break; case TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK: { - struct TALER_EXCHANGEDB_PaybackRefresh *pr = + struct TALER_EXCHANGEDB_PaybackRefreshListEntry *pr = pos->details.old_coin_payback; struct TALER_PaybackRefreshConfirmationPS pc; struct TALER_ExchangePublicKeyP epub; @@ -257,7 +263,7 @@ TEH_RESPONSE_compile_transaction_history (const struct pc.timestamp = GNUNET_TIME_absolute_hton (pr->timestamp); TALER_amount_hton (&pc.payback_amount, &pr->value); - pc.coin_pub = pr->coin.coin_pub; + pc.coin_pub = *coin_pub; pc.old_coin_pub = pr->old_coin_pub; if (GNUNET_OK != TEH_KS_sign (&pc.purpose, @@ -299,7 +305,8 @@ TEH_RESPONSE_compile_transaction_history (const struct } case TALER_EXCHANGEDB_TT_PAYBACK: { - const struct TALER_EXCHANGEDB_Payback *payback = pos->details.payback; + const struct TALER_EXCHANGEDB_PaybackListEntry *payback = + pos->details.payback; struct TALER_PaybackConfirmationPS pc; struct TALER_ExchangePublicKeyP epub; struct TALER_ExchangeSignatureP esig; @@ -309,7 +316,7 @@ TEH_RESPONSE_compile_transaction_history (const struct pc.timestamp = GNUNET_TIME_absolute_hton (payback->timestamp); TALER_amount_hton (&pc.payback_amount, &payback->value); - pc.coin_pub = payback->coin.coin_pub; + pc.coin_pub = *coin_pub; pc.reserve_pub = payback->reserve_pub; if (GNUNET_OK != TEH_KS_sign (&pc.purpose, @@ -347,7 +354,7 @@ TEH_RESPONSE_compile_transaction_history (const struct break; case TALER_EXCHANGEDB_TT_PAYBACK_REFRESH: { - struct TALER_EXCHANGEDB_PaybackRefresh *pr = + struct TALER_EXCHANGEDB_PaybackRefreshListEntry *pr = pos->details.payback_refresh; struct TALER_PaybackRefreshConfirmationPS pc; struct TALER_ExchangePublicKeyP epub; @@ -359,7 +366,7 @@ TEH_RESPONSE_compile_transaction_history (const struct pc.timestamp = GNUNET_TIME_absolute_hton (pr->timestamp); TALER_amount_hton (&pc.payback_amount, &pr->value); - pc.coin_pub = pr->coin.coin_pub; + pc.coin_pub = *coin_pub; pc.old_coin_pub = pr->old_coin_pub; if (GNUNET_OK != TEH_KS_sign (&pc.purpose, @@ -415,6 +422,7 @@ TEH_RESPONSE_compile_transaction_history (const struct * * @param connection connection to the client * @param ec error code to return + * @param coin_pub public key of the coin * @param tl transaction list to use to build reply * @return MHD result code */ @@ -422,11 +430,14 @@ int TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, enum TALER_ErrorCode ec, const struct + TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_EXCHANGEDB_TransactionList *tl) { json_t *history; - history = TEH_RESPONSE_compile_transaction_history (tl); + history = TEH_RESPONSE_compile_transaction_history (coin_pub, + tl); if (NULL == history) return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index ec0515829..782e17dd9 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -55,6 +55,7 @@ TEH_RESPONSE_compile_reserve_history (const struct * * @param connection connection to the client * @param ec error code to return + * @param coin_pub public key of the coin * @param tl transaction list to use to build reply * @return MHD result code */ @@ -62,17 +63,22 @@ int TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, enum TALER_ErrorCode ec, const struct + TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_EXCHANGEDB_TransactionList *tl); /** * 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 + * @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); diff --git a/src/exchangedb/exchangedb_transactions.c b/src/exchangedb/exchangedb_transactions.c index 2891f0adb..871061aa2 100644 --- a/src/exchangedb/exchangedb_transactions.c +++ b/src/exchangedb/exchangedb_transactions.c @@ -46,8 +46,9 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals (struct GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (spent.currency, &refunded)); - for (struct TALER_EXCHANGEDB_TransactionList *pos = tl; NULL != pos; pos = - pos->next) + for (struct TALER_EXCHANGEDB_TransactionList *pos = tl; + NULL != pos; + pos = pos->next) { switch (pos->type) { @@ -67,7 +68,7 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals (struct if (GNUNET_OK != TALER_amount_add (&spent, &spent, - &pos->details.melt->session.amount_with_fee)) + &pos->details.melt->amount_with_fee)) { GNUNET_break (0); return GNUNET_SYSERR; diff --git a/src/exchangedb/plugin_exchangedb_common.c b/src/exchangedb/plugin_exchangedb_common.c index dac746b09..02f06cc1f 100644 --- a/src/exchangedb/plugin_exchangedb_common.c +++ b/src/exchangedb/plugin_exchangedb_common.c @@ -92,15 +92,9 @@ common_free_coin_transaction_list (void *cls, case TALER_EXCHANGEDB_TT_DEPOSIT: if (NULL != list->details.deposit->receiver_wire_account) json_decref (list->details.deposit->receiver_wire_account); - if (NULL != list->details.deposit->coin.denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free ( - list->details.deposit->coin.denom_sig.rsa_signature); GNUNET_free (list->details.deposit); break; case TALER_EXCHANGEDB_TT_REFRESH_MELT: - if (NULL != list->details.melt->session.coin.denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free ( - list->details.melt->session.coin.denom_sig.rsa_signature); GNUNET_free (list->details.melt); break; case TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK: @@ -110,15 +104,9 @@ common_free_coin_transaction_list (void *cls, GNUNET_free (list->details.old_coin_payback); break; case TALER_EXCHANGEDB_TT_REFUND: - if (NULL != list->details.refund->coin.denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free ( - list->details.refund->coin.denom_sig.rsa_signature); GNUNET_free (list->details.refund); break; case TALER_EXCHANGEDB_TT_PAYBACK: - if (NULL != list->details.payback->coin.denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free ( - list->details.payback->coin.denom_sig.rsa_signature); GNUNET_free (list->details.payback); break; case TALER_EXCHANGEDB_TT_PAYBACK_REFRESH: diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 65e52e675..59f0efe49 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -1630,12 +1630,8 @@ postgres_get_session (void *cls) ",amount_val" ",amount_frac" ",timestamp" - ",coins.denom_pub_hash" - ",coins.denom_sig" ",payback_uuid" " FROM payback" - " JOIN known_coins coins" - " USING (coin_pub)" " JOIN reserves_out ro" " USING (h_blind_ev)" " WHERE payback.coin_pub=$1" @@ -2982,7 +2978,10 @@ postgres_mark_deposit_tiny (void *cls, * * @param cls the @e cls of this struct with the plugin-specific state * @param session connection to the database - * @param deposit the deposit to check + * @param coin_pub the coin to check for deposit + * @param merchant_pub merchant to receive the deposit + * @param h_contract_terms contract terms of the deposit + * @param h_wire hash of the merchant's wire details * @return #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if is is marked done, * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if not, * otherwise transaction error status (incl. deposit unknown) @@ -2990,13 +2989,16 @@ postgres_mark_deposit_tiny (void *cls, static enum GNUNET_DB_QueryStatus postgres_test_deposit_done (void *cls, struct TALER_EXCHANGEDB_Session *session, - const struct TALER_EXCHANGEDB_Deposit *deposit) + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_contract_terms, + const struct GNUNET_HashCode *h_wire) { struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub), - GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub), - GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms), - GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire), + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), + GNUNET_PQ_query_param_auto_from_type (h_contract_terms), + GNUNET_PQ_query_param_auto_from_type (h_wire), GNUNET_PQ_query_param_end }; uint8_t done = 0; @@ -3517,18 +3519,18 @@ postgres_insert_refund (void *cls, { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (&refund->coin.coin_pub), - GNUNET_PQ_query_param_auto_from_type (&refund->merchant_pub), - GNUNET_PQ_query_param_auto_from_type (&refund->merchant_sig), - GNUNET_PQ_query_param_auto_from_type (&refund->h_contract_terms), - GNUNET_PQ_query_param_uint64 (&refund->rtransaction_id), - TALER_PQ_query_param_amount (&refund->refund_amount), + GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_pub), + GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_sig), + GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms), + GNUNET_PQ_query_param_uint64 (&refund->details.rtransaction_id), + TALER_PQ_query_param_amount (&refund->details.refund_amount), GNUNET_PQ_query_param_end }; (void) cls; GNUNET_assert (GNUNET_YES == - TALER_amount_cmp_currency (&refund->refund_amount, - &refund->refund_fee)); + TALER_amount_cmp_currency (&refund->details.refund_amount, + &refund->details.refund_fee)); return GNUNET_PQ_eval_prepared_non_select (session->conn, "insert_refund", params); @@ -4296,12 +4298,11 @@ add_coin_deposit (void *cls, for (unsigned int i = 0; i < num_results; i++) { - struct TALER_EXCHANGEDB_Deposit *deposit; + struct TALER_EXCHANGEDB_DepositListEntry *deposit; struct TALER_EXCHANGEDB_TransactionList *tl; - enum GNUNET_DB_QueryStatus qs; uint64_t serial_id; - deposit = GNUNET_new (struct TALER_EXCHANGEDB_Deposit); + deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry); { struct GNUNET_PQ_ResultSpec rs[] = { TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", @@ -4339,24 +4340,12 @@ add_coin_deposit (void *cls, chc->status = GNUNET_DB_STATUS_HARD_ERROR; return; } - deposit->coin.coin_pub = *chc->coin_pub; } tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); tl->next = chc->head; tl->type = TALER_EXCHANGEDB_TT_DEPOSIT; tl->details.deposit = deposit; tl->serial_id = serial_id; - qs = postgres_get_known_coin (chc->db_cls, - chc->session, - chc->coin_pub, - &deposit->coin); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - GNUNET_free (deposit); - chc->status = qs; - return; - } chc->head = tl; } } @@ -4380,21 +4369,20 @@ add_coin_melt (void *cls, for (unsigned int i = 0; isession.rc), + &melt->rc), /* oldcoin_index not needed */ GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig", - &melt->session.coin_sig), + &melt->coin_sig), TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", - &melt->session.amount_with_fee), + &melt->amount_with_fee), TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh", &melt->melt_fee), GNUNET_PQ_result_spec_uint64 ("melt_serial_id", @@ -4412,25 +4400,12 @@ add_coin_melt (void *cls, chc->status = GNUNET_DB_STATUS_HARD_ERROR; return; } - melt->session.coin.coin_pub = *chc->coin_pub; } tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); tl->next = chc->head; tl->type = TALER_EXCHANGEDB_TT_REFRESH_MELT; tl->details.melt = melt; tl->serial_id = serial_id; - /* FIXME: integrate via JOIN in main select, instead of using separate query */ - qs = postgres_get_known_coin (chc->db_cls, - chc->session, - chc->coin_pub, - &melt->session.coin); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - GNUNET_free (melt); - chc->status = qs; - return; - } chc->head = tl; } } @@ -4454,12 +4429,11 @@ add_coin_refund (void *cls, for (unsigned int i = 0; istatus = GNUNET_DB_STATUS_HARD_ERROR; return; } - refund->coin.coin_pub = *chc->coin_pub; } tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); tl->next = chc->head; tl->type = TALER_EXCHANGEDB_TT_REFUND; tl->details.refund = refund; tl->serial_id = serial_id; - qs = postgres_get_known_coin (chc->db_cls, - chc->session, - chc->coin_pub, - &refund->coin); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - GNUNET_free (refund); - chc->status = qs; - return; - } chc->head = tl; } } @@ -4530,11 +4492,11 @@ add_old_coin_payback (void *cls, for (unsigned int i = 0; ivalue), GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", &payback->reserve_pub), - GNUNET_PQ_result_spec_auto_from_type ("coin_blind", - &payback->coin_blind), GNUNET_PQ_result_spec_auto_from_type ("coin_sig", &payback->coin_sig), + GNUNET_PQ_result_spec_auto_from_type ("coin_blind", + &payback->coin_blind), + TALER_PQ_RESULT_SPEC_AMOUNT ("amount", + &payback->value), TALER_PQ_result_spec_absolute_time ("timestamp", &payback->timestamp), - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", - &payback->coin.denom_pub_hash), - GNUNET_PQ_result_spec_rsa_signature ("denom_sig", - &payback->coin.denom_sig. - rsa_signature), GNUNET_PQ_result_spec_uint64 ("payback_uuid", &serial_id), GNUNET_PQ_result_spec_end @@ -4634,7 +4591,6 @@ add_coin_payback (void *cls, chc->status = GNUNET_DB_STATUS_HARD_ERROR; return; } - payback->coin.coin_pub = *chc->coin_pub; } tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); tl->next = chc->head; @@ -4664,11 +4620,11 @@ add_coin_payback_refresh (void *cls, for (unsigned int i = 0; imerchant_pub)) + &refund->details.merchant_pub)) { GNUNET_break (0); result = 66; } if (0 != GNUNET_memcmp (merchant_sig, - &refund->merchant_sig)) + &refund->details.merchant_sig)) { GNUNET_break (0); result = 66; } if (0 != GNUNET_memcmp (h_contract, - &refund->h_contract_terms)) + &refund->details.h_contract_terms)) { GNUNET_break (0); result = 66; } - if (rtransaction_id != refund->rtransaction_id) + if (rtransaction_id != refund->details.rtransaction_id) { GNUNET_break (0); result = 66; } if (0 != TALER_amount_cmp (amount_with_fee, - &refund->refund_amount)) + &refund->details.refund_amount)) { GNUNET_break (0); result = 66; } if (0 != TALER_amount_cmp (refund_fee, - &refund->refund_fee)) + &refund->details.refund_fee)) { GNUNET_break (0); result = 66; @@ -1925,7 +1925,10 @@ run (void *cls) FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->test_deposit_done (plugin->cls, session, - &deposit)); + &deposit.coin.coin_pub, + &deposit.merchant_pub, + &deposit.h_contract_terms, + &deposit.h_wire)); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->mark_deposit_done (plugin->cls, session, @@ -1936,7 +1939,10 @@ run (void *cls) FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->test_deposit_done (plugin->cls, session, - &deposit)); + &deposit.coin.coin_pub, + &deposit.merchant_pub, + &deposit.h_contract_terms, + &deposit.h_wire)); result = 10; deposit2 = deposit; @@ -1966,13 +1972,14 @@ run (void *cls) /* test insert_refund! */ refund.coin = deposit.coin; - refund.merchant_pub = deposit.merchant_pub; - RND_BLK (&refund.merchant_sig); - refund.h_contract_terms = deposit.h_contract_terms; - refund.rtransaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX); - refund.refund_amount = deposit.amount_with_fee; - refund.refund_fee = fee_refund; + refund.details.merchant_pub = deposit.merchant_pub; + RND_BLK (&refund.details.merchant_sig); + refund.details.h_contract_terms = deposit.h_contract_terms; + refund.details.rtransaction_id + = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + refund.details.refund_amount = deposit.amount_with_fee; + refund.details.refund_fee = fee_refund; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->insert_refund (plugin->cls, session, @@ -2064,11 +2071,8 @@ run (void *cls) { case TALER_EXCHANGEDB_TT_DEPOSIT: { - struct TALER_EXCHANGEDB_Deposit *have = tlp->details.deposit; + struct TALER_EXCHANGEDB_DepositListEntry *have = tlp->details.deposit; - FAILIF (0 != memcmp (&have->coin.coin_pub, - &deposit.coin.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))); /* Note: we're not comparing the denomination keys, as there is still the question of whether we should even bother exporting them here. */ @@ -2108,31 +2112,29 @@ run (void *cls) #endif case TALER_EXCHANGEDB_TT_REFUND: { - struct TALER_EXCHANGEDB_Refund *have = tlp->details.refund; + struct TALER_EXCHANGEDB_RefundListEntry *have = tlp->details.refund; - FAILIF (0 != memcmp (&have->coin.coin_pub, - &refund.coin.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))); /* Note: we're not comparing the denomination keys, as there is still the question of whether we should even bother exporting them here. */ FAILIF (0 != GNUNET_memcmp (&have->merchant_pub, - &refund.merchant_pub)); + &refund.details.merchant_pub)); FAILIF (0 != GNUNET_memcmp (&have->merchant_sig, - &refund.merchant_sig)); + &refund.details.merchant_sig)); FAILIF (0 != GNUNET_memcmp (&have->h_contract_terms, - &refund.h_contract_terms)); - FAILIF (have->rtransaction_id != refund.rtransaction_id); + &refund.details.h_contract_terms)); + FAILIF (have->rtransaction_id != refund.details.rtransaction_id); FAILIF (0 != TALER_amount_cmp (&have->refund_amount, - &refund.refund_amount)); + &refund.details.refund_amount)); FAILIF (0 != TALER_amount_cmp (&have->refund_fee, - &refund.refund_fee)); + &refund.details.refund_fee)); matched |= 4; break; } case TALER_EXCHANGEDB_TT_PAYBACK: { - struct TALER_EXCHANGEDB_Payback *payback = tlp->details.payback; + struct TALER_EXCHANGEDB_PaybackListEntry *payback = + tlp->details.payback; FAILIF (0 != GNUNET_memcmp (&payback->coin_sig, &coin_sig)); @@ -2140,9 +2142,6 @@ run (void *cls) &coin_blind)); FAILIF (0 != GNUNET_memcmp (&payback->reserve_pub, &reserve_pub)); - FAILIF (0 != memcmp (&payback->coin.coin_pub, - &deposit.coin.coin_pub, - sizeof (deposit.coin.coin_pub))); FAILIF (0 != TALER_amount_cmp (&payback->value, &value)); matched |= 8; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index cb5d6cc68..3178209d0 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -275,7 +275,8 @@ struct TALER_EXCHANGEDB_CollectableBlindcoin /** - * Information the exchange records about a /payback request. + * Information the exchange records about a /payback request + * in a reserve history. */ struct TALER_EXCHANGEDB_Payback { @@ -316,13 +317,52 @@ struct TALER_EXCHANGEDB_Payback /** - * Information the exchange records about a /payback-refresh request. + * Information the exchange records about a /payback request + * in a coin history. */ -struct TALER_EXCHANGEDB_PaybackRefresh +struct TALER_EXCHANGEDB_PaybackListEntry { /** - * Information about the coin that was paid back. + * Blinding factor supplied to prove to the exchange that + * the coin came from this reserve. + */ + struct TALER_DenominationBlindingKeyP coin_blind; + + /** + * Signature of the coin of type + * #TALER_SIGNATURE_WALLET_COIN_PAYBACK. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** + * Public key of the reserve the coin was paid back into. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * How much was the coin still worth at this time? + */ + struct TALER_Amount value; + + /** + * When did the /payback operation happen? + */ + struct GNUNET_TIME_Absolute timestamp; + +}; + + +/** + * Information the exchange records about a /payback-refresh request in + * a coin transaction history. + */ +struct TALER_EXCHANGEDB_PaybackRefreshListEntry +{ + + /** + * Information about the coin that was paid back + * (NOT the coin we are considering the history of!) */ struct TALER_CoinPublicInfo coin; @@ -534,22 +574,95 @@ struct TALER_EXCHANGEDB_Deposit /** - * @brief Specification for a /refund operation. The combination of - * the coin's public key, the merchant's public key and the - * transaction ID must be unique. While a coin can (theoretically) be - * deposited at the same merchant twice (with partial spending), the - * merchant must either use a different public key or a different - * transaction ID for the two transactions. The same goes for - * refunds, hence we also have a "rtransaction" ID which is disjoint - * from the transaction ID. The same coin must not be used twice at - * the same merchant for the same transaction or rtransaction ID. + * @brief Specification for a /deposit operation in the + * `struct TALER_EXCHANGEDB_TransactionList`. */ -struct TALER_EXCHANGEDB_Refund +struct TALER_EXCHANGEDB_DepositListEntry { + /** - * Information about the coin that is being refunded. + * ECDSA signature affirming that the customer intends + * this coin to be deposited at the merchant identified + * by @e h_wire in relation to the proposal data identified + * by @e h_contract_terms. */ - struct TALER_CoinPublicInfo coin; + struct TALER_CoinSpendSignatureP csig; + + /** + * Public key of the merchant. Enables later identification + * of the merchant in case of a need to rollback transactions. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash over the proposa data between merchant and customer + * (remains unknown to the Exchange). + */ + struct GNUNET_HashCode h_contract_terms; + + /** + * Hash of the (canonical) representation of @e wire, used + * to check the signature on the request. Generated by + * the exchange from the detailed wire data provided by the + * merchant. + */ + struct GNUNET_HashCode h_wire; + + /** + * Detailed information about the receiver for executing the transaction. + * Includes URL in payto://-format and salt. + */ + json_t *receiver_wire_account; + + /** + * Time when this request was generated. Used, for example, to + * assess when (roughly) the income was achieved for tax purposes. + * Note that the Exchange will only check that the timestamp is not "too + * far" into the future (i.e. several days). The fact that the + * timestamp falls within the validity period of the coin's + * denomination key is irrelevant for the validity of the deposit + * request, as obviously the customer and merchant could conspire to + * set any timestamp. Also, the Exchange must accept very old deposit + * requests, as the merchant might have been unable to transmit the + * deposit request in a timely fashion (so back-dating is not + * prevented). + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * How much time does the merchant have to issue a refund request? + * Zero if refunds are not allowed. After this time, the coin + * cannot be refunded. + */ + struct GNUNET_TIME_Absolute refund_deadline; + + /** + * How much time does the merchant have to execute the wire transfer? + * This time is advisory for aggregating transactions, not a hard + * constraint (as the merchant can theoretically pick any time, + * including one in the past). + */ + struct GNUNET_TIME_Absolute wire_deadline; + + /** + * Fraction of the coin's remaining value to be deposited, including + * depositing fee (if any). The coin is identified by @e coin_pub. + */ + struct TALER_Amount amount_with_fee; + + /** + * Depositing fee. + */ + struct TALER_Amount deposit_fee; + +}; + + +/** + * @brief Specification for a /refund operation in a coin's transaction list. + */ +struct TALER_EXCHANGEDB_RefundListEntry +{ /** * Public key of the merchant. @@ -587,6 +700,32 @@ struct TALER_EXCHANGEDB_Refund }; +/** + * @brief Specification for a /refund operation. The combination of + * the coin's public key, the merchant's public key and the + * transaction ID must be unique. While a coin can (theoretically) be + * deposited at the same merchant twice (with partial spending), the + * merchant must either use a different public key or a different + * transaction ID for the two transactions. The same goes for + * refunds, hence we also have a "rtransaction" ID which is disjoint + * from the transaction ID. The same coin must not be used twice at + * the same merchant for the same transaction or rtransaction ID. + */ +struct TALER_EXCHANGEDB_Refund +{ + /** + * Information about the coin that is being refunded. + */ + struct TALER_CoinPublicInfo coin; + + /** + * Details about the refund. + */ + struct TALER_EXCHANGEDB_RefundListEntry details; + +}; + + /** * @brief Specification for coin in a /refresh/melt operation. */ @@ -627,7 +766,47 @@ struct TALER_EXCHANGEDB_RefreshSession /** - * Information about a /refresh/melt operation in the transaction history. + * Information about a /refresh/melt operation in a coin transaction history. + */ +struct TALER_EXCHANGEDB_RefreshMeltListEntry +{ + + /** + * Signature over the melting operation. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** + * Refresh commitment this coin is melted into. + */ + struct TALER_RefreshCommitmentP rc; + + /** + * How much value is being melted? This amount includes the fees, + * so the final amount contributed to the melt is this value minus + * the fee for melting the coin. We include the fee in what is + * being signed so that we can verify a reserve's remaining total + * balance without needing to access the respective denomination key + * information each time. + */ + struct TALER_Amount amount_with_fee; + + /** + * Melt fee the exchange charged. + */ + struct TALER_Amount melt_fee; + + /** + * Index (smaller #TALER_CNC_KAPPA) which the exchange has chosen to not + * have revealed during cut and choose. + */ + uint32_t noreveal_index; + +}; + + +/** + * Information about a /refresh/melt operation. */ struct TALER_EXCHANGEDB_RefreshMelt { @@ -744,39 +923,39 @@ struct TALER_EXCHANGEDB_TransactionList * Details if transaction was a /deposit operation. * (#TALER_EXCHANGEDB_TT_DEPOSIT) */ - struct TALER_EXCHANGEDB_Deposit *deposit; + struct TALER_EXCHANGEDB_DepositListEntry *deposit; /** * Details if transaction was a /refresh/melt operation. * (#TALER_EXCHANGEDB_TT_REFRESH_MELT) */ - struct TALER_EXCHANGEDB_RefreshMelt *melt; + struct TALER_EXCHANGEDB_RefreshMeltListEntry *melt; /** * Details if transaction was a /refund operation. * (#TALER_EXCHANGEDB_TT_REFUND) */ - struct TALER_EXCHANGEDB_Refund *refund; + struct TALER_EXCHANGEDB_RefundListEntry *refund; /** * Details if transaction was a /payback-refund operation where * this coin was the OLD coin. * (#TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK). */ - struct TALER_EXCHANGEDB_PaybackRefresh *old_coin_payback; + struct TALER_EXCHANGEDB_PaybackRefreshListEntry *old_coin_payback; /** * Details if transaction was a /payback operation. * (#TALER_EXCHANGEDB_TT_PAYBACK) */ - struct TALER_EXCHANGEDB_Payback *payback; + struct TALER_EXCHANGEDB_PaybackListEntry *payback; /** * Details if transaction was a /payback-refund operation where * this coin was the REFRESHED coin. * (#TALER_EXCHANGEDB_TT_PAYBACK_REFRESH) */ - struct TALER_EXCHANGEDB_PaybackRefresh *payback_refresh; + struct TALER_EXCHANGEDB_PaybackRefreshListEntry *payback_refresh; } details; @@ -1790,7 +1969,10 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls the @e cls of this struct with the plugin-specific state * @param session connection to the database - * @param deposit the deposit to check + * @param coin_pub the coin to check for deposit + * @param merchant_pub merchant to receive the deposit + * @param h_contract_terms contract terms of the deposit + * @param h_wire hash of the merchant's wire details * @return #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if is is marked done, * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if not, * otherwise transaction error status (incl. deposit unknown) @@ -1798,7 +1980,10 @@ struct TALER_EXCHANGEDB_Plugin enum GNUNET_DB_QueryStatus (*test_deposit_done)(void *cls, struct TALER_EXCHANGEDB_Session *session, - const struct TALER_EXCHANGEDB_Deposit *deposit); + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_contract_terms, + const struct GNUNET_HashCode *h_wire); /** -- cgit v1.2.3