Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022-2023 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 : /**
18 : * @file iterate_deposit_confirmations.c
19 : * @brief Low-level (statement-level) Postgres database access for the exchange
20 : * @author Christian Grothoff
21 : */
22 : #include "taler/taler_pq_lib.h"
23 : #include "auditor-database/iterate_deposit_confirmations.h"
24 : #include "pg_helper.h"
25 :
26 :
27 : /**
28 : * Hard upper bound on the number of records returned by a single
29 : * call, regardless of the limit requested by the client.
30 : */
31 : #define MAX_RECORDS 50000
32 :
33 :
34 : /**
35 : * Closure for #deposit_confirmation_cb().
36 : */
37 : struct DepositConfirmationContext
38 : {
39 :
40 : /**
41 : * Function to call for each deposit confirmation.
42 : */
43 : TALER_AUDITORDB_DepositConfirmationCallback cb;
44 :
45 : /**
46 : * Closure for @e cb
47 : */
48 : void *cb_cls;
49 :
50 : /**
51 : * Plugin context.
52 : */
53 : struct TALER_AUDITORDB_PostgresContext *pg;
54 :
55 : /**
56 : * Query status to return.
57 : */
58 : enum GNUNET_DB_QueryStatus qs;
59 : };
60 :
61 :
62 : /**
63 : * Helper function for #TALER_AUDITORDB_iterate_deposit_confirmations().
64 : * To be called with the results of a SELECT statement
65 : * that has returned @a num_results results.
66 : *
67 : * @param cls closure of type `struct DepositConfirmationContext *`
68 : * @param result the postgres result
69 : * @param num_results the number of results in @a result
70 : */
71 : static void
72 4 : deposit_confirmation_cb (void *cls,
73 : PGresult *result,
74 : unsigned int num_results)
75 : {
76 4 : struct DepositConfirmationContext *dcc = cls;
77 4 : struct TALER_AUDITORDB_PostgresContext *pg = dcc->pg;
78 :
79 4 : for (unsigned int i = 0; i < num_results; i++)
80 : {
81 0 : struct TALER_AUDITORDB_DepositConfirmation dc = { 0 };
82 0 : struct TALER_CoinSpendPublicKeyP *coin_pubs = NULL;
83 0 : struct TALER_CoinSpendSignatureP *coin_sigs = NULL;
84 0 : size_t num_pubs = 0;
85 0 : size_t num_sigs = 0;
86 0 : struct GNUNET_PQ_ResultSpec rs[] = {
87 0 : GNUNET_PQ_result_spec_uint64 ("row_id",
88 : &dc.row_id),
89 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
90 : &dc.h_contract_terms),
91 0 : GNUNET_PQ_result_spec_auto_from_type ("h_policy",
92 : &dc.h_policy),
93 0 : GNUNET_PQ_result_spec_auto_from_type ("h_wire",
94 : &dc.h_wire),
95 0 : GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
96 : &dc.exchange_timestamp),
97 0 : GNUNET_PQ_result_spec_timestamp ("refund_deadline",
98 : &dc.refund_deadline),
99 0 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
100 : &dc.wire_deadline),
101 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("total_without_fee",
102 : &dc.total_without_fee),
103 0 : GNUNET_PQ_result_spec_auto_array_from_type (pg->conn,
104 : "coin_pubs",
105 : &num_pubs,
106 : coin_pubs),
107 0 : GNUNET_PQ_result_spec_auto_array_from_type (pg->conn,
108 : "coin_sigs",
109 : &num_sigs,
110 : coin_sigs),
111 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
112 : &dc.merchant),
113 0 : GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
114 : &dc.exchange_sig),
115 0 : GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
116 : &dc.exchange_pub),
117 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
118 : &dc.master_sig),
119 0 : GNUNET_PQ_result_spec_bool ("suppressed",
120 : &dc.suppressed),
121 : GNUNET_PQ_result_spec_end
122 : };
123 : enum GNUNET_GenericReturnValue rval;
124 :
125 0 : if (GNUNET_OK !=
126 0 : GNUNET_PQ_extract_result (result,
127 : rs,
128 : i))
129 : {
130 0 : GNUNET_break (0);
131 0 : dcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
132 0 : return;
133 : }
134 0 : if (num_sigs != num_pubs)
135 : {
136 0 : GNUNET_break (0);
137 0 : dcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
138 0 : GNUNET_PQ_cleanup_result (rs);
139 0 : return;
140 : }
141 0 : dcc->qs = i + 1;
142 0 : dc.coin_pubs = coin_pubs;
143 0 : dc.coin_sigs = coin_sigs;
144 0 : dc.num_coins = num_sigs;
145 0 : rval = dcc->cb (dcc->cb_cls,
146 : &dc);
147 0 : GNUNET_PQ_cleanup_result (rs);
148 0 : if (GNUNET_OK != rval)
149 0 : break;
150 : }
151 : }
152 :
153 :
154 : enum GNUNET_DB_QueryStatus
155 4 : TALER_AUDITORDB_iterate_deposit_confirmations (
156 : struct TALER_AUDITORDB_PostgresContext *pg,
157 : int64_t limit,
158 : uint64_t offset,
159 : bool return_suppressed,
160 : TALER_AUDITORDB_DepositConfirmationCallback cb,
161 : void *cb_cls)
162 : {
163 4 : uint64_t plimit = GNUNET_MIN ((uint64_t) MAX_RECORDS,
164 : TALER_AUDITORDB_abs_limit (limit));
165 4 : struct GNUNET_PQ_QueryParam params[] = {
166 4 : GNUNET_PQ_query_param_uint64 (&offset),
167 4 : GNUNET_PQ_query_param_bool (return_suppressed),
168 4 : GNUNET_PQ_query_param_uint64 (&plimit),
169 : GNUNET_PQ_query_param_end
170 : };
171 4 : struct DepositConfirmationContext dcc = {
172 : .cb = cb,
173 : .cb_cls = cb_cls,
174 : .pg = pg
175 : };
176 : enum GNUNET_DB_QueryStatus qs;
177 :
178 4 : PREPARE (pg,
179 : "iterate_deposit_confirmations_confirmation_select_desc",
180 : "SELECT"
181 : " row_id"
182 : ",h_contract_terms"
183 : ",h_policy"
184 : ",h_wire"
185 : ",exchange_timestamp"
186 : ",wire_deadline"
187 : ",refund_deadline"
188 : ",total_without_fee"
189 : ",coin_pubs"
190 : ",coin_sigs"
191 : ",merchant_pub"
192 : ",exchange_sig"
193 : ",exchange_pub"
194 : ",master_sig"
195 : ",suppressed"
196 : " FROM auditor_deposit_confirmations"
197 : " WHERE (row_id < $1)"
198 : " AND ($2 OR NOT suppressed)"
199 : " ORDER BY row_id DESC"
200 : " LIMIT $3"
201 : );
202 4 : PREPARE (pg,
203 : "iterate_deposit_confirmations_confirmation_select_asc",
204 : "SELECT"
205 : " row_id"
206 : ",h_contract_terms"
207 : ",h_policy"
208 : ",h_wire"
209 : ",exchange_timestamp"
210 : ",wire_deadline"
211 : ",refund_deadline"
212 : ",total_without_fee"
213 : ",coin_pubs"
214 : ",coin_sigs"
215 : ",merchant_pub"
216 : ",exchange_sig"
217 : ",exchange_pub"
218 : ",master_sig"
219 : ",suppressed"
220 : " FROM auditor_deposit_confirmations"
221 : " WHERE (row_id > $1)"
222 : " AND ($2 OR NOT suppressed)"
223 : " ORDER BY row_id ASC"
224 : " LIMIT $3"
225 : );
226 4 : qs = GNUNET_PQ_eval_prepared_multi_select (
227 : pg->conn,
228 : (limit > 0)
229 : ? "iterate_deposit_confirmations_confirmation_select_asc"
230 : : "iterate_deposit_confirmations_confirmation_select_desc",
231 : params,
232 : &deposit_confirmation_cb,
233 : &dcc);
234 4 : if (qs > 0)
235 0 : return dcc.qs;
236 4 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
237 4 : return qs;
238 : }
|