diff options
m--------- | contrib/gana | 0 | ||||
-rw-r--r-- | src/exchange/Makefile.am | 1 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 12 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_management.h | 13 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_management_global_fees.c | 268 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 429 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 27 |
7 files changed, 747 insertions, 3 deletions
diff --git a/contrib/gana b/contrib/gana -Subproject 24eb905bac48869b4184801571c0728c772b299 +Subproject 2b8a5d1376cc20acb2d67251f636b5a9d1cf7a6 diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index e4526f1c7..3a07b6f46 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -94,6 +94,7 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_management_auditors_AP_disable.c \ taler-exchange-httpd_management_denominations_HDP_revoke.c \ taler-exchange-httpd_management_extensions.c \ + taler-exchange-httpd_management_global_fees.c \ taler-exchange-httpd_management_post_keys.c \ taler-exchange-httpd_management_signkey_EP_revoke.c \ taler-exchange-httpd_management_wire_enable.c \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 909c8544c..f0dc365a9 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -733,6 +733,18 @@ handle_post_management (struct TEH_RequestContext *rc, root); } if (0 == strcmp (args[0], + "global-fee")) + { + if (NULL != args[1]) + { + GNUNET_break_op (0); + return r404 (rc->connection, + "/management/global-fee/*"); + } + return TEH_handler_management_post_global_fees (rc->connection, + root); + } + if (0 == strcmp (args[0], "extensions")) { return TEH_handler_management_post_extensions (rc->connection, diff --git a/src/exchange/taler-exchange-httpd_management.h b/src/exchange/taler-exchange-httpd_management.h index 67302c96c..1bae49011 100644 --- a/src/exchange/taler-exchange-httpd_management.h +++ b/src/exchange/taler-exchange-httpd_management.h @@ -136,6 +136,19 @@ TEH_handler_management_post_wire_fees ( /** + * Handle a POST "/management/global-fees" request. + * + * @param connection the MHD connection to handle + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +TEH_handler_management_post_global_fees ( + struct MHD_Connection *connection, + const json_t *root); + + +/** * Handle a POST "/management/extensions" request. * * @param connection the MHD connection to handle diff --git a/src/exchange/taler-exchange-httpd_management_global_fees.c b/src/exchange/taler-exchange-httpd_management_global_fees.c new file mode 100644 index 000000000..0753da84b --- /dev/null +++ b/src/exchange/taler-exchange-httpd_management_global_fees.c @@ -0,0 +1,268 @@ +/* + This file is part of TALER + Copyright (C) 2020, 2021, 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 + 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_management_global_fees.c + * @brief Handle request to add global fee details + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_json_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" +#include "taler_signatures.h" +#include "taler-exchange-httpd_management.h" +#include "taler-exchange-httpd_responses.h" + + +/** + * Closure for the #add_fee transaction. + */ +struct AddFeeContext +{ + /** + * Fee's signature affirming the #TALER_SIGNATURE_MASTER_GLOBAL_FEES operation. + */ + struct TALER_MasterSignatureP master_sig; + + /** + * Starting period. + */ + struct GNUNET_TIME_Timestamp start_time; + + /** + * End of period. + */ + struct GNUNET_TIME_Timestamp end_time; + + /** + * Global fee amounts. + */ + struct TALER_GlobalFeeSet fees; + + /** + * When does an unmerged purse expire? + */ + struct GNUNET_TIME_Relative purse_timeout; + + /** + * When does an account without KYC expire? + */ + struct GNUNET_TIME_Relative kyc_timeout; + + /** + * When does an account history expire? + */ + struct GNUNET_TIME_Relative history_expiration; + + /** + * Number of free purses per account. + */ + uint32_t purse_account_limit; + +}; + + +/** + * Function implementing database transaction to add a fee. Runs the + * transaction logic; IF it returns a non-error code, the transaction logic + * MUST NOT queue a MHD response. IF it returns an hard error, the + * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it + * returns the soft error code, the function MAY be called again to retry and + * MUST not queue a MHD response. + * + * @param cls closure with a `struct AddFeeContext` + * @param connection MHD request which triggered the transaction + * @param[out] mhd_ret set to MHD response status for @a connection, + * if transaction failed (!) + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +add_fee (void *cls, + struct MHD_Connection *connection, + MHD_RESULT *mhd_ret) +{ + struct AddFeeContext *afc = cls; + enum GNUNET_DB_QueryStatus qs; + struct TALER_GlobalFeeSet fees; + struct GNUNET_TIME_Relative purse_timeout; + struct GNUNET_TIME_Relative kyc_timeout; + struct GNUNET_TIME_Relative history_expiration; + uint32_t purse_account_limit; + + qs = TEH_plugin->lookup_global_fee_by_time ( + TEH_plugin->cls, + afc->start_time, + afc->end_time, + &fees, + &purse_timeout, + &kyc_timeout, + &history_expiration, + &purse_account_limit); + if (qs < 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "lookup global fee"); + return qs; + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs) + { + if ( (GNUNET_OK == + TALER_amount_is_valid (&fees.history)) && + (0 == + TALER_global_fee_set_cmp (&fees, + &afc->fees)) ) + { + /* this will trigger the 'success' response */ + return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + } + else + { + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_CONFLICT, + TALER_EC_EXCHANGE_MANAGEMENT_GLOBAL_FEE_MISMATCH, + NULL); + } + return GNUNET_DB_STATUS_HARD_ERROR; + } + + qs = TEH_plugin->insert_global_fee ( + TEH_plugin->cls, + afc->start_time, + afc->end_time, + &afc->fees, + afc->purse_timeout, + afc->kyc_timeout, + afc->history_expiration, + afc->purse_account_limit, + &afc->master_sig); + if (qs < 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert fee"); + return qs; + } + return qs; +} + + +MHD_RESULT +TEH_handler_management_post_global_fees ( + struct MHD_Connection *connection, + const json_t *root) +{ + struct AddFeeContext afc; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("master_sig", + &afc.master_sig), + GNUNET_JSON_spec_timestamp ("fee_start", + &afc.start_time), + GNUNET_JSON_spec_timestamp ("fee_end", + &afc.end_time), + TALER_JSON_spec_amount ("history_fee", + TEH_currency, + &afc.fees.history), + TALER_JSON_spec_amount ("kyc_fee", + TEH_currency, + &afc.fees.kyc), + TALER_JSON_spec_amount ("account_fee", + TEH_currency, + &afc.fees.account), + TALER_JSON_spec_amount ("purse_fee", + TEH_currency, + &afc.fees.purse), + GNUNET_JSON_spec_relative_time ("purse_timeout", + &afc.purse_timeout), + GNUNET_JSON_spec_relative_time ("kyc_timeout", + &afc.kyc_timeout), + GNUNET_JSON_spec_relative_time ("history_expiration", + &afc.history_expiration), + GNUNET_JSON_spec_uint32 ("purse_account_limit", + &afc.purse_account_limit), + GNUNET_JSON_spec_end () + }; + + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + root, + spec); + if (GNUNET_SYSERR == res) + return MHD_NO; /* hard failure */ + if (GNUNET_NO == res) + return MHD_YES; /* failure */ + } + + if (GNUNET_OK != + TALER_exchange_offline_global_fee_verify ( + afc.start_time, + afc.end_time, + &afc.fees, + afc.purse_timeout, + afc.kyc_timeout, + afc.history_expiration, + afc.purse_account_limit, + &TEH_master_public_key, + &afc.master_sig)) + { + /* signature invalid */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_MANAGEMENT_GLOBAL_FEE_SIGNATURE_INVALID, + NULL); + } + + { + enum GNUNET_GenericReturnValue res; + MHD_RESULT ret; + + res = TEH_DB_run_transaction (connection, + "add global fee", + TEH_MT_OTHER, + &ret, + &add_fee, + &afc); + if (GNUNET_SYSERR == res) + return ret; + } + // TEH_global_update_state (); // FIXME: trigger! + return TALER_MHD_reply_static ( + connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/* end of taler-exchange-httpd_management_global_fees.c */ diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index fe06634fc..09fa05620 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -1355,6 +1355,29 @@ prepare_statements (struct PostgresClosure *pg) " AND start_date <= $2" " AND end_date > $2;", 2), + /* Used in #postgres_get_global_fee() */ + GNUNET_PQ_make_prepare ( + "get_global_fee", + "SELECT " + " start_date" + ",end_date" + ",history_fee_val" + ",history_fee_frac" + ",kyc_fee_val" + ",kyc_fee_frac" + ",account_fee_val" + ",account_fee_frac" + ",purse_fee_val" + ",purse_fee_frac" + ",purse_timeout" + ",kyc_timeout" + ",history_expiration" + ",purse_account_limit" + ",master_sig" + " FROM global_fee" + " WHERE start_date <= $1" + " AND end_date > $1;", + 1), /* Used in #postgres_insert_wire_fee */ GNUNET_PQ_make_prepare ( "insert_wire_fee", @@ -1372,6 +1395,28 @@ prepare_statements (struct PostgresClosure *pg) ") VALUES " "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);", 10), + /* Used in #postgres_insert_global_fee */ + GNUNET_PQ_make_prepare ( + "insert_global_fee", + "INSERT INTO global_fee " + "(start_date" + ",end_date" + ",history_fee_val" + ",history_fee_frac" + ",kyc_fee_val" + ",kyc_fee_frac" + ",account_fee_val" + ",account_fee_frac" + ",purse_fee_val" + ",purse_fee_frac" + ",purse_timeout" + ",kyc_timeout" + ",history_expiration" + ",purse_account_limit" + ",master_sig" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);", + 15), /* Used in #postgres_store_wire_transfer_out */ GNUNET_PQ_make_prepare ( "insert_wire_out", @@ -1949,6 +1994,26 @@ prepare_statements (struct PostgresClosure *pg) " AND end_date > $2" " AND start_date < $3;", 1), + /* used in #postgres_lookup_wire_fee_by_time() */ + GNUNET_PQ_make_prepare ( + "lookup_global_fee_by_time", + "SELECT" + " history_fee_val" + ",history_fee_frac" + ",kyc_fee_val" + ",kyc_fee_frac" + ",account_fee_val" + ",account_fee_frac" + ",purse_fee_val" + ",purse_fee_frac" + ",purse_timeout" + ",kyc_timeout" + ",history_expiration" + ",purse_account_limit" + " FROM global_fee" + " WHERE end_date > $1" + " AND start_date < $2;", + 1), /* used in #postgres_commit */ GNUNET_PQ_make_prepare ( "do_commit", @@ -7662,6 +7727,71 @@ postgres_get_wire_fee (void *cls, /** + * Obtain global fees from database. + * + * @param cls closure + * @param date for which date do we want the fee? + * @param[out] start_date when does the fee go into effect + * @param[out] end_date when does the fee end being valid + * @param[out] fees how high are the wire fees + * @param[out] purse_timeout set to how long we keep unmerged purses + * @param[out] kyc_timeout set to how long we keep accounts without KYC + * @param[out] history_expiration set to how long we keep account histories + * @param[out] purse_account_limit set to the number of free purses per account + * @param[out] master_sig signature over the above by the exchange master key + * @return status of the transaction + */ +static enum GNUNET_DB_QueryStatus +postgres_get_global_fee (void *cls, + struct GNUNET_TIME_Timestamp date, + struct GNUNET_TIME_Timestamp *start_date, + struct GNUNET_TIME_Timestamp *end_date, + struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative *purse_timeout, + struct GNUNET_TIME_Relative *kyc_timeout, + struct GNUNET_TIME_Relative *history_expiration, + uint32_t *purse_account_limit, + struct TALER_MasterSignatureP *master_sig) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_timestamp (&date), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_timestamp ("start_date", + start_date), + GNUNET_PQ_result_spec_timestamp ("end_date", + end_date), + TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee", + &fees->history), + TALER_PQ_RESULT_SPEC_AMOUNT ("kyc_fee", + &fees->kyc), + TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee", + &fees->account), + TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee", + &fees->purse), + GNUNET_PQ_result_spec_relative_time ("purse_timeout", + purse_timeout), + GNUNET_PQ_result_spec_relative_time ("kyc_timeout", + kyc_timeout), + GNUNET_PQ_result_spec_relative_time ("history_expiration", + history_expiration), + GNUNET_PQ_result_spec_uint32 ("purse_account_limit", + purse_account_limit), + GNUNET_PQ_result_spec_auto_from_type ("master_sig", + master_sig), + GNUNET_PQ_result_spec_end + }; + + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "get_global_fee", + params, + rs); +} + + +/** * Insert wire transfer fee into database. * * @param cls closure @@ -7742,6 +7872,119 @@ postgres_insert_wire_fee (void *cls, /** + * Insert global fee data into database. + * + * @param cls closure + * @param start_date when does the fee go into effect + * @param fees how high is are the global fees + * @param purse_timeout when do purses time out + * @param kyc_timeout when do reserves without KYC time out + * @param history_expiration how long are account histories preserved + * @param purse_account_limit how many purses are free per account * @param master_sig signature over the above by the exchange master key + * @return transaction status code + */ +static enum GNUNET_DB_QueryStatus +postgres_insert_global_fee (void *cls, + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + const struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative purse_timeout, + struct GNUNET_TIME_Relative kyc_timeout, + struct GNUNET_TIME_Relative history_expiration, + uint32_t purse_account_limit, + const struct TALER_MasterSignatureP *master_sig) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_timestamp (&start_date), + GNUNET_PQ_query_param_timestamp (&end_date), + TALER_PQ_query_param_amount (&fees->history), + TALER_PQ_query_param_amount (&fees->kyc), + TALER_PQ_query_param_amount (&fees->account), + TALER_PQ_query_param_amount (&fees->purse), + GNUNET_PQ_query_param_relative_time (&purse_timeout), + GNUNET_PQ_query_param_relative_time (&kyc_timeout), + GNUNET_PQ_query_param_relative_time (&history_expiration), + GNUNET_PQ_query_param_uint32 (&purse_account_limit), + GNUNET_PQ_query_param_auto_from_type (master_sig), + GNUNET_PQ_query_param_end + }; + struct TALER_GlobalFeeSet wx; + struct TALER_MasterSignatureP sig; + struct GNUNET_TIME_Timestamp sd; + struct GNUNET_TIME_Timestamp ed; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_TIME_Relative pt; + struct GNUNET_TIME_Relative kt; + struct GNUNET_TIME_Relative he; + uint32_t pal; + + qs = postgres_get_global_fee (pg, + start_date, + &sd, + &ed, + &wx, + &pt, + &kt, + &he, + &pal, + &sig); + if (qs < 0) + return qs; + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + { + if (0 != GNUNET_memcmp (&sig, + master_sig)) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (0 != + TALER_global_fee_set_cmp (fees, + &wx)) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if ( (GNUNET_TIME_timestamp_cmp (sd, + !=, + start_date)) || + (GNUNET_TIME_timestamp_cmp (ed, + !=, + end_date)) ) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if ( (GNUNET_TIME_relative_cmp (purse_timeout, + !=, + pt)) || + (GNUNET_TIME_relative_cmp (kyc_timeout, + !=, + kt)) || + (GNUNET_TIME_relative_cmp (history_expiration, + !=, + he)) ) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (purse_account_limit != pal) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + /* equal record already exists */ + return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + } + + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_global_fee", + params); +} + + +/** * Closure for #reserve_expired_cb(). */ struct ExpiredReserveContext @@ -10679,10 +10922,10 @@ struct WireFeeLookupContext /** - * Helper function for #postgres_iterate_denomination_info(). - * Calls the callback with each denomination key. + * Helper function for #postgres_lookup_wire_fee_by_time(). + * Calls the callback with the wire fee structure. * - * @param cls a `struct DenomIteratorContext` + * @param cls a `struct WireFeeLookupContext` * @param result db results * @param num_results number of results in @a result */ @@ -10783,6 +11026,182 @@ postgres_lookup_wire_fee_by_time ( /** + * Closure for #global_fee_by_time_helper() + */ +struct GlobalFeeLookupContext +{ + + /** + * Set to the wire fees. Set to invalid if fees conflict over + * the given time period. + */ + struct TALER_GlobalFeeSet *fees; + + /** + * Set to timeout of unmerged purses + */ + struct GNUNET_TIME_Relative *purse_timeout; + + /** + * Set to timeout of accounts without kyc. + */ + struct GNUNET_TIME_Relative *kyc_timeout; + + /** + * Set to history expiration for reserves. + */ + struct GNUNET_TIME_Relative *history_expiration; + + /** + * Set to number of free purses per account. + */ + uint32_t *purse_account_limit; + + /** + * Plugin context. + */ + struct PostgresClosure *pg; +}; + + +/** + * Helper function for #postgres_lookup_global_fee_by_time(). + * Calls the callback with each denomination key. + * + * @param cls a `struct GlobalFeeLookupContext` + * @param result db results + * @param num_results number of results in @a result + */ +static void +global_fee_by_time_helper (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct GlobalFeeLookupContext *wlc = cls; + struct PostgresClosure *pg = wlc->pg; + + for (unsigned int i = 0; i<num_results; i++) + { + struct TALER_GlobalFeeSet fs; + struct GNUNET_TIME_Relative purse_timeout; + struct GNUNET_TIME_Relative kyc_timeout; + struct GNUNET_TIME_Relative history_expiration; + uint32_t purse_account_limit; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee", + &fs.history), + TALER_PQ_RESULT_SPEC_AMOUNT ("kyc_fee", + &fs.kyc), + TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee", + &fs.account), + TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee", + &fs.purse), + GNUNET_PQ_result_spec_relative_time ("purse_timeout", + &purse_timeout), + GNUNET_PQ_result_spec_relative_time ("kyc_timeout", + &kyc_timeout), + GNUNET_PQ_result_spec_relative_time ("history_expiration", + &history_expiration), + GNUNET_PQ_result_spec_uint32 ("purse_account_limit", + &purse_account_limit), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + /* invalidate */ + memset (wlc->fees, + 0, + sizeof (struct TALER_GlobalFeeSet)); + return; + } + if (0 == i) + { + *wlc->fees = fs; + *wlc->purse_timeout = purse_timeout; + *wlc->kyc_timeout = kyc_timeout; + *wlc->history_expiration = history_expiration; + *wlc->purse_account_limit = purse_account_limit; + continue; + } + if ( (0 != + TALER_global_fee_set_cmp (&fs, + wlc->fees)) || + (purse_account_limit != *wlc->purse_account_limit) || + (GNUNET_TIME_relative_cmp (purse_timeout, + !=, + *wlc->purse_timeout)) || + (GNUNET_TIME_relative_cmp (kyc_timeout, + !=, + *wlc->kyc_timeout)) || + (GNUNET_TIME_relative_cmp (history_expiration, + !=, + *wlc->history_expiration)) ) + { + /* invalidate */ + memset (wlc->fees, + 0, + sizeof (struct TALER_GlobalFeeSet)); + return; + } + } +} + + +/** + * Lookup information about known global fees. + * + * @param cls closure + * @param start_time starting time of fee + * @param end_time end time of fee + * @param[out] fees set to wire fees for that time period; if + * different global fee exists within this time + * period, an 'invalid' amount is returned. + * @param[out] purse_timeout set to when unmerged purses expire + * @param[out] kyc_timeout set to when reserves without kyc expire + * @param[out] history_expiration set to when we expire reserve histories + * @param[out] purse_account_limit set to number of free purses + * @return transaction status code + */ +static enum GNUNET_DB_QueryStatus +postgres_lookup_global_fee_by_time ( + void *cls, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Timestamp end_time, + struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative *purse_timeout, + struct GNUNET_TIME_Relative *kyc_timeout, + struct GNUNET_TIME_Relative *history_expiration, + uint32_t *purse_account_limit) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_timestamp (&start_time), + GNUNET_PQ_query_param_timestamp (&end_time), + GNUNET_PQ_query_param_end + }; + struct GlobalFeeLookupContext wlc = { + .fees = fees, + .purse_timeout = purse_timeout, + .kyc_timeout = kyc_timeout, + .history_expiration = history_expiration, + .purse_account_limit = purse_account_limit, + .pg = pg + }; + + return GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "lookup_global_fee_by_time", + params, + &global_fee_by_time_helper, + &wlc); +} + + +/** * Lookup the latest serial number of @a table. Used in * exchange-auditor database replication. * @@ -11914,7 +12333,9 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) plugin->lookup_transfer_by_deposit = &postgres_lookup_transfer_by_deposit; plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking; plugin->insert_wire_fee = &postgres_insert_wire_fee; + plugin->insert_global_fee = &postgres_insert_global_fee; plugin->get_wire_fee = &postgres_get_wire_fee; + plugin->get_global_fee = &postgres_get_global_fee; 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; @@ -11988,6 +12409,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_select_auditor_denom_sig; plugin->lookup_wire_fee_by_time = &postgres_lookup_wire_fee_by_time; + plugin->lookup_global_fee_by_time + = &postgres_lookup_global_fee_by_time; plugin->add_denomination_key = &postgres_add_denomination_key; plugin->activate_signing_key diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 683d4f574..7440a8aae 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4129,6 +4129,33 @@ struct TALER_EXCHANGEDB_Plugin /** + * Lookup information about known global fees. + * + * @param cls closure + * @param start_time starting time of fee + * @param end_time end time of fee + * @param[out] fees set to wire fees for that time period; if + * different global fee exists within this time + * period, an 'invalid' amount is returned. + * @param[out] purse_timeout set to when unmerged purses expire + * @param[out] kyc_timeout set to when reserves without kyc expire + * @param[out] history_expiration set to when we expire reserve histories + * @param[out] purse_account_limit set to number of free purses + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*lookup_global_fee_by_time)( + void *cls, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Timestamp end_time, + struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative *purse_timeout, + struct GNUNET_TIME_Relative *kyc_timeout, + struct GNUNET_TIME_Relative *history_expiration, + uint32_t *purse_account_limit); + + + /** * Lookup the latest serial number of @a table. Used in * exchange-auditor database replication. * |