Line data Source code
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 8 : 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 8 : struct GNUNET_PQ_QueryParam params[] = {
43 8 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
44 8 : GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
45 8 : 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 8 : struct GNUNET_PQ_ResultSpec rs[] = {
51 8 : GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
52 : wtid),
53 8 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
54 : &wire_salt),
55 8 : GNUNET_PQ_result_spec_string ("payto_uri",
56 : &payto_uri.full_payto),
57 8 : GNUNET_PQ_result_spec_timestamp ("execution_date",
58 : exec_time),
59 8 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
60 : amount_with_fee),
61 8 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
62 : deposit_fee),
63 8 : 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 8 : memset (kyc,
71 : 0,
72 : sizeof (*kyc));
73 : /* check if the aggregation record exists and get it */
74 8 : 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 8 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
106 : "lookup_deposit_wtid",
107 : params,
108 : rs);
109 8 : if (0 > qs)
110 0 : return qs;
111 8 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
112 : {
113 : struct TALER_MerchantWireHashP wh;
114 :
115 2 : TALER_merchant_wire_signature_hash (payto_uri,
116 : &wire_salt,
117 : &wh);
118 2 : if (0 ==
119 2 : GNUNET_memcmp (&wh,
120 : h_wire))
121 : {
122 2 : *pending = false;
123 2 : kyc->ok = true;
124 2 : GNUNET_PQ_cleanup_result (rs);
125 2 : return qs;
126 : }
127 0 : qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
128 0 : GNUNET_PQ_cleanup_result (rs);
129 : }
130 6 : *pending = true;
131 6 : memset (wtid,
132 : 0,
133 : sizeof (*wtid));
134 6 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
135 6 : 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 6 : struct GNUNET_PQ_ResultSpec rs2[] = {
142 6 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
143 : &wire_salt),
144 6 : GNUNET_PQ_result_spec_string ("payto_uri",
145 : &payto_uri.full_payto),
146 6 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
147 : amount_with_fee),
148 6 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
149 : deposit_fee),
150 6 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
151 : exec_time),
152 6 : GNUNET_PQ_result_spec_allow_null (
153 : GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
154 : &kyc->requirement_row),
155 : NULL),
156 6 : 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 6 : 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 6 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
195 : "get_deposit_without_wtid",
196 : params,
197 : rs2);
198 6 : if (0 > qs)
199 0 : return qs;
200 6 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
201 : {
202 : struct TALER_MerchantWireHashP wh;
203 :
204 4 : TALER_merchant_wire_signature_hash (payto_uri,
205 : &wire_salt,
206 : &wh);
207 4 : if (0 !=
208 4 : GNUNET_memcmp (&wh,
209 : h_wire))
210 : {
211 0 : GNUNET_PQ_cleanup_result (rs2);
212 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
213 : }
214 4 : GNUNET_PQ_cleanup_result (rs2);
215 4 : if (0 == kyc->requirement_row)
216 3 : kyc->ok = true; /* technically: unknown */
217 : }
218 6 : return qs;
219 : }
220 : }
|