diff --git a/src/exchange/taler-exchange-httpd_reserves_close.c b/src/exchange/taler-exchange-httpd_reserves_close.c index 6d998bb93..be36f1e73 100644 --- a/src/exchange/taler-exchange-httpd_reserves_close.c +++ b/src/exchange/taler-exchange-httpd_reserves_close.c @@ -297,14 +297,13 @@ reserve_close_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } - qs = TEH_plugin->insert_close_request (TEH_plugin->cls, rcc->reserve_pub, payto_uri, &rcc->reserve_sig, rcc->timestamp, - &wf->closing, - &rcc->wire_amount); + &balance, + &wf->closing); GNUNET_free (payto_uri); if (GNUNET_DB_STATUS_HARD_ERROR == qs) { diff --git a/src/exchange/taler-exchange-httpd_reserves_open.c b/src/exchange/taler-exchange-httpd_reserves_open.c index c9f5e4019..d446d9b40 100644 --- a/src/exchange/taler-exchange-httpd_reserves_open.c +++ b/src/exchange/taler-exchange-httpd_reserves_open.c @@ -191,6 +191,7 @@ reserve_open_transaction (void *cls, coin->known_coin_id, &coin->amount, &rsc->reserve_sig, + rsc->reserve_pub, &insufficient_funds); /* 0 == qs is fine, then the coin was already spent for this very operation as identified diff --git a/src/exchangedb/common-0001.sql b/src/exchangedb/common-0001.sql index 4a0aac381..564bf3b35 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_insert_close_request.c b/src/exchangedb/pg_insert_close_request.c index 3622149a7..43ca944f4 100644 --- a/src/exchangedb/pg_insert_close_request.c +++ b/src/exchangedb/pg_insert_close_request.c @@ -33,32 +33,35 @@ TEH_PG_insert_close_request ( const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *closing_fee, - struct TALER_Amount *final_balance) + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee) { struct PostgresClosure *pg = cls; - // FIXME: deal with payto_uri and closing_fee!! 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 }; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_RESULT_SPEC_AMOUNT ("out_final_balance", - final_balance), - GNUNET_PQ_result_spec_end - }; PREPARE (pg, - "call_account_close", - "SELECT " - " out_final_balance_val" - ",out_final_balance_frac" - " FROM exchange_do_close_request" - " ($1, $2, $3)"); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "call_account_close", - params, - rs); + "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 index 09404094f..c014a10b9 100644 --- a/src/exchangedb/pg_insert_close_request.h +++ b/src/exchangedb/pg_insert_close_request.h @@ -34,8 +34,8 @@ * @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 - * @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 */ enum GNUNET_DB_QueryStatus @@ -45,8 +45,8 @@ TEH_PG_insert_close_request ( const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *closing_fee, - struct TALER_Amount *final_balance); + 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 index c767bfeee..8bf70e7b2 100644 --- a/src/exchangedb/pg_insert_reserve_open_deposit.c +++ b/src/exchangedb/pg_insert_reserve_open_deposit.c @@ -34,6 +34,7 @@ TEH_PG_insert_reserve_open_deposit ( 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; @@ -42,11 +43,12 @@ TEH_PG_insert_reserve_open_deposit ( 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 ("insufficient_funds", + GNUNET_PQ_result_spec_bool ("out_insufficient_funds", insufficient_funds), GNUNET_PQ_result_spec_end }; @@ -54,9 +56,9 @@ TEH_PG_insert_reserve_open_deposit ( PREPARE (pg, "insert_reserve_open_deposit", "SELECT " - " insufficient_funds" + " out_insufficient_funds" " FROM exchange_do_reserve_open_deposit" - " ($1,$2,$3,$4,$5,$6);"); + " ($1,$2,$3,$4,$5,$6,$7);"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "insert_reserve_open_deposit", params, diff --git a/src/exchangedb/pg_insert_reserve_open_deposit.h b/src/exchangedb/pg_insert_reserve_open_deposit.h index 335fda52d..7eb2fe093 100644 --- a/src/exchangedb/pg_insert_reserve_open_deposit.h +++ b/src/exchangedb/pg_insert_reserve_open_deposit.h @@ -36,6 +36,7 @@ * @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 */ @@ -47,6 +48,7 @@ TEH_PG_insert_reserve_open_deposit ( 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 index 4a94722c4..772c51e2c 100644 --- a/src/exchangedb/pg_iterate_kyc_reference.c +++ b/src/exchangedb/pg_iterate_kyc_reference.c @@ -69,11 +69,11 @@ iterate_kyc_reference_cb (void *cls, char *provider_user_id; char *legitimization_id; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_string ("section_name", + 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 ("legi_id", + GNUNET_PQ_result_spec_string ("provider_legitimization_id", &legitimization_id), GNUNET_PQ_result_spec_end }; @@ -116,10 +116,10 @@ TEH_PG_iterate_kyc_reference ( PREPARE (pg, "iterate_kyc_reference", "SELECT " - " section_name" + " provider_section" ",provider_user_id" - ",legi_id" - " FROM FIXME" + ",provider_legitimization_id" + " FROM legitimization_processes" " WHERE h_payto=$1;"); return GNUNET_PQ_eval_prepared_multi_select (pg->conn, "iterate_kyc_reference", diff --git a/src/exchangedb/pg_iterate_reserve_close_info.c b/src/exchangedb/pg_iterate_reserve_close_info.c index c5ff61322..f1b2d452b 100644 --- a/src/exchangedb/pg_iterate_reserve_close_info.c +++ b/src/exchangedb/pg_iterate_reserve_close_info.c @@ -68,7 +68,7 @@ iterate_reserve_close_info_cb (void *cls, struct TALER_Amount amount; struct GNUNET_TIME_Absolute ts; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("timestamp", + GNUNET_PQ_result_spec_absolute_time ("execution_date", &ts), TALER_PQ_RESULT_SPEC_AMOUNT ("amount", &amount), @@ -115,14 +115,15 @@ TEH_PG_iterate_reserve_close_info ( "SELECT" " amount_val" ",amount_frac" - ",timestamp" - " FROM FIXME" - " WHERE h_payto=$1" - " AND timestamp >= $2" - " ORDER BY timestamp DESC"); - return GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "iterate_reserve_close_info", - params, - &iterate_reserve_close_info_cb, - &ic); + ",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_select_reserve_close_info.c b/src/exchangedb/pg_select_reserve_close_info.c index 53ea45682..0b373b7bb 100644 --- a/src/exchangedb/pg_select_reserve_close_info.c +++ b/src/exchangedb/pg_select_reserve_close_info.c @@ -39,7 +39,7 @@ TEH_PG_select_reserve_close_info ( GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_RESULT_SPEC_AMOUNT ("balance", + TALER_PQ_RESULT_SPEC_AMOUNT ("close", balance), GNUNET_PQ_result_spec_string ("payto_uri", payto_uri), @@ -49,10 +49,10 @@ TEH_PG_select_reserve_close_info ( PREPARE (pg, "select_reserve_close_info", "SELECT " - " balance_frac" - ",balance_val" + " close_frac" + ",close_val" ",payto_uri" - " FROM FIXME" + " FROM close_requests" " WHERE reserve_pub=$1;"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "select_reserve_close_info", diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 341364f9f..d2e2eb5df 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -32,6 +32,9 @@ #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 #include #include @@ -17264,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 - = &TEH_PG_insert_close_request; plugin->insert_drain_profit = &postgres_insert_drain_profit; plugin->profit_drains_get_pending @@ -17294,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 1940fa7b8..8407f20c7 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; - - IF NOT FOUND - THEN - out_final_balance_val=0; - out_final_balance_frac=0; - out_balance_ok = FALSE; - out_conflict = FALSE; - 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) +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; - 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; +IF NOT FOUND +THEN + -- Idempotent request known, return success. + out_insufficient_funds=FALSE; + RETURN; +END IF; + + +-- 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) ) ); + +IF NOT FOUND +THEN + -- Insufficient balance. + out_insufficient_funds=TRUE; + RETURN; +END IF; + +-- Everything fine, return success! +out_insufficient_funds=FALSE; END $$; - COMMIT; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index bde3c8136..0ce8ff473 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4072,6 +4072,7 @@ struct TALER_EXCHANGEDB_Plugin * @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 */ @@ -4083,6 +4084,7 @@ struct TALER_EXCHANGEDB_Plugin 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); @@ -5600,8 +5602,8 @@ struct TALER_EXCHANGEDB_Plugin * @param payto_uri where to wire the funds * @param reserve_sig signature affiming that the account is to be closed * @param request_timestamp timestamp of the close request + * @param balance balance at the time of closing * @param closing_fee closing fee to charge - * @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 */ enum GNUNET_DB_QueryStatus @@ -5610,8 +5612,8 @@ struct TALER_EXCHANGEDB_Plugin const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *closing_fee, - struct TALER_Amount *final_balance); + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee); /**