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 }