exchange

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

iterate_legitimization_outcomes_above_serial_id.c (6213B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2026 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 src/exchangedb/iterate_legitimization_outcomes_above_serial_id.c
     18  * @brief Implementation of the iterate_legitimization_outcomes_above_serial_id function for Postgres
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/taler_pq_lib.h"
     22 #include "helper.h"
     23 #include "exchange-database/iterate_legitimization_outcomes_above_serial_id.h"
     24 
     25 
     26 /**
     27  * Closure for #legitimization_outcome_cb().
     28  */
     29 struct LegitimizationOutcomeContext
     30 {
     31   /**
     32    * Function to call for each outcome.
     33    */
     34   TALER_EXCHANGEDB_LegitimizationOutcomeCallback cb;
     35 
     36   /**
     37    * Closure for @e cb.
     38    */
     39   void *cb_cls;
     40 
     41   /**
     42    * Query status to return.
     43    */
     44   enum GNUNET_DB_QueryStatus qs;
     45 };
     46 
     47 
     48 /**
     49  * Helper function for
     50  * #TALER_EXCHANGEDB_iterate_legitimization_outcomes_above_serial_id().
     51  * To be called with the results of a SELECT statement
     52  * that has returned @a num_results results.
     53  *
     54  * @param cls closure of type `struct LegitimizationOutcomeContext *`
     55  * @param result the postgres result
     56  * @param num_results the number of results in @a result
     57  */
     58 static void
     59 legitimization_outcome_cb (void *cls,
     60                            PGresult *result,
     61                            unsigned int num_results)
     62 {
     63   struct LegitimizationOutcomeContext *loc = cls;
     64 
     65   for (unsigned int i = 0; i < num_results; i++)
     66   {
     67     uint64_t rowid;
     68     struct TALER_NormalizedPaytoHashP h_payto;
     69     struct GNUNET_TIME_Timestamp decision_time;
     70     struct GNUNET_TIME_Timestamp expiration_time;
     71     bool has_aml_decision;
     72     bool has_legitimization_process;
     73     bool has_expired_predecessor;
     74     struct GNUNET_PQ_ResultSpec rs[] = {
     75       GNUNET_PQ_result_spec_uint64 ("outcome_serial_id",
     76                                     &rowid),
     77       GNUNET_PQ_result_spec_auto_from_type ("h_payto",
     78                                             &h_payto),
     79       GNUNET_PQ_result_spec_timestamp ("decision_time",
     80                                        &decision_time),
     81       GNUNET_PQ_result_spec_timestamp ("expiration_time",
     82                                        &expiration_time),
     83       GNUNET_PQ_result_spec_bool ("has_aml_decision",
     84                                   &has_aml_decision),
     85       GNUNET_PQ_result_spec_bool ("has_legitimization_process",
     86                                   &has_legitimization_process),
     87       GNUNET_PQ_result_spec_bool ("has_expired_predecessor",
     88                                   &has_expired_predecessor),
     89       GNUNET_PQ_result_spec_end
     90     };
     91     enum GNUNET_GenericReturnValue rval;
     92 
     93     if (GNUNET_OK !=
     94         GNUNET_PQ_extract_result (result,
     95                                   rs,
     96                                   i))
     97     {
     98       GNUNET_break (0);
     99       loc->qs = GNUNET_DB_STATUS_HARD_ERROR;
    100       return;
    101     }
    102     loc->qs = i + 1;
    103     rval = loc->cb (loc->cb_cls,
    104                     rowid,
    105                     &h_payto,
    106                     decision_time,
    107                     expiration_time,
    108                     has_aml_decision,
    109                     has_legitimization_process,
    110                     has_expired_predecessor);
    111     GNUNET_PQ_cleanup_result (rs);
    112     if (GNUNET_OK != rval)
    113       break;
    114   }
    115 }
    116 
    117 
    118 enum GNUNET_DB_QueryStatus
    119 TALER_EXCHANGEDB_iterate_legitimization_outcomes_above_serial_id (
    120   struct TALER_EXCHANGEDB_PostgresContext *pg,
    121   uint64_t serial_id,
    122   TALER_EXCHANGEDB_LegitimizationOutcomeCallback cb,
    123   TALER_EXCHANGEDB_LEGITIMIZATION_OUTCOME_RESULT_CLOSURE *cb_cls)
    124 {
    125   struct GNUNET_PQ_QueryParam params[] = {
    126     GNUNET_PQ_query_param_uint64 (&serial_id),
    127     GNUNET_PQ_query_param_end
    128   };
    129   struct LegitimizationOutcomeContext loc = {
    130     .cb = cb,
    131     .cb_cls = cb_cls
    132   };
    133   enum GNUNET_DB_QueryStatus qs;
    134 
    135   /* The three EXISTS clauses are the three ways the exchange's own code
    136      creates an outcome; the caller decides what to make of them.
    137 
    138      `decision_time' is a *rounded* timestamp while `start_time' is not, so a
    139      process started at the very moment of the decision can have a start_time
    140      up to a second past it.  Hence the second of slack, subtracted from
    141      start_time rather than added to decision_time so that a decision_time of
    142      "forever" does not overflow. */
    143   PREPARE (pg,
    144            "iterate_legitimization_outcomes_above_serial_id",
    145            "SELECT"
    146            " lo.outcome_serial_id"
    147            ",lo.h_payto"
    148            ",lo.decision_time"
    149            ",lo.expiration_time"
    150            ",EXISTS ("
    151            "   SELECT 1"
    152            "     FROM aml_history ah"
    153            "    WHERE ah.outcome_serial_id=lo.outcome_serial_id"
    154            " ) AS has_aml_decision"
    155            ",EXISTS ("
    156            "   SELECT 1"
    157            "     FROM legitimization_processes lp"
    158            "    WHERE lp.h_payto=lo.h_payto"
    159            "      AND lp.start_time-1000000<lo.decision_time"
    160            " ) AS has_legitimization_process"
    161            ",EXISTS ("
    162            "   SELECT 1"
    163            "     FROM legitimization_outcomes pre"
    164            "    WHERE pre.h_payto=lo.h_payto"
    165            "      AND pre.outcome_serial_id<lo.outcome_serial_id"
    166            "      AND pre.expiration_time<=lo.decision_time"
    167            " ) AS has_expired_predecessor"
    168            " FROM legitimization_outcomes lo"
    169            " WHERE lo.outcome_serial_id>=$1"
    170            " ORDER BY lo.outcome_serial_id ASC;");
    171   qs = GNUNET_PQ_eval_prepared_multi_select (
    172     pg->conn,
    173     "iterate_legitimization_outcomes_above_serial_id",
    174     params,
    175     &legitimization_outcome_cb,
    176     &loc);
    177   if (qs > 0)
    178     return loc.qs;
    179   GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    180   return qs;
    181 }