From 76b8a2a8de551db8801bd42111bd959a28517cb3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 23 May 2022 16:02:55 +0200 Subject: include purse deposits in coin history --- src/exchange/taler-exchange-httpd_responses.c | 29 +++++++- src/exchangedb/exchangedb_transactions.c | 12 ++++ src/exchangedb/plugin_exchangedb_common.c | 9 +++ src/exchangedb/plugin_exchangedb_postgres.c | 97 ++++++++++++++++++++++++++- src/include/taler_exchangedb_plugin.h | 47 ++++++++++++- src/lib/exchange_api_purse_deposit.c | 2 + src/testing/test_exchange_p2p.c | 4 +- 7 files changed, 193 insertions(+), 7 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index b52f0b88e..0e5c217a9 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -391,8 +391,33 @@ TEH_RESPONSE_compile_transaction_history ( } break; } - default: - GNUNET_assert (0); + + case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: + { + struct TALER_EXCHANGEDB_PurseDepositListEntry *pd + = pos->details.purse_deposit; + + 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", + pd->exchange_base_url), + GNUNET_JSON_pack_data_auto ("purse_pub", + &pd->purse_pub), + GNUNET_JSON_pack_data_auto ("coin_sig", + &pd->coin_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } } } return history; diff --git a/src/exchangedb/exchangedb_transactions.c b/src/exchangedb/exchangedb_transactions.c index 81a33b172..ef46bace6 100644 --- a/src/exchangedb/exchangedb_transactions.c +++ b/src/exchangedb/exchangedb_transactions.c @@ -119,6 +119,18 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals ( return GNUNET_SYSERR; } break; + case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: + /* spent += pos->amount_with_fee */ + if (0 > + TALER_amount_add (&spent, + &spent, + &pos->details.purse_deposit->amount)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + deposit_fee = pos->details.purse_deposit->deposit_fee; + break; } } if (have_refund) diff --git a/src/exchangedb/plugin_exchangedb_common.c b/src/exchangedb/plugin_exchangedb_common.c index e36074e32..ca5903501 100644 --- a/src/exchangedb/plugin_exchangedb_common.c +++ b/src/exchangedb/plugin_exchangedb_common.c @@ -150,6 +150,15 @@ common_free_coin_transaction_list (void *cls, GNUNET_free (rr); break; } + case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: + { + struct TALER_EXCHANGEDB_PurseDepositListEntry *deposit; + + deposit = tl->details.purse_deposit; + GNUNET_free (deposit->exchange_base_url); + GNUNET_free (deposit); + break; + } } { struct TALER_EXCHANGEDB_TransactionList *next; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 0db3d4df0..273cffa09 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -1235,7 +1235,8 @@ prepare_statements (struct PostgresClosure *pg) " WHERE melt_serial_id>=$1" " ORDER BY melt_serial_id ASC;", 1), - /* Query the 'refresh_commitments' by coin public key */ + /* Query the 'refresh_commitments' by coin public key, + used in #postgres_get_coin_transactions() */ GNUNET_PQ_make_prepare ( "get_refresh_session_by_coin", "SELECT" @@ -1255,6 +1256,30 @@ prepare_statements (struct PostgresClosure *pg) " USING (denominations_serial)" " WHERE old_coin_pub=$1;", 1), + /* Find purse deposits by coin, + used in #postgres_get_coin_transactions() */ + GNUNET_PQ_make_prepare ( + "get_purse_deposit_by_coin_pub", + "SELECT" + " partner_url" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",denoms.fee_deposit_val" + ",denoms.fee_deposit_frac" + ",purse_pub" + ",coin_sig" + ",purse_deposit_serial_id" + " FROM purse_deposits pd" + " LEFT JOIN partners" + " USING (partner_serial_id)" + " JOIN known_coins kc" + " ON (refresh_commitments.old_coin_pub = kc.coin_pub)" + " JOIN denominations denoms" + " USING (denominations_serial)" + // FIXME: use to-be-created materialized index + // on coin_pub (query crosses partitions!) + " WHERE coin_pub=$1;", + 1), /* Store information about the desired denominations for a refresh operation, used in #postgres_insert_refresh_reveal() */ GNUNET_PQ_make_prepare ( @@ -7941,6 +7966,70 @@ add_coin_deposit (void *cls, } +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct CoinHistoryContext` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +add_coin_purse_deposit (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct CoinHistoryContext *chc = cls; + struct PostgresClosure *pg = chc->pg; + + for (unsigned int i = 0; i < num_results; i++) + { + struct TALER_EXCHANGEDB_PurseDepositListEntry *deposit; + struct TALER_EXCHANGEDB_TransactionList *tl; + uint64_t serial_id; + + chc->have_deposit_or_melt = true; + deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry); + { + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", + &deposit->amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", + &deposit->deposit_fee), + GNUNET_PQ_result_spec_auto_from_type ("purse_pub", + &deposit->purse_pub), + GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id", + &serial_id), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("partner_url", + &deposit->exchange_base_url), + NULL), + GNUNET_PQ_result_spec_auto_from_type ("coin_sig", + &deposit->coin_sig), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + GNUNET_free (deposit); + chc->failed = true; + return; + } + } + tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); + tl->next = chc->head; + tl->type = TALER_EXCHANGEDB_TT_PURSE_DEPOSIT; + tl->details.purse_deposit = deposit; + tl->serial_id = serial_id; + chc->head = tl; + } +} + + /** * Function to be called with the results of a SELECT statement * that has returned @a num_results results. @@ -8309,6 +8398,9 @@ postgres_get_coin_transactions ( /** #TALER_EXCHANGEDB_TT_MELT */ { "get_refresh_session_by_coin", &add_coin_melt }, + /** #TALER_EXCHANGEDB_TT_PURSE_DEPOSIT */ + { "get_purse_deposit_by_coin_pub", + &add_coin_purse_deposit }, /** #TALER_EXCHANGEDB_TT_REFUND */ { "get_refunds_by_coin", &add_coin_refund }, @@ -8321,6 +8413,9 @@ postgres_get_coin_transactions ( /** #TALER_EXCHANGEDB_TT_MELT */ { "get_refresh_session_by_coin", &add_coin_melt }, + /** #TALER_EXCHANGEDB_TT_PURSE_DEPOSIT */ + { "get_purse_deposit_by_coin_pub", + &add_coin_purse_deposit }, /** #TALER_EXCHANGEDB_TT_REFUND */ { "get_refunds_by_coin", &add_coin_refund }, diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 5a5443eaf..d08c9ff12 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1536,6 +1536,40 @@ struct TALER_EXCHANGEDB_MeltListEntry }; +/** + * Information about a /purses/$PID/deposit operation in a coin transaction history. + */ +struct TALER_EXCHANGEDB_PurseDepositListEntry +{ + + /** + * Exchange hosting the purse, NULL for this exchange. + */ + char *exchange_base_url; + + /** + * Public key of the purse. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Contribution of the coin to the purse, including + * deposit fee. + */ + struct TALER_Amount amount; + + /** + * Depositing fee. + */ + struct TALER_Amount deposit_fee; + + /** + * Signature by the coin affirming the deposit. + */ + struct TALER_CoinSpendSignatureP coin_sig; + +}; + /** * Information about a melt operation. */ @@ -1639,7 +1673,12 @@ enum TALER_EXCHANGEDB_TransactionType /** * Recoup-refresh operation (on the new coin, eliminating its value) */ - TALER_EXCHANGEDB_TT_RECOUP_REFRESH = 5 + TALER_EXCHANGEDB_TT_RECOUP_REFRESH = 5, + + /** + * Purse deposit operation. + */ + TALER_EXCHANGEDB_TT_PURSE_DEPOSIT = 6 }; @@ -1709,6 +1748,12 @@ struct TALER_EXCHANGEDB_TransactionList */ struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup_refresh; + /** + * Coin was deposited into a purse. + * (#TALER_EXCHANGEDB_TT_PURSE_DEPOSIT) + */ + struct TALER_EXCHANGEDB_PurseDepositListEntry *purse_deposit; + } details; }; diff --git a/src/lib/exchange_api_purse_deposit.c b/src/lib/exchange_api_purse_deposit.c index 3ed523b64..2027ca0d8 100644 --- a/src/lib/exchange_api_purse_deposit.c +++ b/src/lib/exchange_api_purse_deposit.c @@ -378,6 +378,7 @@ handle_purse_deposit_finished (void *cls, break; } /* everything OK, proof of double-spending was provided */ + break; } case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: { @@ -455,6 +456,7 @@ handle_purse_deposit_finished (void *cls, break; } /* everything OK, proof of conflicting denomination was provided */ + break; } default: GNUNET_break_op (0); diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c index 2f82d1243..b5cd69a62 100644 --- a/src/testing/test_exchange_p2p.c +++ b/src/testing/test_exchange_p2p.c @@ -251,14 +251,12 @@ run (void *cls, "create-reserve-1", "EUR:2", MHD_HTTP_OK), -#if 1 /* POST history doesn't yet support P2P transfers */ TALER_TESTING_cmd_reserve_status ( "push-check-post-merge-reserve-balance-post", "create-reserve-1", "EUR:2", MHD_HTTP_OK), -#endif /* create 2nd purse for a deposit conflict */ TALER_TESTING_cmd_purse_create_with_reserve ( "purse-create-with-reserve-2", @@ -267,7 +265,7 @@ run (void *cls, true /* upload contract */, GNUNET_TIME_UNIT_MINUTES, /* expiration */ "create-reserve-1"), -#if FIXME_RESERVE_HISTORY +#if 1 TALER_TESTING_cmd_purse_deposit_coins ( "purse-deposit-coins-conflict", MHD_HTTP_CONFLICT, -- cgit v1.2.3