diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2022-10-04 11:35:21 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2022-10-04 11:35:21 +0200 |
commit | 77266e6c93f3368171a8b17288f279195f1931dc (patch) | |
tree | 6d3a00cc796feb3724c035b8c0be999717d9eaa3 /src/exchangedb | |
parent | 3fdf88f612719f062e5a19969f22204075941128 (diff) | |
parent | 856b8e26c2b83ebce31eb35c9fc9f23641187be9 (diff) |
Merge branch 'master' into auction_brandt
Diffstat (limited to 'src/exchangedb')
-rw-r--r-- | src/exchangedb/Makefile.am | 8 | ||||
-rw-r--r-- | src/exchangedb/common-0001.sql | 8 | ||||
-rw-r--r-- | src/exchangedb/pg_do_reserve_open.c | 73 | ||||
-rw-r--r-- | src/exchangedb/pg_do_reserve_open.h | 55 | ||||
-rw-r--r-- | src/exchangedb/pg_helper.h | 149 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_close_request.c | 67 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_close_request.h | 52 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_reserve_open_deposit.c | 66 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_reserve_open_deposit.h | 54 | ||||
-rw-r--r-- | src/exchangedb/pg_iterate_kyc_reference.c | 129 | ||||
-rw-r--r-- | src/exchangedb/pg_iterate_kyc_reference.h | 46 | ||||
-rw-r--r-- | src/exchangedb/pg_iterate_reserve_close_info.c | 129 | ||||
-rw-r--r-- | src/exchangedb/pg_iterate_reserve_close_info.h | 50 | ||||
-rw-r--r-- | src/exchangedb/pg_select_reserve_close_info.c | 61 | ||||
-rw-r--r-- | src/exchangedb/pg_select_reserve_close_info.h | 49 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 150 | ||||
-rw-r--r-- | src/exchangedb/procedures.sql | 117 |
17 files changed, 1079 insertions, 184 deletions
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 01ce13de..1fc89d1b 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -68,7 +68,13 @@ plugin_LTLIBRARIES = \ endif libtaler_plugin_exchangedb_postgres_la_SOURCES = \ - plugin_exchangedb_postgres.c + plugin_exchangedb_postgres.c pg_helper.h \ + pg_do_reserve_open.c pg_do_reserve_open.h \ + pg_insert_close_request.c pg_insert_close_request.h \ + pg_insert_reserve_open_deposit.c pg_insert_reserve_open_deposit.h \ + pg_iterate_kyc_reference.c pg_iterate_kyc_reference.h \ + pg_iterate_reserve_close_info.c pg_iterate_reserve_close_info.h \ + pg_select_reserve_close_info.c pg_select_reserve_close_info.h libtaler_plugin_exchangedb_postgres_la_LIBADD = \ $(LTLIBINTL) libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \ diff --git a/src/exchangedb/common-0001.sql b/src/exchangedb/common-0001.sql index 4a0aac38..564bf3b3 100644 --- a/src/exchangedb/common-0001.sql +++ b/src/exchangedb/common-0001.sql @@ -459,7 +459,8 @@ BEGIN PERFORM create_partitioned_table( 'CREATE TABLE IF NOT EXISTS %I' '(reserve_open_deposit_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE / PRIMARY KEY' - ',reserve_pub BYTEA NOT NULL' -- REFERENCES reserves (reserve_pub) ON DELETE CASCADE' + ',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)' + ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=32)' ',request_timestamp INT8 NOT NULL' ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)' ',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)' @@ -496,7 +497,7 @@ BEGIN EXECUTE FORMAT ( 'ALTER TABLE reserves_open_deposits_' || partition_suffix || ' ' 'ADD CONSTRAINT reserves_open_deposits_' || partition_suffix || '_coin_unique ' - 'PRIMARY KEY (coin_pub,reserve_pub)' + 'PRIMARY KEY (coin_pub,coin_sig)' ); END $$; @@ -1749,6 +1750,9 @@ BEGIN ',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)' ',close_val INT8 NOT NULL' ',close_frac INT4 NOT NULL' + ',close_fee_val INT8 NOT NULL' + ',close_fee_frac INT4 NOT NULL' + ',payto_uri VARCHAR NOT NULL' ',PRIMARY KEY (reserve_pub,close_timestamp)' ') %s ;' ,table_name diff --git a/src/exchangedb/pg_do_reserve_open.c b/src/exchangedb/pg_do_reserve_open.c new file mode 100644 index 00000000..bd4f7240 --- /dev/null +++ b/src/exchangedb/pg_do_reserve_open.c @@ -0,0 +1,73 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_do_reserve_open.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_do_reserve_open.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TEH_PG_do_reserve_open ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *total_paid, + uint32_t min_purse_limit, + const struct TALER_ReserveSignatureP *reserve_sig, + struct GNUNET_TIME_Timestamp desired_expiration, + struct GNUNET_TIME_Timestamp now, + const struct TALER_Amount *open_fee, + struct TALER_Amount *open_cost, + struct GNUNET_TIME_Timestamp *final_expiration) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + TALER_PQ_query_param_amount (total_paid), + GNUNET_PQ_query_param_uint32 (&min_purse_limit), + GNUNET_PQ_query_param_auto_from_type (reserve_sig), + GNUNET_PQ_query_param_timestamp (&desired_expiration), + GNUNET_PQ_query_param_timestamp (&now), + TALER_PQ_query_param_amount (open_fee), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("open_cost", + open_cost), + GNUNET_PQ_result_spec_timestamp ("final_expiration", + final_expiration), + GNUNET_PQ_result_spec_end + }; + + PREPARE (pg, + "do_reserve_open", + "SELECT " + " open_cost_val" + ",open_cost_frac" + ",final_expiration" + " FROM exchange_do_reserve_open" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9);"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "do_reserve_open", + params, + rs); +} diff --git a/src/exchangedb/pg_do_reserve_open.h b/src/exchangedb/pg_do_reserve_open.h new file mode 100644 index 00000000..aeef59eb --- /dev/null +++ b/src/exchangedb/pg_do_reserve_open.h @@ -0,0 +1,55 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_do_reserve_open.h + * @brief implementation of the do_reserve_open function + * @author Christian Grothoff + */ +#ifndef PG_DO_RESERVE_OPEN_H +#define PG_DO_RESERVE_OPEN_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Insert reserve close operation into database. + * + * @param cls closure + * @param reserve_pub which reserve is this about? + * @param execution_date when did we perform the transfer? + * @param receiver_account to which account do we transfer, in payto://-format + * @param wtid identifier for the wire transfer + * @param amount_with_fee amount we charged to the reserve + * @param closing_fee how high is the closing fee + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TEH_PG_do_reserve_open ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *total_paid, + uint32_t min_purse_limit, + const struct TALER_ReserveSignatureP *reserve_sig, + struct GNUNET_TIME_Timestamp desired_expiration, + struct GNUNET_TIME_Timestamp now, + const struct TALER_Amount *open_fee, + struct TALER_Amount *open_cost, + struct GNUNET_TIME_Timestamp *final_expiration); + + +#endif diff --git a/src/exchangedb/pg_helper.h b/src/exchangedb/pg_helper.h new file mode 100644 index 00000000..e0a4be49 --- /dev/null +++ b/src/exchangedb/pg_helper.h @@ -0,0 +1,149 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_helper.h + * @brief shared internal definitions for postgres DB plugin + * @author Christian Grothoff + */ +#ifndef PG_HELPER_H +#define PG_HELPER_H + + +/** + * Type of the "cls" argument given to each of the functions in + * our API. + */ +struct PostgresClosure +{ + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Directory with SQL statements to run to create tables. + */ + char *sql_dir; + + /** + * After how long should idle reserves be closed? + */ + struct GNUNET_TIME_Relative idle_reserve_expiration_time; + + /** + * After how long should reserves that have seen withdraw operations + * be garbage collected? + */ + struct GNUNET_TIME_Relative legal_reserve_expiration_time; + + /** + * What delay should we introduce before ready transactions + * are actually aggregated? + */ + struct GNUNET_TIME_Relative aggregator_shift; + + /** + * Which currency should we assume all amounts to be in? + */ + char *currency; + + /** + * Our base URL. + */ + char *exchange_url; + + /** + * Postgres connection handle. + */ + struct GNUNET_PQ_Context *conn; + + /** + * Name of the current transaction, for debugging. + */ + const char *transaction_name; + + /** + * Counts how often we have established a fresh @e conn + * to the database. Used to re-prepare statements. + */ + unsigned long long prep_gen; + + /** + * Did we initialize the prepared statements + * for this session? (To be replaced with @e prep_gen.) + */ + bool init; + +}; + + +/** + * Prepares SQL statement @a sql under @a name for + * connection @a pg once. + * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure. + * + * @param pg a `struct PostgresClosure` + * @param name name to prepare the statement under + * @param sql actual SQL text + */ +#define PREPARE(pg,name,sql) \ + do { \ + static unsigned long long prep_cnt; \ + \ + if (prep_cnt < pg->prep_gen) \ + { \ + struct GNUNET_PQ_PreparedStatement ps[] = { \ + GNUNET_PQ_make_prepare (name, sql, 0), \ + GNUNET_PQ_PREPARED_STATEMENT_END \ + }; \ + \ + if (GNUNET_OK != \ + GNUNET_PQ_prepare_statements (pg->conn, \ + ps)) \ + { \ + GNUNET_break (0); \ + return GNUNET_DB_STATUS_HARD_ERROR; \ + } \ + prep_cnt = pg->prep_gen; \ + } \ + } while (0) + + +/** + * Wrapper macro to add the currency from the plugin's state + * when fetching amounts from the database. + * + * @param field name of the database field to fetch amount from + * @param[out] amountp pointer to amount to set + */ +#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \ + field,pg->currency,amountp) + + +/** + * Wrapper macro to add the currency from the plugin's state + * when fetching amounts from the database. NBO variant. + * + * @param field name of the database field to fetch amount from + * @param[out] amountp pointer to amount to set + */ +#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \ + amountp) TALER_PQ_result_spec_amount_nbo ( \ + field,pg->currency,amountp) + + +#endif diff --git a/src/exchangedb/pg_insert_close_request.c b/src/exchangedb/pg_insert_close_request.c new file mode 100644 index 00000000..43ca944f --- /dev/null +++ b/src/exchangedb/pg_insert_close_request.c @@ -0,0 +1,67 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_insert_close_request.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_insert_close_request.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TEH_PG_insert_close_request ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + const char *payto_uri, + const struct TALER_ReserveSignatureP *reserve_sig, + struct GNUNET_TIME_Timestamp request_timestamp, + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_timestamp (&request_timestamp), + GNUNET_PQ_query_param_auto_from_type (reserve_sig), + TALER_PQ_query_param_amount (balance), + TALER_PQ_query_param_amount (closing_fee), + GNUNET_PQ_query_param_string (payto_uri), + GNUNET_PQ_query_param_end + }; + + PREPARE (pg, + "insert_account_close", + "INSERT INTO close_requests" + "(reserve_pub" + ",close_timestamp" + ",reserve_sig" + ",close_val" + ",close_frac," + ",close_fee_val" + ",close_fee_frac" + ",payto_uri" + ")" + "VALUES ($1, $2, $3, $4, $5, $6, $7)" + " ON CONFLICT DO NOTHING;"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_account_close", + params); +} diff --git a/src/exchangedb/pg_insert_close_request.h b/src/exchangedb/pg_insert_close_request.h new file mode 100644 index 00000000..c014a10b --- /dev/null +++ b/src/exchangedb/pg_insert_close_request.h @@ -0,0 +1,52 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_insert_close_request.h + * @brief implementation of the insert_close_request function + * @author Christian Grothoff + */ +#ifndef PG_INSERT_CLOSE_REQUEST_H +#define PG_INSERT_CLOSE_REQUEST_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Function called to initiate closure of an account. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param reserve_pub public key of the account to close + * @param payto_uri where to wire the funds + * @param reserve_sig signature affiming that the account is to be closed + * @param request_timestamp time of the close request (client-side?) + * @param balance final balance in the reserve + * @param closing_fee closing fee to charge + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TEH_PG_insert_close_request ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + const char *payto_uri, + const struct TALER_ReserveSignatureP *reserve_sig, + struct GNUNET_TIME_Timestamp request_timestamp, + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee); + + +#endif diff --git a/src/exchangedb/pg_insert_reserve_open_deposit.c b/src/exchangedb/pg_insert_reserve_open_deposit.c new file mode 100644 index 00000000..8bf70e7b --- /dev/null +++ b/src/exchangedb/pg_insert_reserve_open_deposit.c @@ -0,0 +1,66 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_insert_reserve_open_deposit.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_insert_reserve_open_deposit.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TEH_PG_insert_reserve_open_deposit ( + void *cls, + const struct TALER_CoinPublicInfo *cpi, + const struct TALER_CoinSpendSignatureP *coin_sig, + uint64_t known_coin_id, + const struct TALER_Amount *coin_total, + const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_ReservePublicKeyP *reserve_pub, + bool *insufficient_funds) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&cpi->coin_pub), + GNUNET_PQ_query_param_uint64 (&known_coin_id), + GNUNET_PQ_query_param_auto_from_type (coin_sig), + GNUNET_PQ_query_param_auto_from_type (reserve_sig), + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + TALER_PQ_query_param_amount (coin_total), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("out_insufficient_funds", + insufficient_funds), + GNUNET_PQ_result_spec_end + }; + + PREPARE (pg, + "insert_reserve_open_deposit", + "SELECT " + " out_insufficient_funds" + " FROM exchange_do_reserve_open_deposit" + " ($1,$2,$3,$4,$5,$6,$7);"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "insert_reserve_open_deposit", + params, + rs); +} diff --git a/src/exchangedb/pg_insert_reserve_open_deposit.h b/src/exchangedb/pg_insert_reserve_open_deposit.h new file mode 100644 index 00000000..7eb2fe09 --- /dev/null +++ b/src/exchangedb/pg_insert_reserve_open_deposit.h @@ -0,0 +1,54 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_insert_reserve_open_deposit.h + * @brief implementation of the insert_reserve_open_deposit function + * @author Christian Grothoff + */ +#ifndef PG_INSERT_RESERVE_OPEN_DEPOSIT_H +#define PG_INSERT_RESERVE_OPEN_DEPOSIT_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Insert reserve open coin deposit data into database. + * Subtracts the @a coin_total from the coin's balance. + * + * @param cls closure + * @param cpi public information about the coin + * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT + * @param known_coin_id ID of the coin in the known_coins table + * @param coin_total amount to be spent of the coin (including deposit fee) + * @param reserve_sig signature by the reserve affirming the open operation + * @param reserve_pub public key of the reserve being opened + * @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false + * @return transaction status code, 0 if operation is already in the DB + */ +enum GNUNET_DB_QueryStatus +TEH_PG_insert_reserve_open_deposit ( + void *cls, + const struct TALER_CoinPublicInfo *cpi, + const struct TALER_CoinSpendSignatureP *coin_sig, + uint64_t known_coin_id, + const struct TALER_Amount *coin_total, + const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_ReservePublicKeyP *reserve_pub, + bool *insufficient_funds); + +#endif diff --git a/src/exchangedb/pg_iterate_kyc_reference.c b/src/exchangedb/pg_iterate_kyc_reference.c new file mode 100644 index 00000000..772c51e2 --- /dev/null +++ b/src/exchangedb/pg_iterate_kyc_reference.c @@ -0,0 +1,129 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_iterate_kyc_reference.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_iterate_kyc_reference.h" +#include "pg_helper.h" + + +/** + * Closure for #iterate_kyc_reference_cb() + */ +struct IteratorContext +{ + /** + * Function to call with the results. + */ + TALER_EXCHANGEDB_LegitimizationProcessCallback cb; + + /** + * Closure to pass to @e cb + */ + void *cb_cls; + + /** + * Plugin context. + */ + struct PostgresClosure *pg; +}; + + +/** + * Helper function for #TEH_PG_iterate_kyc_reference(). + * Calls the callback with each denomination key. + * + * @param cls a `struct IteratorContext` + * @param result db results + * @param num_results number of results in @a result + */ +static void +iterate_kyc_reference_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct IteratorContext *ic = cls; + + for (unsigned int i = 0; i<num_results; i++) + { + char *kyc_provider_section_name; + char *provider_user_id; + char *legitimization_id; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_string ("provider_section", + &kyc_provider_section_name), + GNUNET_PQ_result_spec_string ("provider_user_id", + &provider_user_id), + GNUNET_PQ_result_spec_string ("provider_legitimization_id", + &legitimization_id), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + return; + } + ic->cb (ic->cb_cls, + kyc_provider_section_name, + provider_user_id, + legitimization_id); + GNUNET_PQ_cleanup_result (rs); + } +} + + +enum GNUNET_DB_QueryStatus +TEH_PG_iterate_kyc_reference ( + void *cls, + const struct TALER_PaytoHashP *h_payto, + TALER_EXCHANGEDB_LegitimizationProcessCallback lpc, + void *lpc_cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_end + }; + struct IteratorContext ic = { + .cb = lpc, + .cb_cls = lpc_cls, + .pg = pg + }; + + PREPARE (pg, + "iterate_kyc_reference", + "SELECT " + " provider_section" + ",provider_user_id" + ",provider_legitimization_id" + " FROM legitimization_processes" + " WHERE h_payto=$1;"); + return GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "iterate_kyc_reference", + params, + &iterate_kyc_reference_cb, + &ic); +} diff --git a/src/exchangedb/pg_iterate_kyc_reference.h b/src/exchangedb/pg_iterate_kyc_reference.h new file mode 100644 index 00000000..0242fdcf --- /dev/null +++ b/src/exchangedb/pg_iterate_kyc_reference.h @@ -0,0 +1,46 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_iterate_kyc_reference.h + * @brief implementation of the iterate_kyc_reference function + * @author Christian Grothoff + */ +#ifndef PG_ITERATE_KYC_REFERENCE_H +#define PG_ITERATE_KYC_REFERENCE_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Call us on KYC legitimization processes satisfied and not expired for the + * given account. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param h_payto account identifier + * @param lpc function to call for each satisfied KYC legitimization process + * @param lpc_cls closure for @a lpc + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TEH_PG_iterate_kyc_reference ( + void *cls, + const struct TALER_PaytoHashP *h_payto, + TALER_EXCHANGEDB_LegitimizationProcessCallback lpc, + void *lpc_cls); + +#endif diff --git a/src/exchangedb/pg_iterate_reserve_close_info.c b/src/exchangedb/pg_iterate_reserve_close_info.c new file mode 100644 index 00000000..f1b2d452 --- /dev/null +++ b/src/exchangedb/pg_iterate_reserve_close_info.c @@ -0,0 +1,129 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_iterate_reserve_close_info.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_insert_reserve_open_deposit.h" +#include "pg_helper.h" + +/** + * Closure for #iterate_reserve_close_info_cb() + */ +struct IteratorContext +{ + /** + * Function to call with the results. + */ + TALER_EXCHANGEDB_KycAmountCallback cb; + + /** + * Closure to pass to @e cb + */ + void *cb_cls; + + /** + * Plugin context. + */ + struct PostgresClosure *pg; +}; + + +/** + * Helper function for #TEH_PG_iterate_reserve_close_info(). + * Calls the callback with each denomination key. + * + * @param cls a `struct IteratorContext` + * @param result db results + * @param num_results number of results in @a result + */ +static void +iterate_reserve_close_info_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct IteratorContext *ic = cls; + struct PostgresClosure *pg = ic->pg; + + for (unsigned int i = 0; i<num_results; i++) + { + struct TALER_Amount amount; + struct GNUNET_TIME_Absolute ts; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_absolute_time ("execution_date", + &ts), + TALER_PQ_RESULT_SPEC_AMOUNT ("amount", + &amount), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + return; + } + ic->cb (ic->cb_cls, + &amount, + ts); + } +} + + +enum GNUNET_DB_QueryStatus +TEH_PG_iterate_reserve_close_info ( + void *cls, + const struct TALER_PaytoHashP *h_payto, + struct GNUNET_TIME_Absolute time_limit, + TALER_EXCHANGEDB_KycAmountCallback kac, + void *kac_cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_absolute_time (&time_limit), + GNUNET_PQ_query_param_end + }; + struct IteratorContext ic = { + .cb = kac, + .cb_cls = kac_cls, + .pg = pg + }; + + PREPARE (pg, + "iterate_reserve_close_info", + "SELECT" + " amount_val" + ",amount_frac" + ",execution_date" + " FROM reserves_close" + " WHERE wire_target_h_payto=$1" + " AND execution_date >= $2" + " ORDER BY execution_date DESC"); + return GNUNET_PQ_eval_prepared_multi_select ( + pg->conn, + "iterate_reserve_close_info", + params, + &iterate_reserve_close_info_cb, + &ic); +} diff --git a/src/exchangedb/pg_iterate_reserve_close_info.h b/src/exchangedb/pg_iterate_reserve_close_info.h new file mode 100644 index 00000000..a7e7c8d4 --- /dev/null +++ b/src/exchangedb/pg_iterate_reserve_close_info.h @@ -0,0 +1,50 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_iterate_reserve_close_info.h + * @brief implementation of the iterate_reserve_close_info function + * @author Christian Grothoff + */ +#ifndef PG_ITERATE_RESERVE_CLOSE_INFO_H +#define PG_ITERATE_RESERVE_CLOSE_INFO_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Select information needed for KYC checks on reserve close: historic + * reserve closures going to the same account. + * + * @param cls closure + * @param h_payto which target account is this about? + * @param h_payto account identifier + * @param time_limit oldest transaction that could be relevant + * @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK). + * @param kac_cls closure for @a kac + * @return transaction status code, @a kac aborting with #GNUNET_NO is not an error + */ +enum GNUNET_DB_QueryStatus +TEH_PG_iterate_reserve_close_info ( + void *cls, + const struct TALER_PaytoHashP *h_payto, + struct GNUNET_TIME_Absolute time_limit, + TALER_EXCHANGEDB_KycAmountCallback kac, + void *kac_cls); + + +#endif diff --git a/src/exchangedb/pg_select_reserve_close_info.c b/src/exchangedb/pg_select_reserve_close_info.c new file mode 100644 index 00000000..0b373b7b --- /dev/null +++ b/src/exchangedb/pg_select_reserve_close_info.c @@ -0,0 +1,61 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_select_reserve_close_info.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_select_reserve_close_info.h" +#include "pg_helper.h" + + +enum GNUNET_DB_QueryStatus +TEH_PG_select_reserve_close_info ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_Amount *balance, + char **payto_uri) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("close", + balance), + GNUNET_PQ_result_spec_string ("payto_uri", + payto_uri), + GNUNET_PQ_result_spec_end + }; + + PREPARE (pg, + "select_reserve_close_info", + "SELECT " + " close_frac" + ",close_val" + ",payto_uri" + " FROM close_requests" + " WHERE reserve_pub=$1;"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "select_reserve_close_info", + params, + rs); +} diff --git a/src/exchangedb/pg_select_reserve_close_info.h b/src/exchangedb/pg_select_reserve_close_info.h new file mode 100644 index 00000000..2b90ffd0 --- /dev/null +++ b/src/exchangedb/pg_select_reserve_close_info.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 <http://www.gnu.org/licenses/> + */ +/** + * @file pg_select_reserve_close_info.h + * @brief implementation of the select_reserve_close_info function + * @author Christian Grothoff + */ +#ifndef PG_SELECT_RESERVE_CLOSE_INFO_H +#define PG_SELECT_RESERVE_CLOSE_INFO_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Select information needed to see if we can close + * a reserve. + * + * @param cls closure + * @param reserve_pub which reserve is this about? + * @param[out] balance current reserve balance + * @param[out] payto_uri set to URL of account that + * originally funded the reserve; + * could be set to NULL if not known + * @return transaction status code, 0 if reserve unknown + */ +enum GNUNET_DB_QueryStatus +TEH_PG_select_reserve_close_info ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_Amount *balance, + char **payto_uri); + + +#endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index e3da5216..d2e2eb5d 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -29,6 +29,12 @@ #include "taler_util.h" #include "taler_json_lib.h" #include "taler_exchangedb_plugin.h" +#include "pg_helper.h" +#include "pg_insert_close_request.h" +#include "pg_insert_reserve_open_deposit.h" +#include "pg_iterate_kyc_reference.h" +#include "pg_iterate_reserve_close_info.h" +#include "pg_select_reserve_close_info.h" #include <poll.h> #include <pthread.h> #include <libpq-fe.h> @@ -42,26 +48,6 @@ */ #define AUTO_EXPLAIN 1 -/** - * Wrapper macro to add the currency from the plugin's state - * when fetching amounts from the database. - * - * @param field name of the database field to fetch amount from - * @param[out] amountp pointer to amount to set - */ -#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \ - field,pg->currency,amountp) - -/** - * Wrapper macro to add the currency from the plugin's state - * when fetching amounts from the database. NBO variant. - * - * @param field name of the database field to fetch amount from - * @param[out] amountp pointer to amount to set - */ -#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \ - amountp) TALER_PQ_result_spec_amount_nbo ( \ - field,pg->currency,amountp) /** * Log a really unexpected PQ error with all the details we can get hold of. @@ -82,69 +68,6 @@ /** - * Type of the "cls" argument given to each of the functions in - * our API. - */ -struct PostgresClosure -{ - - /** - * Our configuration. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Directory with SQL statements to run to create tables. - */ - char *sql_dir; - - /** - * After how long should idle reserves be closed? - */ - struct GNUNET_TIME_Relative idle_reserve_expiration_time; - - /** - * After how long should reserves that have seen withdraw operations - * be garbage collected? - */ - struct GNUNET_TIME_Relative legal_reserve_expiration_time; - - /** - * What delay should we introduce before ready transactions - * are actually aggregated? - */ - struct GNUNET_TIME_Relative aggregator_shift; - - /** - * Which currency should we assume all amounts to be in? - */ - char *currency; - - /** - * Our base URL. - */ - char *exchange_url; - - /** - * Postgres connection handle. - */ - struct GNUNET_PQ_Context *conn; - - /** - * Name of the current transaction, for debugging. - */ - const char *transaction_name; - - /** - * Did we initialize the prepared statements - * for this session? - */ - bool init; - -}; - - -/** * Drop all Taler tables. This should only be used by testcases. * * @param cls the `struct PostgresClosure` with the plugin-specific state @@ -4467,15 +4390,7 @@ prepare_statements (struct PostgresClosure *pg) " FROM exchange_do_history_request" " ($1, $2, $3, $4, $5)", 5), - /* Used in #postgres_insert_close_request() */ - GNUNET_PQ_make_prepare ( - "call_account_close", - "SELECT " - " out_final_balance_val" - ",out_final_balance_frac" - " FROM exchange_do_close_request" - " ($1, $2, $3)", - 3), + /* Used in #postgres_insert_kyc_requirement_for_account() */ GNUNET_PQ_make_prepare ( "insert_legitimization_requirement", @@ -4674,6 +4589,7 @@ internal_setup (struct PostgresClosure *pg, NULL); if (NULL == db_conn) return GNUNET_SYSERR; + pg->prep_gen++; pg->conn = db_conn; } if (NULL == pg->transaction_name) @@ -16237,44 +16153,6 @@ postgres_insert_history_request ( /** - * Function called to initiate closure of an account. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param reserve_pub public key of the account to close - * @param reserve_sig signature affiming that the account is to be closed - * @param request_timestamp time of the close request (client-side?) - * @param[out] final_balance set to the final balance in the account that will be wired back to the origin account - * @return transaction status code - */ -static enum GNUNET_DB_QueryStatus -postgres_insert_close_request ( - void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig, - struct GNUNET_TIME_Timestamp request_timestamp, - struct TALER_Amount *final_balance) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_timestamp (&request_timestamp), - GNUNET_PQ_query_param_auto_from_type (reserve_sig), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_RESULT_SPEC_AMOUNT ("out_final_balance", - final_balance), - GNUNET_PQ_result_spec_end - }; - - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "call_account_close", - params, - rs); -} - - -/** * Function called to persist a request to drain profits. * * @param cls the @e cls of this struct with the plugin-specific state @@ -17389,8 +17267,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_select_purse_merge; plugin->insert_history_request = &postgres_insert_history_request; - plugin->insert_close_request - = &postgres_insert_close_request; plugin->insert_drain_profit = &postgres_insert_drain_profit; plugin->profit_drains_get_pending @@ -17419,6 +17295,16 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_select_aggregation_amounts_for_kyc_check; plugin->select_merge_amounts_for_kyc_check = &postgres_select_merge_amounts_for_kyc_check; + /* NEW style, sort alphabetically! */ + plugin->insert_close_request + = &TEH_PG_insert_close_request; + plugin->iterate_reserve_close_info + = &TEH_PG_iterate_reserve_close_info; + plugin->iterate_kyc_reference + = &TEH_PG_iterate_kyc_reference; + plugin->select_reserve_close_info + = &TEH_PG_select_reserve_close_info; + return plugin; } diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql index 1940fa7b..8407f20c 100644 --- a/src/exchangedb/procedures.sql +++ b/src/exchangedb/procedures.sql @@ -1778,7 +1778,7 @@ ELSE my_amount_val = my_amount_val + my_amount_frac / 100000000; my_amount_frac = my_amount_frac % 100000000; - UPDATE reserves + UPDATE exchange.reserves SET current_balance_frac=current_balance_frac+my_amount_frac - CASE @@ -1795,7 +1795,7 @@ ELSE WHERE reserve_pub=in_reserve_pub; -- ... and mark purse as finished. - UPDATE purse_requests + UPDATE exchange.purse_requests SET finished=true WHERE purse_pub=in_purse_pub; END IF; @@ -1881,7 +1881,7 @@ THEN out_no_funds=TRUE; RETURN; END IF; - UPDATE reserves + UPDATE exchange.reserves SET purses_active=purses_active+1 WHERE reserve_pub=in_reserve_pub AND purses_active < purses_allowed; @@ -1901,7 +1901,7 @@ ELSE RETURN; END IF; ELSE - UPDATE reserves + UPDATE exchange.reserves SET current_balance_frac=current_balance_frac-in_purse_fee_frac + CASE @@ -1993,7 +1993,7 @@ THEN RETURN; END IF; -UPDATE purse_requests +UPDATE exchange.purse_requests SET refunded=TRUE, finished=TRUE WHERE purse_pub=my_purse_pub; @@ -2011,7 +2011,7 @@ FOR my_deposit IN FROM exchange.purse_deposits WHERE purse_pub = my_purse_pub LOOP - UPDATE known_coins SET + UPDATE exchange.known_coins SET remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac - CASE WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 @@ -2071,7 +2071,7 @@ BEGIN out_idempotent=FALSE; -- Update reserve balance. - UPDATE reserves + UPDATE exchange.reserves SET current_balance_frac=current_balance_frac-in_history_fee_frac + CASE @@ -2103,57 +2103,76 @@ BEGIN END $$; -CREATE OR REPLACE FUNCTION exchange_do_close_request( - IN in_reserve_pub BYTEA, - IN in_close_timestamp INT8, +CREATE OR REPLACE FUNCTION exchange_do_reserve_open_deposit( + IN in_coin_pub BYTEA, + IN in_known_coin_id INT8, + IN in_coin_sig BYTEA, IN in_reserve_sig BYTEA, - OUT out_final_balance_val INT8, - OUT out_final_balance_frac INT4, - OUT out_balance_ok BOOLEAN, - OUT out_conflict BOOLEAN) + IN in_reserve_pub BYTEA, + IN in_coin_total_val INT8, + IN in_coin_total_frac INT4, + OUT out_insufficient_funds BOOLEAN) LANGUAGE plpgsql AS $$ BEGIN - SELECT - current_balance_val - ,current_balance_frac - INTO - out_final_balance_val - ,out_final_balance_frac - FROM exchange.reserves - WHERE reserve_pub=in_reserve_pub; +INSERT INTO exchange.reserves_open_deposits + (reserve_sig + ,reserve_pub + ,request_timestamp + ,coin_pub + ,coin_sig + ,contribution_val + ,contribution_frac + ) + VALUES + (in_reserve_sig + ,in_reserve_pub + ,in_request_timestamp + ,in_coin_pub + ,in_coin_sig + ,in_coin_total_val + ,in_coin_total_frac) + ON CONFLICT DO NOTHING; - IF NOT FOUND - THEN - out_final_balance_val=0; - out_final_balance_frac=0; - out_balance_ok = FALSE; - out_conflict = FALSE; - END IF; +IF NOT FOUND +THEN + -- Idempotent request known, return success. + out_insufficient_funds=FALSE; + RETURN; +END IF; - INSERT INTO exchange.close_requests - (reserve_pub - ,close_timestamp - ,reserve_sig - ,close_val - ,close_frac) - VALUES - (in_reserve_pub - ,in_close_timestamp - ,in_reserve_sig - ,out_final_balance_val - ,out_final_balance_frac) - ON CONFLICT DO NOTHING; - out_conflict = NOT FOUND; - UPDATE reserves SET - current_balance_val=0 - ,current_balance_frac=0 - WHERE reserve_pub=in_reserve_pub; - out_balance_ok = TRUE; +-- Check and update balance of the coin. +UPDATE exchange.known_coins + SET + remaining_frac=remaining_frac-in_coin_total_frac + + CASE + WHEN remaining_frac < in_coin_total_frac + THEN 100000000 + ELSE 0 + END, + remaining_val=remaining_val-in_coin_total_val + - CASE + WHEN remaining_frac < in_coin_total_frac + THEN 1 + ELSE 0 + END + WHERE coin_pub=in_coin_pub + AND ( (remaining_val > in_coin_total_val) OR + ( (remaining_frac >= in_coin_total_frac) AND + (remaining_val >= in_coin_total_val) ) ); -END $$; +IF NOT FOUND +THEN + -- Insufficient balance. + out_insufficient_funds=TRUE; + RETURN; +END IF; +-- Everything fine, return success! +out_insufficient_funds=FALSE; + +END $$; COMMIT; |