exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

helper.h (5977B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022 Taler Systems SA
      4 
      5    TALER is free software; you can redistribute it and/or modify it under the
      6    terms of the GNU General Public License as published by the Free Software
      7    Foundation; either version 3, or (at your option) any later version.
      8 
      9    TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13    You should have received a copy of the GNU General Public License along with
     14    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15  */
     16 /**
     17  * @file pg_helper.h
     18  * @brief shared internal definitions for postgres DB plugin
     19  * @author Christian Grothoff
     20  */
     21 #ifndef PG_HELPER_H
     22 #define PG_HELPER_H
     23 
     24 #include "taler/taler_dbevents.h"  /* UNNECESSARY? */
     25 #include "taler/taler_error_codes.h"  /* UNNECESSARY? */
     26 #include "exchangedb_lib.h"
     27 #include "taler/taler_json_lib.h"
     28 #include "taler/taler_pq_lib.h"
     29 #include "taler/taler_util.h"
     30 
     31 
     32 /**
     33  * Context for a Postgres database connection for the exchange.
     34  */
     35 struct TALER_EXCHANGEDB_PostgresContext
     36 {
     37 
     38   /**
     39    * Our configuration.
     40    */
     41   const struct GNUNET_CONFIGURATION_Handle *cfg;
     42 
     43   /**
     44    * Directory with SQL statements to run to create tables.
     45    */
     46   char *sql_dir;
     47 
     48   /**
     49    * How long are AML programs allowed to run?
     50    */
     51   struct GNUNET_TIME_Relative max_aml_program_runtime;
     52 
     53   /**
     54    * After how long should idle reserves be closed?
     55    */
     56   struct GNUNET_TIME_Relative idle_reserve_expiration_time;
     57 
     58   /**
     59    * After how long should reserves that have seen withdraw operations
     60    * be garbage collected?
     61    */
     62   struct GNUNET_TIME_Relative legal_reserve_expiration_time;
     63 
     64   /**
     65    * What delay should we introduce before ready transactions
     66    * are actually aggregated?
     67    */
     68   struct GNUNET_TIME_Relative aggregator_shift;
     69 
     70   /**
     71    * Which currency should we assume all amounts to be in?
     72    */
     73   char *currency;
     74 
     75   /**
     76    * Our base URL.
     77    */
     78   char *exchange_url;
     79 
     80   /**
     81    * Postgres connection handle.
     82    */
     83   struct GNUNET_PQ_Context *conn;
     84 
     85   /**
     86    * Name of the current transaction, for debugging.
     87    */
     88   const char *transaction_name;
     89 
     90   /**
     91    * Number of purses we allow to be opened concurrently
     92    * for one year per annual fee payment.
     93    */
     94   uint32_t def_purse_limit;
     95 
     96 };
     97 
     98 
     99 /**
    100  * Counts how often we have established a fresh @e conn
    101  * to the database. Used to re-prepare statements.
    102  */
    103 extern unsigned long long TEH_PG_prep_gen_;
    104 
    105 
    106 /**
    107  * Convert the signed @a limit of a paginated listing into the row
    108  * limit to pass to SQL.  The sign selects the iteration direction and
    109  * the magnitude the number of rows, but computing `-limit` directly is
    110  * undefined behaviour for `INT64_MIN`, and the resulting value would
    111  * reach Postgres as `LIMIT -9223372036854775808`, which errors out.
    112  * `INT64_MIN` is therefore saturated to `INT64_MAX`.
    113  *
    114  * @param limit signed limit as given by the caller
    115  * @return absolute value of @a limit, without signed overflow
    116  */
    117 static inline uint64_t
    118 TALER_EXCHANGEDB_abs_limit (int64_t limit)
    119 {
    120   /* Postgres binds INT8 as a *signed* 64-bit integer, so a magnitude
    121      above INT64_MAX would reach LIMIT as a negative number. */
    122   if (INT64_MIN == limit)
    123     return (uint64_t) INT64_MAX;
    124   if (limit < 0)
    125     return (uint64_t) -limit;
    126   return (uint64_t) limit;
    127 }
    128 
    129 
    130 /**
    131  * Prepares SQL statement @a sql under @a name for
    132  * connection @a pg once.
    133  * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
    134  *
    135  * @param pg a `struct TALER_EXCHANGEDB_PostgresContext`
    136  * @param name name to prepare the statement under
    137  * @param sql actual SQL text
    138  */
    139 #define PREPARE(pg,name,sql)                            \
    140         do {                                            \
    141           static struct {                               \
    142             unsigned long long cnt;                     \
    143             struct TALER_EXCHANGEDB_PostgresContext *pg;                 \
    144           } preps_[2]; /* 2 ctrs for taler-auditor-sync*/ \
    145           unsigned int off_ = 0;                        \
    146                                                         \
    147           while ( (NULL != preps_[off_].pg) &&          \
    148                   (pg != preps_[off_].pg) &&            \
    149                   (off_ < sizeof(preps_) / sizeof(*preps_)) ) \
    150           off_++;                                       \
    151           GNUNET_assert (off_ <                         \
    152                          sizeof(preps_) / sizeof(*preps_)); \
    153           if (preps_[off_].cnt < TEH_PG_prep_gen_)      \
    154           {                                             \
    155             struct GNUNET_PQ_PreparedStatement ps[] = { \
    156               GNUNET_PQ_make_prepare (name, sql),       \
    157               GNUNET_PQ_PREPARED_STATEMENT_END          \
    158             };                                          \
    159                                                         \
    160             if (GNUNET_OK !=                            \
    161                 GNUNET_PQ_prepare_statements (pg->conn, \
    162                                               ps))      \
    163             {                                           \
    164               GNUNET_break (0);                         \
    165               return GNUNET_DB_STATUS_HARD_ERROR;       \
    166             }                                           \
    167             preps_[off_].pg = pg;                       \
    168             preps_[off_].cnt = TEH_PG_prep_gen_;        \
    169           }                                             \
    170         } while (0)
    171 
    172 
    173 /**
    174  * Wrapper macro to add the currency from the plugin's state
    175  * when fetching amounts from the database.
    176  *
    177  * @param field name of the database field to fetch amount from
    178  * @param[out] amountp pointer to amount to set
    179  */
    180 #define TALER_PQ_RESULT_SPEC_AMOUNT(field, \
    181                                     amountp) TALER_PQ_result_spec_amount ( \
    182           field,pg->currency,amountp)
    183 
    184 
    185 #endif