diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 755de66af..694ac8089 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -212,6 +212,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_insert_denomination_info.h pg_insert_denomination_info.c \ pg_do_batch_withdraw_insert.h pg_do_batch_withdraw_insert.c \ pg_do_reserve_open.c pg_do_reserve_open.h \ + pg_do_purse_delete.c pg_do_purse_delete.h \ pg_do_withdraw.h pg_do_withdraw.c \ pg_preflight.h pg_preflight.c \ pg_iterate_active_signkeys.h pg_iterate_active_signkeys.c \ diff --git a/src/exchangedb/pg_do_purse_delete.c b/src/exchangedb/pg_do_purse_delete.c new file mode 100644 index 000000000..27b81cab9 --- /dev/null +++ b/src/exchangedb/pg_do_purse_delete.c @@ -0,0 +1,64 @@ +/* + This file is part of TALER + Copyright (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + */ +/** + * @file exchangedb/pg_do_purse_delete.c + * @brief Implementation of the do_purse_delete function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_do_purse_delete.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TEH_PG_do_purse_delete ( + void *cls, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig, + bool *decided, + bool *found) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (purse_pub), + GNUNET_PQ_query_param_auto_from_type (purse_sig), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("decided", + decided), + GNUNET_PQ_result_spec_bool ("found", + found), + GNUNET_PQ_result_spec_end + }; + + PREPARE (pg, + "call_purse_delete", + "SELECT " + " out_decided AS decided" + ",out_found AS found" + " FROM exchange_do_purse_delete" + " ($1,$2,$3);"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "call_purse_delete", + params, + rs); +} diff --git a/src/exchangedb/pg_do_purse_delete.h b/src/exchangedb/pg_do_purse_delete.h new file mode 100644 index 000000000..01c7dd91b --- /dev/null +++ b/src/exchangedb/pg_do_purse_delete.h @@ -0,0 +1,49 @@ +/* + This file is part of TALER + Copyright (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + */ +/** + * @file exchangedb/pg_do_purse_delete.h + * @brief implementation of the do_purse_delete function for Postgres + * @author Christian Grothoff + */ +#ifndef PG_DO_PURSE_DELETE_H +#define PG_DO_PURSE_DELETE_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Function called to explicitly delete a purse. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param purse_pub purse to delete + * @param purse_sig signature affirming the deletion + * @param[out] decided set to true if the purse was + * already decided and thus could not be deleted + * @param[out] found set to true if the purse was found + * (if false, purse could not be deleted) + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TEH_PG_do_purse_delete ( + void *cls, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig, + bool *decided, + bool *found); + +#endif diff --git a/src/exchangedb/pg_drop_tables.c b/src/exchangedb/pg_drop_tables.c index 4693e1154..55857018b 100644 --- a/src/exchangedb/pg_drop_tables.c +++ b/src/exchangedb/pg_drop_tables.c @@ -43,7 +43,6 @@ TEH_PG_drop_tables (void *cls) { GNUNET_PQ_disconnect (pg->conn); pg->conn = NULL; - pg->init = false; } conn = GNUNET_PQ_connect_with_cfg (pg->cfg, "exchangedb-postgres", diff --git a/src/exchangedb/pg_helper.h b/src/exchangedb/pg_helper.h index 4b5859662..512f75056 100644 --- a/src/exchangedb/pg_helper.h +++ b/src/exchangedb/pg_helper.h @@ -88,12 +88,6 @@ struct PostgresClosure */ uint32_t def_purse_limit; - /** - * Did we initialize the prepared statements - * for this session? (To be replaced with @e prep_gen.) - */ - bool init; - }; diff --git a/src/exchangedb/pg_insert_refresh_reveal.c b/src/exchangedb/pg_insert_refresh_reveal.c index 098a3aed8..bddca472b 100644 --- a/src/exchangedb/pg_insert_refresh_reveal.c +++ b/src/exchangedb/pg_insert_refresh_reveal.c @@ -43,6 +43,22 @@ TEH_PG_insert_refresh_reveal ( GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } + PREPARE (pg, + "insert_refresh_revealed_coin", + "INSERT INTO refresh_revealed_coins " + "(melt_serial_id " + ",freshcoin_index " + ",link_sig " + ",denominations_serial " + ",coin_ev" + ",ewv" + ",h_coin_ev" + ",ev_sig" + ") SELECT $1, $2, $3, " + " denominations_serial, $5, $6, $7, $8" + " FROM denominations" + " WHERE denom_pub_hash=$4" + " ON CONFLICT DO NOTHING;"); for (uint32_t i = 0; iconn, "insert_refresh_transfer_keys", params); diff --git a/src/exchangedb/pg_preflight.c b/src/exchangedb/pg_preflight.c index cc4de6f76..4533c9a97 100644 --- a/src/exchangedb/pg_preflight.c +++ b/src/exchangedb/pg_preflight.c @@ -30,12 +30,10 @@ * Connect to the database if the connection does not exist yet. * * @param pg the plugin-specific state - * @param skip_prepare true if we should skip prepared statement setup * @return #GNUNET_OK on success */ enum GNUNET_GenericReturnValue -TEH_PG_internal_setup (struct PostgresClosure *pg, - bool skip_prepare); +TEH_PG_internal_setup (struct PostgresClosure *pg); enum GNUNET_GenericReturnValue @@ -47,13 +45,9 @@ TEH_PG_preflight (void *cls) GNUNET_PQ_EXECUTE_STATEMENT_END }; - if (! pg->init) - { - if (GNUNET_OK != - TEH_PG_internal_setup (pg, - false)) - return GNUNET_SYSERR; - } + if (GNUNET_OK != + TEH_PG_internal_setup (pg)) + return GNUNET_SYSERR; if (NULL == pg->transaction_name) return GNUNET_OK; /* all good */ if (GNUNET_OK == diff --git a/src/exchangedb/pg_select_refunds_above_serial_id.c b/src/exchangedb/pg_select_refunds_above_serial_id.c index a5f7d3df6..d8c87d7d4 100644 --- a/src/exchangedb/pg_select_refunds_above_serial_id.c +++ b/src/exchangedb/pg_select_refunds_above_serial_id.c @@ -178,7 +178,7 @@ TEH_PG_select_refunds_above_serial_id ( }; enum GNUNET_DB_QueryStatus qs; - /* Fetch refunds with rowid '\geq' the given parameter */ + /* Fetch refunds with rowid '\geq' the given parameter */ PREPARE (pg, "audit_get_refunds_incr", "SELECT" @@ -200,6 +200,19 @@ TEH_PG_select_refunds_above_serial_id ( " ON (kc.denominations_serial=denom.denominations_serial)" " WHERE ref.refund_serial_id>=$1" " ORDER BY ref.refund_serial_id ASC;"); + PREPARE (pg, + "test_refund_full", + "SELECT" + " CAST(SUM(CAST(ref.amount_with_fee_frac AS INT8)) AS INT8) AS s_f" + ",CAST(SUM(ref.amount_with_fee_val) AS INT8) AS s_v" + ",dep.amount_with_fee_val" + ",dep.amount_with_fee_frac" + " FROM refunds ref" + " JOIN deposits dep" + " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)" + " WHERE ref.refund_serial_id=$1" + " GROUP BY (dep.amount_with_fee_val, dep.amount_with_fee_frac);"); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, "audit_get_refunds_incr", params, diff --git a/src/exchangedb/pg_update_kyc_process_by_row.c b/src/exchangedb/pg_update_kyc_process_by_row.c index b15472839..4ae44ce53 100644 --- a/src/exchangedb/pg_update_kyc_process_by_row.c +++ b/src/exchangedb/pg_update_kyc_process_by_row.c @@ -51,6 +51,16 @@ TEH_PG_update_kyc_process_by_row ( }; enum GNUNET_DB_QueryStatus qs; + PREPARE (pg, + "update_legitimization_process", + "UPDATE legitimization_processes" + " SET provider_user_id=$4" + " ,provider_legitimization_id=$5" + " ,expiration_time=GREATEST(expiration_time,$6)" + " WHERE" + " h_payto=$3" + " AND legitimization_process_serial_id=$1" + " AND provider_section=$2;"); qs = GNUNET_PQ_eval_prepared_non_select ( pg->conn, "update_legitimization_process", diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 9e7242cc4..03c138f78 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -23,6 +23,9 @@ * @author Marcello Stanisci */ #include "platform.h" +#include +#include +#include #include "taler_error_codes.h" #include "taler_dbevents.h" #include "taler_pq_lib.h" @@ -56,11 +59,6 @@ #include "pg_select_reserve_close_info.h" #include "pg_select_reserve_closed_above_serial_id.h" #include "pg_select_reserve_open_above_serial_id.h" -#include -#include -#include - -/**NEW INCLUDES**/ #include "pg_insert_purse_request.h" #include "pg_iterate_active_signkeys.h" #include "pg_preflight.h" @@ -94,6 +92,7 @@ #include "pg_begin_revolving_shard.h" #include "pg_get_extension_manifest.h" #include "pg_insert_history_request.h" +#include "pg_do_purse_delete.h" #include "pg_do_purse_merge.h" #include "pg_start_read_committed.h" #include "pg_start_read_only.h" @@ -232,95 +231,14 @@ } while (0) -/** - * Initialize prepared statements for @a pg. - * - * @param[in,out] pg connection to initialize - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -prepare_statements (struct PostgresClosure *pg) -{ - enum GNUNET_GenericReturnValue ret; - struct GNUNET_PQ_PreparedStatement ps[] = { - GNUNET_PQ_make_prepare ( - "get_kyc_h_payto", - "SELECT" - " wire_target_h_payto" - " FROM wire_targets" - " WHERE wire_target_h_payto=$1" - " LIMIT 1;"), - /* Used in #postgres_ensure_coin_known() */ - GNUNET_PQ_make_prepare ( - "get_known_coin_dh", - "SELECT" - " denominations.denom_pub_hash" - " FROM known_coins" - " JOIN denominations USING (denominations_serial)" - " WHERE coin_pub=$1;"), - /* Store information about the desired denominations for a - refresh operation, used in #postgres_insert_refresh_reveal() */ - GNUNET_PQ_make_prepare ( - "insert_refresh_revealed_coin", - "INSERT INTO refresh_revealed_coins " - "(melt_serial_id " - ",freshcoin_index " - ",link_sig " - ",denominations_serial " - ",coin_ev" - ",ewv" - ",h_coin_ev" - ",ev_sig" - ") SELECT $1, $2, $3, " - " denominations_serial, $5, $6, $7, $8" - " FROM denominations" - " WHERE denom_pub_hash=$4" - " ON CONFLICT DO NOTHING;"), - GNUNET_PQ_make_prepare ( - "test_refund_full", - "SELECT" - " CAST(SUM(CAST(ref.amount_with_fee_frac AS INT8)) AS INT8) AS s_f" - ",CAST(SUM(ref.amount_with_fee_val) AS INT8) AS s_v" - ",dep.amount_with_fee_val" - ",dep.amount_with_fee_frac" - " FROM refunds ref" - " JOIN deposits dep" - " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)" - " WHERE ref.refund_serial_id=$1" - " GROUP BY (dep.amount_with_fee_val, dep.amount_with_fee_frac);"), - /* Used in #postgres_update_kyc_requirement_by_row() */ - GNUNET_PQ_make_prepare ( - "update_legitimization_process", - "UPDATE legitimization_processes" - " SET provider_user_id=$4" - " ,provider_legitimization_id=$5" - " ,expiration_time=GREATEST(expiration_time,$6)" - " WHERE" - " h_payto=$3" - " AND legitimization_process_serial_id=$1" - " AND provider_section=$2;"), - GNUNET_PQ_PREPARED_STATEMENT_END - }; - - ret = GNUNET_PQ_prepare_statements (pg->conn, - ps); - if (GNUNET_OK != ret) - return ret; - pg->init = true; - return GNUNET_OK; -} - - /** * Connect to the database if the connection does not exist yet. * * @param pg the plugin-specific state - * @param skip_prepare true if we should skip prepared statement setup * @return #GNUNET_OK on success */ enum GNUNET_GenericReturnValue -TEH_PG_internal_setup (struct PostgresClosure *pg, - bool skip_prepare) +TEH_PG_internal_setup (struct PostgresClosure *pg) { if (NULL == pg->conn) { @@ -366,11 +284,7 @@ TEH_PG_internal_setup (struct PostgresClosure *pg, } if (NULL == pg->transaction_name) GNUNET_PQ_reconnect_if_down (pg->conn); - if (pg->init) - return GNUNET_OK; - if (skip_prepare) - return GNUNET_OK; - return prepare_statements (pg); + return GNUNET_OK; } @@ -472,8 +386,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) return NULL; } if (GNUNET_OK != - TEH_PG_internal_setup (pg, - true)) + TEH_PG_internal_setup (pg)) { GNUNET_free (pg->exchange_url); GNUNET_free (pg->currency); @@ -483,7 +396,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) } plugin = GNUNET_new (struct TALER_EXCHANGEDB_Plugin); plugin->cls = pg; - /* New style, sort alphabetically! */ plugin->do_reserve_open = &TEH_PG_do_reserve_open; plugin->drop_tables @@ -542,7 +454,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_select_reserve_closed_above_serial_id; plugin->select_reserve_open_above_serial_id = &TEH_PG_select_reserve_open_above_serial_id; - /*need to sort*/ plugin->insert_purse_request = &TEH_PG_insert_purse_request; plugin->iterate_active_signkeys @@ -555,7 +466,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_insert_aggregation_tracking; plugin->select_aggregation_amounts_for_kyc_check = &TEH_PG_select_aggregation_amounts_for_kyc_check; - plugin->select_satisfied_kyc_processes = &TEH_PG_select_satisfied_kyc_processes; plugin->kyc_provider_account_lookup @@ -610,6 +520,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_insert_history_request; plugin->do_purse_merge = &TEH_PG_do_purse_merge; + plugin->do_purse_delete + = &TEH_PG_do_purse_delete; plugin->start_read_committed = &TEH_PG_start_read_committed; plugin->start_read_only diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index d680cd731..5dcad4f71 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -5933,6 +5933,27 @@ struct TALER_EXCHANGEDB_Plugin bool *conflict); + /** + * Function called to explicitly delete a purse. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param purse_pub purse to delete + * @param purse_sig signature affirming the deletion + * @param[out] decided set to true if the purse was + * already decided and thus could not be deleted + * @param[out] found set to true if the purse was found + * (if false, purse could not be deleted) + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*do_purse_delete)( + void *cls, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig, + bool *dediced, + bool *found); + + /** * Set the current @a balance in the purse * identified by @a purse_pub. Used by the auditor