merchant

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

pg_insert_transfer_details.c (6080B)


      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 backenddb/pg_insert_transfer_details.c
     18  * @brief Implementation of the insert_transfer_details function for Postgres
     19  * @author Christian Grothoff
     20  */
     21 #include "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            " FROM merchant_do_insert_transfer_details"
     73            " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
     74 
     75   for (unsigned int retries = 0;
     76        retries < MAX_RETRIES;
     77        retries++)
     78   {
     79     if (GNUNET_OK !=
     80         TMH_PG_start (pg,
     81                       "insert transfer details"))
     82     {
     83       GNUNET_break (0);
     84       return GNUNET_DB_STATUS_HARD_ERROR;
     85     }
     86 
     87     {
     88       struct GNUNET_PQ_QueryParam params[] = {
     89         GNUNET_PQ_query_param_string (instance_id),
     90         GNUNET_PQ_query_param_string (exchange_url),
     91         GNUNET_PQ_query_param_string (payto_uri.full_payto),
     92         GNUNET_PQ_query_param_auto_from_type (wtid),
     93         GNUNET_PQ_query_param_timestamp (&td->execution_time),
     94         GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
     95         GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
     96         TALER_PQ_query_param_amount_with_currency (pg->conn,
     97                                                    &td->total_amount),
     98         TALER_PQ_query_param_amount_with_currency (pg->conn,
     99                                                    &td->wire_fee),
    100         TALER_PQ_query_param_array_amount_with_currency (
    101           len,
    102           coin_values,
    103           pg->conn),
    104         TALER_PQ_query_param_array_amount_with_currency (
    105           len,
    106           deposit_fees,
    107           pg->conn),
    108         GNUNET_PQ_query_param_array_ptrs_auto_from_type (
    109           len,
    110           coin_pubs,
    111           pg->conn),
    112         GNUNET_PQ_query_param_array_ptrs_auto_from_type (
    113           len,
    114           contract_terms,
    115           pg->conn),
    116         GNUNET_PQ_query_param_end
    117       };
    118       bool no_instance;
    119       bool no_account;
    120       bool no_exchange;
    121       bool conflict;
    122       struct GNUNET_PQ_ResultSpec rs[] = {
    123         GNUNET_PQ_result_spec_bool ("out_no_instance",
    124                                     &no_instance),
    125         GNUNET_PQ_result_spec_bool ("out_no_account",
    126                                     &no_account),
    127         GNUNET_PQ_result_spec_bool ("out_no_exchange",
    128                                     &no_exchange),
    129         GNUNET_PQ_result_spec_bool ("out_duplicate",
    130                                     &duplicate),
    131         GNUNET_PQ_result_spec_bool ("out_conflict",
    132                                     &conflict),
    133         GNUNET_PQ_result_spec_end
    134       };
    135 
    136       qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    137                                                      "insert_transfer_details",
    138                                                      params,
    139                                                      rs);
    140       GNUNET_PQ_cleanup_query_params_closures (params);
    141       if (0 >= qs)
    142       {
    143         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    144         TMH_PG_rollback (pg);
    145         if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    146           continue;
    147         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    148                     "'insert_transfer_details' failed with status %d\n",
    149                     qs);
    150         return qs;
    151       }
    152       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    153                   "Transfer details inserted: %s%s%s%s%s\n",
    154                   no_instance ? "no instance " : "",
    155                   no_account ? "no account " : "",
    156                   no_exchange ? "no exchange ": "",
    157                   duplicate ? "duplicate ": "",
    158                   conflict ? "conflict" : "");
    159     }
    160 
    161     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    162                 "Committing transaction...\n");
    163     qs = TMH_PG_commit (pg);
    164     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    165       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    166     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    167     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
    168       break;
    169   }
    170   if (duplicate)
    171     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    172   return qs;
    173 }