pg_lookup_pending_deposits.c (6624B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2023, 2025 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_lookup_pending_deposits.c 18 * @brief Implementation of the lookup_pending_deposits 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_lookup_pending_deposits.h" 26 #include "pg_helper.h" 27 28 29 /** 30 * Context for lookup_pending_deposits(). 31 */ 32 struct LookupDepositsContext 33 { 34 /** 35 * Function to call with the results. 36 */ 37 TALER_MERCHANTDB_PendingDepositsCallback cb; 38 39 /** 40 * Closure for @e cb. 41 */ 42 void *cb_cls; 43 44 /** 45 * Database context. 46 */ 47 struct PostgresClosure *pg; 48 49 /** 50 * Set to the return value on errors. 51 */ 52 enum GNUNET_DB_QueryStatus qs; 53 54 }; 55 56 57 /** 58 * Function to be called with the results of a SELECT statement 59 * that has returned @a num_results results about instances. 60 * 61 * @param cls of type `struct LookupDepositsContext *` 62 * @param result the postgres result 63 * @param num_results the number of results in @a result 64 */ 65 static void 66 lookup_deposits_cb (void *cls, 67 PGresult *result, 68 unsigned int num_results) 69 { 70 struct LookupDepositsContext *ldc = cls; 71 72 for (unsigned int i = 0; i < num_results; i++) 73 { 74 uint64_t deposit_serial; 75 struct GNUNET_TIME_Absolute wire_deadline; 76 struct GNUNET_TIME_Absolute retry_time; 77 struct TALER_PrivateContractHashP h_contract_terms; 78 struct TALER_MerchantPrivateKeyP merchant_priv; 79 char *instance_id; 80 struct TALER_MerchantWireHashP h_wire; 81 struct TALER_Amount amount_with_fee; 82 struct TALER_Amount deposit_fee; 83 struct TALER_CoinSpendPublicKeyP coin_pub; 84 struct GNUNET_PQ_ResultSpec rs[] = { 85 GNUNET_PQ_result_spec_uint64 ("deposit_serial", 86 &deposit_serial), 87 GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", 88 &h_contract_terms), 89 GNUNET_PQ_result_spec_auto_from_type ("merchant_priv", 90 &merchant_priv), 91 GNUNET_PQ_result_spec_string ("merchant_id", 92 &instance_id), 93 GNUNET_PQ_result_spec_absolute_time ("wire_transfer_deadline", 94 &wire_deadline), 95 GNUNET_PQ_result_spec_absolute_time ("retry_time", 96 &retry_time), 97 GNUNET_PQ_result_spec_auto_from_type ("h_wire", 98 &h_wire), 99 TALER_PQ_result_spec_amount_with_currency ("amount_with_fee", 100 &amount_with_fee), 101 TALER_PQ_result_spec_amount_with_currency ("deposit_fee", 102 &deposit_fee), 103 GNUNET_PQ_result_spec_auto_from_type ("coin_pub", 104 &coin_pub), 105 GNUNET_PQ_result_spec_end 106 }; 107 108 if (GNUNET_OK != 109 GNUNET_PQ_extract_result (result, 110 rs, 111 i)) 112 { 113 GNUNET_break (0); 114 ldc->qs = GNUNET_DB_STATUS_HARD_ERROR; 115 return; 116 } 117 ldc->cb (ldc->cb_cls, 118 deposit_serial, 119 wire_deadline, 120 retry_time, 121 &h_contract_terms, 122 &merchant_priv, 123 instance_id, 124 &h_wire, 125 &amount_with_fee, 126 &deposit_fee, 127 &coin_pub); 128 GNUNET_PQ_cleanup_result (rs); 129 } 130 } 131 132 133 enum GNUNET_DB_QueryStatus 134 TMH_PG_lookup_pending_deposits ( 135 void *cls, 136 const char *exchange_url, 137 uint64_t limit, 138 bool allow_future, 139 TALER_MERCHANTDB_PendingDepositsCallback cb, 140 void *cb_cls) 141 { 142 struct PostgresClosure *pg = cls; 143 struct LookupDepositsContext ldc = { 144 .cb = cb, 145 .cb_cls = cb_cls, 146 .pg = pg 147 }; 148 struct GNUNET_TIME_Absolute now 149 = GNUNET_TIME_absolute_get (); 150 struct GNUNET_PQ_QueryParam params[] = { 151 GNUNET_PQ_query_param_string (exchange_url), 152 GNUNET_PQ_query_param_absolute_time (&now), 153 GNUNET_PQ_query_param_uint64 (&limit), 154 GNUNET_PQ_query_param_bool (allow_future), 155 GNUNET_PQ_query_param_end 156 }; 157 enum GNUNET_DB_QueryStatus qs; 158 159 check_connection (pg); 160 PREPARE (pg, 161 "lookup_pending_deposits", 162 "SELECT" 163 " md.deposit_serial" 164 ",mct.h_contract_terms" 165 ",mk.merchant_priv" 166 ",mi.merchant_id" 167 ",mdc.wire_transfer_deadline" 168 ",md.settlement_retry_time AS retry_time" 169 ",ma.h_wire" 170 ",md.amount_with_fee" 171 ",md.deposit_fee" 172 ",md.coin_pub" 173 " FROM merchant_deposits md" 174 " JOIN merchant_deposit_confirmations mdc" 175 " USING (deposit_confirmation_serial)" 176 " JOIN merchant_contract_terms mct" 177 " ON (mct.order_serial=mdc.order_serial)" 178 " JOIN merchant_accounts ma" 179 " ON (mdc.account_serial=ma.account_serial)" 180 " LEFT JOIN merchant_kyc kyc" 181 " ON (mdc.account_serial=kyc.account_serial)" 182 " JOIN merchant_instances mi" 183 " ON (mct.merchant_serial=mi.merchant_serial)" 184 " JOIN merchant_keys mk" 185 " ON (mi.merchant_serial=mk.merchant_serial)" 186 " WHERE (mdc.exchange_url=$1)" 187 " AND md.settlement_retry_needed" 188 " AND ($4 OR (md.settlement_retry_time < $2))" 189 " AND ( (kyc.kyc_ok IS NULL) OR kyc.kyc_ok)" 190 " ORDER BY md.settlement_retry_time ASC" 191 " LIMIT $3"); 192 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 193 "lookup_pending_deposits", 194 params, 195 &lookup_deposits_cb, 196 &ldc); 197 if (0 > ldc.qs) 198 return ldc.qs; 199 return qs; 200 }