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 }