-implement reserve closure in test
This commit is contained in:
parent
4fc77b9dbf
commit
09310cc66e
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016-2021 Taler Systems SA
|
||||
Copyright (C) 2016-2022 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -431,11 +431,18 @@ run_reserve_closures (void *cls)
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Checking for reserves to close by date %s\n",
|
||||
GNUNET_TIME_timestamp2s (now));
|
||||
qs = db_plugin->get_expired_reserves (db_plugin->cls,
|
||||
qs = db_plugin->get_unfinished_close_requests (db_plugin->cls,
|
||||
&expired_reserve_cb,
|
||||
NULL);
|
||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
||||
{
|
||||
/* Try expired reserves as well */
|
||||
qs = db_plugin->get_expired_reserves (
|
||||
db_plugin->cls,
|
||||
now,
|
||||
&expired_reserve_cb,
|
||||
NULL);
|
||||
GNUNET_assert (1 >= qs);
|
||||
}
|
||||
switch (qs)
|
||||
{
|
||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||
|
@ -70,6 +70,8 @@ endif
|
||||
libtaler_plugin_exchangedb_postgres_la_SOURCES = \
|
||||
plugin_exchangedb_postgres.c pg_helper.h \
|
||||
pg_do_reserve_open.c pg_do_reserve_open.h \
|
||||
pg_get_expired_reserves.c pg_get_expired_reserves.h \
|
||||
pg_get_unfinished_close_requests.c pg_get_unfinished_close_requests.h \
|
||||
pg_insert_close_request.c pg_insert_close_request.h \
|
||||
pg_insert_records_by_table.c pg_insert_records_by_table.h \
|
||||
pg_insert_reserve_open_deposit.c pg_insert_reserve_open_deposit.h \
|
||||
|
@ -51,32 +51,28 @@ prepare (struct GNUNET_PQ_Context *conn)
|
||||
"(hc"
|
||||
",expiration_date"
|
||||
") VALUES "
|
||||
"($1, $2);",
|
||||
2),
|
||||
"($1, $2);"),
|
||||
/* Used in #postgres_iterate_denomination_info() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"bm_select",
|
||||
"SELECT"
|
||||
" expiration_date"
|
||||
" FROM benchmap"
|
||||
" WHERE hc=$1;",
|
||||
1),
|
||||
" WHERE hc=$1;"),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"bhm_insert",
|
||||
"INSERT INTO benchhmap "
|
||||
"(hc"
|
||||
",expiration_date"
|
||||
") VALUES "
|
||||
"($1, $2);",
|
||||
2),
|
||||
"($1, $2);"),
|
||||
/* Used in #postgres_iterate_denomination_info() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"bhm_select",
|
||||
"SELECT"
|
||||
" expiration_date"
|
||||
" FROM benchhmap"
|
||||
" WHERE hc=$1;",
|
||||
1),
|
||||
" WHERE hc=$1;"),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"bem_insert",
|
||||
"INSERT INTO benchemap "
|
||||
@ -84,16 +80,14 @@ prepare (struct GNUNET_PQ_Context *conn)
|
||||
",ihc"
|
||||
",expiration_date"
|
||||
") VALUES "
|
||||
"($1, $2, $3);",
|
||||
3),
|
||||
"($1, $2, $3);"),
|
||||
/* Used in #postgres_iterate_denomination_info() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"bem_select",
|
||||
"SELECT"
|
||||
" expiration_date"
|
||||
" FROM benchemap"
|
||||
" WHERE ihc=$1 AND hc=$2;",
|
||||
2),
|
||||
" WHERE ihc=$1 AND hc=$2;"),
|
||||
GNUNET_PQ_PREPARED_STATEMENT_END
|
||||
};
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
@ -502,57 +502,6 @@ END
|
||||
$$;
|
||||
|
||||
|
||||
--------------------------- reserves_close_requests -------------------------------
|
||||
|
||||
CREATE OR REPLACE FUNCTION create_table_reserves_close_requests(
|
||||
IN shard_suffix VARCHAR DEFAULT NULL
|
||||
)
|
||||
RETURNS VOID
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
table_name VARCHAR default 'reserves_close_requests';
|
||||
BEGIN
|
||||
|
||||
PERFORM create_partitioned_table(
|
||||
'CREATE TABLE IF NOT EXISTS %I'
|
||||
'(close_request_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE / PRIMARY KEY'
|
||||
',reserve_pub BYTEA NOT NULL' -- REFERENCES reserves (reserve_pub) ON DELETE CASCADE'
|
||||
',execution_date INT8 NOT NULL'
|
||||
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
|
||||
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
|
||||
') %s ;'
|
||||
,table_name
|
||||
,'PARTITION BY HASH (reserve_pub)'
|
||||
,shard_suffix
|
||||
);
|
||||
|
||||
table_name = concat_ws('_', table_name, shard_suffix);
|
||||
|
||||
EXECUTE FORMAT (
|
||||
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_uuid_index '
|
||||
'ON ' || table_name || ' '
|
||||
'(close_request_uuid);'
|
||||
);
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_constraints_to_reserves_close_requests_partition(
|
||||
IN partition_suffix VARCHAR
|
||||
)
|
||||
RETURNS void
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
EXECUTE FORMAT (
|
||||
'ALTER TABLE reserves_close_requests_' || partition_suffix || ' '
|
||||
'ADD CONSTRAINT reserves_close_' || partition_suffix || '_close_request_uuid_pkey '
|
||||
'PRIMARY KEY (close_request_uuid)'
|
||||
);
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
---------------------------- reserves_out -------------------------------
|
||||
|
||||
CREATE OR REPLACE FUNCTION create_table_reserves_out(
|
||||
@ -1752,16 +1701,57 @@ BEGIN
|
||||
',close_fee_val INT8 NOT NULL'
|
||||
',close_fee_frac INT4 NOT NULL'
|
||||
',payto_uri VARCHAR NOT NULL'
|
||||
',done BOOL NOT NULL DEFAULT(FALSE)'
|
||||
',PRIMARY KEY (reserve_pub,close_timestamp)'
|
||||
') %s ;'
|
||||
,table_name
|
||||
,'PARTITION BY HASH (reserve_pub)'
|
||||
,shard_suffix
|
||||
);
|
||||
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_constraints_to_close_requests(
|
||||
IN partition_suffix VARCHAR
|
||||
)
|
||||
RETURNS VOID
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
table_name VARCHAR DEFAULT 'close_requests';
|
||||
BEGIN
|
||||
|
||||
EXECUTE FORMAT (
|
||||
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_uuid_index '
|
||||
'ON ' || table_name || ' '
|
||||
'(close_request_serial_id);'
|
||||
);
|
||||
EXECUTE FORMAT (
|
||||
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_done_index '
|
||||
'ON ' || table_name || ' '
|
||||
'(done);'
|
||||
);
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_constraints_to_close_requests_partition(
|
||||
IN partition_suffix VARCHAR
|
||||
)
|
||||
RETURNS void
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
EXECUTE FORMAT (
|
||||
'ALTER TABLE close_requests_' || partition_suffix || ' '
|
||||
'ADD CONSTRAINT close_requests_' || partition_suffix || '_close_request_uuid_pkey '
|
||||
'UNIQUE (close_request_serial_id)'
|
||||
);
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
------------------------------- purse_deposits -------------------------------
|
||||
|
||||
CREATE OR REPLACE FUNCTION create_table_purse_deposits(
|
||||
|
@ -269,22 +269,6 @@ CREATE TABLE IF NOT EXISTS reserves_open_deposits_default
|
||||
SELECT add_constraints_to_reserves_open_deposits_partition('default');
|
||||
|
||||
|
||||
-- ------------------------------ reserves_close_requests ----------------------------------------
|
||||
|
||||
SELECT create_table_reserves_close_requests();
|
||||
|
||||
COMMENT ON TABLE reserves_close_requests
|
||||
IS 'explicit requests by clients to affect an immediate closure of a reserve';
|
||||
COMMENT ON COLUMN reserves_close_requests.wire_target_h_payto
|
||||
IS 'Identifies the credited bank account. Optional.';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS reserves_close_requests_default
|
||||
PARTITION OF reserves_close_requests
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
|
||||
SELECT add_constraints_to_reserves_close_requests_partition('default');
|
||||
|
||||
|
||||
-- ------------------------------ reserves_out ----------------------------------------
|
||||
|
||||
SELECT create_table_reserves_out();
|
||||
@ -1284,11 +1268,14 @@ COMMENT ON COLUMN close_requests.reserve_sig
|
||||
IS 'Signature affirming that the reserve is to be closed';
|
||||
COMMENT ON COLUMN close_requests.close_val
|
||||
IS 'Balance of the reserve at the time of closing, to be wired to the associated bank account (minus the closing fee)';
|
||||
COMMENT ON COLUMN close_requests.payto_uri
|
||||
IS 'Identifies the credited bank account. Optional.';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS close_requests_default
|
||||
PARTITION OF close_requests
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
|
||||
SELECT add_constraints_to_close_requests_partition('default');
|
||||
|
||||
-- ------------------------------ purse_deposits ----------------------------------------
|
||||
|
||||
|
173
src/exchangedb/pg_get_expired_reserves.c
Normal file
173
src/exchangedb/pg_get_expired_reserves.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
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_get_expired_reserves.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_get_expired_reserves.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_expired_cb().
|
||||
*/
|
||||
struct ExpiredReserveContext
|
||||
{
|
||||
/**
|
||||
* Function to call for each expired reserve.
|
||||
*/
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec;
|
||||
|
||||
/**
|
||||
* Closure to give to @e rec.
|
||||
*/
|
||||
void *rec_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
|
||||
/**
|
||||
* Set to #GNUNET_SYSERR on error.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue status;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
reserve_expired_cb (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct ExpiredReserveContext *erc = cls;
|
||||
struct PostgresClosure *pg = erc->pg;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = GNUNET_OK;
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp exp_date;
|
||||
char *account_details;
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct TALER_Amount remaining_balance;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_timestamp ("expiration_date",
|
||||
&exp_date),
|
||||
GNUNET_PQ_result_spec_string ("account_details",
|
||||
&account_details),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||
&reserve_pub),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
|
||||
&remaining_balance),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ret = GNUNET_SYSERR;
|
||||
break;
|
||||
}
|
||||
ret = erc->rec (erc->rec_cls,
|
||||
&reserve_pub,
|
||||
&remaining_balance,
|
||||
account_details,
|
||||
exp_date);
|
||||
GNUNET_PQ_cleanup_result (rs);
|
||||
if (GNUNET_OK != ret)
|
||||
break;
|
||||
}
|
||||
erc->status = ret;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_get_expired_reserves (void *cls,
|
||||
struct GNUNET_TIME_Timestamp now,
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec,
|
||||
void *rec_cls)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_timestamp (&now),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct ExpiredReserveContext ectx = {
|
||||
.rec = rec,
|
||||
.rec_cls = rec_cls,
|
||||
.pg = pg,
|
||||
.status = GNUNET_OK
|
||||
};
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
PREPARE (pg,
|
||||
"get_expired_reserves",
|
||||
"WITH ed AS MATERIALIZED ( "
|
||||
" SELECT * "
|
||||
" FROM reserves "
|
||||
" WHERE expiration_date <= $1 "
|
||||
" AND (current_balance_val != 0 OR current_balance_frac != 0) "
|
||||
" ORDER BY expiration_date ASC "
|
||||
" LIMIT 1 "
|
||||
") "
|
||||
"SELECT "
|
||||
" ed.expiration_date "
|
||||
" ,payto_uri AS account_details "
|
||||
" ,ed.reserve_pub "
|
||||
" ,current_balance_val "
|
||||
" ,current_balance_frac "
|
||||
"FROM ( "
|
||||
" SELECT "
|
||||
" * "
|
||||
" FROM reserves_in "
|
||||
" WHERE reserve_pub = ( "
|
||||
" SELECT reserve_pub FROM ed) "
|
||||
" ) ri "
|
||||
"JOIN wire_targets wt ON (ri.wire_source_h_payto = wt.wire_target_h_payto) "
|
||||
"JOIN ed ON (ri.reserve_pub = ed.reserve_pub);");
|
||||
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||
"get_expired_reserves",
|
||||
params,
|
||||
&reserve_expired_cb,
|
||||
&ectx);
|
||||
switch (ectx.status)
|
||||
{
|
||||
case GNUNET_SYSERR:
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
case GNUNET_NO:
|
||||
return GNUNET_DB_STATUS_SOFT_ERROR;
|
||||
case GNUNET_OK:
|
||||
break;
|
||||
}
|
||||
return qs;
|
||||
}
|
45
src/exchangedb/pg_get_expired_reserves.h
Normal file
45
src/exchangedb/pg_get_expired_reserves.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
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_get_expired_reserves.h
|
||||
* @brief implementation of the get_expired_reserves function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_GET_EXPIRED_RESERVES_H
|
||||
#define PG_GET_EXPIRED_RESERVES_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about expired reserves and their
|
||||
* remaining balances.
|
||||
*
|
||||
* @param cls closure of the plugin
|
||||
* @param now timestamp based on which we decide expiration
|
||||
* @param rec function to call on expired reserves
|
||||
* @param rec_cls closure for @a rec
|
||||
* @return transaction status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_get_expired_reserves (void *cls,
|
||||
struct GNUNET_TIME_Timestamp now,
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec,
|
||||
void *rec_cls);
|
||||
|
||||
#endif
|
162
src/exchangedb/pg_get_unfinished_close_requests.c
Normal file
162
src/exchangedb/pg_get_unfinished_close_requests.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
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_get_unfinished_close_requests.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_get_unfinished_close_requests.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_close_cb().
|
||||
*/
|
||||
struct CloseReserveContext
|
||||
{
|
||||
/**
|
||||
* Function to call for each to be closed reserve.
|
||||
*/
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec;
|
||||
|
||||
/**
|
||||
* Closure to give to @e rec.
|
||||
*/
|
||||
void *rec_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
|
||||
/**
|
||||
* Set to #GNUNET_SYSERR on error.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue status;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
reserve_cb (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CloseReserveContext *erc = cls;
|
||||
struct PostgresClosure *pg = erc->pg;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = GNUNET_OK;
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp exp_date;
|
||||
char *account_details;
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct TALER_Amount remaining_balance;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_timestamp ("expiration_date",
|
||||
&exp_date),
|
||||
GNUNET_PQ_result_spec_string ("account_details",
|
||||
&account_details),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||
&reserve_pub),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("close",
|
||||
&remaining_balance),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ret = GNUNET_SYSERR;
|
||||
break;
|
||||
}
|
||||
ret = erc->rec (erc->rec_cls,
|
||||
&reserve_pub,
|
||||
&remaining_balance,
|
||||
account_details,
|
||||
exp_date);
|
||||
GNUNET_PQ_cleanup_result (rs);
|
||||
if (GNUNET_OK != ret)
|
||||
break;
|
||||
}
|
||||
erc->status = ret;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_get_unfinished_close_requests (
|
||||
void *cls,
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec,
|
||||
void *rec_cls)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct CloseReserveContext ectx = {
|
||||
.rec = rec,
|
||||
.rec_cls = rec_cls,
|
||||
.pg = pg,
|
||||
.status = GNUNET_OK
|
||||
};
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
PREPARE (pg,
|
||||
"get_unfinished_close_requests",
|
||||
"UPDATE close_requests AS rc"
|
||||
" SET done=TRUE"
|
||||
" WHERE done=FALSE"
|
||||
" RETURNING"
|
||||
" reserve_pub"
|
||||
" ,close_timestamp AS expiration_date"
|
||||
" ,close_val"
|
||||
" ,close_frac"
|
||||
" ,(SELECT payto_uri"
|
||||
" FROM reserves_in ri"
|
||||
" JOIN wire_targets wt ON (ri.wire_source_h_payto = wt.wire_target_h_payto)"
|
||||
" WHERE ri.reserve_pub=rc.reserve_pub)"
|
||||
" AS account_details;");
|
||||
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||
"get_unfinished_close_requests",
|
||||
params,
|
||||
&reserve_cb,
|
||||
&ectx);
|
||||
switch (ectx.status)
|
||||
{
|
||||
case GNUNET_SYSERR:
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
case GNUNET_NO:
|
||||
return GNUNET_DB_STATUS_SOFT_ERROR;
|
||||
case GNUNET_OK:
|
||||
break;
|
||||
}
|
||||
return qs;
|
||||
}
|
46
src/exchangedb/pg_get_unfinished_close_requests.h
Normal file
46
src/exchangedb/pg_get_unfinished_close_requests.h
Normal file
@ -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_get_unfinished_close_requests.h
|
||||
* @brief implementation of the get_unfinished_close_requests function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_GET_UNFINISHED_CLOSE_REQUESTS_H
|
||||
#define PG_GET_UNFINISHED_CLOSE_REQUESTS_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about force-closed reserves
|
||||
* where the close was not yet done (and their remaining
|
||||
* balances). Updates the returned reserve's close
|
||||
* status to "done".
|
||||
*
|
||||
* @param cls closure of the plugin
|
||||
* @param rec function to call on expired reserves
|
||||
* @param rec_cls closure for @a rec
|
||||
* @return transaction status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_get_unfinished_close_requests (
|
||||
void *cls,
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec,
|
||||
void *rec_cls);
|
||||
|
||||
#endif
|
@ -429,46 +429,6 @@ irbt_cb_table_reserves_open_deposits (
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with reserves_close records to insert into table.
|
||||
*
|
||||
* @param pg plugin context
|
||||
* @param td record to insert
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
irbt_cb_table_reserves_close_requests (
|
||||
struct PostgresClosure *pg,
|
||||
const struct TALER_EXCHANGEDB_TableData *td)
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_uint64 (&td->serial),
|
||||
GNUNET_PQ_query_param_auto_from_type (
|
||||
&td->details.reserves_close_requests.reserve_pub),
|
||||
GNUNET_PQ_query_param_timestamp (
|
||||
&td->details.reserves_close_requests.execution_date),
|
||||
GNUNET_PQ_query_param_auto_from_type (
|
||||
&td->details.reserves_close_requests.reserve_sig),
|
||||
GNUNET_PQ_query_param_auto_from_type (
|
||||
&td->details.reserves_close_requests.wire_target_h_payto),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"insert_into_table_reserves_close_requests",
|
||||
"INSERT INTO reserves_close_requests"
|
||||
"(close_request_uuid"
|
||||
",reserve_pub"
|
||||
",execution_date"
|
||||
",reserve_sig"
|
||||
",wire_target_h_payto"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5);");
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"insert_into_table_reserves_close_requests",
|
||||
params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with reserves_close records to insert into table.
|
||||
*
|
||||
@ -1582,6 +1542,10 @@ irbt_cb_table_close_requests (struct PostgresClosure *pg,
|
||||
&td->details.close_requests.reserve_sig),
|
||||
TALER_PQ_query_param_amount (
|
||||
&td->details.close_requests.close),
|
||||
TALER_PQ_query_param_amount (
|
||||
&td->details.close_requests.close_fee),
|
||||
GNUNET_PQ_query_param_string (
|
||||
td->details.close_requests.payto_uri),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
@ -1594,8 +1558,11 @@ irbt_cb_table_close_requests (struct PostgresClosure *pg,
|
||||
",reserve_sig"
|
||||
",close_val"
|
||||
",close_frac"
|
||||
",close_fee_val"
|
||||
",close_fee_frac"
|
||||
",payto_uri"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6);");
|
||||
"($1, $2, $3, $4, $5, $6, $7, $8, $9);");
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"insert_into_table_close_requests",
|
||||
params);
|
||||
@ -1883,9 +1850,6 @@ TEH_PG_insert_records_by_table (void *cls,
|
||||
case TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS:
|
||||
rh = &irbt_cb_table_reserves_open_deposits;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_RESERVES_CLOSE_REQUESTS:
|
||||
rh = &irbt_cb_table_reserves_close_requests;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_RESERVES_OUT:
|
||||
rh = &irbt_cb_table_reserves_out;
|
||||
break;
|
||||
|
@ -1867,12 +1867,21 @@ lrbt_cb_table_close_requests (void *cls,
|
||||
GNUNET_PQ_result_spec_auto_from_type (
|
||||
"reserve_pub",
|
||||
&td.details.close_requests.reserve_pub),
|
||||
GNUNET_PQ_result_spec_timestamp (
|
||||
"close_timestamp",
|
||||
&td.details.close_requests.close_timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type (
|
||||
"reserve_sig",
|
||||
&td.details.close_requests.reserve_sig),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT (
|
||||
"close",
|
||||
&td.details.close_requests.close),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT (
|
||||
"close_fee",
|
||||
&td.details.close_requests.close_fee),
|
||||
GNUNET_PQ_result_spec_string (
|
||||
"payto_uri",
|
||||
&td.details.close_requests.payto_uri),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
|
@ -133,14 +133,6 @@ TEH_PG_lookup_serial_by_table (void *cls,
|
||||
" ORDER BY open_request_uuid DESC"
|
||||
" LIMIT 1;");
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_RESERVES_CLOSE_REQUESTS:
|
||||
XPREPARE ("select_serial_by_table_reserves_close_requests",
|
||||
"SELECT"
|
||||
" close_request_uuid AS serial"
|
||||
" FROM reserves_close_requests"
|
||||
" ORDER BY close_request_uuid DESC"
|
||||
" LIMIT 1;");
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_RESERVES_OUT:
|
||||
XPREPARE ("select_serial_by_table_reserves_out",
|
||||
"SELECT"
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
#include "pg_helper.h"
|
||||
#include "pg_do_reserve_open.h"
|
||||
#include "pg_get_expired_reserves.h"
|
||||
#include "pg_get_unfinished_close_requests.h"
|
||||
#include "pg_insert_close_request.h"
|
||||
#include "pg_insert_records_by_table.h"
|
||||
#include "pg_insert_reserve_open_deposit.h"
|
||||
@ -2344,32 +2346,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" FROM history_requests"
|
||||
" WHERE reserve_pub=$1"
|
||||
" AND request_timestamp>=$2;"),
|
||||
/* Used in #postgres_get_expired_reserves() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_expired_reserves",
|
||||
"WITH ed AS MATERIALIZED ( "
|
||||
" SELECT * "
|
||||
" FROM reserves "
|
||||
" WHERE expiration_date <= $1 "
|
||||
" AND (current_balance_val != 0 OR current_balance_frac != 0) "
|
||||
" ORDER BY expiration_date ASC "
|
||||
" LIMIT 1 "
|
||||
") "
|
||||
"SELECT "
|
||||
" ed.expiration_date "
|
||||
" ,payto_uri AS account_details "
|
||||
" ,ed.reserve_pub "
|
||||
" ,current_balance_val "
|
||||
" ,current_balance_frac "
|
||||
"FROM ( "
|
||||
" SELECT "
|
||||
" * "
|
||||
" FROM reserves_in "
|
||||
" WHERE reserve_pub = ( "
|
||||
" SELECT reserve_pub FROM ed) "
|
||||
" ) ri "
|
||||
"JOIN wire_targets wt ON (ri.wire_source_h_payto = wt.wire_target_h_payto) "
|
||||
"JOIN ed ON (ri.reserve_pub = ed.reserve_pub);"),
|
||||
/* Used in #postgres_get_coin_transactions() to obtain recoup transactions
|
||||
for a coin */
|
||||
GNUNET_PQ_make_prepare (
|
||||
@ -8550,138 +8526,6 @@ postgres_insert_global_fee (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_expired_cb().
|
||||
*/
|
||||
struct ExpiredReserveContext
|
||||
{
|
||||
/**
|
||||
* Function to call for each expired reserve.
|
||||
*/
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec;
|
||||
|
||||
/**
|
||||
* Closure to give to @e rec.
|
||||
*/
|
||||
void *rec_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
|
||||
/**
|
||||
* Set to #GNUNET_SYSERR on error.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue status;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
reserve_expired_cb (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct ExpiredReserveContext *erc = cls;
|
||||
struct PostgresClosure *pg = erc->pg;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = GNUNET_OK;
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp exp_date;
|
||||
char *account_details;
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct TALER_Amount remaining_balance;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_timestamp ("expiration_date",
|
||||
&exp_date),
|
||||
GNUNET_PQ_result_spec_string ("account_details",
|
||||
&account_details),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||
&reserve_pub),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
|
||||
&remaining_balance),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ret = GNUNET_SYSERR;
|
||||
break;
|
||||
}
|
||||
ret = erc->rec (erc->rec_cls,
|
||||
&reserve_pub,
|
||||
&remaining_balance,
|
||||
account_details,
|
||||
exp_date);
|
||||
GNUNET_PQ_cleanup_result (rs);
|
||||
if (GNUNET_OK != ret)
|
||||
break;
|
||||
}
|
||||
erc->status = ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about expired reserves and their
|
||||
* remaining balances.
|
||||
*
|
||||
* @param cls closure of the plugin
|
||||
* @param now timestamp based on which we decide expiration
|
||||
* @param rec function to call on expired reserves
|
||||
* @param rec_cls closure for @a rec
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_get_expired_reserves (void *cls,
|
||||
struct GNUNET_TIME_Timestamp now,
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec,
|
||||
void *rec_cls)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_timestamp (&now),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct ExpiredReserveContext ectx = {
|
||||
.rec = rec,
|
||||
.rec_cls = rec_cls,
|
||||
.pg = pg,
|
||||
.status = GNUNET_OK
|
||||
};
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||
"get_expired_reserves",
|
||||
params,
|
||||
&reserve_expired_cb,
|
||||
&ectx);
|
||||
switch (ectx.status)
|
||||
{
|
||||
case GNUNET_SYSERR:
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
case GNUNET_NO:
|
||||
return GNUNET_DB_STATUS_SOFT_ERROR;
|
||||
case GNUNET_OK:
|
||||
break;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve close operation into database.
|
||||
*
|
||||
@ -15118,7 +14962,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin->get_wire_fee = &postgres_get_wire_fee;
|
||||
plugin->get_global_fee = &postgres_get_global_fee;
|
||||
plugin->get_global_fees = &postgres_get_global_fees;
|
||||
plugin->get_expired_reserves = &postgres_get_expired_reserves;
|
||||
plugin->insert_reserve_closed = &postgres_insert_reserve_closed;
|
||||
plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert;
|
||||
plugin->wire_prepare_data_mark_finished =
|
||||
@ -15290,6 +15133,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
/* NEW style, sort alphabetically! */
|
||||
plugin->do_reserve_open
|
||||
= &TEH_PG_do_reserve_open;
|
||||
plugin->get_expired_reserves
|
||||
= &TEH_PG_get_expired_reserves;
|
||||
plugin->get_unfinished_close_requests
|
||||
= &TEH_PG_get_unfinished_close_requests;
|
||||
plugin->insert_records_by_table
|
||||
= &TEH_PG_insert_records_by_table;
|
||||
plugin->insert_reserve_open_deposit
|
||||
|
@ -50,9 +50,6 @@ BEGIN
|
||||
PERFORM create_table_reserves_open_deposits(shard_suffix);
|
||||
PERFORM add_constraints_to_reserves_open_deposits_partition(shard_suffix);
|
||||
|
||||
PERFORM create_table_reserves_close_requests(shard_suffix);
|
||||
PERFORM add_constraints_to_reserves_close_requests_partition(shard_suffix);
|
||||
|
||||
PERFORM create_table_reserves_out(shard_suffix);
|
||||
PERFORM add_constraints_to_reserves_out_partition(shard_suffix);
|
||||
|
||||
@ -119,6 +116,8 @@ BEGIN
|
||||
PERFORM create_table_history_requests(shard_suffix);
|
||||
|
||||
PERFORM create_table_close_requests(shard_suffix);
|
||||
PERFORM add_constraints_to_close_requests_partition(shard_suffix);
|
||||
|
||||
|
||||
PERFORM create_table_purse_deposits(shard_suffix);
|
||||
PERFORM add_constraints_to_purse_deposits_partition(shard_suffix);
|
||||
|
@ -202,7 +202,6 @@ enum TALER_EXCHANGEDB_ReplicatedTable
|
||||
TALER_EXCHANGEDB_RT_RESERVES_CLOSE,
|
||||
TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS,
|
||||
TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS,
|
||||
TALER_EXCHANGEDB_RT_RESERVES_CLOSE_REQUESTS,
|
||||
TALER_EXCHANGEDB_RT_RESERVES_OUT,
|
||||
TALER_EXCHANGEDB_RT_AUDITORS,
|
||||
TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS,
|
||||
@ -337,14 +336,6 @@ struct TALER_EXCHANGEDB_TableData
|
||||
struct TALER_Amount contribution;
|
||||
} reserves_open_deposits;
|
||||
|
||||
struct
|
||||
{
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct GNUNET_TIME_Timestamp execution_date;
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
struct TALER_PaytoHashP wire_target_h_payto;
|
||||
} reserves_close_requests;
|
||||
|
||||
struct
|
||||
{
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
@ -587,6 +578,8 @@ struct TALER_EXCHANGEDB_TableData
|
||||
struct GNUNET_TIME_Timestamp close_timestamp;
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
struct TALER_Amount close;
|
||||
struct TALER_Amount close_fee;
|
||||
char *payto_uri;
|
||||
} close_requests;
|
||||
|
||||
struct
|
||||
@ -4110,6 +4103,24 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
void *rec_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about force-closed reserves
|
||||
* where the close was not yet done (and their remaining
|
||||
* balances). Updates the returned reserve's close
|
||||
* status to "done".
|
||||
*
|
||||
* @param cls closure of the plugin
|
||||
* @param rec function to call on (to be) closed reserves
|
||||
* @param rec_cls closure for @a rec
|
||||
* @return transaction status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*get_unfinished_close_requests)(
|
||||
void *cls,
|
||||
TALER_EXCHANGEDB_ReserveExpiredCallback rec,
|
||||
void *rec_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve open coin deposit data into database.
|
||||
* Subtracts the @a coin_total from the coin's balance.
|
||||
|
@ -446,8 +446,6 @@ run (void *cls,
|
||||
"create-reserve-101",
|
||||
NULL, /* to origin */
|
||||
MHD_HTTP_OK),
|
||||
#if FIXME
|
||||
/* reserve close logic is not yet implemented, hence this fails: */
|
||||
TALER_TESTING_cmd_exec_closer ("close-reserves-101",
|
||||
config_file,
|
||||
"EUR:1.02",
|
||||
@ -459,7 +457,6 @@ run (void *cls,
|
||||
"create-reserve-101",
|
||||
"EUR:0",
|
||||
MHD_HTTP_OK),
|
||||
#endif
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user