merchant

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

pg_insert_transfer_details.c (7339B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022, 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 backenddb/pg_insert_transfer_details.c
     18  * @brief Implementation of the insert_transfer_details function for Postgres
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include <taler/taler_error_codes.h>
     23 #include <taler/taler_dbevents.h>
     24 #include <taler/taler_pq_lib.h>
     25 #include "pg_insert_transfer_details.h"
     26 #include "pg_helper.h"
     27 
     28 
     29 /**
     30  * How often do we re-try if we run into a DB serialization error?
     31  */
     32 #define MAX_RETRIES 3
     33 
     34 
     35 enum GNUNET_DB_QueryStatus
     36 TMH_PG_insert_transfer_details (
     37   void *cls,
     38   const char *instance_id,
     39   const char *exchange_url,
     40   struct TALER_FullPayto payto_uri,
     41   const struct TALER_WireTransferIdentifierRawP *wtid,
     42   const struct TALER_EXCHANGE_TransferData *td)
     43 {
     44   struct PostgresClosure *pg = cls;
     45   unsigned int len = td->details_length;
     46   struct TALER_Amount coin_values[GNUNET_NZL (len)];
     47   struct TALER_Amount deposit_fees[GNUNET_NZL (len)];
     48   const struct TALER_CoinSpendPublicKeyP *coin_pubs[GNUNET_NZL (len)];
     49   const struct TALER_PrivateContractHashP *contract_terms[GNUNET_NZL (len)];
     50   enum GNUNET_DB_QueryStatus qs;
     51   bool duplicate;
     52 
     53   for (unsigned int i = 0; i<len; i++)
     54   {
     55     const struct TALER_TrackTransferDetails *tdd = &td->details[i];
     56 
     57     coin_values[i] = tdd->coin_value;
     58     deposit_fees[i] = tdd->coin_fee;
     59     coin_pubs[i] = &tdd->coin_pub;
     60     contract_terms[i] = &tdd->h_contract_terms;
     61   }
     62 
     63   check_connection (pg);
     64   PREPARE (pg,
     65            "insert_transfer_details",
     66            "SELECT"
     67            " out_no_instance"
     68            ",out_no_account"
     69            ",out_no_exchange"
     70            ",out_duplicate"
     71            ",out_conflict"
     72            ",out_order_id"
     73            ",out_merchant_pub"
     74            " FROM merchant_do_insert_transfer_details"
     75            " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
     76 
     77   for (unsigned int retries = 0;
     78        retries < MAX_RETRIES;
     79        retries++)
     80   {
     81     if (GNUNET_OK !=
     82         TMH_PG_start (pg,
     83                       "insert transfer details"))
     84     {
     85       GNUNET_break (0);
     86       return GNUNET_DB_STATUS_HARD_ERROR;
     87     }
     88 
     89     {
     90       struct GNUNET_PQ_QueryParam params[] = {
     91         GNUNET_PQ_query_param_string (instance_id),
     92         GNUNET_PQ_query_param_string (exchange_url),
     93         GNUNET_PQ_query_param_string (payto_uri.full_payto),
     94         GNUNET_PQ_query_param_auto_from_type (wtid),
     95         GNUNET_PQ_query_param_timestamp (&td->execution_time),
     96         GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
     97         GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
     98         TALER_PQ_query_param_amount_with_currency (pg->conn,
     99                                                    &td->total_amount),
    100         TALER_PQ_query_param_amount_with_currency (pg->conn,
    101                                                    &td->wire_fee),
    102         TALER_PQ_query_param_array_amount_with_currency (
    103           len,
    104           coin_values,
    105           pg->conn),
    106         TALER_PQ_query_param_array_amount_with_currency (
    107           len,
    108           deposit_fees,
    109           pg->conn),
    110         GNUNET_PQ_query_param_array_ptrs_auto_from_type (
    111           len,
    112           coin_pubs,
    113           pg->conn),
    114         GNUNET_PQ_query_param_array_ptrs_auto_from_type (
    115           len,
    116           contract_terms,
    117           pg->conn),
    118         GNUNET_PQ_query_param_end
    119       };
    120       bool no_instance;
    121       bool no_account;
    122       bool no_exchange;
    123       bool conflict;
    124       char *order_id = NULL;
    125       struct TALER_MerchantPublicKeyP merchant_pub;
    126       struct GNUNET_PQ_ResultSpec rs[] = {
    127         GNUNET_PQ_result_spec_bool ("out_no_instance",
    128                                     &no_instance),
    129         GNUNET_PQ_result_spec_bool ("out_no_account",
    130                                     &no_account),
    131         GNUNET_PQ_result_spec_bool ("out_no_exchange",
    132                                     &no_exchange),
    133         GNUNET_PQ_result_spec_bool ("out_duplicate",
    134                                     &duplicate),
    135         GNUNET_PQ_result_spec_bool ("out_conflict",
    136                                     &conflict),
    137         GNUNET_PQ_result_spec_allow_null (
    138           GNUNET_PQ_result_spec_string ("out_order_id",
    139                                         &order_id),
    140           NULL),
    141         GNUNET_PQ_result_spec_allow_null (
    142           GNUNET_PQ_result_spec_auto_from_type ("out_merchant_pub",
    143                                                 &merchant_pub),
    144           NULL),
    145         GNUNET_PQ_result_spec_end
    146       };
    147 
    148       qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    149                                                      "insert_transfer_details",
    150                                                      params,
    151                                                      rs);
    152       GNUNET_PQ_cleanup_query_params_closures (params);
    153       if (0 >= qs)
    154       {
    155         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    156         TMH_PG_rollback (pg);
    157         if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    158           continue;
    159         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    160                     "'insert_transfer_details' failed with status %d\n",
    161                     qs);
    162         return qs;
    163       }
    164       if (NULL != order_id)
    165       {
    166         struct TMH_OrderPayEventP pay_eh = {
    167           .header.size = htons (sizeof (pay_eh)),
    168           .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_STATUS_CHANGED),
    169           .merchant_pub = merchant_pub
    170         };
    171 
    172         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    173                     "Notifying clients about status change of order %s\n",
    174                     order_id);
    175         GNUNET_CRYPTO_hash (order_id,
    176                             strlen (order_id),
    177                             &pay_eh.h_order_id);
    178         GNUNET_PQ_event_notify (pg->conn,
    179                                 &pay_eh.header,
    180                                 NULL,
    181                                 0);
    182         GNUNET_free (order_id);
    183       }
    184       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    185                   "Transfer details inserted: %s%s%s%s%s\n",
    186                   no_instance ? "no instance " : "",
    187                   no_account ? "no account " : "",
    188                   no_exchange ? "no exchange ": "",
    189                   duplicate ? "duplicate ": "",
    190                   conflict ? "conflict" : "");
    191     }
    192 
    193     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    194                 "Committing transaction...\n");
    195     qs = TMH_PG_commit (pg);
    196     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    197       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    198     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    199     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
    200       break;
    201   }
    202   if (duplicate)
    203     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    204   return qs;
    205 }