exchange

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

iterate_unfinished_close_requests.c (5367B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022, 2024 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 iterate_unfinished_close_requests.c
     18  * @brief Low-level (statement-level) Postgres database access for the exchange
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/taler_pq_lib.h"
     22 #include "exchange-database/iterate_unfinished_close_requests.h"
     23 #include "helper.h"
     24 
     25 
     26 /**
     27  * Closure for #reserve_close_cb().
     28  */
     29 struct CloseReserveContext
     30 {
     31   /**
     32    * Function to call for each to be closed reserve.
     33    */
     34   TALER_EXCHANGEDB_ReserveExpiredCallback rec;
     35 
     36   /**
     37    * Closure to give to @e rec.
     38    */
     39   void *rec_cls;
     40 
     41   /**
     42    * Plugin context.
     43    */
     44   struct TALER_EXCHANGEDB_PostgresContext *pg;
     45 
     46   /**
     47    * Set to #GNUNET_SYSERR on error.
     48    */
     49   enum GNUNET_GenericReturnValue status;
     50 };
     51 
     52 
     53 /**
     54  * Function to be called with the results of a SELECT statement
     55  * that has returned @a num_results results.
     56  *
     57  * @param cls closure
     58  * @param result the postgres result
     59  * @param num_results the number of results in @a result
     60  */
     61 static void
     62 reserve_cb (void *cls,
     63             PGresult *result,
     64             unsigned int num_results)
     65 {
     66   struct CloseReserveContext *erc = cls;
     67   struct TALER_EXCHANGEDB_PostgresContext *pg = erc->pg;
     68   enum GNUNET_GenericReturnValue ret = GNUNET_OK;
     69 
     70   for (unsigned int i = 0; i<num_results; i++)
     71   {
     72     struct GNUNET_TIME_Timestamp exp_date;
     73     struct TALER_FullPayto account_details;
     74     struct TALER_ReservePublicKeyP reserve_pub;
     75     struct TALER_Amount remaining_balance;
     76     uint64_t close_request_row;
     77     struct GNUNET_PQ_ResultSpec rs[] = {
     78       GNUNET_PQ_result_spec_timestamp ("expiration_date",
     79                                        &exp_date),
     80       GNUNET_PQ_result_spec_allow_null (
     81         GNUNET_PQ_result_spec_string ("account_details",
     82                                       &account_details.full_payto),
     83         NULL),
     84       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
     85                                             &reserve_pub),
     86       TALER_PQ_RESULT_SPEC_AMOUNT ("close",
     87                                    &remaining_balance),
     88       GNUNET_PQ_result_spec_uint64 ("close_request_serial_id",
     89                                     &close_request_row),
     90       GNUNET_PQ_result_spec_end
     91     };
     92 
     93     /* If neither the close request nor the reserve identifies a bank
     94        account, the callback is given a NULL payto URI. */
     95     account_details.full_payto = NULL;
     96     if (GNUNET_OK !=
     97         GNUNET_PQ_extract_result (result,
     98                                   rs,
     99                                   i))
    100     {
    101       GNUNET_break (0);
    102       ret = GNUNET_SYSERR;
    103       break;
    104     }
    105     ret = erc->rec (erc->rec_cls,
    106                     &reserve_pub,
    107                     &remaining_balance,
    108                     account_details,
    109                     exp_date,
    110                     close_request_row);
    111     GNUNET_PQ_cleanup_result (rs);
    112     if (GNUNET_OK != ret)
    113       break;
    114   }
    115   erc->status = ret;
    116 }
    117 
    118 
    119 enum GNUNET_DB_QueryStatus
    120 TALER_EXCHANGEDB_iterate_unfinished_close_requests (
    121   struct TALER_EXCHANGEDB_PostgresContext *pg,
    122   TALER_EXCHANGEDB_ReserveExpiredCallback rec,
    123   void *rec_cls)
    124 {
    125   struct GNUNET_PQ_QueryParam params[] = {
    126     GNUNET_PQ_query_param_end
    127   };
    128   struct CloseReserveContext ectx = {
    129     .rec = rec,
    130     .rec_cls = rec_cls,
    131     .pg = pg,
    132     .status = GNUNET_OK
    133   };
    134   enum GNUNET_DB_QueryStatus qs;
    135 
    136   PREPARE (pg,
    137            "iterate_unfinished_close_requests",
    138            "UPDATE close_requests AS rc"
    139            " SET done=TRUE"
    140            " WHERE NOT done"
    141            " RETURNING"
    142            "    reserve_pub"
    143            "   ,close_request_serial_id"
    144            "   ,close_timestamp AS expiration_date"
    145            "   ,close"
    146            /* The account designated by the client (and covered by the KYC
    147               check done at the time of the request) takes precedence over
    148               the account the reserve was funded from. */
    149            "   ,COALESCE(rc.payto_uri"
    150            "     ,(SELECT payto_uri"
    151            "         FROM reserves_in ri"
    152            "         JOIN wire_targets wt"
    153            "           ON (ri.wire_source_h_payto = wt.wire_target_h_payto)"
    154            "        WHERE ri.reserve_pub=rc.reserve_pub))"
    155            "    AS account_details;");
    156   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
    157                                              "iterate_unfinished_close_requests",
    158                                              params,
    159                                              &reserve_cb,
    160                                              &ectx);
    161   switch (ectx.status)
    162   {
    163   case GNUNET_SYSERR:
    164     return GNUNET_DB_STATUS_HARD_ERROR;
    165   case GNUNET_NO:
    166     return GNUNET_DB_STATUS_SOFT_ERROR;
    167   case GNUNET_OK:
    168     break;
    169   }
    170   return qs;
    171 }