exchange

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

lookup_transfer_by_deposit.c (8664B)


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