merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

get_fountain_withdraw.c (5552B)


      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/backenddb/get_fountain_withdraw.c
     18  * @brief look up the signatures of a completed fountain withdrawal
     19  */
     20 #include "platform.h"
     21 #include <taler/taler_pq_lib.h>
     22 #include "merchant-database/get_fountain_withdraw.h"
     23 #include "helper.h"
     24 
     25 
     26 /**
     27  * Closure for #restore_sig_cb().
     28  */
     29 struct RestoreContext
     30 {
     31   /**
     32    * Callback to hand each signature to.
     33    */
     34   TALER_MERCHANTDB_FountainWithdrawSigCallback cb;
     35 
     36   /**
     37    * Closure for @e cb.
     38    */
     39   void *cb_cls;
     40 
     41   /**
     42    * Set to a hard error if a row could not be extracted.
     43    */
     44   enum GNUNET_DB_QueryStatus qs;
     45 };
     46 
     47 
     48 /**
     49  * Extract the stored signatures and pass them on in response order.
     50  *
     51  * @param cls a `struct RestoreContext *`
     52  * @param result the postgres result
     53  * @param num_results number of rows in @a result
     54  */
     55 static void
     56 restore_sig_cb (void *cls,
     57                 PGresult *result,
     58                 unsigned int num_results)
     59 {
     60   struct RestoreContext *rc = cls;
     61 
     62   for (unsigned int i = 0; i < num_results; i++)
     63   {
     64     uint32_t grant_index;
     65     char *slug;
     66     struct TALER_TokenIssuePublicKeyHashP h_issue;
     67     struct GNUNET_CRYPTO_BlindedSignature *sig;
     68     struct GNUNET_PQ_ResultSpec rs[] = {
     69       GNUNET_PQ_result_spec_uint32 ("grant_index",
     70                                     &grant_index),
     71       GNUNET_PQ_result_spec_string ("token_family_slug",
     72                                     &slug),
     73       GNUNET_PQ_result_spec_auto_from_type ("h_issue",
     74                                             &h_issue),
     75       GNUNET_PQ_result_spec_blinded_sig ("token_blinded_signature",
     76                                          &sig),
     77       GNUNET_PQ_result_spec_end
     78     };
     79 
     80     if (GNUNET_OK !=
     81         GNUNET_PQ_extract_result (result,
     82                                   rs,
     83                                   i))
     84     {
     85       GNUNET_break (0);
     86       rc->qs = GNUNET_DB_STATUS_HARD_ERROR;
     87       return;
     88     }
     89     rc->cb (rc->cb_cls,
     90             grant_index,
     91             slug,
     92             &h_issue,
     93             sig);
     94     GNUNET_PQ_cleanup_result (rs);
     95   }
     96 }
     97 
     98 
     99 enum GNUNET_DB_QueryStatus
    100 TALER_MERCHANTDB_get_fountain_withdraw (
    101   struct TALER_MERCHANTDB_PostgresContext *pg,
    102   uint64_t fountain_serial,
    103   const struct GNUNET_HashCode *h_request,
    104   bool *not_found,
    105   TALER_MERCHANTDB_FountainWithdrawSigCallback cb,
    106   void *cb_cls)
    107 {
    108   struct RestoreContext rc = {
    109     .cb = cb,
    110     .cb_cls = cb_cls,
    111     .qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
    112   };
    113   enum GNUNET_DB_QueryStatus qs;
    114 
    115   GNUNET_assert (NULL != pg->current_merchant_id);
    116   GNUNET_assert (NULL != pg->transaction_name);
    117   *not_found = false;
    118   {
    119     uint64_t serial;
    120     struct GNUNET_PQ_QueryParam params[] = {
    121       GNUNET_PQ_query_param_uint64 (&fountain_serial),
    122       GNUNET_PQ_query_param_end
    123     };
    124     struct GNUNET_PQ_ResultSpec rs[] = {
    125       GNUNET_PQ_result_spec_uint64 ("fountain_serial",
    126                                     &serial),
    127       GNUNET_PQ_result_spec_end
    128     };
    129 
    130     TMH_PQ_prepare_anon (pg,
    131                          "SELECT fountain_serial"
    132                          "  FROM merchant_fountains"
    133                          " WHERE fountain_serial = $1"
    134                          "   FOR UPDATE");
    135     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    136                                                    "",
    137                                                    params,
    138                                                    rs);
    139     if (qs <= 0)
    140     {
    141       *not_found = (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
    142       return qs;
    143     }
    144   }
    145   {
    146     struct GNUNET_PQ_QueryParam params[] = {
    147       GNUNET_PQ_query_param_uint64 (&fountain_serial),
    148       GNUNET_PQ_query_param_auto_from_type (h_request),
    149       GNUNET_PQ_query_param_end
    150     };
    151 
    152     /* A fresh statement snapshot: this runs after waiting for the lock,
    153        so it sees a withdrawal that a competing request just committed. */
    154     TMH_PQ_prepare_anon (pg,
    155                          "SELECT"
    156                          "  fws.grant_index"
    157                          " ,fws.token_blinded_signature"
    158                          " ,fws.h_issue"
    159                          " ,fws.token_family_slug"
    160                          "  FROM merchant_fountain_withdraw_sigs AS fws"
    161                          " WHERE fws.fountain_serial = $1"
    162                          "   AND fws.h_request = $2"
    163                          " ORDER BY fws.grant_index ASC"
    164                          "         ,fws.token_index ASC");
    165     qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
    166                                                "",
    167                                                params,
    168                                                &restore_sig_cb,
    169                                                &rc);
    170     /* propagate an extraction failure recorded by the row callback */
    171     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != rc.qs)
    172       return rc.qs;
    173     return qs;
    174   }
    175 }