exchange

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

pg_lookup_transfer_by_deposit.c (8746B)


      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 exchangedb/pg_lookup_transfer_by_deposit.c
     18  * @brief Implementation of the lookup_transfer_by_deposit 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_lookup_transfer_by_deposit.h"
     26 #include "pg_helper.h"
     27 
     28 
     29 enum GNUNET_DB_QueryStatus
     30 TEH_PG_lookup_transfer_by_deposit (
     31   void *cls,
     32   const struct TALER_PrivateContractHashP *h_contract_terms,
     33   const struct TALER_MerchantWireHashP *h_wire,
     34   const struct TALER_CoinSpendPublicKeyP *coin_pub,
     35   const struct TALER_MerchantPublicKeyP *merchant_pub,
     36   bool *pending,
     37   struct TALER_WireTransferIdentifierRawP *wtid,
     38   struct GNUNET_TIME_Timestamp *exec_time,
     39   struct TALER_Amount *amount_with_fee,
     40   struct TALER_Amount *deposit_fee,
     41   struct TALER_EXCHANGEDB_KycStatus *kyc,
     42   union TALER_AccountPublicKeyP *account_pub)
     43 {
     44   struct PostgresClosure *pg = cls;
     45   enum GNUNET_DB_QueryStatus qs;
     46   struct GNUNET_PQ_QueryParam params[] = {
     47     GNUNET_PQ_query_param_auto_from_type (coin_pub),
     48     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     49     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     50     GNUNET_PQ_query_param_end
     51   };
     52   struct TALER_FullPayto payto_uri;
     53   struct TALER_WireSaltP wire_salt;
     54   struct GNUNET_PQ_ResultSpec rs[] = {
     55     GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
     56                                           wtid),
     57     GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
     58                                           &wire_salt),
     59     GNUNET_PQ_result_spec_string ("payto_uri",
     60                                   &payto_uri.full_payto),
     61     GNUNET_PQ_result_spec_timestamp ("execution_date",
     62                                      exec_time),
     63     TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
     64                                  amount_with_fee),
     65     TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
     66                                  deposit_fee),
     67     GNUNET_PQ_result_spec_allow_null (
     68       GNUNET_PQ_result_spec_auto_from_type ("target_pub",
     69                                             account_pub),
     70       NULL),
     71     GNUNET_PQ_result_spec_end
     72   };
     73 
     74   memset (kyc,
     75           0,
     76           sizeof (*kyc));
     77   /* check if the aggregation record exists and get it */
     78   PREPARE (pg,
     79            "lookup_deposit_wtid",
     80            "SELECT"
     81            " atr.wtid_raw"
     82            ",wire_out.execution_date"
     83            ",cdep.amount_with_fee"
     84            ",bdep.wire_salt"
     85            ",wt.payto_uri"
     86            ",kt.target_pub"
     87            ",denom.fee_deposit"
     88            " FROM coin_deposits cdep"
     89            "    JOIN batch_deposits bdep"
     90            "      USING (batch_deposit_serial_id)"
     91            "    JOIN wire_targets wt"
     92            "      USING (wire_target_h_payto)"
     93            /* kyc_targets might not match; then target_pub will be NULL */
     94            "    LEFT JOIN kyc_targets kt"
     95            "      USING (h_normalized_payto)"
     96            "    JOIN aggregation_tracking atr"
     97            "      ON (cdep.batch_deposit_serial_id = atr.batch_deposit_serial_id)"
     98            "    JOIN known_coins kc"
     99            "      ON (kc.coin_pub = cdep.coin_pub)"
    100            "    JOIN denominations denom"
    101            "      USING (denominations_serial)"
    102            "    JOIN wire_out"
    103            "      USING (wtid_raw)"
    104            " WHERE cdep.coin_pub=$1"
    105            "   AND bdep.merchant_pub=$3"
    106            "   AND bdep.h_contract_terms=$2");
    107   /* NOTE: above query might be more efficient if we computed the shard
    108      from the merchant_pub and included that in the query */
    109   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    110                                                  "lookup_deposit_wtid",
    111                                                  params,
    112                                                  rs);
    113   if (0 > qs)
    114     return qs;
    115   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    116   {
    117     struct TALER_MerchantWireHashP wh;
    118 
    119     TALER_merchant_wire_signature_hash (payto_uri,
    120                                         &wire_salt,
    121                                         &wh);
    122     if (0 ==
    123         GNUNET_memcmp (&wh,
    124                        h_wire))
    125     {
    126       *pending = false;
    127       kyc->ok = true;
    128       GNUNET_PQ_cleanup_result (rs);
    129       return qs;
    130     }
    131     qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    132     GNUNET_PQ_cleanup_result (rs);
    133   }
    134   *pending = true;
    135   memset (wtid,
    136           0,
    137           sizeof (*wtid));
    138   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
    139   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    140               "lookup_deposit_wtid returned 0 matching rows\n");
    141   {
    142     /* Check if transaction exists in deposits, so that we just
    143        do not have a WTID yet. In that case, return without wtid
    144        (by setting 'pending' true). */
    145     struct GNUNET_PQ_ResultSpec rs2[] = {
    146       GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
    147                                             &wire_salt),
    148       GNUNET_PQ_result_spec_string ("payto_uri",
    149                                     &payto_uri.full_payto),
    150       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    151                                    amount_with_fee),
    152       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    153                                    deposit_fee),
    154       GNUNET_PQ_result_spec_timestamp ("wire_deadline",
    155                                        exec_time),
    156       GNUNET_PQ_result_spec_allow_null (
    157         GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
    158                                       &kyc->requirement_row),
    159         NULL),
    160       GNUNET_PQ_result_spec_allow_null (
    161         GNUNET_PQ_result_spec_auto_from_type ("target_pub",
    162                                               account_pub),
    163         NULL),
    164       GNUNET_PQ_result_spec_end
    165     };
    166 
    167     PREPARE (pg,
    168              "get_deposit_without_wtid",
    169              "SELECT"
    170              " bdep.wire_salt"
    171              ",wt.payto_uri"
    172              ",cdep.amount_with_fee"
    173              ",denom.fee_deposit"
    174              ",bdep.wire_deadline"
    175              ",agt.legitimization_requirement_serial_id"
    176              ",kt.target_pub"
    177              " FROM coin_deposits cdep"
    178              " JOIN batch_deposits bdep"
    179              "   USING (batch_deposit_serial_id)"
    180              " JOIN wire_targets wt"
    181              "   USING (wire_target_h_payto)"
    182              /* kyc_targets might not match; then target_pub will be NULL */
    183              " LEFT JOIN kyc_targets kt"
    184              "   USING (h_normalized_payto)"
    185              " JOIN known_coins kc"
    186              "   ON (kc.coin_pub = cdep.coin_pub)"
    187              " JOIN denominations denom"
    188              "   USING (denominations_serial)"
    189              " LEFT JOIN aggregation_transient agt "
    190              "   ON ( (bdep.wire_target_h_payto = agt.wire_target_h_payto) AND"
    191              "        (bdep.merchant_pub = agt.merchant_pub) )"
    192              " WHERE cdep.coin_pub=$1"
    193              "   AND bdep.merchant_pub=$3"
    194              "   AND bdep.h_contract_terms=$2"
    195              " LIMIT 1;");
    196     /* NOTE: above query might be more efficient if we computed the shard
    197        from the merchant_pub and included that in the query */
    198     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    199                                                    "get_deposit_without_wtid",
    200                                                    params,
    201                                                    rs2);
    202     if (0 > qs)
    203       return qs;
    204     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    205     {
    206       struct TALER_MerchantWireHashP wh;
    207 
    208       TALER_merchant_wire_signature_hash (payto_uri,
    209                                           &wire_salt,
    210                                           &wh);
    211       if (0 !=
    212           GNUNET_memcmp (&wh,
    213                          h_wire))
    214       {
    215         GNUNET_PQ_cleanup_result (rs2);
    216         return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    217       }
    218       GNUNET_PQ_cleanup_result (rs2);
    219       if (0 == kyc->requirement_row)
    220         kyc->ok = true; /* technically: unknown */
    221     }
    222     return qs;
    223   }
    224 }