exchange

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

helper.h (6092B)


      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 helper.h
     18  * @brief shared internal definitions for the Postgres exchange database
     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 ( (off_ < sizeof(preps_) / sizeof(*preps_)) && \
    148                   (NULL != preps_[off_].pg) &&          \
    149                   (pg != preps_[off_].pg) ) {           \
    150             off_++;                                     \
    151           }                                             \
    152           GNUNET_assert (off_ <                         \
    153                          sizeof(preps_) / sizeof(*preps_)); \
    154           if (preps_[off_].cnt < TEH_PG_prep_gen_)      \
    155           {                                             \
    156             struct GNUNET_PQ_PreparedStatement ps[] = { \
    157               GNUNET_PQ_make_prepare (name, sql),       \
    158               GNUNET_PQ_PREPARED_STATEMENT_END          \
    159             };                                          \
    160                                                         \
    161             if (GNUNET_OK !=                            \
    162                 GNUNET_PQ_prepare_statements (pg->conn, \
    163                                               ps))      \
    164             {                                           \
    165               GNUNET_break (0);                         \
    166               return GNUNET_DB_STATUS_HARD_ERROR;       \
    167             }                                           \
    168             preps_[off_].pg = pg;                       \
    169             preps_[off_].cnt = TEH_PG_prep_gen_;        \
    170           }                                             \
    171         } while (0)
    172 
    173 
    174 /**
    175  * Wrapper macro to add the currency from the database context in
    176  * the `pg` variable of the calling scope when fetching amounts from
    177  * the database.
    178  *
    179  * @param field name of the database field to fetch amount from
    180  * @param[out] amountp pointer to amount to set
    181  */
    182 #define TALER_PQ_RESULT_SPEC_AMOUNT(field, \
    183                                     amountp) TALER_PQ_result_spec_amount ( \
    184           field,pg->currency,amountp)
    185 
    186 
    187 #endif