Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014--2022 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 plugin_exchangedb_postgres.c
19 : * @brief Low-level (statement-level) Postgres database access for the exchange
20 : * @author Florian Dold
21 : * @author Christian Grothoff
22 : * @author Sree Harsha Totakura
23 : * @author Marcello Stanisci
24 : */
25 : #include "platform.h"
26 : #include "taler_error_codes.h"
27 : #include "taler_dbevents.h"
28 : #include "taler_pq_lib.h"
29 : #include "taler_util.h"
30 : #include "taler_json_lib.h"
31 : #include "taler_exchangedb_plugin.h"
32 : #include <poll.h>
33 : #include <pthread.h>
34 : #include <libpq-fe.h>
35 :
36 : #include "plugin_exchangedb_common.c"
37 :
38 : /**
39 : * Set to 1 to enable Postgres auto_explain module. This will
40 : * slow down things a _lot_, but also provide extensive logging
41 : * in the Postgres database logger for performance analysis.
42 : */
43 : #define AUTO_EXPLAIN 1
44 :
45 : /**
46 : * Wrapper macro to add the currency from the plugin's state
47 : * when fetching amounts from the database.
48 : *
49 : * @param field name of the database field to fetch amount from
50 : * @param[out] amountp pointer to amount to set
51 : */
52 : #define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \
53 : field,pg->currency,amountp)
54 :
55 : /**
56 : * Wrapper macro to add the currency from the plugin's state
57 : * when fetching amounts from the database. NBO variant.
58 : *
59 : * @param field name of the database field to fetch amount from
60 : * @param[out] amountp pointer to amount to set
61 : */
62 : #define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \
63 : amountp) TALER_PQ_result_spec_amount_nbo ( \
64 : field,pg->currency,amountp)
65 :
66 : /**
67 : * Log a really unexpected PQ error with all the details we can get hold of.
68 : *
69 : * @param result PQ result object of the PQ operation that failed
70 : * @param conn SQL connection that was used
71 : */
72 : #define BREAK_DB_ERR(result,conn) do { \
73 : GNUNET_break (0); \
74 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
75 : "Database failure: %s/%s/%s/%s/%s", \
76 : PQresultErrorField (result, PG_DIAG_MESSAGE_PRIMARY), \
77 : PQresultErrorField (result, PG_DIAG_MESSAGE_DETAIL), \
78 : PQresultErrorMessage (result), \
79 : PQresStatus (PQresultStatus (result)), \
80 : PQerrorMessage (conn)); \
81 : } while (0)
82 :
83 :
84 : /**
85 : * Type of the "cls" argument given to each of the functions in
86 : * our API.
87 : */
88 : struct PostgresClosure
89 : {
90 :
91 : /**
92 : * Our configuration.
93 : */
94 : const struct GNUNET_CONFIGURATION_Handle *cfg;
95 :
96 : /**
97 : * Directory with SQL statements to run to create tables.
98 : */
99 : char *sql_dir;
100 :
101 : /**
102 : * After how long should idle reserves be closed?
103 : */
104 : struct GNUNET_TIME_Relative idle_reserve_expiration_time;
105 :
106 : /**
107 : * After how long should reserves that have seen withdraw operations
108 : * be garbage collected?
109 : */
110 : struct GNUNET_TIME_Relative legal_reserve_expiration_time;
111 :
112 : /**
113 : * What delay should we introduce before ready transactions
114 : * are actually aggregated?
115 : */
116 : struct GNUNET_TIME_Relative aggregator_shift;
117 :
118 : /**
119 : * Which currency should we assume all amounts to be in?
120 : */
121 : char *currency;
122 :
123 : /**
124 : * Our base URL.
125 : */
126 : char *exchange_url;
127 :
128 : /**
129 : * Postgres connection handle.
130 : */
131 : struct GNUNET_PQ_Context *conn;
132 :
133 : /**
134 : * Name of the current transaction, for debugging.
135 : */
136 : const char *transaction_name;
137 :
138 : /**
139 : * Did we initialize the prepared statements
140 : * for this session?
141 : */
142 : bool init;
143 :
144 : };
145 :
146 :
147 : /**
148 : * Drop all Taler tables. This should only be used by testcases.
149 : *
150 : * @param cls the `struct PostgresClosure` with the plugin-specific state
151 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
152 : */
153 : static enum GNUNET_GenericReturnValue
154 0 : postgres_drop_tables (void *cls)
155 : {
156 0 : struct PostgresClosure *pg = cls;
157 : struct GNUNET_PQ_Context *conn;
158 : enum GNUNET_GenericReturnValue ret;
159 :
160 0 : if (NULL != pg->conn)
161 : {
162 0 : GNUNET_PQ_disconnect (pg->conn);
163 0 : pg->conn = NULL;
164 0 : pg->init = false;
165 : }
166 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
167 : "exchangedb-postgres",
168 : NULL,
169 : NULL,
170 : NULL);
171 0 : if (NULL == conn)
172 0 : return GNUNET_SYSERR;
173 0 : ret = GNUNET_PQ_exec_sql (conn,
174 : "drop");
175 0 : GNUNET_PQ_disconnect (conn);
176 0 : return ret;
177 : }
178 :
179 :
180 : /**
181 : * Create the necessary tables if they are not present
182 : *
183 : * @param cls the `struct PostgresClosure` with the plugin-specific state
184 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
185 : */
186 : static enum GNUNET_GenericReturnValue
187 0 : postgres_create_tables (void *cls)
188 : {
189 0 : struct PostgresClosure *pg = cls;
190 : struct GNUNET_PQ_Context *conn;
191 : enum GNUNET_GenericReturnValue ret;
192 :
193 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
194 : "exchangedb-postgres",
195 : "exchange-",
196 : NULL,
197 : NULL);
198 0 : if (NULL == conn)
199 0 : return GNUNET_SYSERR;
200 0 : ret = GNUNET_PQ_exec_sql (conn,
201 : "procedures");
202 0 : GNUNET_PQ_disconnect (conn);
203 0 : return ret;
204 : }
205 :
206 :
207 : /**
208 : * Create tables of a shard node with index idx
209 : *
210 : * @param cls the `struct PostgresClosure` with the plugin-specific state
211 : * @param idx the shards index, will be appended as suffix to all tables
212 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
213 : */
214 : static enum GNUNET_GenericReturnValue
215 0 : postgres_create_shard_tables (void *cls,
216 : uint32_t idx)
217 : {
218 0 : struct PostgresClosure *pg = cls;
219 : struct GNUNET_PQ_Context *conn;
220 0 : enum GNUNET_GenericReturnValue ret = GNUNET_OK;
221 0 : struct GNUNET_PQ_QueryParam params[] = {
222 0 : GNUNET_PQ_query_param_uint32 (&idx),
223 : GNUNET_PQ_query_param_end
224 : };
225 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
226 0 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
227 : GNUNET_PQ_EXECUTE_STATEMENT_END
228 : };
229 :
230 0 : struct GNUNET_PQ_PreparedStatement ps[] = {
231 0 : GNUNET_PQ_make_prepare ("create_shard_tables",
232 : "SELECT"
233 : " setup_shard"
234 : " ($1);",
235 : 1),
236 : GNUNET_PQ_PREPARED_STATEMENT_END
237 : };
238 :
239 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
240 : "exchangedb-postgres",
241 : "shard-",
242 : es,
243 : ps);
244 0 : if (NULL == conn)
245 0 : return GNUNET_SYSERR;
246 0 : if (0 > GNUNET_PQ_eval_prepared_non_select (conn,
247 : "create_shard_tables",
248 : params))
249 0 : ret = GNUNET_SYSERR;
250 0 : GNUNET_PQ_disconnect (conn);
251 0 : return ret;
252 : }
253 :
254 :
255 : /**
256 : * Setup partitions of already existing tables
257 : *
258 : * @param cls the `struct PostgresClosure` with the plugin-specific state
259 : * @param num the number of partitions to create for each partitioned table
260 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
261 : */
262 : static enum GNUNET_GenericReturnValue
263 0 : postgres_setup_partitions (void *cls,
264 : uint32_t num)
265 : {
266 0 : struct PostgresClosure *pg = cls;
267 : struct GNUNET_PQ_Context *conn;
268 0 : enum GNUNET_GenericReturnValue ret = GNUNET_OK;
269 0 : struct GNUNET_PQ_QueryParam params[] = {
270 0 : GNUNET_PQ_query_param_uint32 (&num),
271 : GNUNET_PQ_query_param_end
272 : };
273 0 : struct GNUNET_PQ_PreparedStatement ps[] = {
274 0 : GNUNET_PQ_make_prepare ("setup_partitions",
275 : "SELECT"
276 : " create_partitions"
277 : " ($1);",
278 : 1),
279 : GNUNET_PQ_PREPARED_STATEMENT_END
280 : };
281 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
282 0 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
283 : GNUNET_PQ_EXECUTE_STATEMENT_END
284 : };
285 :
286 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
287 : "exchangedb-postgres",
288 : NULL,
289 : es,
290 : ps);
291 0 : if (NULL == conn)
292 0 : return GNUNET_SYSERR;
293 0 : ret = GNUNET_OK;
294 0 : if (0 > GNUNET_PQ_eval_prepared_non_select (conn,
295 : "setup_partitions",
296 : params))
297 0 : ret = GNUNET_SYSERR;
298 0 : GNUNET_PQ_disconnect (conn);
299 0 : return ret;
300 : }
301 :
302 :
303 : /**
304 : * Setup foreign servers (shards) for already existing tables
305 : *
306 : * @param cls the `struct PostgresClosure` with the plugin-specific state
307 : * @param num the number of foreign servers (shards) to create for each partitioned table
308 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
309 : */
310 : static enum GNUNET_GenericReturnValue
311 0 : postgres_setup_foreign_servers (void *cls,
312 : uint32_t num)
313 : {
314 0 : struct PostgresClosure *pg = cls;
315 : struct GNUNET_PQ_Context *conn;
316 0 : enum GNUNET_GenericReturnValue ret = GNUNET_OK;
317 0 : char *shard_domain = NULL;
318 0 : char *remote_user = NULL;
319 0 : char *remote_user_pw = NULL;
320 :
321 0 : if (GNUNET_OK !=
322 0 : GNUNET_CONFIGURATION_get_value_string (pg->cfg,
323 : "exchange",
324 : "SHARD_DOMAIN",
325 : &shard_domain))
326 : {
327 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
328 : "exchange",
329 : "SHARD_DOMAIN");
330 0 : return GNUNET_SYSERR;
331 : }
332 0 : if (GNUNET_OK !=
333 0 : GNUNET_CONFIGURATION_get_value_string (pg->cfg,
334 : "exchangedb-postgres",
335 : "SHARD_REMOTE_USER",
336 : &remote_user))
337 : {
338 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
339 : "exchangedb-postgres",
340 : "SHARD_REMOTE_USER");
341 0 : GNUNET_free (shard_domain);
342 0 : return GNUNET_SYSERR;
343 : }
344 0 : if (GNUNET_OK !=
345 0 : GNUNET_CONFIGURATION_get_value_string (pg->cfg,
346 : "exchangedb-postgres",
347 : "SHARD_REMOTE_USER_PW",
348 : &remote_user_pw))
349 : {
350 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
351 : "exchangedb-postgres",
352 : "SHARD_REMOTE_USER_PW");
353 0 : GNUNET_free (shard_domain);
354 0 : GNUNET_free (remote_user);
355 0 : return GNUNET_SYSERR;
356 : }
357 :
358 0 : struct GNUNET_PQ_QueryParam params[] = {
359 0 : GNUNET_PQ_query_param_uint32 (&num),
360 0 : GNUNET_PQ_query_param_string (shard_domain),
361 0 : GNUNET_PQ_query_param_string (remote_user),
362 0 : GNUNET_PQ_query_param_string (remote_user_pw),
363 : GNUNET_PQ_query_param_end
364 : };
365 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
366 0 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
367 : GNUNET_PQ_EXECUTE_STATEMENT_END
368 : };
369 0 : struct GNUNET_PQ_PreparedStatement ps[] = {
370 0 : GNUNET_PQ_make_prepare ("create_foreign_servers",
371 : "SELECT"
372 : " create_foreign_servers"
373 : " ($1, $2, $3, $4);",
374 : 4),
375 : GNUNET_PQ_PREPARED_STATEMENT_END
376 : };
377 :
378 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
379 : "exchangedb-postgres",
380 : NULL,
381 : es,
382 : ps);
383 0 : if (NULL == conn)
384 : {
385 0 : ret = GNUNET_SYSERR;
386 : }
387 0 : else if (0 > GNUNET_PQ_eval_prepared_non_select (conn,
388 : "create_foreign_servers",
389 : params))
390 : {
391 0 : ret = GNUNET_SYSERR;
392 : }
393 0 : GNUNET_free (shard_domain);
394 0 : GNUNET_free (remote_user);
395 0 : GNUNET_free (remote_user_pw);
396 0 : GNUNET_PQ_disconnect (conn);
397 0 : return ret;
398 : }
399 :
400 :
401 : /**
402 : * Initialize prepared statements for @a pg.
403 : *
404 : * @param[in,out] pg connection to initialize
405 : * @return #GNUNET_OK on success
406 : */
407 : static enum GNUNET_GenericReturnValue
408 0 : prepare_statements (struct PostgresClosure *pg)
409 : {
410 : enum GNUNET_GenericReturnValue ret;
411 0 : struct GNUNET_PQ_PreparedStatement ps[] = {
412 : /* Used in #postgres_insert_denomination_info() and
413 : #postgres_add_denomination_key() */
414 0 : GNUNET_PQ_make_prepare (
415 : "denomination_insert",
416 : "INSERT INTO denominations "
417 : "(denom_pub_hash"
418 : ",denom_pub"
419 : ",master_sig"
420 : ",valid_from"
421 : ",expire_withdraw"
422 : ",expire_deposit"
423 : ",expire_legal"
424 : ",coin_val" /* value of this denom */
425 : ",coin_frac" /* fractional value of this denom */
426 : ",fee_withdraw_val"
427 : ",fee_withdraw_frac"
428 : ",fee_deposit_val"
429 : ",fee_deposit_frac"
430 : ",fee_refresh_val"
431 : ",fee_refresh_frac"
432 : ",fee_refund_val"
433 : ",fee_refund_frac"
434 : ",age_mask"
435 : ") VALUES "
436 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
437 : " $11, $12, $13, $14, $15, $16, $17, $18);",
438 : 18),
439 : /* Used in #postgres_iterate_denomination_info() */
440 0 : GNUNET_PQ_make_prepare (
441 : "denomination_iterate",
442 : "SELECT"
443 : " master_sig"
444 : ",denom_pub_hash"
445 : ",valid_from"
446 : ",expire_withdraw"
447 : ",expire_deposit"
448 : ",expire_legal"
449 : ",coin_val" /* value of this denom */
450 : ",coin_frac" /* fractional value of this denom */
451 : ",fee_withdraw_val"
452 : ",fee_withdraw_frac"
453 : ",fee_deposit_val"
454 : ",fee_deposit_frac"
455 : ",fee_refresh_val"
456 : ",fee_refresh_frac"
457 : ",fee_refund_val"
458 : ",fee_refund_frac"
459 : ",denom_pub"
460 : ",age_mask"
461 : " FROM denominations;",
462 : 0),
463 : /* Used in #postgres_iterate_denominations() */
464 0 : GNUNET_PQ_make_prepare (
465 : "select_denominations",
466 : "SELECT"
467 : " denominations.master_sig"
468 : ",denom_revocations_serial_id IS NOT NULL AS revoked"
469 : ",valid_from"
470 : ",expire_withdraw"
471 : ",expire_deposit"
472 : ",expire_legal"
473 : ",coin_val" /* value of this denom */
474 : ",coin_frac" /* fractional value of this denom */
475 : ",fee_withdraw_val"
476 : ",fee_withdraw_frac"
477 : ",fee_deposit_val"
478 : ",fee_deposit_frac"
479 : ",fee_refresh_val"
480 : ",fee_refresh_frac"
481 : ",fee_refund_val"
482 : ",fee_refund_frac"
483 : ",denom_type"
484 : ",age_mask"
485 : ",denom_pub"
486 : " FROM denominations"
487 : " LEFT JOIN "
488 : " denomination_revocations USING (denominations_serial);",
489 : 0),
490 : /* Used in #postgres_iterate_active_signkeys() */
491 0 : GNUNET_PQ_make_prepare (
492 : "select_signkeys",
493 : "SELECT"
494 : " master_sig"
495 : ",exchange_pub"
496 : ",valid_from"
497 : ",expire_sign"
498 : ",expire_legal"
499 : " FROM exchange_sign_keys esk"
500 : " WHERE"
501 : " expire_sign > $1"
502 : " AND NOT EXISTS "
503 : " (SELECT esk_serial "
504 : " FROM signkey_revocations skr"
505 : " WHERE esk.esk_serial = skr.esk_serial);",
506 : 1),
507 : /* Used in #postgres_iterate_auditor_denominations() */
508 0 : GNUNET_PQ_make_prepare (
509 : "select_auditor_denoms",
510 : "SELECT"
511 : " auditors.auditor_pub"
512 : ",denominations.denom_pub_hash"
513 : ",auditor_denom_sigs.auditor_sig"
514 : " FROM auditor_denom_sigs"
515 : " JOIN auditors USING (auditor_uuid)"
516 : " JOIN denominations USING (denominations_serial)"
517 : " WHERE auditors.is_active;",
518 : 0),
519 : /* Used in #postgres_iterate_active_auditors() */
520 0 : GNUNET_PQ_make_prepare (
521 : "select_auditors",
522 : "SELECT"
523 : " auditor_pub"
524 : ",auditor_url"
525 : ",auditor_name"
526 : " FROM auditors"
527 : " WHERE"
528 : " is_active;",
529 : 0),
530 : /* Used in #postgres_get_denomination_info() */
531 0 : GNUNET_PQ_make_prepare (
532 : "denomination_get",
533 : "SELECT"
534 : " master_sig"
535 : ",valid_from"
536 : ",expire_withdraw"
537 : ",expire_deposit"
538 : ",expire_legal"
539 : ",coin_val" /* value of this denom */
540 : ",coin_frac" /* fractional value of this denom */
541 : ",fee_withdraw_val"
542 : ",fee_withdraw_frac"
543 : ",fee_deposit_val"
544 : ",fee_deposit_frac"
545 : ",fee_refresh_val"
546 : ",fee_refresh_frac"
547 : ",fee_refund_val"
548 : ",fee_refund_frac"
549 : ",age_mask"
550 : " FROM denominations"
551 : " WHERE denom_pub_hash=$1;",
552 : 1),
553 : /* Used in #postgres_insert_denomination_revocation() */
554 0 : GNUNET_PQ_make_prepare (
555 : "denomination_revocation_insert",
556 : "INSERT INTO denomination_revocations "
557 : "(denominations_serial"
558 : ",master_sig"
559 : ") SELECT denominations_serial,$2"
560 : " FROM denominations"
561 : " WHERE denom_pub_hash=$1;",
562 : 2),
563 : /* Used in #postgres_get_denomination_revocation() */
564 0 : GNUNET_PQ_make_prepare (
565 : "denomination_revocation_get",
566 : "SELECT"
567 : " master_sig"
568 : ",denom_revocations_serial_id"
569 : " FROM denomination_revocations"
570 : " WHERE denominations_serial="
571 : " (SELECT denominations_serial"
572 : " FROM denominations"
573 : " WHERE denom_pub_hash=$1);",
574 : 1),
575 : /* Used in #postgres_reserves_get_origin() */
576 0 : GNUNET_PQ_make_prepare (
577 : "get_h_wire_source_of_reserve",
578 : "SELECT"
579 : " wire_source_h_payto"
580 : " FROM reserves_in"
581 : " WHERE reserve_pub=$1",
582 : 1),
583 0 : GNUNET_PQ_make_prepare (
584 : "get_kyc_h_payto",
585 : "SELECT"
586 : " wire_target_h_payto"
587 : " FROM wire_targets"
588 : " WHERE wire_target_h_payto=$1"
589 : " LIMIT 1;",
590 : 1),
591 : /* Used in #postgres_insert_partner() */
592 0 : GNUNET_PQ_make_prepare (
593 : "insert_partner",
594 : "INSERT INTO partners"
595 : " (partner_master_pub"
596 : " ,start_date"
597 : " ,end_date"
598 : " ,wad_frequency"
599 : " ,wad_fee_val"
600 : " ,wad_fee_frac"
601 : " ,master_sig"
602 : " ,partner_base_url"
603 : " ) VALUES "
604 : " ($1, $2, $3, $4, $5, $6, $7, $8);",
605 : 8),
606 : /* Used in #setup_wire_target() */
607 0 : GNUNET_PQ_make_prepare (
608 : "insert_kyc_status",
609 : "INSERT INTO wire_targets"
610 : " (wire_target_h_payto"
611 : " ,payto_uri"
612 : " ) VALUES "
613 : " ($1, $2)"
614 : " ON CONFLICT DO NOTHING",
615 : 2),
616 : /* Used in #postgres_drain_kyc_alert() */
617 0 : GNUNET_PQ_make_prepare (
618 : "drain_kyc_alert",
619 : "DELETE FROM kyc_alerts"
620 : " WHERE trigger_type=$1"
621 : " AND h_payto = "
622 : " (SELECT h_payto "
623 : " FROM kyc_alerts"
624 : " WHERE trigger_type=$1"
625 : " LIMIT 1)"
626 : " RETURNING h_payto;",
627 : 1),
628 : /* Used in #postgres_reserves_get() */
629 0 : GNUNET_PQ_make_prepare (
630 : "reserves_get",
631 : "SELECT"
632 : " current_balance_val"
633 : ",current_balance_frac"
634 : ",expiration_date"
635 : ",gc_date"
636 : " FROM reserves"
637 : " WHERE reserve_pub=$1"
638 : " LIMIT 1;",
639 : 1),
640 0 : GNUNET_PQ_make_prepare (
641 : "reserve_create",
642 : "INSERT INTO reserves "
643 : "(reserve_pub"
644 : ",current_balance_val"
645 : ",current_balance_frac"
646 : ",expiration_date"
647 : ",gc_date"
648 : ") VALUES "
649 : "($1, $2, $3, $4, $5)"
650 : " ON CONFLICT DO NOTHING"
651 : " RETURNING reserve_uuid;",
652 : 5),
653 : /* Used in #postgres_insert_reserve_closed() */
654 0 : GNUNET_PQ_make_prepare (
655 : "reserves_close_insert",
656 : "INSERT INTO reserves_close "
657 : "(reserve_pub"
658 : ",execution_date"
659 : ",wtid"
660 : ",wire_target_h_payto"
661 : ",amount_val"
662 : ",amount_frac"
663 : ",closing_fee_val"
664 : ",closing_fee_frac"
665 : ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8);",
666 : 8),
667 : /* Used in #postgres_insert_drain_profit() */
668 0 : GNUNET_PQ_make_prepare (
669 : "drain_profit_insert",
670 : "INSERT INTO profit_drains "
671 : "(wtid"
672 : ",account_section"
673 : ",payto_uri"
674 : ",trigger_date"
675 : ",amount_val"
676 : ",amount_frac"
677 : ",master_sig"
678 : ") VALUES ($1, $2, $3, $4, $5, $6, $7);",
679 : 7),
680 : /* Used in #postgres_profit_drains_get_pending() */
681 0 : GNUNET_PQ_make_prepare (
682 : "get_ready_profit_drain",
683 : "SELECT"
684 : " profit_drain_serial_id"
685 : ",wtid"
686 : ",account_section"
687 : ",payto_uri"
688 : ",trigger_date"
689 : ",amount_val"
690 : ",amount_frac"
691 : ",master_sig"
692 : " FROM profit_drains"
693 : " WHERE NOT executed"
694 : " ORDER BY trigger_date ASC;",
695 : 0),
696 : /* Used in #postgres_profit_drains_get() */
697 0 : GNUNET_PQ_make_prepare (
698 : "get_profit_drain",
699 : "SELECT"
700 : " profit_drain_serial_id"
701 : ",account_section"
702 : ",payto_uri"
703 : ",trigger_date"
704 : ",amount_val"
705 : ",amount_frac"
706 : ",master_sig"
707 : " FROM profit_drains"
708 : " WHERE wtid=$1;",
709 : 1),
710 : /* Used in #postgres_profit_drains_set_finished() */
711 0 : GNUNET_PQ_make_prepare (
712 : "drain_profit_set_finished",
713 : "UPDATE profit_drains"
714 : " SET"
715 : " executed=TRUE"
716 : " WHERE profit_drain_serial_id=$1;",
717 : 1),
718 : /* Used in #postgres_reserves_update() when the reserve is updated */
719 0 : GNUNET_PQ_make_prepare (
720 : "reserve_update",
721 : "UPDATE reserves"
722 : " SET"
723 : " expiration_date=$1"
724 : ",gc_date=$2"
725 : ",current_balance_val=$3"
726 : ",current_balance_frac=$4"
727 : " WHERE reserve_pub=$5;",
728 : 5),
729 : /* Used in #postgres_reserves_in_insert() to store transaction details */
730 0 : GNUNET_PQ_make_prepare (
731 : "reserves_in_add_transaction",
732 : "INSERT INTO reserves_in "
733 : "(reserve_pub"
734 : ",wire_reference"
735 : ",credit_val"
736 : ",credit_frac"
737 : ",exchange_account_section"
738 : ",wire_source_h_payto"
739 : ",execution_date"
740 : ") VALUES ($1, $2, $3, $4, $5, $6, $7)"
741 : " ON CONFLICT DO NOTHING;",
742 : 7),
743 : /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
744 : transactions for reserves with serial id '\geq' the given parameter */
745 0 : GNUNET_PQ_make_prepare (
746 : "audit_reserves_in_get_transactions_incr",
747 : "SELECT"
748 : " reserves.reserve_pub"
749 : ",wire_reference"
750 : ",credit_val"
751 : ",credit_frac"
752 : ",execution_date"
753 : ",payto_uri AS sender_account_details"
754 : ",reserve_in_serial_id"
755 : " FROM reserves_in"
756 : " JOIN reserves"
757 : " USING (reserve_pub)"
758 : " JOIN wire_targets"
759 : " ON (wire_source_h_payto = wire_target_h_payto)"
760 : " WHERE reserve_in_serial_id>=$1"
761 : " ORDER BY reserve_in_serial_id;",
762 : 1),
763 : /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
764 : transactions for reserves with serial id '\geq' the given parameter */
765 0 : GNUNET_PQ_make_prepare (
766 : "audit_reserves_in_get_transactions_incr_by_account",
767 : "SELECT"
768 : " reserves.reserve_pub"
769 : ",wire_reference"
770 : ",credit_val"
771 : ",credit_frac"
772 : ",execution_date"
773 : ",payto_uri AS sender_account_details"
774 : ",reserve_in_serial_id"
775 : " FROM reserves_in"
776 : " JOIN reserves "
777 : " USING (reserve_pub)"
778 : " JOIN wire_targets"
779 : " ON (wire_source_h_payto = wire_target_h_payto)"
780 : " WHERE reserve_in_serial_id>=$1 AND exchange_account_section=$2"
781 : " ORDER BY reserve_in_serial_id;",
782 : 2),
783 : /* Used in #postgres_get_reserve_history() to obtain inbound transactions
784 : for a reserve */
785 0 : GNUNET_PQ_make_prepare (
786 : "reserves_in_get_transactions",
787 : /*
788 : "SELECT"
789 : " wire_reference"
790 : ",credit_val"
791 : ",credit_frac"
792 : ",execution_date"
793 : ",payto_uri AS sender_account_details"
794 : " FROM reserves_in"
795 : " JOIN wire_targets"
796 : " ON (wire_source_h_payto = wire_target_h_payto)"
797 : " WHERE reserve_pub=$1;",
798 : */
799 : "WITH ri AS MATERIALIZED ( "
800 : " SELECT * "
801 : " FROM reserves_in "
802 : " WHERE reserve_pub = $1 "
803 : ") "
804 : "SELECT "
805 : " wire_reference "
806 : " ,credit_val "
807 : " ,credit_frac "
808 : " ,execution_date "
809 : " ,payto_uri AS sender_account_details "
810 : "FROM wire_targets "
811 : "JOIN ri "
812 : " ON (wire_target_h_payto = wire_source_h_payto) "
813 : "WHERE wire_target_h_payto = ( "
814 : " SELECT wire_source_h_payto FROM ri "
815 : "); ",
816 : 1),
817 : /* Used in #postgres_get_reserve_status() to obtain inbound transactions
818 : for a reserve */
819 0 : GNUNET_PQ_make_prepare (
820 : "reserves_in_get_transactions_truncated",
821 : /*
822 : "SELECT"
823 : " wire_reference"
824 : ",credit_val"
825 : ",credit_frac"
826 : ",execution_date"
827 : ",payto_uri AS sender_account_details"
828 : " FROM reserves_in"
829 : " JOIN wire_targets"
830 : " ON (wire_source_h_payto = wire_target_h_payto)"
831 : " WHERE reserve_pub=$1"
832 : " AND execution_date>=$2;",
833 : */
834 : "WITH ri AS MATERIALIZED ( "
835 : " SELECT * "
836 : " FROM reserves_in "
837 : " WHERE reserve_pub = $1 "
838 : ") "
839 : "SELECT "
840 : " wire_reference "
841 : " ,credit_val "
842 : " ,credit_frac "
843 : " ,execution_date "
844 : " ,payto_uri AS sender_account_details "
845 : "FROM wire_targets "
846 : "JOIN ri "
847 : " ON (wire_target_h_payto = wire_source_h_payto) "
848 : "WHERE execution_date >= $2"
849 : " AND wire_target_h_payto = ( "
850 : " SELECT wire_source_h_payto FROM ri "
851 : "); ",
852 : 2),
853 : /* Used in #postgres_do_withdraw() to store
854 : the signature of a blinded coin with the blinded coin's
855 : details before returning it during /reserve/withdraw. We store
856 : the coin's denomination information (public key, signature)
857 : and the blinded message as well as the reserve that the coin
858 : is being withdrawn from and the signature of the message
859 : authorizing the withdrawal. */
860 0 : GNUNET_PQ_make_prepare (
861 : "call_withdraw",
862 : "SELECT "
863 : " reserve_found"
864 : ",balance_ok"
865 : ",nonce_ok"
866 : ",ruuid"
867 : " FROM exchange_do_withdraw"
868 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);",
869 : 10),
870 : /* Used in #postgres_do_batch_withdraw() to
871 : update the reserve balance and check its status */
872 0 : GNUNET_PQ_make_prepare (
873 : "call_batch_withdraw",
874 : "SELECT "
875 : " reserve_found"
876 : ",balance_ok"
877 : ",ruuid"
878 : " FROM exchange_do_batch_withdraw"
879 : " ($1,$2,$3,$4,$5);",
880 : 5),
881 : /* Used in #postgres_do_batch_withdraw_insert() to store
882 : the signature of a blinded coin with the blinded coin's
883 : details. */
884 0 : GNUNET_PQ_make_prepare (
885 : "call_batch_withdraw_insert",
886 : "SELECT "
887 : " out_denom_unknown AS denom_unknown"
888 : ",out_conflict AS conflict"
889 : ",out_nonce_reuse AS nonce_reuse"
890 : " FROM exchange_do_batch_withdraw_insert"
891 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9);",
892 : 9),
893 : /* Used in #postgres_do_deposit() to execute a deposit,
894 : checking the coin's balance in the process as needed. */
895 0 : GNUNET_PQ_make_prepare (
896 : "call_deposit",
897 : "SELECT "
898 : " out_exchange_timestamp AS exchange_timestamp"
899 : ",out_balance_ok AS balance_ok"
900 : ",out_conflict AS conflicted"
901 : " FROM exchange_do_deposit"
902 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);",
903 : 17),
904 : /* used in postgres_do_purse_deposit() */
905 0 : GNUNET_PQ_make_prepare (
906 : "call_purse_deposit",
907 : "SELECT "
908 : " out_balance_ok AS balance_ok"
909 : ",out_conflict AS conflict"
910 : " FROM exchange_do_purse_deposit"
911 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9);",
912 : 9),
913 : /* Used in #postgres_update_aggregation_transient() */
914 0 : GNUNET_PQ_make_prepare (
915 : "set_purse_balance",
916 : "UPDATE purse_requests"
917 : " SET balance_val=$2"
918 : " ,balance_frac=$3"
919 : " WHERE purse_pub=$1;",
920 : 3),
921 : /* used in #postgres_expire_purse() */
922 0 : GNUNET_PQ_make_prepare (
923 : "call_expire_purse",
924 : "SELECT "
925 : " out_found AS found"
926 : " FROM exchange_do_expire_purse"
927 : " ($1,$2);",
928 : 2),
929 : /* Used in #postgres_do_melt() to melt a coin. */
930 0 : GNUNET_PQ_make_prepare (
931 : "call_melt",
932 : "SELECT "
933 : " out_balance_ok AS balance_ok"
934 : ",out_zombie_bad AS zombie_required"
935 : ",out_noreveal_index AS noreveal_index"
936 : " FROM exchange_do_melt"
937 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9);",
938 : 9),
939 : /* Used in #postgres_do_refund() to refund a deposit. */
940 0 : GNUNET_PQ_make_prepare (
941 : "call_refund",
942 : "SELECT "
943 : " out_not_found AS not_found"
944 : ",out_refund_ok AS refund_ok"
945 : ",out_gone AS gone"
946 : ",out_conflict AS conflict"
947 : " FROM exchange_do_refund"
948 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);",
949 : 13),
950 : /* Used in #postgres_do_recoup() to recoup a coin to a reserve. */
951 0 : GNUNET_PQ_make_prepare (
952 : "call_recoup",
953 : "SELECT "
954 : " out_recoup_timestamp AS recoup_timestamp"
955 : ",out_recoup_ok AS recoup_ok"
956 : ",out_internal_failure AS internal_failure"
957 : " FROM exchange_do_recoup_to_reserve"
958 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9);",
959 : 9),
960 : /* Used in #postgres_do_recoup_refresh() to recoup a coin to a zombie coin. */
961 0 : GNUNET_PQ_make_prepare (
962 : "call_recoup_refresh",
963 : "SELECT "
964 : " out_recoup_timestamp AS recoup_timestamp"
965 : ",out_recoup_ok AS recoup_ok"
966 : ",out_internal_failure AS internal_failure"
967 : " FROM exchange_do_recoup_to_coin"
968 : " ($1,$2,$3,$4,$5,$6,$7);",
969 : 7),
970 : /* Used in #postgres_get_withdraw_info() to
971 : locate the response for a /reserve/withdraw request
972 : using the hash of the blinded message. Used to
973 : make sure /reserve/withdraw requests are idempotent. */
974 0 : GNUNET_PQ_make_prepare (
975 : "get_withdraw_info",
976 : "SELECT"
977 : " denom.denom_pub_hash"
978 : ",denom_sig"
979 : ",reserve_sig"
980 : ",reserves.reserve_pub"
981 : ",execution_date"
982 : ",h_blind_ev"
983 : ",amount_with_fee_val"
984 : ",amount_with_fee_frac"
985 : ",denom.fee_withdraw_val"
986 : ",denom.fee_withdraw_frac"
987 : " FROM reserves_out"
988 : " JOIN reserves"
989 : " USING (reserve_uuid)"
990 : " JOIN denominations denom"
991 : " USING (denominations_serial)"
992 : " WHERE h_blind_ev=$1;",
993 : 1),
994 : /* Used during #postgres_get_reserve_history() to
995 : obtain all of the /reserve/withdraw operations that
996 : have been performed on a given reserve. (i.e. to
997 : demonstrate double-spending) */
998 0 : GNUNET_PQ_make_prepare (
999 : "get_reserves_out",
1000 : /*
1001 : "SELECT"
1002 : " ro.h_blind_ev"
1003 : ",denom.denom_pub_hash"
1004 : ",ro.denom_sig"
1005 : ",ro.reserve_sig"
1006 : ",ro.execution_date"
1007 : ",ro.amount_with_fee_val"
1008 : ",ro.amount_with_fee_frac"
1009 : ",denom.fee_withdraw_val"
1010 : ",denom.fee_withdraw_frac"
1011 : " FROM reserves res"
1012 : " JOIN reserves_out_by_reserve ror"
1013 : " ON (res.reserve_uuid = ror.reserve_uuid)"
1014 : " JOIN reserves_out ro"
1015 : " ON (ro.h_blind_ev = ror.h_blind_ev)"
1016 : " JOIN denominations denom"
1017 : " ON (ro.denominations_serial = denom.denominations_serial)"
1018 : " WHERE res.reserve_pub=$1;",
1019 : */
1020 : "WITH robr AS MATERIALIZED ( "
1021 : " SELECT h_blind_ev "
1022 : " FROM reserves_out_by_reserve "
1023 : " WHERE reserve_uuid= ( "
1024 : " SELECT reserve_uuid "
1025 : " FROM reserves "
1026 : " WHERE reserve_pub = $1 "
1027 : " ) "
1028 : ") SELECT "
1029 : " ro.h_blind_ev "
1030 : " ,denom.denom_pub_hash "
1031 : " ,ro.denom_sig "
1032 : " ,ro.reserve_sig "
1033 : " ,ro.execution_date "
1034 : " ,ro.amount_with_fee_val "
1035 : " ,ro.amount_with_fee_frac "
1036 : " ,denom.fee_withdraw_val "
1037 : " ,denom.fee_withdraw_frac "
1038 : "FROM robr "
1039 : "JOIN reserves_out ro "
1040 : " ON (ro.h_blind_ev = robr.h_blind_ev) "
1041 : "JOIN denominations denom "
1042 : " ON (ro.denominations_serial = denom.denominations_serial); ",
1043 : 1),
1044 : /* Used during #postgres_get_reserve_status() to
1045 : obtain all of the /reserve/withdraw operations that
1046 : have been performed on a given reserve. (i.e. to
1047 : demonstrate double-spending) */
1048 0 : GNUNET_PQ_make_prepare (
1049 : "get_reserves_out_truncated",
1050 : /*
1051 : "SELECT"
1052 : " ro.h_blind_ev"
1053 : ",denom.denom_pub_hash"
1054 : ",ro.denom_sig"
1055 : ",ro.reserve_sig"
1056 : ",ro.execution_date"
1057 : ",ro.amount_with_fee_val"
1058 : ",ro.amount_with_fee_frac"
1059 : ",denom.fee_withdraw_val"
1060 : ",denom.fee_withdraw_frac"
1061 : " FROM reserves res"
1062 : " JOIN reserves_out_by_reserve ror"
1063 : " ON (res.reserve_uuid = ror.reserve_uuid)"
1064 : " JOIN reserves_out ro"
1065 : " ON (ro.h_blind_ev = ror.h_blind_ev)"
1066 : " JOIN denominations denom"
1067 : " ON (ro.denominations_serial = denom.denominations_serial)"
1068 : " WHERE res.reserve_pub=$1"
1069 : " AND execution_date>=$2;",
1070 : */
1071 : "WITH robr AS MATERIALIZED ( "
1072 : " SELECT h_blind_ev "
1073 : " FROM reserves_out_by_reserve "
1074 : " WHERE reserve_uuid= ( "
1075 : " SELECT reserve_uuid "
1076 : " FROM reserves "
1077 : " WHERE reserve_pub = $1 "
1078 : " ) "
1079 : ") SELECT "
1080 : " ro.h_blind_ev "
1081 : " ,denom.denom_pub_hash "
1082 : " ,ro.denom_sig "
1083 : " ,ro.reserve_sig "
1084 : " ,ro.execution_date "
1085 : " ,ro.amount_with_fee_val "
1086 : " ,ro.amount_with_fee_frac "
1087 : " ,denom.fee_withdraw_val "
1088 : " ,denom.fee_withdraw_frac "
1089 : "FROM robr "
1090 : "JOIN reserves_out ro "
1091 : " ON (ro.h_blind_ev = robr.h_blind_ev) "
1092 : "JOIN denominations denom "
1093 : " ON (ro.denominations_serial = denom.denominations_serial)"
1094 : " WHERE ro.execution_date>=$2;",
1095 : 2),
1096 : /* Used in #postgres_select_withdrawals_above_serial_id() */
1097 :
1098 0 : GNUNET_PQ_make_prepare (
1099 : "get_reserve_balance",
1100 : "SELECT"
1101 : " current_balance_val"
1102 : ",current_balance_frac"
1103 : " FROM reserves"
1104 : " WHERE reserve_pub=$1;",
1105 : 1),
1106 : /* Fetch deposits with rowid '\geq' the given parameter */
1107 :
1108 0 : GNUNET_PQ_make_prepare (
1109 : "audit_get_reserves_out_incr",
1110 : "SELECT"
1111 : " h_blind_ev"
1112 : ",denom.denom_pub"
1113 : ",reserve_sig"
1114 : ",reserves.reserve_pub"
1115 : ",execution_date"
1116 : ",amount_with_fee_val"
1117 : ",amount_with_fee_frac"
1118 : ",reserve_out_serial_id"
1119 : " FROM reserves_out"
1120 : " JOIN reserves"
1121 : " USING (reserve_uuid)"
1122 : " JOIN denominations denom"
1123 : " USING (denominations_serial)"
1124 : " WHERE reserve_out_serial_id>=$1"
1125 : " ORDER BY reserve_out_serial_id ASC;",
1126 : 1),
1127 :
1128 : /* Used in #postgres_count_known_coins() */
1129 0 : GNUNET_PQ_make_prepare (
1130 : "count_known_coins",
1131 : "SELECT"
1132 : " COUNT(*) AS count"
1133 : " FROM known_coins"
1134 : " WHERE denominations_serial="
1135 : " (SELECT denominations_serial"
1136 : " FROM denominations"
1137 : " WHERE denom_pub_hash=$1);",
1138 : 1),
1139 : /* Used in #postgres_get_known_coin() to fetch
1140 : the denomination public key and signature for
1141 : a coin known to the exchange. */
1142 0 : GNUNET_PQ_make_prepare (
1143 : "get_known_coin",
1144 : "SELECT"
1145 : " denominations.denom_pub_hash"
1146 : ",age_commitment_hash"
1147 : ",denom_sig"
1148 : " FROM known_coins"
1149 : " JOIN denominations USING (denominations_serial)"
1150 : " WHERE coin_pub=$1;",
1151 : 1),
1152 : /* Used in #postgres_ensure_coin_known() */
1153 0 : GNUNET_PQ_make_prepare (
1154 : "get_known_coin_dh",
1155 : "SELECT"
1156 : " denominations.denom_pub_hash"
1157 : " FROM known_coins"
1158 : " JOIN denominations USING (denominations_serial)"
1159 : " WHERE coin_pub=$1;",
1160 : 1),
1161 : /* Used in #postgres_get_coin_denomination() to fetch
1162 : the denomination public key hash for
1163 : a coin known to the exchange. */
1164 0 : GNUNET_PQ_make_prepare (
1165 : "get_coin_denomination",
1166 : "SELECT"
1167 : " denominations.denom_pub_hash"
1168 : ",known_coin_id"
1169 : " FROM known_coins"
1170 : " JOIN denominations USING (denominations_serial)"
1171 : " WHERE coin_pub=$1"
1172 : " FOR SHARE;",
1173 : 1),
1174 : /* Used in #postgres_insert_known_coin() to store the denomination public
1175 : key and signature for a coin known to the exchange.
1176 :
1177 : See also:
1178 : https://stackoverflow.com/questions/34708509/how-to-use-returning-with-on-conflict-in-postgresql/37543015#37543015
1179 : */
1180 0 : GNUNET_PQ_make_prepare (
1181 : "insert_known_coin",
1182 : "WITH dd"
1183 : " (denominations_serial"
1184 : " ,coin_val"
1185 : " ,coin_frac"
1186 : " ) AS ("
1187 : " SELECT "
1188 : " denominations_serial"
1189 : " ,coin_val"
1190 : " ,coin_frac"
1191 : " FROM denominations"
1192 : " WHERE denom_pub_hash=$2"
1193 : " ), input_rows"
1194 : " (coin_pub) AS ("
1195 : " VALUES ($1::BYTEA)"
1196 : " ), ins AS ("
1197 : " INSERT INTO known_coins "
1198 : " (coin_pub"
1199 : " ,denominations_serial"
1200 : " ,age_commitment_hash"
1201 : " ,denom_sig"
1202 : " ,remaining_val"
1203 : " ,remaining_frac"
1204 : " ) SELECT "
1205 : " $1"
1206 : " ,denominations_serial"
1207 : " ,$3"
1208 : " ,$4"
1209 : " ,coin_val"
1210 : " ,coin_frac"
1211 : " FROM dd"
1212 : " ON CONFLICT DO NOTHING" /* CONFLICT on (coin_pub) */
1213 : " RETURNING "
1214 : " known_coin_id"
1215 : " ) "
1216 : "SELECT "
1217 : " FALSE AS existed"
1218 : " ,known_coin_id"
1219 : " ,NULL AS denom_pub_hash"
1220 : " ,NULL AS age_commitment_hash"
1221 : " FROM ins "
1222 : "UNION ALL "
1223 : "SELECT "
1224 : " TRUE AS existed"
1225 : " ,known_coin_id"
1226 : " ,denom_pub_hash"
1227 : " ,kc.age_commitment_hash"
1228 : " FROM input_rows"
1229 : " JOIN known_coins kc USING (coin_pub)"
1230 : " JOIN denominations USING (denominations_serial)"
1231 : " LIMIT 1",
1232 : 4),
1233 :
1234 : /* Used in #postgres_get_melt() to fetch
1235 : high-level information about a melt operation */
1236 0 : GNUNET_PQ_make_prepare (
1237 : "get_melt",
1238 : /* "SELECT"
1239 : " denoms.denom_pub_hash"
1240 : ",denoms.fee_refresh_val"
1241 : ",denoms.fee_refresh_frac"
1242 : ",old_coin_pub"
1243 : ",old_coin_sig"
1244 : ",kc.age_commitment_hash"
1245 : ",amount_with_fee_val"
1246 : ",amount_with_fee_frac"
1247 : ",noreveal_index"
1248 : ",melt_serial_id"
1249 : " FROM refresh_commitments"
1250 : " JOIN known_coins kc"
1251 : " ON (old_coin_pub = kc.coin_pub)"
1252 : " JOIN denominations denoms"
1253 : " ON (kc.denominations_serial = denoms.denominations_serial)"
1254 : " WHERE rc=$1;", */
1255 : "WITH rc AS MATERIALIZED ( "
1256 : " SELECT"
1257 : " * FROM refresh_commitments"
1258 : " WHERE rc=$1"
1259 : ")"
1260 : "SELECT"
1261 : " denoms.denom_pub_hash"
1262 : ",denoms.fee_refresh_val"
1263 : ",denoms.fee_refresh_frac"
1264 : ",rc.old_coin_pub"
1265 : ",rc.old_coin_sig"
1266 : ",kc.age_commitment_hash"
1267 : ",amount_with_fee_val"
1268 : ",amount_with_fee_frac"
1269 : ",noreveal_index"
1270 : ",melt_serial_id "
1271 : "FROM ("
1272 : " SELECT"
1273 : " * "
1274 : " FROM known_coins"
1275 : " WHERE coin_pub=(SELECT old_coin_pub from rc)"
1276 : ") kc "
1277 : "JOIN rc"
1278 : " ON (kc.coin_pub=rc.old_coin_pub) "
1279 : "JOIN denominations denoms"
1280 : " USING (denominations_serial);",
1281 : 1),
1282 : /* Used in #postgres_select_refreshes_above_serial_id() to fetch
1283 : refresh session with id '\geq' the given parameter */
1284 0 : GNUNET_PQ_make_prepare (
1285 : "audit_get_refresh_commitments_incr",
1286 : "SELECT"
1287 : " denom.denom_pub"
1288 : ",kc.coin_pub AS old_coin_pub"
1289 : ",kc.age_commitment_hash"
1290 : ",old_coin_sig"
1291 : ",amount_with_fee_val"
1292 : ",amount_with_fee_frac"
1293 : ",noreveal_index"
1294 : ",melt_serial_id"
1295 : ",rc"
1296 : " FROM refresh_commitments"
1297 : " JOIN known_coins kc"
1298 : " ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
1299 : " JOIN denominations denom"
1300 : " ON (kc.denominations_serial = denom.denominations_serial)"
1301 : " WHERE melt_serial_id>=$1"
1302 : " ORDER BY melt_serial_id ASC;",
1303 : 1),
1304 : /* Query the 'refresh_commitments' by coin public key,
1305 : used in #postgres_get_coin_transactions() */
1306 0 : GNUNET_PQ_make_prepare (
1307 : "get_refresh_session_by_coin",
1308 : "SELECT"
1309 : " rc"
1310 : ",old_coin_sig"
1311 : ",amount_with_fee_val"
1312 : ",amount_with_fee_frac"
1313 : ",denoms.denom_pub_hash"
1314 : ",denoms.fee_refresh_val"
1315 : ",denoms.fee_refresh_frac"
1316 : ",kc.age_commitment_hash"
1317 : ",melt_serial_id"
1318 : " FROM refresh_commitments"
1319 : " JOIN known_coins kc"
1320 : " ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
1321 : " JOIN denominations denoms"
1322 : " USING (denominations_serial)"
1323 : " WHERE old_coin_pub=$1;",
1324 : 1),
1325 : /* Find purse deposits by coin,
1326 : used in #postgres_get_coin_transactions() */
1327 0 : GNUNET_PQ_make_prepare (
1328 : "get_purse_deposit_by_coin_pub",
1329 : "SELECT"
1330 : " partner_base_url"
1331 : ",pd.amount_with_fee_val"
1332 : ",pd.amount_with_fee_frac"
1333 : ",denoms.fee_deposit_val"
1334 : ",denoms.fee_deposit_frac"
1335 : ",pd.purse_pub"
1336 : ",kc.age_commitment_hash"
1337 : ",pd.coin_sig"
1338 : ",pd.purse_deposit_serial_id"
1339 : ",pr.refunded"
1340 : " FROM purse_deposits pd"
1341 : " LEFT JOIN partners"
1342 : " USING (partner_serial_id)"
1343 : " JOIN purse_requests pr"
1344 : " USING (purse_pub)"
1345 : " JOIN known_coins kc"
1346 : " ON (pd.coin_pub = kc.coin_pub)"
1347 : " JOIN denominations denoms"
1348 : " USING (denominations_serial)"
1349 : // FIXME: use to-be-created materialized index
1350 : // on coin_pub (query crosses partitions!)
1351 : " WHERE pd.coin_pub=$1;",
1352 : 1),
1353 : /* Store information about the desired denominations for a
1354 : refresh operation, used in #postgres_insert_refresh_reveal() */
1355 0 : GNUNET_PQ_make_prepare (
1356 : "insert_refresh_revealed_coin",
1357 : "INSERT INTO refresh_revealed_coins "
1358 : "(melt_serial_id "
1359 : ",freshcoin_index "
1360 : ",link_sig "
1361 : ",denominations_serial "
1362 : ",coin_ev"
1363 : ",ewv"
1364 : ",h_coin_ev"
1365 : ",ev_sig"
1366 : ") SELECT $1, $2, $3, "
1367 : " denominations_serial, $5, $6, $7, $8"
1368 : " FROM denominations"
1369 : " WHERE denom_pub_hash=$4"
1370 : " ON CONFLICT DO NOTHING;",
1371 : 8),
1372 : /* Obtain information about the coins created in a refresh
1373 : operation, used in #postgres_get_refresh_reveal() */
1374 0 : GNUNET_PQ_make_prepare (
1375 : "get_refresh_revealed_coins",
1376 : "SELECT "
1377 : " rrc.freshcoin_index"
1378 : ",denom.denom_pub_hash"
1379 : ",rrc.h_coin_ev"
1380 : ",rrc.link_sig"
1381 : ",rrc.coin_ev"
1382 : ",rrc.ewv"
1383 : ",rrc.ev_sig"
1384 : " FROM refresh_commitments"
1385 : " JOIN refresh_revealed_coins rrc"
1386 : " USING (melt_serial_id)"
1387 : " JOIN denominations denom "
1388 : " USING (denominations_serial)"
1389 : " WHERE rc=$1;",
1390 : 1),
1391 :
1392 : /* Used in #postgres_insert_refresh_reveal() to store the transfer
1393 : keys we learned */
1394 0 : GNUNET_PQ_make_prepare (
1395 : "insert_refresh_transfer_keys",
1396 : "INSERT INTO refresh_transfer_keys "
1397 : "(melt_serial_id"
1398 : ",transfer_pub"
1399 : ",transfer_privs"
1400 : ") VALUES ($1, $2, $3)"
1401 : " ON CONFLICT DO NOTHING;",
1402 : 3),
1403 : /* Used in #postgres_insert_refund() to store refund information */
1404 0 : GNUNET_PQ_make_prepare (
1405 : "insert_refund",
1406 : "INSERT INTO refunds "
1407 : "(coin_pub "
1408 : ",deposit_serial_id"
1409 : ",merchant_sig "
1410 : ",rtransaction_id "
1411 : ",amount_with_fee_val "
1412 : ",amount_with_fee_frac "
1413 : ") SELECT $1, deposit_serial_id, $3, $5, $6, $7"
1414 : " FROM deposits"
1415 : " WHERE coin_pub=$1"
1416 : " AND h_contract_terms=$4"
1417 : " AND merchant_pub=$2",
1418 : 7),
1419 : /* Query the 'refunds' by coin public key */
1420 0 : GNUNET_PQ_make_prepare (
1421 : "get_refunds_by_coin",
1422 : "SELECT"
1423 : " dep.merchant_pub"
1424 : ",ref.merchant_sig"
1425 : ",dep.h_contract_terms"
1426 : ",ref.rtransaction_id"
1427 : ",ref.amount_with_fee_val"
1428 : ",ref.amount_with_fee_frac"
1429 : ",denom.fee_refund_val "
1430 : ",denom.fee_refund_frac "
1431 : ",ref.refund_serial_id"
1432 : " FROM refunds ref"
1433 : " JOIN deposits dep"
1434 : " ON (ref.coin_pub = dep.coin_pub AND ref.deposit_serial_id = dep.deposit_serial_id)"
1435 : " JOIN known_coins kc"
1436 : " ON (ref.coin_pub = kc.coin_pub)"
1437 : " JOIN denominations denom"
1438 : " USING (denominations_serial)"
1439 : " WHERE ref.coin_pub=$1;",
1440 : 1),
1441 : /* Query the 'refunds' by coin public key, merchant_pub and contract hash */
1442 0 : GNUNET_PQ_make_prepare (
1443 : "get_refunds_by_coin_and_contract",
1444 : "SELECT"
1445 : " ref.amount_with_fee_val"
1446 : ",ref.amount_with_fee_frac"
1447 : " FROM refunds ref"
1448 : " JOIN deposits dep"
1449 : " USING (coin_pub,deposit_serial_id)"
1450 : " WHERE ref.coin_pub=$1"
1451 : " AND dep.merchant_pub=$2"
1452 : " AND dep.h_contract_terms=$3;",
1453 : 3),
1454 : /* Fetch refunds with rowid '\geq' the given parameter */
1455 0 : GNUNET_PQ_make_prepare (
1456 : "audit_get_refunds_incr",
1457 : "SELECT"
1458 : " dep.merchant_pub"
1459 : ",ref.merchant_sig"
1460 : ",dep.h_contract_terms"
1461 : ",ref.rtransaction_id"
1462 : ",denom.denom_pub"
1463 : ",kc.coin_pub"
1464 : ",ref.amount_with_fee_val"
1465 : ",ref.amount_with_fee_frac"
1466 : ",ref.refund_serial_id"
1467 : " FROM refunds ref"
1468 : " JOIN deposits dep"
1469 : " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)"
1470 : " JOIN known_coins kc"
1471 : " ON (dep.coin_pub=kc.coin_pub)"
1472 : " JOIN denominations denom"
1473 : " ON (kc.denominations_serial=denom.denominations_serial)"
1474 : " WHERE ref.refund_serial_id>=$1"
1475 : " ORDER BY ref.refund_serial_id ASC;",
1476 : 1),
1477 0 : GNUNET_PQ_make_prepare (
1478 : "test_refund_full",
1479 : "SELECT"
1480 : " CAST(SUM(CAST(ref.amount_with_fee_frac AS INT8)) AS INT8) AS s_f"
1481 : ",CAST(SUM(ref.amount_with_fee_val) AS INT8) AS s_v"
1482 : ",dep.amount_with_fee_val"
1483 : ",dep.amount_with_fee_frac"
1484 : " FROM refunds ref"
1485 : " JOIN deposits dep"
1486 : " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)"
1487 : " WHERE ref.refund_serial_id=$1"
1488 : " GROUP BY (dep.amount_with_fee_val, dep.amount_with_fee_frac);",
1489 : 1),
1490 :
1491 : /* Store information about a /deposit the exchange is to execute.
1492 : Used in #postgres_insert_deposit(). Only used in test cases. */
1493 0 : GNUNET_PQ_make_prepare (
1494 : "insert_deposit",
1495 : "INSERT INTO deposits "
1496 : "(known_coin_id"
1497 : ",coin_pub"
1498 : ",amount_with_fee_val"
1499 : ",amount_with_fee_frac"
1500 : ",wallet_timestamp"
1501 : ",refund_deadline"
1502 : ",wire_deadline"
1503 : ",merchant_pub"
1504 : ",h_contract_terms"
1505 : ",wire_salt"
1506 : ",wire_target_h_payto"
1507 : ",coin_sig"
1508 : ",exchange_timestamp"
1509 : ",shard"
1510 : ") SELECT known_coin_id, $1, $2, $3, $4, $5, $6, "
1511 : " $7, $8, $9, $10, $11, $12, $13"
1512 : " FROM known_coins"
1513 : " WHERE coin_pub=$1"
1514 : " ON CONFLICT DO NOTHING;",
1515 : 13),
1516 : /* Fetch an existing deposit request, used to ensure idempotency
1517 : during /deposit processing. Used in #postgres_have_deposit(). */
1518 0 : GNUNET_PQ_make_prepare (
1519 : "get_deposit",
1520 : "SELECT"
1521 : " dep.amount_with_fee_val"
1522 : ",dep.amount_with_fee_frac"
1523 : ",denominations.fee_deposit_val"
1524 : ",denominations.fee_deposit_frac"
1525 : ",dep.wallet_timestamp"
1526 : ",dep.exchange_timestamp"
1527 : ",dep.refund_deadline"
1528 : ",dep.wire_deadline"
1529 : ",dep.h_contract_terms"
1530 : ",dep.wire_salt"
1531 : ",wt.payto_uri AS receiver_wire_account"
1532 : " FROM deposits dep"
1533 : " JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)"
1534 : " JOIN denominations USING (denominations_serial)"
1535 : " JOIN wire_targets wt USING (wire_target_h_payto)"
1536 : " WHERE dep.coin_pub=$1"
1537 : " AND dep.merchant_pub=$3"
1538 : " AND dep.h_contract_terms=$2;",
1539 : 3),
1540 : /* Fetch deposits with rowid '\geq' the given parameter */
1541 0 : GNUNET_PQ_make_prepare (
1542 : "audit_get_deposits_incr",
1543 : "SELECT"
1544 : " amount_with_fee_val"
1545 : ",amount_with_fee_frac"
1546 : ",wallet_timestamp"
1547 : ",exchange_timestamp"
1548 : ",merchant_pub"
1549 : ",denom.denom_pub"
1550 : ",kc.coin_pub"
1551 : ",kc.age_commitment_hash"
1552 : ",coin_sig"
1553 : ",refund_deadline"
1554 : ",wire_deadline"
1555 : ",h_contract_terms"
1556 : ",wire_salt"
1557 : ",payto_uri AS receiver_wire_account"
1558 : ",done"
1559 : ",deposit_serial_id"
1560 : " FROM deposits"
1561 : " JOIN wire_targets USING (wire_target_h_payto)"
1562 : " JOIN known_coins kc USING (coin_pub)"
1563 : " JOIN denominations denom USING (denominations_serial)"
1564 : " WHERE ("
1565 : " (deposit_serial_id>=$1)"
1566 : " )"
1567 : " ORDER BY deposit_serial_id ASC;",
1568 : 1),
1569 : /* Fetch purse deposits with rowid '\geq' the given parameter */
1570 0 : GNUNET_PQ_make_prepare (
1571 : "audit_get_purse_deposits_incr",
1572 : "SELECT"
1573 : " pd.amount_with_fee_val"
1574 : ",pd.amount_with_fee_frac"
1575 : ",pr.amount_with_fee_val AS total_val"
1576 : ",pr.amount_with_fee_frac AS total_frac"
1577 : ",pr.balance_val"
1578 : ",pr.balance_frac"
1579 : ",pr.flags"
1580 : ",pd.purse_pub"
1581 : ",pd.coin_sig"
1582 : ",partner_base_url"
1583 : ",denom.denom_pub"
1584 : ",pm.reserve_pub"
1585 : ",kc.coin_pub"
1586 : ",kc.age_commitment_hash"
1587 : ",pd.purse_deposit_serial_id"
1588 : " FROM purse_deposits pd"
1589 : " LEFT JOIN partners USING (partner_serial_id)"
1590 : " LEFT JOIN purse_merges pm USING (purse_pub)"
1591 : " JOIN purse_requests pr USING (purse_pub)"
1592 : " JOIN known_coins kc USING (coin_pub)"
1593 : " JOIN denominations denom USING (denominations_serial)"
1594 : " WHERE ("
1595 : " (purse_deposit_serial_id>=$1)"
1596 : " )"
1597 : " ORDER BY purse_deposit_serial_id ASC;",
1598 : 1),
1599 :
1600 0 : GNUNET_PQ_make_prepare (
1601 : "audit_get_account_merge_incr",
1602 : "SELECT"
1603 : " am.account_merge_request_serial_id"
1604 : ",am.reserve_pub"
1605 : ",am.purse_pub"
1606 : ",pr.h_contract_terms"
1607 : ",pr.purse_expiration"
1608 : ",pr.amount_with_fee_val"
1609 : ",pr.amount_with_fee_frac"
1610 : ",pr.age_limit"
1611 : ",pr.flags"
1612 : ",pr.purse_fee_val"
1613 : ",pr.purse_fee_frac"
1614 : ",pm.merge_timestamp"
1615 : ",am.reserve_sig"
1616 : " FROM account_merges am"
1617 : " JOIN purse_requests pr USING (purse_pub)"
1618 : " JOIN purse_merges pm USING (purse_pub)"
1619 : " WHERE ("
1620 : " (account_merge_request_serial_id>=$1)"
1621 : " )"
1622 : " ORDER BY account_merge_request_serial_id ASC;",
1623 : 1),
1624 :
1625 0 : GNUNET_PQ_make_prepare (
1626 : "audit_get_purse_merge_incr",
1627 : "SELECT"
1628 : " pm.purse_merge_request_serial_id"
1629 : ",partner_base_url"
1630 : ",pr.amount_with_fee_val"
1631 : ",pr.amount_with_fee_frac"
1632 : ",pr.balance_val"
1633 : ",pr.balance_frac"
1634 : ",pr.flags"
1635 : ",pr.merge_pub"
1636 : ",pm.reserve_pub"
1637 : ",pm.merge_sig"
1638 : ",pm.purse_pub"
1639 : ",pm.merge_timestamp"
1640 : " FROM purse_merges pm"
1641 : " JOIN purse_requests pr USING (purse_pub)"
1642 : " LEFT JOIN partners USING (partner_serial_id)"
1643 : " WHERE ("
1644 : " (purse_merge_request_serial_id>=$1)"
1645 : " )"
1646 : " ORDER BY purse_merge_request_serial_id ASC;",
1647 : 1),
1648 :
1649 0 : GNUNET_PQ_make_prepare (
1650 : "audit_get_history_requests_incr",
1651 : "SELECT"
1652 : " history_request_serial_id"
1653 : ",history_fee_val"
1654 : ",history_fee_frac"
1655 : ",request_timestamp"
1656 : ",reserve_pub"
1657 : ",reserve_sig"
1658 : " FROM history_requests"
1659 : " WHERE ("
1660 : " (history_request_serial_id>=$1)"
1661 : " )"
1662 : " ORDER BY history_request_serial_id ASC;",
1663 : 1),
1664 :
1665 :
1666 0 : GNUNET_PQ_make_prepare (
1667 : "audit_get_purse_deposits_by_purse",
1668 : "SELECT"
1669 : " pd.purse_deposit_serial_id"
1670 : ",pd.amount_with_fee_val"
1671 : ",pd.amount_with_fee_frac"
1672 : ",pd.coin_pub"
1673 : ",denom.denom_pub"
1674 : " FROM purse_deposits pd"
1675 : " JOIN known_coins kc USING (coin_pub)"
1676 : " JOIN denominations denom USING (denominations_serial)"
1677 : " WHERE purse_pub=$1;",
1678 : 1),
1679 0 : GNUNET_PQ_make_prepare (
1680 : "audit_get_purse_refunds_incr",
1681 : "SELECT"
1682 : " purse_pub"
1683 : ",purse_refunds_serial_id"
1684 : " FROM purse_refunds"
1685 : " WHERE ("
1686 : " (purse_refunds_serial_id>=$1)"
1687 : " )"
1688 : " ORDER BY purse_refunds_serial_id ASC;",
1689 : 1),
1690 : /* Fetch an existing deposit request.
1691 : Used in #postgres_lookup_transfer_by_deposit(). */
1692 0 : GNUNET_PQ_make_prepare (
1693 : "get_deposit_without_wtid",
1694 : "SELECT"
1695 : " agt.legitimization_requirement_serial_id"
1696 : ",dep.wire_salt"
1697 : ",wt.payto_uri"
1698 : ",dep.amount_with_fee_val"
1699 : ",dep.amount_with_fee_frac"
1700 : ",denom.fee_deposit_val"
1701 : ",denom.fee_deposit_frac"
1702 : ",dep.wire_deadline"
1703 : " FROM deposits dep"
1704 : " JOIN wire_targets wt"
1705 : " USING (wire_target_h_payto)"
1706 : " JOIN known_coins kc"
1707 : " ON (kc.coin_pub = dep.coin_pub)"
1708 : " JOIN denominations denom"
1709 : " USING (denominations_serial)"
1710 : " LEFT JOIN aggregation_transient agt "
1711 : " ON ( (dep.wire_target_h_payto = agt.wire_target_h_payto) AND"
1712 : " (dep.merchant_pub = agt.merchant_pub) )"
1713 : " WHERE dep.coin_pub=$1"
1714 : " AND dep.merchant_pub=$3"
1715 : " AND dep.h_contract_terms=$2"
1716 : " LIMIT 1;",
1717 : 3),
1718 : /* Used in #postgres_get_ready_deposit() */
1719 0 : GNUNET_PQ_make_prepare (
1720 : "deposits_get_ready",
1721 : "SELECT"
1722 : " payto_uri"
1723 : ",merchant_pub"
1724 : " FROM deposits_by_ready dbr"
1725 : " JOIN deposits dep"
1726 : " ON (dbr.coin_pub = dep.coin_pub AND"
1727 : " dbr.deposit_serial_id = dep.deposit_serial_id)"
1728 : " JOIN wire_targets wt"
1729 : " USING (wire_target_h_payto)"
1730 : " WHERE dbr.wire_deadline<=$1"
1731 : " AND dbr.shard >= $2"
1732 : " AND dbr.shard <= $3"
1733 : " ORDER BY "
1734 : " dbr.wire_deadline ASC"
1735 : " ,dbr.shard ASC"
1736 : " LIMIT 1;",
1737 : 3),
1738 : /* Used in #postgres_aggregate() */
1739 0 : GNUNET_PQ_make_prepare (
1740 : "aggregate",
1741 : "WITH rdy AS (" /* find deposits ready by merchant */
1742 : " SELECT"
1743 : " coin_pub"
1744 : " FROM deposits_for_matching"
1745 : " WHERE refund_deadline<$1" /* filter by shard, only actually executable deposits */
1746 : " AND merchant_pub=$2" /* filter by target merchant */
1747 : " ORDER BY refund_deadline ASC" /* ordering is not critical */
1748 : " LIMIT "
1749 : TALER_QUOTE (TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT) /* limits transaction size */
1750 : " )"
1751 : " ,dep AS (" /* restrict to our merchant and account and mark as done */
1752 : " UPDATE deposits"
1753 : " SET done=TRUE"
1754 : " WHERE coin_pub IN (SELECT coin_pub FROM rdy)"
1755 : " AND merchant_pub=$2" /* theoretically, same coin could be spent at another merchant */
1756 : " AND wire_target_h_payto=$3" /* merchant could have a 2nd bank account */
1757 : " AND done=FALSE" /* theoretically, same coin could be spend at the same merchant a 2nd time */
1758 : " RETURNING"
1759 : " deposit_serial_id"
1760 : " ,coin_pub"
1761 : " ,amount_with_fee_val AS amount_val"
1762 : " ,amount_with_fee_frac AS amount_frac)"
1763 : " ,ref AS (" /* find applicable refunds -- NOTE: may do a full join on the master, maybe find a left-join way to integrate with query above to push it to the shards? */
1764 : " SELECT"
1765 : " amount_with_fee_val AS refund_val"
1766 : " ,amount_with_fee_frac AS refund_frac"
1767 : " ,coin_pub"
1768 : " ,deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
1769 : " FROM refunds"
1770 : " WHERE coin_pub IN (SELECT coin_pub FROM dep)"
1771 : " AND deposit_serial_id IN (SELECT deposit_serial_id FROM dep))"
1772 : " ,ref_by_coin AS (" /* total up refunds by coin */
1773 : " SELECT"
1774 : " SUM(refund_val) AS sum_refund_val"
1775 : " ,SUM(refund_frac) AS sum_refund_frac"
1776 : " ,coin_pub"
1777 : " ,deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
1778 : " FROM ref"
1779 : " GROUP BY coin_pub, deposit_serial_id)"
1780 : " ,norm_ref_by_coin AS (" /* normalize */
1781 : " SELECT"
1782 : " sum_refund_val + sum_refund_frac / 100000000 AS norm_refund_val"
1783 : " ,sum_refund_frac % 100000000 AS norm_refund_frac"
1784 : " ,coin_pub"
1785 : " ,deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
1786 : " FROM ref_by_coin)"
1787 : " ,fully_refunded_coins AS (" /* find applicable refunds -- NOTE: may do a full join on the master, maybe find a left-join way to integrate with query above to push it to the shards? */
1788 : " SELECT"
1789 : " dep.coin_pub"
1790 : " FROM norm_ref_by_coin norm"
1791 : " JOIN dep"
1792 : " ON (norm.coin_pub = dep.coin_pub"
1793 : " AND norm.deposit_serial_id = dep.deposit_Serial_id"
1794 : " AND norm.norm_refund_val = dep.amount_val"
1795 : " AND norm.norm_refund_frac = dep.amount_frac))"
1796 : " ,fees AS (" /* find deposit fees for not fully refunded deposits */
1797 : " SELECT"
1798 : " denom.fee_deposit_val AS fee_val"
1799 : " ,denom.fee_deposit_frac AS fee_frac"
1800 : " ,cs.deposit_serial_id" /* ensures we get the fee for each coin, not once per denomination */
1801 : " FROM dep cs"
1802 : " JOIN known_coins kc" /* NOTE: may do a full join on the master, maybe find a left-join way to integrate with query above to push it to the shards? */
1803 : " USING (coin_pub)"
1804 : " JOIN denominations denom"
1805 : " USING (denominations_serial)"
1806 : " WHERE coin_pub NOT IN (SELECT coin_pub FROM fully_refunded_coins))"
1807 : " ,dummy AS (" /* add deposits to aggregation_tracking */
1808 : " INSERT INTO aggregation_tracking"
1809 : " (deposit_serial_id"
1810 : " ,wtid_raw)"
1811 : " SELECT deposit_serial_id,$4"
1812 : " FROM dep)"
1813 : "SELECT" /* calculate totals (deposits, refunds and fees) */
1814 : " CAST(COALESCE(SUM(dep.amount_val),0) AS INT8) AS sum_deposit_value" /* cast needed, otherwise we get NUMBER */
1815 : " ,COALESCE(SUM(dep.amount_frac),0) AS sum_deposit_fraction" /* SUM over INT returns INT8 */
1816 : " ,CAST(COALESCE(SUM(ref.refund_val),0) AS INT8) AS sum_refund_value"
1817 : " ,COALESCE(SUM(ref.refund_frac),0) AS sum_refund_fraction"
1818 : " ,CAST(COALESCE(SUM(fees.fee_val),0) AS INT8) AS sum_fee_value"
1819 : " ,COALESCE(SUM(fees.fee_frac),0) AS sum_fee_fraction"
1820 : " FROM dep "
1821 : " FULL OUTER JOIN ref ON (FALSE)" /* We just want all sums */
1822 : " FULL OUTER JOIN fees ON (FALSE);",
1823 : 4),
1824 :
1825 :
1826 : /* Used in #postgres_create_aggregation_transient() */
1827 0 : GNUNET_PQ_make_prepare (
1828 : "create_aggregation_transient",
1829 : "INSERT INTO aggregation_transient"
1830 : " (amount_val"
1831 : " ,amount_frac"
1832 : " ,merchant_pub"
1833 : " ,wire_target_h_payto"
1834 : " ,legitimization_requirement_serial_id"
1835 : " ,exchange_account_section"
1836 : " ,wtid_raw)"
1837 : " VALUES ($1, $2, $3, $4, $5, $6, $7);",
1838 : 7),
1839 : /* Used in #postgres_select_aggregation_transient() */
1840 0 : GNUNET_PQ_make_prepare (
1841 : "select_aggregation_transient",
1842 : "SELECT"
1843 : " amount_val"
1844 : " ,amount_frac"
1845 : " ,wtid_raw"
1846 : " FROM aggregation_transient"
1847 : " WHERE wire_target_h_payto=$1"
1848 : " AND merchant_pub=$2"
1849 : " AND exchange_account_section=$3;",
1850 : 3),
1851 : /* Used in #postgres_find_aggregation_transient() */
1852 0 : GNUNET_PQ_make_prepare (
1853 : "find_transient_aggregations",
1854 : "SELECT"
1855 : " amount_val"
1856 : " ,amount_frac"
1857 : " ,wtid_raw"
1858 : " ,merchant_pub"
1859 : " ,payto_uri"
1860 : " FROM aggregation_transient atr"
1861 : " JOIN wire_targets wt USING (wire_target_h_payto)"
1862 : " WHERE atr.wire_target_h_payto=$1;",
1863 : 1),
1864 : /* Used in #postgres_update_aggregation_transient() */
1865 0 : GNUNET_PQ_make_prepare (
1866 : "update_aggregation_transient",
1867 : "UPDATE aggregation_transient"
1868 : " SET amount_val=$1"
1869 : " ,amount_frac=$2"
1870 : " ,legitimization_requirement_serial_id=$5"
1871 : " WHERE wire_target_h_payto=$3"
1872 : " AND wtid_raw=$4",
1873 : 5),
1874 : /* Used in #postgres_delete_aggregation_transient() */
1875 0 : GNUNET_PQ_make_prepare (
1876 : "delete_aggregation_transient",
1877 : "DELETE FROM aggregation_transient"
1878 : " WHERE wire_target_h_payto=$1"
1879 : " AND wtid_raw=$2",
1880 : 2),
1881 :
1882 : /* Used in #postgres_get_coin_transactions() to obtain information
1883 : about how a coin has been spend with /deposit requests. */
1884 0 : GNUNET_PQ_make_prepare (
1885 : "get_deposit_with_coin_pub",
1886 : "SELECT"
1887 : " dep.amount_with_fee_val"
1888 : ",dep.amount_with_fee_frac"
1889 : ",denoms.fee_deposit_val"
1890 : ",denoms.fee_deposit_frac"
1891 : ",denoms.denom_pub_hash"
1892 : ",kc.age_commitment_hash"
1893 : ",dep.wallet_timestamp"
1894 : ",dep.refund_deadline"
1895 : ",dep.wire_deadline"
1896 : ",dep.merchant_pub"
1897 : ",dep.h_contract_terms"
1898 : ",dep.wire_salt"
1899 : ",wt.payto_uri"
1900 : ",dep.coin_sig"
1901 : ",dep.deposit_serial_id"
1902 : ",dep.done"
1903 : " FROM deposits dep"
1904 : " JOIN wire_targets wt"
1905 : " USING (wire_target_h_payto)"
1906 : " JOIN known_coins kc"
1907 : " ON (kc.coin_pub = dep.coin_pub)"
1908 : " JOIN denominations denoms"
1909 : " USING (denominations_serial)"
1910 : " WHERE dep.coin_pub=$1;",
1911 : 1),
1912 :
1913 : /* Used in #postgres_get_link_data(). */
1914 0 : GNUNET_PQ_make_prepare (
1915 : "get_link",
1916 : "SELECT "
1917 : " tp.transfer_pub"
1918 : ",denoms.denom_pub"
1919 : ",rrc.ev_sig"
1920 : ",rrc.ewv"
1921 : ",rrc.link_sig"
1922 : ",rrc.freshcoin_index"
1923 : ",rrc.coin_ev"
1924 : " FROM refresh_commitments"
1925 : " JOIN refresh_revealed_coins rrc"
1926 : " USING (melt_serial_id)"
1927 : " JOIN refresh_transfer_keys tp"
1928 : " USING (melt_serial_id)"
1929 : " JOIN denominations denoms"
1930 : " ON (rrc.denominations_serial = denoms.denominations_serial)"
1931 : " WHERE old_coin_pub=$1"
1932 : " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC",
1933 : 1),
1934 : /* Used in #postgres_lookup_wire_transfer */
1935 0 : GNUNET_PQ_make_prepare (
1936 : "lookup_transactions",
1937 : "SELECT"
1938 : " aggregation_serial_id"
1939 : ",deposits.h_contract_terms"
1940 : ",payto_uri"
1941 : ",wire_targets.wire_target_h_payto"
1942 : ",kc.coin_pub"
1943 : ",deposits.merchant_pub"
1944 : ",wire_out.execution_date"
1945 : ",deposits.amount_with_fee_val"
1946 : ",deposits.amount_with_fee_frac"
1947 : ",denom.fee_deposit_val"
1948 : ",denom.fee_deposit_frac"
1949 : ",denom.denom_pub"
1950 : " FROM aggregation_tracking"
1951 : " JOIN deposits"
1952 : " USING (deposit_serial_id)"
1953 : " JOIN wire_targets"
1954 : " USING (wire_target_h_payto)"
1955 : " JOIN known_coins kc"
1956 : " USING (coin_pub)"
1957 : " JOIN denominations denom"
1958 : " USING (denominations_serial)"
1959 : " JOIN wire_out"
1960 : " USING (wtid_raw)"
1961 : " WHERE wtid_raw=$1;",
1962 : 1),
1963 : /* Used in #postgres_lookup_transfer_by_deposit */
1964 0 : GNUNET_PQ_make_prepare (
1965 : "lookup_deposit_wtid",
1966 : "SELECT"
1967 : " aggregation_tracking.wtid_raw"
1968 : ",wire_out.execution_date"
1969 : ",dep.amount_with_fee_val"
1970 : ",dep.amount_with_fee_frac"
1971 : ",dep.wire_salt"
1972 : ",wt.payto_uri"
1973 : ",denom.fee_deposit_val"
1974 : ",denom.fee_deposit_frac"
1975 : " FROM deposits dep"
1976 : " JOIN wire_targets wt"
1977 : " USING (wire_target_h_payto)"
1978 : " JOIN aggregation_tracking"
1979 : " USING (deposit_serial_id)"
1980 : " JOIN known_coins kc"
1981 : " ON (kc.coin_pub = dep.coin_pub)"
1982 : " JOIN denominations denom"
1983 : " USING (denominations_serial)"
1984 : " JOIN wire_out"
1985 : " USING (wtid_raw)"
1986 : " WHERE dep.coin_pub=$1"
1987 : " AND dep.merchant_pub=$3"
1988 : " AND dep.h_contract_terms=$2",
1989 : 3),
1990 : /* Used in #postgres_insert_aggregation_tracking */
1991 0 : GNUNET_PQ_make_prepare (
1992 : "insert_aggregation_tracking",
1993 : "INSERT INTO aggregation_tracking "
1994 : "(deposit_serial_id"
1995 : ",wtid_raw"
1996 : ") VALUES "
1997 : "($1, $2);",
1998 : 2),
1999 : /* Used in #postgres_get_wire_fee() */
2000 0 : GNUNET_PQ_make_prepare (
2001 : "get_wire_fee",
2002 : "SELECT "
2003 : " start_date"
2004 : ",end_date"
2005 : ",wire_fee_val"
2006 : ",wire_fee_frac"
2007 : ",closing_fee_val"
2008 : ",closing_fee_frac"
2009 : ",wad_fee_val"
2010 : ",wad_fee_frac"
2011 : ",master_sig"
2012 : " FROM wire_fee"
2013 : " WHERE wire_method=$1"
2014 : " AND start_date <= $2"
2015 : " AND end_date > $2;",
2016 : 2),
2017 : /* Used in #postgres_get_global_fee() */
2018 0 : GNUNET_PQ_make_prepare (
2019 : "get_global_fee",
2020 : "SELECT "
2021 : " start_date"
2022 : ",end_date"
2023 : ",history_fee_val"
2024 : ",history_fee_frac"
2025 : ",kyc_fee_val"
2026 : ",kyc_fee_frac"
2027 : ",account_fee_val"
2028 : ",account_fee_frac"
2029 : ",purse_fee_val"
2030 : ",purse_fee_frac"
2031 : ",purse_timeout"
2032 : ",kyc_timeout"
2033 : ",history_expiration"
2034 : ",purse_account_limit"
2035 : ",master_sig"
2036 : " FROM global_fee"
2037 : " WHERE start_date <= $1"
2038 : " AND end_date > $1;",
2039 : 1),
2040 : /* Used in #postgres_get_global_fees() */
2041 0 : GNUNET_PQ_make_prepare (
2042 : "get_global_fees",
2043 : "SELECT "
2044 : " start_date"
2045 : ",end_date"
2046 : ",history_fee_val"
2047 : ",history_fee_frac"
2048 : ",kyc_fee_val"
2049 : ",kyc_fee_frac"
2050 : ",account_fee_val"
2051 : ",account_fee_frac"
2052 : ",purse_fee_val"
2053 : ",purse_fee_frac"
2054 : ",purse_timeout"
2055 : ",kyc_timeout"
2056 : ",history_expiration"
2057 : ",purse_account_limit"
2058 : ",master_sig"
2059 : " FROM global_fee"
2060 : " WHERE start_date >= $1",
2061 : 1),
2062 : /* Used in #postgres_insert_wire_fee */
2063 0 : GNUNET_PQ_make_prepare (
2064 : "insert_wire_fee",
2065 : "INSERT INTO wire_fee "
2066 : "(wire_method"
2067 : ",start_date"
2068 : ",end_date"
2069 : ",wire_fee_val"
2070 : ",wire_fee_frac"
2071 : ",closing_fee_val"
2072 : ",closing_fee_frac"
2073 : ",wad_fee_val"
2074 : ",wad_fee_frac"
2075 : ",master_sig"
2076 : ") VALUES "
2077 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);",
2078 : 10),
2079 : /* Used in #postgres_insert_global_fee */
2080 0 : GNUNET_PQ_make_prepare (
2081 : "insert_global_fee",
2082 : "INSERT INTO global_fee "
2083 : "(start_date"
2084 : ",end_date"
2085 : ",history_fee_val"
2086 : ",history_fee_frac"
2087 : ",kyc_fee_val"
2088 : ",kyc_fee_frac"
2089 : ",account_fee_val"
2090 : ",account_fee_frac"
2091 : ",purse_fee_val"
2092 : ",purse_fee_frac"
2093 : ",purse_timeout"
2094 : ",kyc_timeout"
2095 : ",history_expiration"
2096 : ",purse_account_limit"
2097 : ",master_sig"
2098 : ") VALUES "
2099 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);",
2100 : 15),
2101 : /* Used in #postgres_store_wire_transfer_out */
2102 0 : GNUNET_PQ_make_prepare (
2103 : "insert_wire_out",
2104 : "INSERT INTO wire_out "
2105 : "(execution_date"
2106 : ",wtid_raw"
2107 : ",wire_target_h_payto"
2108 : ",exchange_account_section"
2109 : ",amount_val"
2110 : ",amount_frac"
2111 : ") VALUES "
2112 : "($1, $2, $3, $4, $5, $6);",
2113 : 6),
2114 0 : GNUNET_PQ_make_prepare (
2115 : "insert_into_table_wire_out",
2116 : "INSERT INTO wire_out"
2117 : "(wireout_uuid"
2118 : ",execution_date"
2119 : ",wtid_raw"
2120 : ",wire_target_h_payto"
2121 : ",exchange_account_section"
2122 : ",amount_val"
2123 : ",amount_frac"
2124 : ") VALUES "
2125 : "($1, $2, $3, $4, $5, $6, $7);",
2126 : 7),
2127 : /* Used in #postgres_wire_prepare_data_insert() to store
2128 : wire transfer information before actually committing it with the bank */
2129 0 : GNUNET_PQ_make_prepare (
2130 : "wire_prepare_data_insert",
2131 : "INSERT INTO prewire "
2132 : "(wire_method"
2133 : ",buf"
2134 : ") VALUES "
2135 : "($1, $2);",
2136 : 2),
2137 : /* Used in #postgres_wire_prepare_data_mark_finished() */
2138 0 : GNUNET_PQ_make_prepare (
2139 : "wire_prepare_data_mark_done",
2140 : "UPDATE prewire"
2141 : " SET finished=TRUE"
2142 : " WHERE prewire_uuid=$1;",
2143 : 1),
2144 : /* Used in #postgres_wire_prepare_data_mark_failed() */
2145 0 : GNUNET_PQ_make_prepare (
2146 : "wire_prepare_data_mark_failed",
2147 : "UPDATE prewire"
2148 : " SET failed=TRUE"
2149 : " WHERE prewire_uuid=$1;",
2150 : 1),
2151 : /* Used in #postgres_wire_prepare_data_get() */
2152 0 : GNUNET_PQ_make_prepare (
2153 : "wire_prepare_data_get",
2154 : "SELECT"
2155 : " prewire_uuid"
2156 : ",wire_method"
2157 : ",buf"
2158 : " FROM prewire"
2159 : " WHERE prewire_uuid >= $1"
2160 : " AND finished=FALSE"
2161 : " AND failed=FALSE"
2162 : " ORDER BY prewire_uuid ASC"
2163 : " LIMIT $2;",
2164 : 2),
2165 : /* Used in #postgres_select_deposits_missing_wire */
2166 : // FIXME: used by the auditor; can probably be done
2167 : // smarter by checking if 'done' or 'blocked'
2168 : // are set correctly when going over deposits, instead
2169 : // of JOINing with refunds.
2170 0 : GNUNET_PQ_make_prepare (
2171 : "deposits_get_overdue",
2172 : "SELECT"
2173 : " deposit_serial_id"
2174 : ",coin_pub"
2175 : ",amount_with_fee_val"
2176 : ",amount_with_fee_frac"
2177 : ",payto_uri"
2178 : ",wire_deadline"
2179 : ",done"
2180 : " FROM deposits d"
2181 : " JOIN known_coins"
2182 : " USING (coin_pub)"
2183 : " JOIN wire_targets"
2184 : " USING (wire_target_h_payto)"
2185 : " WHERE wire_deadline >= $1"
2186 : " AND wire_deadline < $2"
2187 : " AND NOT (EXISTS (SELECT 1"
2188 : " FROM refunds r"
2189 : " WHERE (r.coin_pub = d.coin_pub) AND (r.deposit_serial_id = d.deposit_serial_id))"
2190 : " OR EXISTS (SELECT 1"
2191 : " FROM aggregation_tracking"
2192 : " WHERE (aggregation_tracking.deposit_serial_id = d.deposit_serial_id)))"
2193 : " ORDER BY wire_deadline ASC",
2194 : 2),
2195 : /* Used in #postgres_select_wire_out_above_serial_id() */
2196 0 : GNUNET_PQ_make_prepare (
2197 : "audit_get_wire_incr",
2198 : "SELECT"
2199 : " wireout_uuid"
2200 : ",execution_date"
2201 : ",wtid_raw"
2202 : ",payto_uri"
2203 : ",amount_val"
2204 : ",amount_frac"
2205 : " FROM wire_out"
2206 : " JOIN wire_targets"
2207 : " USING (wire_target_h_payto)"
2208 : " WHERE wireout_uuid>=$1"
2209 : " ORDER BY wireout_uuid ASC;",
2210 : 1),
2211 : /* Used in #postgres_select_wire_out_above_serial_id_by_account() */
2212 0 : GNUNET_PQ_make_prepare (
2213 : "audit_get_wire_incr_by_account",
2214 : "SELECT"
2215 : " wireout_uuid"
2216 : ",execution_date"
2217 : ",wtid_raw"
2218 : ",payto_uri"
2219 : ",amount_val"
2220 : ",amount_frac"
2221 : " FROM wire_out"
2222 : " JOIN wire_targets"
2223 : " USING (wire_target_h_payto)"
2224 : " WHERE "
2225 : " wireout_uuid>=$1 "
2226 : " AND exchange_account_section=$2"
2227 : " ORDER BY wireout_uuid ASC;",
2228 : 2),
2229 : /* Used in #postgres_select_recoup_above_serial_id() to obtain recoup transactions */
2230 0 : GNUNET_PQ_make_prepare (
2231 : "recoup_get_incr",
2232 : "SELECT"
2233 : " recoup_uuid"
2234 : ",recoup_timestamp"
2235 : ",reserves.reserve_pub"
2236 : ",coins.coin_pub"
2237 : ",coin_sig"
2238 : ",coin_blind"
2239 : ",ro.h_blind_ev"
2240 : ",denoms.denom_pub_hash"
2241 : ",coins.denom_sig"
2242 : ",coins.age_commitment_hash"
2243 : ",denoms.denom_pub"
2244 : ",amount_val"
2245 : ",amount_frac"
2246 : " FROM recoup"
2247 : " JOIN known_coins coins"
2248 : " USING (coin_pub)"
2249 : " JOIN reserves_out ro"
2250 : " USING (reserve_out_serial_id)"
2251 : " JOIN reserves"
2252 : " USING (reserve_uuid)"
2253 : " JOIN denominations denoms"
2254 : " ON (coins.denominations_serial = denoms.denominations_serial)"
2255 : " WHERE recoup_uuid>=$1"
2256 : " ORDER BY recoup_uuid ASC;",
2257 : 1),
2258 : /* Used in #postgres_select_recoup_refresh_above_serial_id() to obtain
2259 : recoup-refresh transactions */
2260 0 : GNUNET_PQ_make_prepare (
2261 : "recoup_refresh_get_incr",
2262 : "SELECT"
2263 : " recoup_refresh_uuid"
2264 : ",recoup_timestamp"
2265 : ",old_coins.coin_pub AS old_coin_pub"
2266 : ",new_coins.age_commitment_hash"
2267 : ",old_denoms.denom_pub_hash AS old_denom_pub_hash"
2268 : ",new_coins.coin_pub As coin_pub"
2269 : ",coin_sig"
2270 : ",coin_blind"
2271 : ",new_denoms.denom_pub AS denom_pub"
2272 : ",rrc.h_coin_ev AS h_blind_ev"
2273 : ",new_denoms.denom_pub_hash"
2274 : ",new_coins.denom_sig AS denom_sig"
2275 : ",amount_val"
2276 : ",amount_frac"
2277 : " FROM recoup_refresh"
2278 : " INNER JOIN refresh_revealed_coins rrc"
2279 : " USING (rrc_serial)"
2280 : " INNER JOIN refresh_commitments rfc"
2281 : " ON (rrc.melt_serial_id = rfc.melt_serial_id)"
2282 : " INNER JOIN known_coins old_coins"
2283 : " ON (rfc.old_coin_pub = old_coins.coin_pub)"
2284 : " INNER JOIN known_coins new_coins"
2285 : " ON (new_coins.coin_pub = recoup_refresh.coin_pub)"
2286 : " INNER JOIN denominations new_denoms"
2287 : " ON (new_coins.denominations_serial = new_denoms.denominations_serial)"
2288 : " INNER JOIN denominations old_denoms"
2289 : " ON (old_coins.denominations_serial = old_denoms.denominations_serial)"
2290 : " WHERE recoup_refresh_uuid>=$1"
2291 : " ORDER BY recoup_refresh_uuid ASC;",
2292 : 1),
2293 : /* Used in #postgres_select_reserve_closed_above_serial_id() to
2294 : obtain information about closed reserves */
2295 0 : GNUNET_PQ_make_prepare (
2296 : "reserves_close_get_incr",
2297 : "SELECT"
2298 : " close_uuid"
2299 : ",reserves.reserve_pub"
2300 : ",execution_date"
2301 : ",wtid"
2302 : ",payto_uri AS receiver_account"
2303 : ",amount_val"
2304 : ",amount_frac"
2305 : ",closing_fee_val"
2306 : ",closing_fee_frac"
2307 : " FROM reserves_close"
2308 : " JOIN wire_targets"
2309 : " USING (wire_target_h_payto)"
2310 : " JOIN reserves"
2311 : " USING (reserve_pub)"
2312 : " WHERE close_uuid>=$1"
2313 : " ORDER BY close_uuid ASC;",
2314 : 1),
2315 : /* Used in #postgres_get_reserve_history() to obtain recoup transactions
2316 : for a reserve - query optimization should be disabled i.e.
2317 : BEGIN; SET LOCAL join_collapse_limit=1; query; COMMIT; */
2318 0 : GNUNET_PQ_make_prepare (
2319 : "recoup_by_reserve",
2320 : /*
2321 : "SELECT"
2322 : " recoup.coin_pub"
2323 : ",recoup.coin_sig"
2324 : ",recoup.coin_blind"
2325 : ",recoup.amount_val"
2326 : ",recoup.amount_frac"
2327 : ",recoup.recoup_timestamp"
2328 : ",denominations.denom_pub_hash"
2329 : ",known_coins.denom_sig"
2330 : " FROM denominations"
2331 : " JOIN (known_coins"
2332 : " JOIN recoup "
2333 : " ON (recoup.coin_pub = known_coins.coin_pub))"
2334 : " ON (known_coins.denominations_serial = denominations.denominations_serial)"
2335 : " WHERE recoup.coin_pub"
2336 : " IN (SELECT coin_pub"
2337 : " FROM recoup_by_reserve"
2338 : " JOIN (reserves_out"
2339 : " JOIN (reserves_out_by_reserve"
2340 : " JOIN reserves"
2341 : " ON (reserves.reserve_uuid = reserves_out_by_reserve.reserve_uuid))"
2342 : " ON (reserves_out_by_reserve.h_blind_ev = reserves_out.h_blind_ev))"
2343 : " ON (recoup_by_reserve.reserve_out_serial_id = reserves_out.reserve_out_serial_id)"
2344 : " WHERE reserves.reserve_pub=$1);",
2345 : */
2346 : "SELECT robr.coin_pub "
2347 : " ,robr.coin_sig "
2348 : " ,robr.coin_blind "
2349 : " ,robr.amount_val "
2350 : " ,robr.amount_frac "
2351 : " ,robr.recoup_timestamp "
2352 : " ,denominations.denom_pub_hash "
2353 : " ,robr.denom_sig "
2354 : "FROM denominations "
2355 : " JOIN exchange_do_recoup_by_reserve($1) robr"
2356 : " USING (denominations_serial);",
2357 : 1),
2358 : /* Used in #postgres_get_reserve_status() to obtain recoup transactions
2359 : for a reserve - query optimization should be disabled i.e.
2360 : BEGIN; SET LOCAL join_collapse_limit=1; query; COMMIT; */
2361 0 : GNUNET_PQ_make_prepare (
2362 : "recoup_by_reserve_truncated",
2363 : /*
2364 : "SELECT"
2365 : " recoup.coin_pub"
2366 : ",recoup.coin_sig"
2367 : ",recoup.coin_blind"
2368 : ",recoup.amount_val"
2369 : ",recoup.amount_frac"
2370 : ",recoup.recoup_timestamp"
2371 : ",denominations.denom_pub_hash"
2372 : ",known_coins.denom_sig"
2373 : " FROM denominations"
2374 : " JOIN (known_coins"
2375 : " JOIN recoup "
2376 : " ON (recoup.coin_pub = known_coins.coin_pub))"
2377 : " ON (known_coins.denominations_serial = denominations.denominations_serial)"
2378 : " WHERE recoup_timestamp>=$2"
2379 : " AND recoup.coin_pub"
2380 : " IN (SELECT coin_pub"
2381 : " FROM recoup_by_reserve"
2382 : " JOIN (reserves_out"
2383 : " JOIN (reserves_out_by_reserve"
2384 : " JOIN reserves"
2385 : " ON (reserves.reserve_uuid = reserves_out_by_reserve.reserve_uuid))"
2386 : " ON (reserves_out_by_reserve.h_blind_ev = reserves_out.h_blind_ev))"
2387 : " ON (recoup_by_reserve.reserve_out_serial_id = reserves_out.reserve_out_serial_id)"
2388 : " WHERE reserves.reserve_pub=$1);",
2389 : */
2390 : "SELECT robr.coin_pub "
2391 : " ,robr.coin_sig "
2392 : " ,robr.coin_blind "
2393 : " ,robr.amount_val "
2394 : " ,robr.amount_frac "
2395 : " ,robr.recoup_timestamp "
2396 : " ,denominations.denom_pub_hash "
2397 : " ,robr.denom_sig "
2398 : "FROM denominations "
2399 : " JOIN exchange_do_recoup_by_reserve($1) robr"
2400 : " USING (denominations_serial)"
2401 : " WHERE recoup_timestamp>=$2;",
2402 : 2),
2403 : /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
2404 : affecting old coins of refreshed coins */
2405 0 : GNUNET_PQ_make_prepare (
2406 : "recoup_by_old_coin",
2407 : "SELECT"
2408 : " coins.coin_pub"
2409 : ",coin_sig"
2410 : ",coin_blind"
2411 : ",amount_val"
2412 : ",amount_frac"
2413 : ",recoup_timestamp"
2414 : ",denoms.denom_pub_hash"
2415 : ",coins.denom_sig"
2416 : ",recoup_refresh_uuid"
2417 : " FROM recoup_refresh"
2418 : " JOIN known_coins coins"
2419 : " USING (coin_pub)"
2420 : " JOIN denominations denoms"
2421 : " USING (denominations_serial)"
2422 : " WHERE rrc_serial IN"
2423 : " (SELECT rrc.rrc_serial"
2424 : " FROM refresh_commitments"
2425 : " JOIN refresh_revealed_coins rrc"
2426 : " USING (melt_serial_id)"
2427 : " WHERE old_coin_pub=$1);",
2428 : 1),
2429 : /* Used in #postgres_get_reserve_history() */
2430 0 : GNUNET_PQ_make_prepare (
2431 : "close_by_reserve",
2432 : "SELECT"
2433 : " amount_val"
2434 : ",amount_frac"
2435 : ",closing_fee_val"
2436 : ",closing_fee_frac"
2437 : ",execution_date"
2438 : ",payto_uri AS receiver_account"
2439 : ",wtid"
2440 : " FROM reserves_close"
2441 : " JOIN wire_targets"
2442 : " USING (wire_target_h_payto)"
2443 : " WHERE reserve_pub=$1;",
2444 : 1),
2445 : /* Used in #postgres_get_reserve_status() */
2446 0 : GNUNET_PQ_make_prepare (
2447 : "close_by_reserve_truncated",
2448 : "SELECT"
2449 : " amount_val"
2450 : ",amount_frac"
2451 : ",closing_fee_val"
2452 : ",closing_fee_frac"
2453 : ",execution_date"
2454 : ",payto_uri AS receiver_account"
2455 : ",wtid"
2456 : " FROM reserves_close"
2457 : " JOIN wire_targets"
2458 : " USING (wire_target_h_payto)"
2459 : " WHERE reserve_pub=$1"
2460 : " AND execution_date>=$2;",
2461 : 2),
2462 : /* Used in #postgres_get_reserve_history() */
2463 0 : GNUNET_PQ_make_prepare (
2464 : "merge_by_reserve",
2465 : "SELECT"
2466 : " pr.amount_with_fee_val"
2467 : ",pr.amount_with_fee_frac"
2468 : ",pr.balance_val"
2469 : ",pr.balance_frac"
2470 : ",pr.purse_fee_val"
2471 : ",pr.purse_fee_frac"
2472 : ",pr.h_contract_terms"
2473 : ",pr.merge_pub"
2474 : ",am.reserve_sig"
2475 : ",pm.purse_pub"
2476 : ",pm.merge_timestamp"
2477 : ",pr.purse_expiration"
2478 : ",pr.age_limit"
2479 : ",pr.flags"
2480 : " FROM purse_merges pm"
2481 : " JOIN purse_requests pr"
2482 : " USING (purse_pub)"
2483 : " JOIN account_merges am"
2484 : " ON (am.purse_pub = pm.purse_pub AND"
2485 : " am.reserve_pub = pm.reserve_pub)"
2486 : " WHERE pm.reserve_pub=$1"
2487 : " AND pm.partner_serial_id=0" /* must be local! */
2488 : " AND pr.finished"
2489 : " AND NOT pr.refunded;",
2490 : 1),
2491 : /* Used in #postgres_get_reserve_status() */
2492 0 : GNUNET_PQ_make_prepare (
2493 : "merge_by_reserve_truncated",
2494 : "SELECT"
2495 : " pr.amount_with_fee_val"
2496 : ",pr.amount_with_fee_frac"
2497 : ",pr.balance_val"
2498 : ",pr.balance_frac"
2499 : ",pr.purse_fee_val"
2500 : ",pr.purse_fee_frac"
2501 : ",pr.h_contract_terms"
2502 : ",pr.merge_pub"
2503 : ",am.reserve_sig"
2504 : ",pm.purse_pub"
2505 : ",pm.merge_timestamp"
2506 : ",pr.purse_expiration"
2507 : ",pr.age_limit"
2508 : ",pr.flags"
2509 : " FROM purse_merges pm"
2510 : " JOIN purse_requests pr"
2511 : " USING (purse_pub)"
2512 : " JOIN account_merges am"
2513 : " ON (am.purse_pub = pm.purse_pub AND"
2514 : " am.reserve_pub = pm.reserve_pub)"
2515 : " WHERE pm.reserve_pub=$1"
2516 : " AND pm.merge_timestamp >= $2"
2517 : " AND pm.partner_serial_id=0" /* must be local! */
2518 : " AND pr.finished"
2519 : " AND NOT pr.refunded;",
2520 : 2),
2521 : /* Used in #postgres_get_reserve_history() */
2522 0 : GNUNET_PQ_make_prepare (
2523 : "history_by_reserve",
2524 : "SELECT"
2525 : " history_fee_val"
2526 : ",history_fee_frac"
2527 : ",request_timestamp"
2528 : ",reserve_sig"
2529 : " FROM history_requests"
2530 : " WHERE reserve_pub=$1;",
2531 : 1),
2532 : /* Used in #postgres_get_reserve_status() */
2533 0 : GNUNET_PQ_make_prepare (
2534 : "history_by_reserve_truncated",
2535 : "SELECT"
2536 : " history_fee_val"
2537 : ",history_fee_frac"
2538 : ",request_timestamp"
2539 : ",reserve_sig"
2540 : " FROM history_requests"
2541 : " WHERE reserve_pub=$1"
2542 : " AND request_timestamp>=$2;",
2543 : 2),
2544 : /* Used in #postgres_get_expired_reserves() */
2545 0 : GNUNET_PQ_make_prepare (
2546 : "get_expired_reserves",
2547 : "WITH ed AS MATERIALIZED ( "
2548 : " SELECT * "
2549 : " FROM reserves "
2550 : " WHERE expiration_date <= $1 "
2551 : " AND (current_balance_val != 0 OR current_balance_frac != 0) "
2552 : " ORDER BY expiration_date ASC "
2553 : " LIMIT 1 "
2554 : ") "
2555 : "SELECT "
2556 : " ed.expiration_date "
2557 : " ,payto_uri AS account_details "
2558 : " ,ed.reserve_pub "
2559 : " ,current_balance_val "
2560 : " ,current_balance_frac "
2561 : "FROM ( "
2562 : " SELECT "
2563 : " * "
2564 : " FROM reserves_in "
2565 : " WHERE reserve_pub = ( "
2566 : " SELECT reserve_pub FROM ed) "
2567 : " ) ri "
2568 : "JOIN wire_targets wt ON (ri.wire_source_h_payto = wt.wire_target_h_payto) "
2569 : "JOIN ed ON (ri.reserve_pub = ed.reserve_pub); ",
2570 : 1),
2571 : /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
2572 : for a coin */
2573 0 : GNUNET_PQ_make_prepare (
2574 : "recoup_by_coin",
2575 : "SELECT"
2576 : " reserves.reserve_pub"
2577 : ",denoms.denom_pub_hash"
2578 : ",coin_sig"
2579 : ",coin_blind"
2580 : ",amount_val"
2581 : ",amount_frac"
2582 : ",recoup_timestamp"
2583 : ",recoup_uuid"
2584 : " FROM recoup rcp"
2585 : /* NOTE: suboptimal JOIN follows: crosses shards!
2586 : Could theoretically be improved via a materialized
2587 : index. But likely not worth it (query is rare and
2588 : number of reserve shards might be limited) */
2589 : " JOIN reserves_out ro"
2590 : " USING (reserve_out_serial_id)"
2591 : " JOIN reserves"
2592 : " USING (reserve_uuid)"
2593 : " JOIN known_coins coins"
2594 : " USING (coin_pub)"
2595 : " JOIN denominations denoms"
2596 : " ON (denoms.denominations_serial = coins.denominations_serial)"
2597 : " WHERE coins.coin_pub=$1;",
2598 : 1),
2599 : /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
2600 : for a refreshed coin */
2601 0 : GNUNET_PQ_make_prepare (
2602 : "recoup_by_refreshed_coin",
2603 : "SELECT"
2604 : " old_coins.coin_pub AS old_coin_pub"
2605 : ",coin_sig"
2606 : ",coin_blind"
2607 : ",amount_val"
2608 : ",amount_frac"
2609 : ",recoup_timestamp"
2610 : ",denoms.denom_pub_hash"
2611 : ",coins.denom_sig"
2612 : ",recoup_refresh_uuid"
2613 : " FROM recoup_refresh"
2614 : " JOIN refresh_revealed_coins rrc"
2615 : " USING (rrc_serial)"
2616 : " JOIN refresh_commitments rfc"
2617 : " ON (rrc.melt_serial_id = rfc.melt_serial_id)"
2618 : " JOIN known_coins old_coins"
2619 : " ON (rfc.old_coin_pub = old_coins.coin_pub)"
2620 : " JOIN known_coins coins"
2621 : " ON (recoup_refresh.coin_pub = coins.coin_pub)"
2622 : " JOIN denominations denoms"
2623 : " ON (denoms.denominations_serial = coins.denominations_serial)"
2624 : " WHERE coins.coin_pub=$1;",
2625 : 1),
2626 : /* Used in #postgres_get_reserve_by_h_blind() */
2627 0 : GNUNET_PQ_make_prepare (
2628 : "reserve_by_h_blind",
2629 : "SELECT"
2630 : " reserves.reserve_pub"
2631 : ",reserve_out_serial_id"
2632 : " FROM reserves_out"
2633 : " JOIN reserves"
2634 : " USING (reserve_uuid)"
2635 : " WHERE h_blind_ev=$1"
2636 : " LIMIT 1;",
2637 : 1),
2638 : /* Used in #postgres_get_old_coin_by_h_blind() */
2639 0 : GNUNET_PQ_make_prepare (
2640 : "old_coin_by_h_blind",
2641 : "SELECT"
2642 : " okc.coin_pub AS old_coin_pub"
2643 : ",rrc_serial"
2644 : " FROM refresh_revealed_coins rrc"
2645 : " JOIN refresh_commitments rcom USING (melt_serial_id)"
2646 : " JOIN known_coins okc ON (rcom.old_coin_pub = okc.coin_pub)"
2647 : " WHERE h_coin_ev=$1"
2648 : " LIMIT 1;",
2649 : 1),
2650 : /* Used in #postgres_lookup_auditor_timestamp() */
2651 0 : GNUNET_PQ_make_prepare (
2652 : "lookup_auditor_timestamp",
2653 : "SELECT"
2654 : " last_change"
2655 : " FROM auditors"
2656 : " WHERE auditor_pub=$1;",
2657 : 1),
2658 : /* Used in #postgres_lookup_auditor_status() */
2659 0 : GNUNET_PQ_make_prepare (
2660 : "lookup_auditor_status",
2661 : "SELECT"
2662 : " auditor_url"
2663 : ",is_active"
2664 : " FROM auditors"
2665 : " WHERE auditor_pub=$1;",
2666 : 1),
2667 : /* Used in #postgres_lookup_wire_timestamp() */
2668 0 : GNUNET_PQ_make_prepare (
2669 : "lookup_wire_timestamp",
2670 : "SELECT"
2671 : " last_change"
2672 : " FROM wire_accounts"
2673 : " WHERE payto_uri=$1;",
2674 : 1),
2675 : /* used in #postgres_insert_auditor() */
2676 0 : GNUNET_PQ_make_prepare (
2677 : "insert_auditor",
2678 : "INSERT INTO auditors "
2679 : "(auditor_pub"
2680 : ",auditor_name"
2681 : ",auditor_url"
2682 : ",is_active"
2683 : ",last_change"
2684 : ") VALUES "
2685 : "($1, $2, $3, true, $4);",
2686 : 4),
2687 : /* used in #postgres_update_auditor() */
2688 0 : GNUNET_PQ_make_prepare (
2689 : "update_auditor",
2690 : "UPDATE auditors"
2691 : " SET"
2692 : " auditor_url=$2"
2693 : " ,auditor_name=$3"
2694 : " ,is_active=$4"
2695 : " ,last_change=$5"
2696 : " WHERE auditor_pub=$1",
2697 : 5),
2698 : /* used in #postgres_insert_wire() */
2699 0 : GNUNET_PQ_make_prepare (
2700 : "insert_wire",
2701 : "INSERT INTO wire_accounts "
2702 : "(payto_uri"
2703 : ",master_sig"
2704 : ",is_active"
2705 : ",last_change"
2706 : ") VALUES "
2707 : "($1, $2, true, $3);",
2708 : 3),
2709 : /* used in #postgres_update_wire() */
2710 0 : GNUNET_PQ_make_prepare (
2711 : "update_wire",
2712 : "UPDATE wire_accounts"
2713 : " SET"
2714 : " is_active=$2"
2715 : " ,last_change=$3"
2716 : " WHERE payto_uri=$1",
2717 : 3),
2718 : /* used in #postgres_update_wire() */
2719 0 : GNUNET_PQ_make_prepare (
2720 : "get_wire_accounts",
2721 : "SELECT"
2722 : " payto_uri"
2723 : ",master_sig"
2724 : " FROM wire_accounts"
2725 : " WHERE is_active",
2726 : 0),
2727 : /* used in #postgres_update_wire() */
2728 0 : GNUNET_PQ_make_prepare (
2729 : "get_wire_fees",
2730 : "SELECT"
2731 : " wire_fee_val"
2732 : ",wire_fee_frac"
2733 : ",closing_fee_val"
2734 : ",closing_fee_frac"
2735 : ",wad_fee_val"
2736 : ",wad_fee_frac"
2737 : ",start_date"
2738 : ",end_date"
2739 : ",master_sig"
2740 : " FROM wire_fee"
2741 : " WHERE wire_method=$1",
2742 : 1),
2743 : /* used in #postgres_insert_signkey_revocation() */
2744 0 : GNUNET_PQ_make_prepare (
2745 : "insert_signkey_revocation",
2746 : "INSERT INTO signkey_revocations "
2747 : "(esk_serial"
2748 : ",master_sig"
2749 : ") SELECT esk_serial, $2 "
2750 : " FROM exchange_sign_keys"
2751 : " WHERE exchange_pub=$1;",
2752 : 2),
2753 : /* used in #postgres_insert_signkey_revocation() */
2754 0 : GNUNET_PQ_make_prepare (
2755 : "lookup_signkey_revocation",
2756 : "SELECT "
2757 : " master_sig"
2758 : " FROM signkey_revocations"
2759 : " WHERE esk_serial="
2760 : " (SELECT esk_serial"
2761 : " FROM exchange_sign_keys"
2762 : " WHERE exchange_pub=$1);",
2763 : 1),
2764 : /* used in #postgres_insert_signkey() */
2765 0 : GNUNET_PQ_make_prepare (
2766 : "insert_signkey",
2767 : "INSERT INTO exchange_sign_keys "
2768 : "(exchange_pub"
2769 : ",valid_from"
2770 : ",expire_sign"
2771 : ",expire_legal"
2772 : ",master_sig"
2773 : ") VALUES "
2774 : "($1, $2, $3, $4, $5);",
2775 : 5),
2776 : /* used in #postgres_lookup_signing_key() */
2777 0 : GNUNET_PQ_make_prepare (
2778 : "lookup_signing_key",
2779 : "SELECT"
2780 : " valid_from"
2781 : ",expire_sign"
2782 : ",expire_legal"
2783 : " FROM exchange_sign_keys"
2784 : " WHERE exchange_pub=$1",
2785 : 1),
2786 : /* used in #postgres_lookup_denomination_key() */
2787 0 : GNUNET_PQ_make_prepare (
2788 : "lookup_denomination_key",
2789 : "SELECT"
2790 : " valid_from"
2791 : ",expire_withdraw"
2792 : ",expire_deposit"
2793 : ",expire_legal"
2794 : ",coin_val"
2795 : ",coin_frac"
2796 : ",fee_withdraw_val"
2797 : ",fee_withdraw_frac"
2798 : ",fee_deposit_val"
2799 : ",fee_deposit_frac"
2800 : ",fee_refresh_val"
2801 : ",fee_refresh_frac"
2802 : ",fee_refund_val"
2803 : ",fee_refund_frac"
2804 : ",age_mask"
2805 : " FROM denominations"
2806 : " WHERE denom_pub_hash=$1;",
2807 : 1),
2808 : /* used in #postgres_insert_auditor_denom_sig() */
2809 0 : GNUNET_PQ_make_prepare (
2810 : "insert_auditor_denom_sig",
2811 : "WITH ax AS"
2812 : " (SELECT auditor_uuid"
2813 : " FROM auditors"
2814 : " WHERE auditor_pub=$1)"
2815 : "INSERT INTO auditor_denom_sigs "
2816 : "(auditor_uuid"
2817 : ",denominations_serial"
2818 : ",auditor_sig"
2819 : ") SELECT ax.auditor_uuid, denominations_serial, $3 "
2820 : " FROM denominations"
2821 : " CROSS JOIN ax"
2822 : " WHERE denom_pub_hash=$2;",
2823 : 3),
2824 : /* used in #postgres_select_auditor_denom_sig() */
2825 0 : GNUNET_PQ_make_prepare (
2826 : "select_auditor_denom_sig",
2827 : "SELECT"
2828 : " auditor_sig"
2829 : " FROM auditor_denom_sigs"
2830 : " WHERE auditor_uuid="
2831 : " (SELECT auditor_uuid"
2832 : " FROM auditors"
2833 : " WHERE auditor_pub=$1)"
2834 : " AND denominations_serial="
2835 : " (SELECT denominations_serial"
2836 : " FROM denominations"
2837 : " WHERE denom_pub_hash=$2);",
2838 : 2),
2839 : /* used in #postgres_lookup_wire_fee_by_time() */
2840 0 : GNUNET_PQ_make_prepare (
2841 : "lookup_wire_fee_by_time",
2842 : "SELECT"
2843 : " wire_fee_val"
2844 : ",wire_fee_frac"
2845 : ",closing_fee_val"
2846 : ",closing_fee_frac"
2847 : ",wad_fee_val"
2848 : ",wad_fee_frac"
2849 : " FROM wire_fee"
2850 : " WHERE wire_method=$1"
2851 : " AND end_date > $2"
2852 : " AND start_date < $3;",
2853 : 1),
2854 : /* used in #postgres_lookup_wire_fee_by_time() */
2855 0 : GNUNET_PQ_make_prepare (
2856 : "lookup_global_fee_by_time",
2857 : "SELECT"
2858 : " history_fee_val"
2859 : ",history_fee_frac"
2860 : ",kyc_fee_val"
2861 : ",kyc_fee_frac"
2862 : ",account_fee_val"
2863 : ",account_fee_frac"
2864 : ",purse_fee_val"
2865 : ",purse_fee_frac"
2866 : ",purse_timeout"
2867 : ",kyc_timeout"
2868 : ",history_expiration"
2869 : ",purse_account_limit"
2870 : " FROM global_fee"
2871 : " WHERE end_date > $1"
2872 : " AND start_date < $2;",
2873 : 1),
2874 : /* used in #postgres_commit */
2875 0 : GNUNET_PQ_make_prepare (
2876 : "do_commit",
2877 : "COMMIT",
2878 : 0),
2879 : /* used in #postgres_lookup_serial_by_table() */
2880 0 : GNUNET_PQ_make_prepare (
2881 : "select_serial_by_table_denominations",
2882 : "SELECT"
2883 : " denominations_serial AS serial"
2884 : " FROM denominations"
2885 : " ORDER BY denominations_serial DESC"
2886 : " LIMIT 1;",
2887 : 0),
2888 0 : GNUNET_PQ_make_prepare (
2889 : "select_serial_by_table_denomination_revocations",
2890 : "SELECT"
2891 : " denom_revocations_serial_id AS serial"
2892 : " FROM denomination_revocations"
2893 : " ORDER BY denom_revocations_serial_id DESC"
2894 : " LIMIT 1;",
2895 : 0),
2896 0 : GNUNET_PQ_make_prepare (
2897 : "select_serial_by_table_wire_targets",
2898 : "SELECT"
2899 : " wire_target_serial_id AS serial"
2900 : " FROM wire_targets"
2901 : " ORDER BY wire_target_serial_id DESC"
2902 : " LIMIT 1;",
2903 : 0),
2904 0 : GNUNET_PQ_make_prepare (
2905 : "select_serial_by_table_reserves",
2906 : "SELECT"
2907 : " reserve_uuid AS serial"
2908 : " FROM reserves"
2909 : " ORDER BY reserve_uuid DESC"
2910 : " LIMIT 1;",
2911 : 0),
2912 0 : GNUNET_PQ_make_prepare (
2913 : "select_serial_by_table_reserves_in",
2914 : "SELECT"
2915 : " reserve_in_serial_id AS serial"
2916 : " FROM reserves_in"
2917 : " ORDER BY reserve_in_serial_id DESC"
2918 : " LIMIT 1;",
2919 : 0),
2920 0 : GNUNET_PQ_make_prepare (
2921 : "select_serial_by_table_reserves_close",
2922 : "SELECT"
2923 : " close_uuid AS serial"
2924 : " FROM reserves_close"
2925 : " ORDER BY close_uuid DESC"
2926 : " LIMIT 1;",
2927 : 0),
2928 0 : GNUNET_PQ_make_prepare (
2929 : "select_serial_by_table_reserves_out",
2930 : "SELECT"
2931 : " reserve_out_serial_id AS serial"
2932 : " FROM reserves_out"
2933 : " ORDER BY reserve_out_serial_id DESC"
2934 : " LIMIT 1;",
2935 : 0),
2936 0 : GNUNET_PQ_make_prepare (
2937 : "select_serial_by_table_auditors",
2938 : "SELECT"
2939 : " auditor_uuid AS serial"
2940 : " FROM auditors"
2941 : " ORDER BY auditor_uuid DESC"
2942 : " LIMIT 1;",
2943 : 0),
2944 0 : GNUNET_PQ_make_prepare (
2945 : "select_serial_by_table_auditor_denom_sigs",
2946 : "SELECT"
2947 : " auditor_denom_serial AS serial"
2948 : " FROM auditor_denom_sigs"
2949 : " ORDER BY auditor_denom_serial DESC"
2950 : " LIMIT 1;",
2951 : 0),
2952 0 : GNUNET_PQ_make_prepare (
2953 : "select_serial_by_table_exchange_sign_keys",
2954 : "SELECT"
2955 : " esk_serial AS serial"
2956 : " FROM exchange_sign_keys"
2957 : " ORDER BY esk_serial DESC"
2958 : " LIMIT 1;",
2959 : 0),
2960 0 : GNUNET_PQ_make_prepare (
2961 : "select_serial_by_table_signkey_revocations",
2962 : "SELECT"
2963 : " signkey_revocations_serial_id AS serial"
2964 : " FROM signkey_revocations"
2965 : " ORDER BY signkey_revocations_serial_id DESC"
2966 : " LIMIT 1;",
2967 : 0),
2968 0 : GNUNET_PQ_make_prepare (
2969 : "select_serial_by_table_known_coins",
2970 : "SELECT"
2971 : " known_coin_id AS serial"
2972 : " FROM known_coins"
2973 : " ORDER BY known_coin_id DESC"
2974 : " LIMIT 1;",
2975 : 0),
2976 0 : GNUNET_PQ_make_prepare (
2977 : "select_serial_by_table_refresh_commitments",
2978 : "SELECT"
2979 : " melt_serial_id AS serial"
2980 : " FROM refresh_commitments"
2981 : " ORDER BY melt_serial_id DESC"
2982 : " LIMIT 1;",
2983 : 0),
2984 0 : GNUNET_PQ_make_prepare (
2985 : "select_serial_by_table_refresh_revealed_coins",
2986 : "SELECT"
2987 : " rrc_serial AS serial"
2988 : " FROM refresh_revealed_coins"
2989 : " ORDER BY rrc_serial DESC"
2990 : " LIMIT 1;",
2991 : 0),
2992 0 : GNUNET_PQ_make_prepare (
2993 : "select_serial_by_table_refresh_transfer_keys",
2994 : "SELECT"
2995 : " rtc_serial AS serial"
2996 : " FROM refresh_transfer_keys"
2997 : " ORDER BY rtc_serial DESC"
2998 : " LIMIT 1;",
2999 : 0),
3000 0 : GNUNET_PQ_make_prepare (
3001 : "select_serial_by_table_deposits",
3002 : "SELECT"
3003 : " deposit_serial_id AS serial"
3004 : " FROM deposits"
3005 : " ORDER BY deposit_serial_id DESC"
3006 : " LIMIT 1;",
3007 : 0),
3008 0 : GNUNET_PQ_make_prepare (
3009 : "select_serial_by_table_refunds",
3010 : "SELECT"
3011 : " refund_serial_id AS serial"
3012 : " FROM refunds"
3013 : " ORDER BY refund_serial_id DESC"
3014 : " LIMIT 1;",
3015 : 0),
3016 0 : GNUNET_PQ_make_prepare (
3017 : "select_serial_by_table_wire_out",
3018 : "SELECT"
3019 : " wireout_uuid AS serial"
3020 : " FROM wire_out"
3021 : " ORDER BY wireout_uuid DESC"
3022 : " LIMIT 1;",
3023 : 0),
3024 0 : GNUNET_PQ_make_prepare (
3025 : "select_serial_by_table_aggregation_tracking",
3026 : "SELECT"
3027 : " aggregation_serial_id AS serial"
3028 : " FROM aggregation_tracking"
3029 : " ORDER BY aggregation_serial_id DESC"
3030 : " LIMIT 1;",
3031 : 0),
3032 0 : GNUNET_PQ_make_prepare (
3033 : "select_serial_by_table_wire_fee",
3034 : "SELECT"
3035 : " wire_fee_serial AS serial"
3036 : " FROM wire_fee"
3037 : " ORDER BY wire_fee_serial DESC"
3038 : " LIMIT 1;",
3039 : 0),
3040 0 : GNUNET_PQ_make_prepare (
3041 : "select_serial_by_table_global_fee",
3042 : "SELECT"
3043 : " global_fee_serial AS serial"
3044 : " FROM global_fee"
3045 : " ORDER BY global_fee_serial DESC"
3046 : " LIMIT 1;",
3047 : 0),
3048 0 : GNUNET_PQ_make_prepare (
3049 : "select_serial_by_table_recoup",
3050 : "SELECT"
3051 : " recoup_uuid AS serial"
3052 : " FROM recoup"
3053 : " ORDER BY recoup_uuid DESC"
3054 : " LIMIT 1;",
3055 : 0),
3056 0 : GNUNET_PQ_make_prepare (
3057 : "select_serial_by_table_recoup_refresh",
3058 : "SELECT"
3059 : " recoup_refresh_uuid AS serial"
3060 : " FROM recoup_refresh"
3061 : " ORDER BY recoup_refresh_uuid DESC"
3062 : " LIMIT 1;",
3063 : 0),
3064 0 : GNUNET_PQ_make_prepare (
3065 : "select_serial_by_table_extensions",
3066 : "SELECT"
3067 : " extension_id AS serial"
3068 : " FROM extensions"
3069 : " ORDER BY extension_id DESC"
3070 : " LIMIT 1;",
3071 : 0),
3072 0 : GNUNET_PQ_make_prepare (
3073 : "select_serial_by_table_extension_details",
3074 : "SELECT"
3075 : " extension_details_serial_id AS serial"
3076 : " FROM extension_details"
3077 : " ORDER BY extension_details_serial_id DESC"
3078 : " LIMIT 1;",
3079 : 0),
3080 0 : GNUNET_PQ_make_prepare (
3081 : "select_serial_by_table_purse_requests",
3082 : "SELECT"
3083 : " purse_requests_serial_id AS serial"
3084 : " FROM purse_requests"
3085 : " ORDER BY purse_requests_serial_id DESC"
3086 : " LIMIT 1;",
3087 : 0),
3088 0 : GNUNET_PQ_make_prepare (
3089 : "select_serial_by_table_purse_refunds",
3090 : "SELECT"
3091 : " purse_refunds_serial_id AS serial"
3092 : " FROM purse_refunds"
3093 : " ORDER BY purse_refunds_serial_id DESC"
3094 : " LIMIT 1;",
3095 : 0),
3096 0 : GNUNET_PQ_make_prepare (
3097 : "select_serial_by_table_purse_merges",
3098 : "SELECT"
3099 : " purse_merge_request_serial_id AS serial"
3100 : " FROM purse_merges"
3101 : " ORDER BY purse_merge_request_serial_id DESC"
3102 : " LIMIT 1;",
3103 : 0),
3104 0 : GNUNET_PQ_make_prepare (
3105 : "select_serial_by_table_purse_deposits",
3106 : "SELECT"
3107 : " purse_deposit_serial_id AS serial"
3108 : " FROM purse_deposits"
3109 : " ORDER BY purse_deposit_serial_id DESC"
3110 : " LIMIT 1;",
3111 : 0),
3112 0 : GNUNET_PQ_make_prepare (
3113 : "select_serial_by_table_account_merges",
3114 : "SELECT"
3115 : " account_merge_request_serial_id AS serial"
3116 : " FROM account_merges"
3117 : " ORDER BY account_merge_request_serial_id DESC"
3118 : " LIMIT 1;",
3119 : 0),
3120 0 : GNUNET_PQ_make_prepare (
3121 : "select_serial_by_table_history_requests",
3122 : "SELECT"
3123 : " history_request_serial_id AS serial"
3124 : " FROM history_requests"
3125 : " ORDER BY history_request_serial_id DESC"
3126 : " LIMIT 1;",
3127 : 0),
3128 0 : GNUNET_PQ_make_prepare (
3129 : "select_serial_by_table_close_requests",
3130 : "SELECT"
3131 : " close_request_serial_id AS serial"
3132 : " FROM close_requests"
3133 : " ORDER BY close_request_serial_id DESC"
3134 : " LIMIT 1;",
3135 : 0),
3136 0 : GNUNET_PQ_make_prepare (
3137 : "select_serial_by_table_wads_out",
3138 : "SELECT"
3139 : " wad_out_serial_id AS serial"
3140 : " FROM wads_out"
3141 : " ORDER BY wad_out_serial_id DESC"
3142 : " LIMIT 1;",
3143 : 0),
3144 0 : GNUNET_PQ_make_prepare (
3145 : "select_serial_by_table_wads_out_entries",
3146 : "SELECT"
3147 : " wad_out_entry_serial_id AS serial"
3148 : " FROM wad_out_entries"
3149 : " ORDER BY wad_out_entry_serial_id DESC"
3150 : " LIMIT 1;",
3151 : 0),
3152 0 : GNUNET_PQ_make_prepare (
3153 : "select_serial_by_table_wads_in",
3154 : "SELECT"
3155 : " wad_in_serial_id AS serial"
3156 : " FROM wads_in"
3157 : " ORDER BY wad_in_serial_id DESC"
3158 : " LIMIT 1;",
3159 : 0),
3160 0 : GNUNET_PQ_make_prepare (
3161 : "select_serial_by_table_wads_in_entries",
3162 : "SELECT"
3163 : " wad_in_entry_serial_id AS serial"
3164 : " FROM wad_in_entries"
3165 : " ORDER BY wad_in_entry_serial_id DESC"
3166 : " LIMIT 1;",
3167 : 0),
3168 0 : GNUNET_PQ_make_prepare (
3169 : "select_serial_by_table_profit_drains",
3170 : "SELECT"
3171 : " profit_drain_serial_id AS serial"
3172 : " FROM profit_drains"
3173 : " ORDER BY profit_drain_serial_id DESC"
3174 : " LIMIT 1;",
3175 : 0),
3176 : /* For postgres_lookup_records_by_table */
3177 0 : GNUNET_PQ_make_prepare (
3178 : "select_above_serial_by_table_denominations",
3179 : "SELECT"
3180 : " denominations_serial AS serial"
3181 : ",denom_type"
3182 : ",denom_pub"
3183 : ",master_sig"
3184 : ",valid_from"
3185 : ",expire_withdraw"
3186 : ",expire_deposit"
3187 : ",expire_legal"
3188 : ",coin_val"
3189 : ",coin_frac"
3190 : ",fee_withdraw_val"
3191 : ",fee_withdraw_frac"
3192 : ",fee_deposit_val"
3193 : ",fee_deposit_frac"
3194 : ",fee_refresh_val"
3195 : ",fee_refresh_frac"
3196 : ",fee_refund_val"
3197 : ",fee_refund_frac"
3198 : ",age_mask"
3199 : " FROM denominations"
3200 : " WHERE denominations_serial > $1"
3201 : " ORDER BY denominations_serial ASC;",
3202 : 1),
3203 0 : GNUNET_PQ_make_prepare (
3204 : "select_above_serial_by_table_denomination_revocations",
3205 : "SELECT"
3206 : " denom_revocations_serial_id AS serial"
3207 : ",master_sig"
3208 : ",denominations_serial"
3209 : " FROM denomination_revocations"
3210 : " WHERE denom_revocations_serial_id > $1"
3211 : " ORDER BY denom_revocations_serial_id ASC;",
3212 : 1),
3213 0 : GNUNET_PQ_make_prepare (
3214 : "select_above_serial_by_table_wire_targets",
3215 : "SELECT"
3216 : " wire_target_serial_id AS serial"
3217 : ",payto_uri"
3218 : " FROM wire_targets"
3219 : " WHERE wire_target_serial_id > $1"
3220 : " ORDER BY wire_target_serial_id ASC;",
3221 : 1),
3222 0 : GNUNET_PQ_make_prepare (
3223 : "select_above_serial_by_table_reserves",
3224 : "SELECT"
3225 : " reserve_uuid AS serial"
3226 : ",reserve_pub"
3227 : ",expiration_date"
3228 : ",gc_date"
3229 : " FROM reserves"
3230 : " WHERE reserve_uuid > $1"
3231 : " ORDER BY reserve_uuid ASC;",
3232 : 1),
3233 0 : GNUNET_PQ_make_prepare (
3234 : "select_above_serial_by_table_reserves_in",
3235 : "SELECT"
3236 : " reserve_in_serial_id AS serial"
3237 : ",reserve_pub"
3238 : ",wire_reference"
3239 : ",credit_val"
3240 : ",credit_frac"
3241 : ",wire_source_h_payto"
3242 : ",exchange_account_section"
3243 : ",execution_date"
3244 : " FROM reserves_in"
3245 : " WHERE reserve_in_serial_id > $1"
3246 : " ORDER BY reserve_in_serial_id ASC;",
3247 : 1),
3248 0 : GNUNET_PQ_make_prepare (
3249 : "select_above_serial_by_table_reserves_close",
3250 : "SELECT"
3251 : " close_uuid AS serial"
3252 : ",reserve_pub"
3253 : ",execution_date"
3254 : ",wtid"
3255 : ",wire_target_h_payto"
3256 : ",amount_val"
3257 : ",amount_frac"
3258 : ",closing_fee_val"
3259 : ",closing_fee_frac"
3260 : " FROM reserves_close"
3261 : " WHERE close_uuid > $1"
3262 : " ORDER BY close_uuid ASC;",
3263 : 1),
3264 0 : GNUNET_PQ_make_prepare (
3265 : "select_above_serial_by_table_reserves_out",
3266 : "SELECT"
3267 : " reserve_out_serial_id AS serial"
3268 : ",h_blind_ev"
3269 : ",denominations_serial"
3270 : ",denom_sig"
3271 : ",reserve_uuid"
3272 : ",reserve_sig"
3273 : ",execution_date"
3274 : ",amount_with_fee_val"
3275 : ",amount_with_fee_frac"
3276 : " FROM reserves_out"
3277 : " JOIN reserves USING (reserve_uuid)"
3278 : " WHERE reserve_out_serial_id > $1"
3279 : " ORDER BY reserve_out_serial_id ASC;",
3280 : 1),
3281 0 : GNUNET_PQ_make_prepare (
3282 : "select_above_serial_by_table_auditors",
3283 : "SELECT"
3284 : " auditor_uuid AS serial"
3285 : ",auditor_pub"
3286 : ",auditor_name"
3287 : ",auditor_url"
3288 : ",is_active"
3289 : ",last_change"
3290 : " FROM auditors"
3291 : " WHERE auditor_uuid > $1"
3292 : " ORDER BY auditor_uuid ASC;",
3293 : 1),
3294 0 : GNUNET_PQ_make_prepare (
3295 : "select_above_serial_by_table_auditor_denom_sigs",
3296 : "SELECT"
3297 : " auditor_denom_serial AS serial"
3298 : ",auditor_uuid"
3299 : ",denominations_serial"
3300 : ",auditor_sig"
3301 : " FROM auditor_denom_sigs"
3302 : " WHERE auditor_denom_serial > $1"
3303 : " ORDER BY auditor_denom_serial ASC;",
3304 : 1),
3305 0 : GNUNET_PQ_make_prepare (
3306 : "select_above_serial_by_table_exchange_sign_keys",
3307 : "SELECT"
3308 : " esk_serial AS serial"
3309 : ",exchange_pub"
3310 : ",master_sig"
3311 : ",valid_from"
3312 : ",expire_sign"
3313 : ",expire_legal"
3314 : " FROM exchange_sign_keys"
3315 : " WHERE esk_serial > $1"
3316 : " ORDER BY esk_serial ASC;",
3317 : 1),
3318 0 : GNUNET_PQ_make_prepare (
3319 : "select_above_serial_by_table_signkey_revocations",
3320 : "SELECT"
3321 : " signkey_revocations_serial_id AS serial"
3322 : ",esk_serial"
3323 : ",master_sig"
3324 : " FROM signkey_revocations"
3325 : " WHERE signkey_revocations_serial_id > $1"
3326 : " ORDER BY signkey_revocations_serial_id ASC;",
3327 : 1),
3328 0 : GNUNET_PQ_make_prepare (
3329 : "select_above_serial_by_table_known_coins",
3330 : "SELECT"
3331 : " known_coin_id AS serial"
3332 : ",coin_pub"
3333 : ",denom_sig"
3334 : ",denominations_serial"
3335 : " FROM known_coins"
3336 : " WHERE known_coin_id > $1"
3337 : " ORDER BY known_coin_id ASC;",
3338 : 1),
3339 0 : GNUNET_PQ_make_prepare (
3340 : "select_above_serial_by_table_refresh_commitments",
3341 : "SELECT"
3342 : " melt_serial_id AS serial"
3343 : ",rc"
3344 : ",old_coin_sig"
3345 : ",amount_with_fee_val"
3346 : ",amount_with_fee_frac"
3347 : ",noreveal_index"
3348 : ",old_coin_pub"
3349 : " FROM refresh_commitments"
3350 : " WHERE melt_serial_id > $1"
3351 : " ORDER BY melt_serial_id ASC;",
3352 : 1),
3353 0 : GNUNET_PQ_make_prepare (
3354 : "select_above_serial_by_table_refresh_revealed_coins",
3355 : "SELECT"
3356 : " rrc_serial AS serial"
3357 : ",freshcoin_index"
3358 : ",link_sig"
3359 : ",coin_ev"
3360 : ",ev_sig"
3361 : ",ewv"
3362 : ",denominations_serial"
3363 : ",melt_serial_id"
3364 : " FROM refresh_revealed_coins"
3365 : " WHERE rrc_serial > $1"
3366 : " ORDER BY rrc_serial ASC;",
3367 : 1),
3368 0 : GNUNET_PQ_make_prepare (
3369 : "select_above_serial_by_table_refresh_transfer_keys",
3370 : "SELECT"
3371 : " rtc_serial AS serial"
3372 : ",transfer_pub"
3373 : ",transfer_privs"
3374 : ",melt_serial_id"
3375 : " FROM refresh_transfer_keys"
3376 : " WHERE rtc_serial > $1"
3377 : " ORDER BY rtc_serial ASC;",
3378 : 1),
3379 0 : GNUNET_PQ_make_prepare (
3380 : "select_above_serial_by_table_deposits",
3381 : "SELECT"
3382 : " deposit_serial_id AS serial"
3383 : ",shard"
3384 : ",coin_pub"
3385 : ",known_coin_id"
3386 : ",amount_with_fee_val"
3387 : ",amount_with_fee_frac"
3388 : ",wallet_timestamp"
3389 : ",exchange_timestamp"
3390 : ",refund_deadline"
3391 : ",wire_deadline"
3392 : ",merchant_pub"
3393 : ",h_contract_terms"
3394 : ",coin_sig"
3395 : ",wire_salt"
3396 : ",wire_target_h_payto"
3397 : ",done"
3398 : ",extension_blocked"
3399 : ",extension_details_serial_id"
3400 : " FROM deposits"
3401 : " WHERE deposit_serial_id > $1"
3402 : " ORDER BY deposit_serial_id ASC;",
3403 : 1),
3404 0 : GNUNET_PQ_make_prepare (
3405 : "select_above_serial_by_table_refunds",
3406 : "SELECT"
3407 : " refund_serial_id AS serial"
3408 : ",coin_pub"
3409 : ",merchant_sig"
3410 : ",rtransaction_id"
3411 : ",amount_with_fee_val"
3412 : ",amount_with_fee_frac"
3413 : ",deposit_serial_id"
3414 : " FROM refunds"
3415 : " WHERE refund_serial_id > $1"
3416 : " ORDER BY refund_serial_id ASC;",
3417 : 1),
3418 0 : GNUNET_PQ_make_prepare (
3419 : "select_above_serial_by_table_wire_out",
3420 : "SELECT"
3421 : " wireout_uuid AS serial"
3422 : ",execution_date"
3423 : ",wtid_raw"
3424 : ",wire_target_h_payto"
3425 : ",exchange_account_section"
3426 : ",amount_val"
3427 : ",amount_frac"
3428 : " FROM wire_out"
3429 : " WHERE wireout_uuid > $1"
3430 : " ORDER BY wireout_uuid ASC;",
3431 : 1),
3432 0 : GNUNET_PQ_make_prepare (
3433 : "select_above_serial_by_table_aggregation_tracking",
3434 : "SELECT"
3435 : " aggregation_serial_id AS serial"
3436 : ",deposit_serial_id"
3437 : ",wtid_raw"
3438 : " FROM aggregation_tracking"
3439 : " WHERE aggregation_serial_id > $1"
3440 : " ORDER BY aggregation_serial_id ASC;",
3441 : 1),
3442 0 : GNUNET_PQ_make_prepare (
3443 : "select_above_serial_by_table_wire_fee",
3444 : "SELECT"
3445 : " wire_fee_serial AS serial"
3446 : ",wire_method"
3447 : ",start_date"
3448 : ",end_date"
3449 : ",wire_fee_val"
3450 : ",wire_fee_frac"
3451 : ",closing_fee_val"
3452 : ",closing_fee_frac"
3453 : ",wad_fee_val"
3454 : ",wad_fee_frac"
3455 : ",master_sig"
3456 : " FROM wire_fee"
3457 : " WHERE wire_fee_serial > $1"
3458 : " ORDER BY wire_fee_serial ASC;",
3459 : 1),
3460 0 : GNUNET_PQ_make_prepare (
3461 : "select_above_serial_by_table_global_fee",
3462 : "SELECT"
3463 : " global_fee_serial AS serial"
3464 : ",start_date"
3465 : ",end_date"
3466 : ",history_fee_val"
3467 : ",history_fee_frac"
3468 : ",kyc_fee_val"
3469 : ",kyc_fee_frac"
3470 : ",account_fee_val"
3471 : ",account_fee_frac"
3472 : ",purse_fee_val"
3473 : ",purse_fee_frac"
3474 : ",purse_timeout"
3475 : ",kyc_timeout"
3476 : ",history_expiration"
3477 : ",purse_account_limit"
3478 : ",master_sig"
3479 : " FROM global_fee"
3480 : " WHERE global_fee_serial > $1"
3481 : " ORDER BY global_fee_serial ASC;",
3482 : 1),
3483 0 : GNUNET_PQ_make_prepare (
3484 : "select_above_serial_by_table_recoup",
3485 : "SELECT"
3486 : " recoup_uuid AS serial"
3487 : ",coin_sig"
3488 : ",coin_blind"
3489 : ",amount_val"
3490 : ",amount_frac"
3491 : ",recoup_timestamp"
3492 : ",coin_pub"
3493 : ",reserve_out_serial_id"
3494 : " FROM recoup"
3495 : " WHERE recoup_uuid > $1"
3496 : " ORDER BY recoup_uuid ASC;",
3497 : 1),
3498 0 : GNUNET_PQ_make_prepare (
3499 : "select_above_serial_by_table_recoup_refresh",
3500 : "SELECT"
3501 : " recoup_refresh_uuid AS serial"
3502 : ",coin_sig"
3503 : ",coin_blind"
3504 : ",amount_val"
3505 : ",amount_frac"
3506 : ",recoup_timestamp"
3507 : ",coin_pub"
3508 : ",known_coin_id"
3509 : ",rrc_serial"
3510 : " FROM recoup_refresh"
3511 : " WHERE recoup_refresh_uuid > $1"
3512 : " ORDER BY recoup_refresh_uuid ASC;",
3513 : 1),
3514 :
3515 :
3516 0 : GNUNET_PQ_make_prepare (
3517 : "select_above_serial_by_table_purse_requests",
3518 : "SELECT"
3519 : " purse_requests_serial_id"
3520 : ",purse_pub"
3521 : ",merge_pub"
3522 : ",purse_creation"
3523 : ",purse_expiration"
3524 : ",h_contract_terms"
3525 : ",age_limit"
3526 : ",flags"
3527 : ",amount_with_fee_val"
3528 : ",amount_with_fee_frac"
3529 : ",purse_fee_val"
3530 : ",purse_fee_frac"
3531 : ",purse_sig"
3532 : " FROM purse_requests"
3533 : " WHERE purse_requests_serial_id > $1"
3534 : " ORDER BY purse_requests_serial_id ASC;",
3535 : 1),
3536 0 : GNUNET_PQ_make_prepare (
3537 : "select_above_serial_by_table_purse_refunds",
3538 : "SELECT"
3539 : " purse_refunds_serial_id"
3540 : ",purse_pub"
3541 : " FROM purse_refunds"
3542 : " WHERE purse_refunds_serial_id > $1"
3543 : " ORDER BY purse_refunds_serial_id ASC;",
3544 : 1),
3545 0 : GNUNET_PQ_make_prepare (
3546 : "select_above_serial_by_table_purse_merges",
3547 : "SELECT"
3548 : " purse_merge_request_serial_id"
3549 : ",partner_serial_id"
3550 : ",reserve_pub"
3551 : ",purse_pub"
3552 : ",merge_sig"
3553 : ",merge_timestamp"
3554 : " FROM purse_merges"
3555 : " WHERE purse_merge_request_serial_id > $1"
3556 : " ORDER BY purse_merge_request_serial_id ASC;",
3557 : 1),
3558 0 : GNUNET_PQ_make_prepare (
3559 : "select_above_serial_by_table_purse_deposits",
3560 : "SELECT"
3561 : " purse_deposit_serial_id"
3562 : ",partner_serial_id"
3563 : ",purse_pub"
3564 : ",coin_pub"
3565 : ",amount_with_fee_val"
3566 : ",amount_with_fee_frac"
3567 : ",coin_sig"
3568 : " FROM purse_deposits"
3569 : " WHERE purse_deposit_serial_id > $1"
3570 : " ORDER BY purse_deposit_serial_id ASC;",
3571 : 1),
3572 0 : GNUNET_PQ_make_prepare (
3573 : "select_above_serial_by_table_account_merges",
3574 : "SELECT"
3575 : " account_merge_request_serial_id"
3576 : ",reserve_pub"
3577 : ",reserve_sig"
3578 : ",purse_pub"
3579 : " FROM account_merges"
3580 : " WHERE account_merge_request_serial_id > $1"
3581 : " ORDER BY account_merge_request_serial_id ASC;",
3582 : 1),
3583 0 : GNUNET_PQ_make_prepare (
3584 : "select_above_serial_by_table_history_requests",
3585 : "SELECT"
3586 : " history_request_serial_id"
3587 : ",reserve_pub"
3588 : ",request_timestamp"
3589 : ",reserve_sig"
3590 : ",history_fee_val"
3591 : ",history_fee_frac"
3592 : " FROM history_requests"
3593 : " WHERE history_request_serial_id > $1"
3594 : " ORDER BY history_request_serial_id ASC;",
3595 : 1),
3596 0 : GNUNET_PQ_make_prepare (
3597 : "select_above_serial_by_table_close_requests",
3598 : "SELECT"
3599 : " close_request_serial_id"
3600 : ",reserve_pub"
3601 : ",close_timestamp"
3602 : ",reserve_sig"
3603 : ",close_val"
3604 : ",close_frac"
3605 : " FROM close_requests"
3606 : " WHERE close_request_serial_id > $1"
3607 : " ORDER BY close_request_serial_id ASC;",
3608 : 1),
3609 0 : GNUNET_PQ_make_prepare (
3610 : "select_above_serial_by_table_wads_out",
3611 : "SELECT"
3612 : " wad_out_serial_id"
3613 : ",wad_id"
3614 : ",partner_serial_id"
3615 : ",amount_val"
3616 : ",amount_frac"
3617 : ",execution_time"
3618 : " FROM wads_out"
3619 : " WHERE wad_out_serial_id > $1"
3620 : " ORDER BY wad_out_serial_id ASC;",
3621 : 1),
3622 0 : GNUNET_PQ_make_prepare (
3623 : "select_above_serial_by_table_wads_out_entries",
3624 : "SELECT"
3625 : " wad_out_entry_serial_id"
3626 : ",reserve_pub"
3627 : ",purse_pub"
3628 : ",h_contract"
3629 : ",purse_expiration"
3630 : ",merge_timestamp"
3631 : ",amount_with_fee_val"
3632 : ",amount_with_fee_frac"
3633 : ",wad_fee_val"
3634 : ",wad_fee_frac"
3635 : ",deposit_fees_val"
3636 : ",deposit_fees_frac"
3637 : ",reserve_sig"
3638 : ",purse_sig"
3639 : " FROM wad_out_entries"
3640 : " WHERE wad_out_entry_serial_id > $1"
3641 : " ORDER BY wad_out_entry_serial_id ASC;",
3642 : 1),
3643 0 : GNUNET_PQ_make_prepare (
3644 : "select_above_serial_by_table_wads_in",
3645 : "SELECT"
3646 : " wad_in_serial_id"
3647 : ",wad_id"
3648 : ",origin_exchange_url"
3649 : ",amount_val"
3650 : ",amount_frac"
3651 : ",arrival_time"
3652 : " FROM wads_in"
3653 : " WHERE wad_in_serial_id > $1"
3654 : " ORDER BY wad_in_serial_id ASC;",
3655 : 1),
3656 0 : GNUNET_PQ_make_prepare (
3657 : "select_above_serial_by_table_wads_in_entries",
3658 : "SELECT"
3659 : " wad_in_entry_serial_id"
3660 : ",reserve_pub"
3661 : ",purse_pub"
3662 : ",h_contract"
3663 : ",purse_expiration"
3664 : ",merge_timestamp"
3665 : ",amount_with_fee_val"
3666 : ",amount_with_fee_frac"
3667 : ",wad_fee_val"
3668 : ",wad_fee_frac"
3669 : ",deposit_fees_val"
3670 : ",deposit_fees_frac"
3671 : ",reserve_sig"
3672 : ",purse_sig"
3673 : " FROM wad_in_entries"
3674 : " WHERE wad_in_entry_serial_id > $1"
3675 : " ORDER BY wad_in_entry_serial_id ASC;",
3676 : 1),
3677 0 : GNUNET_PQ_make_prepare (
3678 : "select_above_serial_by_table_profit_drains",
3679 : "SELECT"
3680 : " profit_drain_serial_id"
3681 : ",wtid"
3682 : ",account_section"
3683 : ",payto_uri"
3684 : ",trigger_date"
3685 : ",amount_val"
3686 : ",amount_frac"
3687 : ",master_sig"
3688 : " FROM profit_drains"
3689 : " WHERE profit_drain_serial_id > $1"
3690 : " ORDER BY profit_drain_serial_id ASC;",
3691 : 1),
3692 : /* For postgres_insert_records_by_table */
3693 0 : GNUNET_PQ_make_prepare (
3694 : "insert_into_table_denominations",
3695 : "INSERT INTO denominations"
3696 : "(denominations_serial"
3697 : ",denom_pub_hash"
3698 : ",denom_type"
3699 : ",age_mask"
3700 : ",denom_pub"
3701 : ",master_sig"
3702 : ",valid_from"
3703 : ",expire_withdraw"
3704 : ",expire_deposit"
3705 : ",expire_legal"
3706 : ",coin_val"
3707 : ",coin_frac"
3708 : ",fee_withdraw_val"
3709 : ",fee_withdraw_frac"
3710 : ",fee_deposit_val"
3711 : ",fee_deposit_frac"
3712 : ",fee_refresh_val"
3713 : ",fee_refresh_frac"
3714 : ",fee_refund_val"
3715 : ",fee_refund_frac"
3716 : ") VALUES "
3717 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
3718 : " $11, $12, $13, $14, $15, $16, $17, $18, $19, $20);",
3719 : 20),
3720 0 : GNUNET_PQ_make_prepare (
3721 : "insert_into_table_denomination_revocations",
3722 : "INSERT INTO denomination_revocations"
3723 : "(denom_revocations_serial_id"
3724 : ",master_sig"
3725 : ",denominations_serial"
3726 : ") VALUES "
3727 : "($1, $2, $3);",
3728 : 3),
3729 0 : GNUNET_PQ_make_prepare (
3730 : "insert_into_table_wire_targets",
3731 : "INSERT INTO wire_targets"
3732 : "(wire_target_serial_id"
3733 : ",wire_target_h_payto"
3734 : ",payto_uri"
3735 : ") VALUES "
3736 : "($1, $2, $3);",
3737 : 3),
3738 0 : GNUNET_PQ_make_prepare (
3739 : "insert_into_table_reserves",
3740 : "INSERT INTO reserves"
3741 : "(reserve_uuid"
3742 : ",reserve_pub"
3743 : ",expiration_date"
3744 : ",gc_date"
3745 : ") VALUES "
3746 : "($1, $2, $3, $4);",
3747 : 4),
3748 0 : GNUNET_PQ_make_prepare (
3749 : "insert_into_table_reserves_in",
3750 : "INSERT INTO reserves_in"
3751 : "(reserve_in_serial_id"
3752 : ",wire_reference"
3753 : ",credit_val"
3754 : ",credit_frac"
3755 : ",wire_source_h_payto"
3756 : ",exchange_account_section"
3757 : ",execution_date"
3758 : ",reserve_pub"
3759 : ") VALUES "
3760 : "($1, $2, $3, $4, $5, $6, $7, $8);",
3761 : 8),
3762 0 : GNUNET_PQ_make_prepare (
3763 : "insert_into_table_reserves_close",
3764 : "INSERT INTO reserves_close"
3765 : "(close_uuid"
3766 : ",execution_date"
3767 : ",wtid"
3768 : ",wire_target_h_payto"
3769 : ",amount_val"
3770 : ",amount_frac"
3771 : ",closing_fee_val"
3772 : ",closing_fee_frac"
3773 : ",reserve_pub"
3774 : ") VALUES "
3775 : "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
3776 : 9),
3777 0 : GNUNET_PQ_make_prepare (
3778 : "insert_into_table_reserves_out",
3779 : "INSERT INTO reserves_out"
3780 : "(reserve_out_serial_id"
3781 : ",h_blind_ev"
3782 : ",denominations_serial"
3783 : ",denom_sig"
3784 : ",reserve_uuid"
3785 : ",reserve_sig"
3786 : ",execution_date"
3787 : ",amount_with_fee_val"
3788 : ",amount_with_fee_frac"
3789 : ") VALUES "
3790 : "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
3791 : 9),
3792 0 : GNUNET_PQ_make_prepare (
3793 : "insert_into_table_auditors",
3794 : "INSERT INTO auditors"
3795 : "(auditor_uuid"
3796 : ",auditor_pub"
3797 : ",auditor_name"
3798 : ",auditor_url"
3799 : ",is_active"
3800 : ",last_change"
3801 : ") VALUES "
3802 : "($1, $2, $3, $4, $5, $6);",
3803 : 6),
3804 0 : GNUNET_PQ_make_prepare (
3805 : "insert_into_table_auditor_denom_sigs",
3806 : "INSERT INTO auditor_denom_sigs"
3807 : "(auditor_denom_serial"
3808 : ",auditor_uuid"
3809 : ",denominations_serial"
3810 : ",auditor_sig"
3811 : ") VALUES "
3812 : "($1, $2, $3, $4);",
3813 : 4),
3814 0 : GNUNET_PQ_make_prepare (
3815 : "insert_into_table_exchange_sign_keys",
3816 : "INSERT INTO exchange_sign_keys"
3817 : "(esk_serial"
3818 : ",exchange_pub"
3819 : ",master_sig"
3820 : ",valid_from"
3821 : ",expire_sign"
3822 : ",expire_legal"
3823 : ") VALUES "
3824 : "($1, $2, $3, $4, $5, $6);",
3825 : 6),
3826 0 : GNUNET_PQ_make_prepare (
3827 : "insert_into_table_signkey_revocations",
3828 : "INSERT INTO signkey_revocations"
3829 : "(signkey_revocations_serial_id"
3830 : ",esk_serial"
3831 : ",master_sig"
3832 : ") VALUES "
3833 : "($1, $2, $3);",
3834 : 3),
3835 0 : GNUNET_PQ_make_prepare (
3836 : "insert_into_table_known_coins",
3837 : "INSERT INTO known_coins"
3838 : "(known_coin_id"
3839 : ",coin_pub"
3840 : ",denom_sig"
3841 : ",denominations_serial"
3842 : ") VALUES "
3843 : "($1, $2, $3, $4);",
3844 : 4),
3845 0 : GNUNET_PQ_make_prepare (
3846 : "insert_into_table_refresh_commitments",
3847 : "INSERT INTO refresh_commitments"
3848 : "(melt_serial_id"
3849 : ",rc"
3850 : ",old_coin_sig"
3851 : ",amount_with_fee_val"
3852 : ",amount_with_fee_frac"
3853 : ",noreveal_index"
3854 : ",old_coin_pub"
3855 : ") VALUES "
3856 : "($1, $2, $3, $4, $5, $6, $7);",
3857 : 7),
3858 0 : GNUNET_PQ_make_prepare (
3859 : "insert_into_table_refresh_revealed_coins",
3860 : "INSERT INTO refresh_revealed_coins"
3861 : "(rrc_serial"
3862 : ",freshcoin_index"
3863 : ",link_sig"
3864 : ",coin_ev"
3865 : ",h_coin_ev"
3866 : ",ev_sig"
3867 : ",ewv"
3868 : ",denominations_serial"
3869 : ",melt_serial_id"
3870 : ") VALUES "
3871 : "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
3872 : 9),
3873 0 : GNUNET_PQ_make_prepare (
3874 : "insert_into_table_refresh_transfer_keys",
3875 : "INSERT INTO refresh_transfer_keys"
3876 : "(rtc_serial"
3877 : ",transfer_pub"
3878 : ",transfer_privs"
3879 : ",melt_serial_id"
3880 : ") VALUES "
3881 : "($1, $2, $3, $4);",
3882 : 4),
3883 0 : GNUNET_PQ_make_prepare (
3884 : "insert_into_table_deposits",
3885 : "INSERT INTO deposits"
3886 : "(deposit_serial_id"
3887 : ",shard"
3888 : ",known_coin_id"
3889 : ",coin_pub"
3890 : ",amount_with_fee_val"
3891 : ",amount_with_fee_frac"
3892 : ",wallet_timestamp"
3893 : ",exchange_timestamp"
3894 : ",refund_deadline"
3895 : ",wire_deadline"
3896 : ",merchant_pub"
3897 : ",h_contract_terms"
3898 : ",coin_sig"
3899 : ",wire_salt"
3900 : ",wire_target_h_payto"
3901 : ",extension_blocked"
3902 : ",extension_details_serial_id"
3903 : ") VALUES "
3904 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
3905 : " $11, $12, $13, $14, $15, $16, $17);",
3906 : 17),
3907 0 : GNUNET_PQ_make_prepare (
3908 : "insert_into_table_refunds",
3909 : "INSERT INTO refunds"
3910 : "(refund_serial_id"
3911 : ",coin_pub"
3912 : ",merchant_sig"
3913 : ",rtransaction_id"
3914 : ",amount_with_fee_val"
3915 : ",amount_with_fee_frac"
3916 : ",deposit_serial_id"
3917 : ") VALUES "
3918 : "($1, $2, $3, $4, $5, $6, $7);",
3919 : 7),
3920 0 : GNUNET_PQ_make_prepare (
3921 : "insert_into_table_aggregation_tracking",
3922 : "INSERT INTO aggregation_tracking"
3923 : "(aggregation_serial_id"
3924 : ",deposit_serial_id"
3925 : ",wtid_raw"
3926 : ") VALUES "
3927 : "($1, $2, $3);",
3928 : 3),
3929 0 : GNUNET_PQ_make_prepare (
3930 : "insert_into_table_wire_fee",
3931 : "INSERT INTO wire_fee"
3932 : "(wire_fee_serial"
3933 : ",wire_method"
3934 : ",start_date"
3935 : ",end_date"
3936 : ",wire_fee_val"
3937 : ",wire_fee_frac"
3938 : ",closing_fee_val"
3939 : ",closing_fee_frac"
3940 : ",wad_fee_val"
3941 : ",wad_fee_frac"
3942 : ",master_sig"
3943 : ") VALUES "
3944 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);",
3945 : 11),
3946 0 : GNUNET_PQ_make_prepare (
3947 : "insert_into_table_global_fee",
3948 : "INSERT INTO global_fee"
3949 : "(global_fee_serial"
3950 : ",start_date"
3951 : ",end_date"
3952 : ",history_fee_val"
3953 : ",history_fee_frac"
3954 : ",kyc_fee_val"
3955 : ",kyc_fee_frac"
3956 : ",account_fee_val"
3957 : ",account_fee_frac"
3958 : ",purse_fee_val"
3959 : ",purse_fee_frac"
3960 : ",purse_timeout"
3961 : ",kyc_timeout"
3962 : ",history_expiration"
3963 : ",purse_account_limit"
3964 : ",master_sig"
3965 : ") VALUES "
3966 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);",
3967 : 16),
3968 0 : GNUNET_PQ_make_prepare (
3969 : "insert_into_table_recoup",
3970 : "INSERT INTO recoup"
3971 : "(recoup_uuid"
3972 : ",coin_sig"
3973 : ",coin_blind"
3974 : ",amount_val"
3975 : ",amount_frac"
3976 : ",recoup_timestamp"
3977 : ",coin_pub"
3978 : ",reserve_out_serial_id"
3979 : ") VALUES "
3980 : "($1, $2, $3, $4, $5, $6, $7, $8);",
3981 : 8),
3982 0 : GNUNET_PQ_make_prepare (
3983 : "insert_into_table_recoup_refresh",
3984 : "INSERT INTO recoup_refresh"
3985 : "(recoup_refresh_uuid"
3986 : ",coin_sig"
3987 : ",coin_blind"
3988 : ",amount_val"
3989 : ",amount_frac"
3990 : ",recoup_timestamp"
3991 : ",known_coin_id"
3992 : ",coin_pub"
3993 : ",rrc_serial"
3994 : ") VALUES "
3995 : "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
3996 : 9),
3997 0 : GNUNET_PQ_make_prepare (
3998 : "insert_into_table_extensions",
3999 : "INSERT INTO extensions"
4000 : "(extension_id"
4001 : ",name"
4002 : ",config"
4003 : ") VALUES "
4004 : "($1, $2, $3);",
4005 : 3),
4006 0 : GNUNET_PQ_make_prepare (
4007 : "insert_into_table_extension_details",
4008 : "INSERT INTO extension_details"
4009 : "(extension_details_serial_id"
4010 : ",extension_options"
4011 : ") VALUES "
4012 : "($1, $2);",
4013 : 2),
4014 :
4015 0 : GNUNET_PQ_make_prepare (
4016 : "insert_into_table_purse_requests",
4017 : "INSERT INTO purse_requests"
4018 : "(purse_requests_serial_id"
4019 : ",purse_pub"
4020 : ",merge_pub"
4021 : ",purse_creation"
4022 : ",purse_expiration"
4023 : ",h_contract_terms"
4024 : ",age_limit"
4025 : ",flags"
4026 : ",amount_with_fee_val"
4027 : ",amount_with_fee_frac"
4028 : ",purse_fee_val"
4029 : ",purse_fee_frac"
4030 : ",purse_sig"
4031 : ") VALUES "
4032 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);",
4033 : 13),
4034 0 : GNUNET_PQ_make_prepare (
4035 : "insert_into_table_purse_refunds",
4036 : "INSERT INTO purse_refunds"
4037 : "(purse_refunds_serial_id"
4038 : ",purse_pub"
4039 : ") VALUES "
4040 : "($1, $2);",
4041 : 2),
4042 0 : GNUNET_PQ_make_prepare (
4043 : "insert_into_table_purse_merges",
4044 : "INSERT INTO purse_merges"
4045 : "(purse_merge_request_serial_id"
4046 : ",partner_serial_id"
4047 : ",reserve_pub"
4048 : ",purse_pub"
4049 : ",merge_sig"
4050 : ",merge_timestamp"
4051 : ") VALUES "
4052 : "($1, $2, $3, $4, $5, $6);",
4053 : 6),
4054 0 : GNUNET_PQ_make_prepare (
4055 : "insert_into_table_purse_deposits",
4056 : "INSERT INTO purse_deposits"
4057 : "(purse_deposit_serial_id"
4058 : ",partner_serial_id"
4059 : ",purse_pub"
4060 : ",coin_pub"
4061 : ",amount_with_fee_val"
4062 : ",amount_with_fee_frac"
4063 : ",coin_sig"
4064 : ") VALUES "
4065 : "($1, $2, $3, $4, $5, $6, $7);",
4066 : 7),
4067 0 : GNUNET_PQ_make_prepare (
4068 : "insert_into_table_history_requests",
4069 : "INSERT INTO history_requests"
4070 : "(history_request_serial_id"
4071 : ",reserve_pub"
4072 : ",request_timestamp"
4073 : ",reserve_sig"
4074 : ",history_fee_val"
4075 : ",history_fee_frac"
4076 : ") VALUES "
4077 : "($1, $2, $3, $4, $5, $6);",
4078 : 6),
4079 0 : GNUNET_PQ_make_prepare (
4080 : "insert_into_table_close_requests",
4081 : "INSERT INTO close_requests"
4082 : "(close_request_serial_id"
4083 : ",reserve_pub"
4084 : ",close_timestamp"
4085 : ",reserve_sig"
4086 : ",close_val"
4087 : ",close_frac"
4088 : ") VALUES "
4089 : "($1, $2, $3, $4, $5, $6);",
4090 : 6),
4091 0 : GNUNET_PQ_make_prepare (
4092 : "insert_into_table_wads_out",
4093 : "INSERT INTO wads_out"
4094 : "(wad_out_serial_id"
4095 : ",wad_id"
4096 : ",partner_serial_id"
4097 : ",amount_val"
4098 : ",amount_frac"
4099 : ",execution_time"
4100 : ") VALUES "
4101 : "($1, $2, $3, $4, $5, $6);",
4102 : 6),
4103 0 : GNUNET_PQ_make_prepare (
4104 : "insert_into_table_wad_out_entries",
4105 : "INSERT INTO wad_out_entries"
4106 : "(wad_out_entry_serial_id"
4107 : ",wad_out_serial_id"
4108 : ",reserve_pub"
4109 : ",purse_pub"
4110 : ",h_contract"
4111 : ",purse_expiration"
4112 : ",merge_timestamp"
4113 : ",amount_with_fee_val"
4114 : ",amount_with_fee_frac"
4115 : ",wad_fee_val"
4116 : ",wad_fee_frac"
4117 : ",deposit_fees_val"
4118 : ",deposit_fees_frac"
4119 : ",reserve_sig"
4120 : ",purse_sig"
4121 : ") VALUES "
4122 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);",
4123 : 15),
4124 0 : GNUNET_PQ_make_prepare (
4125 : "insert_into_table_wads_in",
4126 : "INSERT INTO wads_in"
4127 : "(wad_in_serial_id"
4128 : ",wad_id"
4129 : ",origin_exchange_url"
4130 : ",amount_val"
4131 : ",amount_frac"
4132 : ",arrival_time"
4133 : ") VALUES "
4134 : "($1, $2, $3, $4, $5, $6);",
4135 : 6),
4136 0 : GNUNET_PQ_make_prepare (
4137 : "insert_into_table_wad_in_entries",
4138 : "INSERT INTO wad_in_entries"
4139 : "(wad_in_entry_serial_id"
4140 : ",wad_in_serial_id"
4141 : ",reserve_pub"
4142 : ",purse_pub"
4143 : ",h_contract"
4144 : ",purse_expiration"
4145 : ",merge_timestamp"
4146 : ",amount_with_fee_val"
4147 : ",amount_with_fee_frac"
4148 : ",wad_fee_val"
4149 : ",wad_fee_frac"
4150 : ",deposit_fees_val"
4151 : ",deposit_fees_frac"
4152 : ",reserve_sig"
4153 : ",purse_sig"
4154 : ") VALUES "
4155 : "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);",
4156 : 15),
4157 0 : GNUNET_PQ_make_prepare (
4158 : "insert_into_table_profit_drains",
4159 : "INSERT INTO profit_drains"
4160 : "(profit_drain_serial_id"
4161 : ",wtid"
4162 : ",account_section"
4163 : ",payto_uri"
4164 : ",trigger_date"
4165 : ",amount_val"
4166 : ",amount_frac"
4167 : ",master_sig"
4168 : ") VALUES "
4169 : "($1, $2, $3, $4, $5, $6, $7, $8);",
4170 : 8),
4171 :
4172 : /* Used in #postgres_begin_shard() */
4173 0 : GNUNET_PQ_make_prepare (
4174 : "get_open_shard",
4175 : "SELECT"
4176 : " start_row"
4177 : ",end_row"
4178 : " FROM work_shards"
4179 : " WHERE job_name=$1"
4180 : " AND completed=FALSE"
4181 : " AND last_attempt<$2"
4182 : " ORDER BY last_attempt ASC"
4183 : " LIMIT 1;",
4184 : 2),
4185 : /* Used in #postgres_begin_revolving_shard() */
4186 0 : GNUNET_PQ_make_prepare (
4187 : "get_open_revolving_shard",
4188 : "SELECT"
4189 : " start_row"
4190 : ",end_row"
4191 : " FROM revolving_work_shards"
4192 : " WHERE job_name=$1"
4193 : " AND active=FALSE"
4194 : " ORDER BY last_attempt ASC"
4195 : " LIMIT 1;",
4196 : 2),
4197 : /* Used in #postgres_begin_shard() */
4198 0 : GNUNET_PQ_make_prepare (
4199 : "reclaim_shard",
4200 : "UPDATE work_shards"
4201 : " SET last_attempt=$2"
4202 : " WHERE job_name=$1"
4203 : " AND start_row=$3"
4204 : " AND end_row=$4",
4205 : 4),
4206 : /* Used in #postgres_begin_revolving_shard() */
4207 0 : GNUNET_PQ_make_prepare (
4208 : "reclaim_revolving_shard",
4209 : "UPDATE revolving_work_shards"
4210 : " SET last_attempt=$2"
4211 : " ,active=TRUE"
4212 : " WHERE job_name=$1"
4213 : " AND start_row=$3"
4214 : " AND end_row=$4",
4215 : 4),
4216 : /* Used in #postgres_begin_shard() */
4217 0 : GNUNET_PQ_make_prepare (
4218 : "get_last_shard",
4219 : "SELECT"
4220 : " end_row"
4221 : " FROM work_shards"
4222 : " WHERE job_name=$1"
4223 : " ORDER BY end_row DESC"
4224 : " LIMIT 1;",
4225 : 1),
4226 : /* Used in #postgres_begin_revolving_shard() */
4227 0 : GNUNET_PQ_make_prepare (
4228 : "get_last_revolving_shard",
4229 : "SELECT"
4230 : " end_row"
4231 : " FROM revolving_work_shards"
4232 : " WHERE job_name=$1"
4233 : " ORDER BY end_row DESC"
4234 : " LIMIT 1;",
4235 : 1),
4236 : /* Used in #postgres_abort_shard() */
4237 0 : GNUNET_PQ_make_prepare (
4238 : "abort_shard",
4239 : "UPDATE work_shards"
4240 : " SET last_attempt=0"
4241 : " WHERE job_name = $1 "
4242 : " AND start_row = $2 "
4243 : " AND end_row = $3;",
4244 : 3),
4245 : /* Used in #postgres_begin_shard() */
4246 0 : GNUNET_PQ_make_prepare (
4247 : "claim_next_shard",
4248 : "INSERT INTO work_shards"
4249 : "(job_name"
4250 : ",last_attempt"
4251 : ",start_row"
4252 : ",end_row"
4253 : ") VALUES "
4254 : "($1, $2, $3, $4);",
4255 : 4),
4256 : /* Used in #postgres_claim_revolving_shard() */
4257 0 : GNUNET_PQ_make_prepare (
4258 : "create_revolving_shard",
4259 : "INSERT INTO revolving_work_shards"
4260 : "(job_name"
4261 : ",last_attempt"
4262 : ",start_row"
4263 : ",end_row"
4264 : ",active"
4265 : ") VALUES "
4266 : "($1, $2, $3, $4, TRUE);",
4267 : 4),
4268 : /* Used in #postgres_complete_shard() */
4269 0 : GNUNET_PQ_make_prepare (
4270 : "complete_shard",
4271 : "UPDATE work_shards"
4272 : " SET completed=TRUE"
4273 : " WHERE job_name=$1"
4274 : " AND start_row=$2"
4275 : " AND end_row=$3",
4276 : 3),
4277 : /* Used in #postgres_complete_shard() */
4278 0 : GNUNET_PQ_make_prepare (
4279 : "release_revolving_shard",
4280 : "UPDATE revolving_work_shards"
4281 : " SET active=FALSE"
4282 : " WHERE job_name=$1"
4283 : " AND start_row=$2"
4284 : " AND end_row=$3",
4285 : 3),
4286 : /* Used in #postgres_set_extension_config */
4287 0 : GNUNET_PQ_make_prepare (
4288 : "set_extension_config",
4289 : "INSERT INTO extensions (name, config) VALUES ($1, $2) "
4290 : "ON CONFLICT (name) "
4291 : "DO UPDATE SET config=$2",
4292 : 2),
4293 : /* Used in #postgres_get_extension_config */
4294 0 : GNUNET_PQ_make_prepare (
4295 : "get_extension_config",
4296 : "SELECT "
4297 : " config "
4298 : "FROM extensions"
4299 : " WHERE name=$1;",
4300 : 1),
4301 : /* Used in #postgres_insert_contract() */
4302 0 : GNUNET_PQ_make_prepare (
4303 : "insert_contract",
4304 : "INSERT INTO contracts"
4305 : " (purse_pub"
4306 : " ,pub_ckey"
4307 : " ,e_contract"
4308 : " ,contract_sig"
4309 : " ,purse_expiration"
4310 : " ) SELECT "
4311 : " $1, $2, $3, $4, purse_expiration"
4312 : " FROM purse_requests"
4313 : " WHERE purse_pub=$1"
4314 : " ON CONFLICT DO NOTHING;",
4315 : 4),
4316 : /* Used in #postgres_select_contract */
4317 0 : GNUNET_PQ_make_prepare (
4318 : "select_contract",
4319 : "SELECT "
4320 : " purse_pub"
4321 : ",e_contract"
4322 : ",contract_sig"
4323 : " FROM contracts"
4324 : " WHERE pub_ckey=$1;",
4325 : 1),
4326 : /* Used in #postgres_select_contract_by_purse */
4327 0 : GNUNET_PQ_make_prepare (
4328 : "select_contract_by_purse",
4329 : "SELECT "
4330 : " pub_ckey"
4331 : ",e_contract"
4332 : ",contract_sig"
4333 : " FROM contracts"
4334 : " WHERE purse_pub=$1;",
4335 : 1),
4336 : /* Used in #postgres_insert_purse_request() */
4337 0 : GNUNET_PQ_make_prepare (
4338 : "insert_purse_request",
4339 : "INSERT INTO purse_requests"
4340 : " (purse_pub"
4341 : " ,merge_pub"
4342 : " ,purse_creation"
4343 : " ,purse_expiration"
4344 : " ,h_contract_terms"
4345 : " ,age_limit"
4346 : " ,flags"
4347 : " ,in_reserve_quota"
4348 : " ,amount_with_fee_val"
4349 : " ,amount_with_fee_frac"
4350 : " ,purse_fee_val"
4351 : " ,purse_fee_frac"
4352 : " ,purse_sig"
4353 : " ) VALUES "
4354 : " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"
4355 : " ON CONFLICT DO NOTHING;",
4356 : 13),
4357 : /* Used in #postgres_select_purse */
4358 0 : GNUNET_PQ_make_prepare (
4359 : "select_purse",
4360 : "SELECT "
4361 : " merge_pub"
4362 : ",purse_expiration"
4363 : ",h_contract_terms"
4364 : ",amount_with_fee_val"
4365 : ",amount_with_fee_frac"
4366 : ",balance_val"
4367 : ",balance_frac"
4368 : ",merge_timestamp"
4369 : " FROM purse_requests"
4370 : " LEFT JOIN purse_merges USING (purse_pub)"
4371 : " WHERE purse_pub=$1;",
4372 : 1),
4373 : /* Used in #postgres_select_purse_request */
4374 0 : GNUNET_PQ_make_prepare (
4375 : "select_purse_request",
4376 : "SELECT "
4377 : " merge_pub"
4378 : ",purse_expiration"
4379 : ",h_contract_terms"
4380 : ",age_limit"
4381 : ",amount_with_fee_val"
4382 : ",amount_with_fee_frac"
4383 : ",balance_val"
4384 : ",balance_frac"
4385 : ",purse_sig"
4386 : " FROM purse_requests"
4387 : " WHERE purse_pub=$1;",
4388 : 1),
4389 : /* Used in #postgres_select_purse_by_merge_pub */
4390 0 : GNUNET_PQ_make_prepare (
4391 : "select_purse_by_merge_pub",
4392 : "SELECT "
4393 : " purse_pub"
4394 : ",purse_expiration"
4395 : ",h_contract_terms"
4396 : ",age_limit"
4397 : ",amount_with_fee_val"
4398 : ",amount_with_fee_frac"
4399 : ",balance_val"
4400 : ",balance_frac"
4401 : ",purse_sig"
4402 : " FROM purse_requests"
4403 : " WHERE merge_pub=$1;",
4404 : 1),
4405 : /* Used in #postgres_get_purse_deposit */
4406 0 : GNUNET_PQ_make_prepare (
4407 : "select_purse_deposit_by_coin_pub",
4408 : "SELECT "
4409 : " coin_sig"
4410 : ",amount_with_fee_val"
4411 : ",amount_with_fee_frac"
4412 : ",denom_pub_hash"
4413 : ",age_commitment_hash"
4414 : ",partner_base_url"
4415 : " FROM purse_deposits"
4416 : " LEFT JOIN partners USING (partner_serial_id)"
4417 : " JOIN known_coins kc USING (coin_pub)"
4418 : " JOIN denominations USING (denominations_serial)"
4419 : " WHERE coin_pub=$2"
4420 : " AND purse_pub=$1;",
4421 : 2),
4422 : /* Used in #postgres_do_purse_merge() */
4423 0 : GNUNET_PQ_make_prepare (
4424 : "call_purse_merge",
4425 : "SELECT"
4426 : " out_no_partner AS no_partner"
4427 : ",out_no_balance AS no_balance"
4428 : ",out_conflict AS conflict"
4429 : " FROM exchange_do_purse_merge"
4430 : " ($1, $2, $3, $4, $5, $6, $7, $8);",
4431 : 7),
4432 : /* Used in #postgres_do_reserve_purse() */
4433 0 : GNUNET_PQ_make_prepare (
4434 : "call_reserve_purse",
4435 : "SELECT"
4436 : " out_no_funds AS insufficient_funds"
4437 : ",out_no_reserve AS no_reserve"
4438 : ",out_conflict AS conflict"
4439 : " FROM exchange_do_reserve_purse"
4440 : " ($1, $2, $3, $4, $5, $6, $7, $8, $9);",
4441 : 9),
4442 : /* Used in #postgres_select_purse_merge */
4443 0 : GNUNET_PQ_make_prepare (
4444 : "select_purse_merge",
4445 : "SELECT "
4446 : " reserve_pub"
4447 : ",merge_sig"
4448 : ",merge_timestamp"
4449 : ",partner_base_url"
4450 : " FROM purse_merges"
4451 : " LEFT JOIN partners USING (partner_serial_id)"
4452 : " WHERE purse_pub=$1;",
4453 : 1),
4454 : /* Used in #postgres_do_account_merge() */
4455 0 : GNUNET_PQ_make_prepare (
4456 : "call_account_merge",
4457 : "SELECT 1"
4458 : " FROM exchange_do_account_merge"
4459 : " ($1, $2, $3);",
4460 : 3),
4461 : /* Used in #postgres_insert_history_request() */
4462 0 : GNUNET_PQ_make_prepare (
4463 : "call_history_request",
4464 : "SELECT"
4465 : " out_balance_ok AS balance_ok"
4466 : " ,out_idempotent AS idempotent"
4467 : " FROM exchange_do_history_request"
4468 : " ($1, $2, $3, $4, $5)",
4469 : 5),
4470 : /* Used in #postgres_insert_close_request() */
4471 0 : GNUNET_PQ_make_prepare (
4472 : "call_account_close",
4473 : "SELECT "
4474 : " out_final_balance_val"
4475 : ",out_final_balance_frac"
4476 : " FROM exchange_do_close_request"
4477 : " ($1, $2, $3)",
4478 : 3),
4479 : /* Used in #postgres_insert_kyc_requirement_for_account() */
4480 0 : GNUNET_PQ_make_prepare (
4481 : "insert_legitimization_requirement",
4482 : "INSERT INTO legitimization_requirements"
4483 : " (h_payto"
4484 : " ,required_checks"
4485 : " ) VALUES "
4486 : " ($1, $2)"
4487 : " ON CONFLICT (h_payto,required_checks) "
4488 : " DO UPDATE SET h_payto=$1" /* syntax requirement: dummy op */
4489 : " RETURNING legitimization_requirement_serial_id",
4490 : 2),
4491 : /* Used in #postgres_insert_kyc_requirement_process() */
4492 0 : GNUNET_PQ_make_prepare (
4493 : "insert_legitimization_process",
4494 : "INSERT INTO legitimization_processes"
4495 : " (h_payto"
4496 : " ,provider_section"
4497 : " ,provider_user_id"
4498 : " ,provider_legitimization_id"
4499 : " ) VALUES "
4500 : " ($1, $2, $3, $4)"
4501 : " ON CONFLICT (h_payto,provider_section) "
4502 : " DO UPDATE SET"
4503 : " provider_user_id=$3"
4504 : " ,provider_legitimization_id=$4"
4505 : " RETURNING legitimization_process_serial_id",
4506 : 4),
4507 : /* Used in #postgres_update_kyc_requirement_by_row() */
4508 0 : GNUNET_PQ_make_prepare (
4509 : "update_legitimization_process",
4510 : "UPDATE legitimization_processes"
4511 : " SET provider_user_id=$4"
4512 : " ,provider_legitimization_id=$5"
4513 : " ,expiration_time=GREATEST(expiration_time,$6)"
4514 : " WHERE"
4515 : " h_payto=$3"
4516 : " AND legitimization_process_serial_id=$1"
4517 : " AND provider_section=$2;",
4518 : 6),
4519 0 : GNUNET_PQ_make_prepare (
4520 : "alert_kyc_status_change",
4521 : "INSERT INTO kyc_alerts"
4522 : " (h_payto"
4523 : " ,trigger_type)"
4524 : " VALUES"
4525 : " ($1,$2);",
4526 : 2),
4527 : /* Used in #postgres_lookup_kyc_requirement_by_row() */
4528 0 : GNUNET_PQ_make_prepare (
4529 : "lookup_legitimization_requirement_by_row",
4530 : "SELECT "
4531 : " required_checks"
4532 : ",h_payto"
4533 : " FROM legitimization_requirements"
4534 : " WHERE legitimization_requirement_serial_id=$1;",
4535 : 1),
4536 : /* Used in #postgres_lookup_kyc_process_by_account() */
4537 0 : GNUNET_PQ_make_prepare (
4538 : "lookup_process_by_account",
4539 : "SELECT "
4540 : " legitimization_process_serial_id"
4541 : ",expiration_time"
4542 : ",provider_user_id"
4543 : ",provider_legitimization_id"
4544 : " FROM legitimization_processes"
4545 : " WHERE h_payto=$1"
4546 : " AND provider_section=$2;",
4547 : 2),
4548 : /* Used in #postgres_kyc_provider_account_lookup() */
4549 0 : GNUNET_PQ_make_prepare (
4550 : "get_wire_target_by_legitimization_id",
4551 : "SELECT "
4552 : " h_payto"
4553 : ",legitimization_process_serial_id"
4554 : " FROM legitimization_processes"
4555 : " WHERE provider_legitimization_id=$1"
4556 : " AND provider_section=$2;",
4557 : 2),
4558 : /* Used in #postgres_select_satisfied_kyc_processes() */
4559 0 : GNUNET_PQ_make_prepare (
4560 : "get_satisfied_legitimizations",
4561 : "SELECT "
4562 : " provider_section"
4563 : " FROM legitimization_processes"
4564 : " WHERE h_payto=$1"
4565 : " AND expiration_time>=$2;",
4566 : 2),
4567 :
4568 : /* Used in #postgres_select_withdraw_amounts_for_kyc_check (
4569 : () */
4570 0 : GNUNET_PQ_make_prepare (
4571 : "select_kyc_relevant_withdraw_events",
4572 : "SELECT"
4573 : " ro.amount_with_fee_val AS amount_val"
4574 : ",ro.amount_with_fee_frac AS amount_frac"
4575 : ",ro.execution_date AS date"
4576 : " FROM reserves_out ro"
4577 : " JOIN reserves_out_by_reserve USING (h_blind_ev)"
4578 : " JOIN reserves res ON (ro.reserve_uuid = res.reserve_uuid)"
4579 : " JOIN reserves_in ri ON (res.reserve_pub = ri.reserve_pub)"
4580 : " WHERE wire_source_h_payto=$1"
4581 : " AND ro.execution_date >= $2"
4582 : " ORDER BY ro.execution_date DESC",
4583 : 2),
4584 : /* Used in #postgres_select_aggregation_amounts_for_kyc_check (
4585 : () */
4586 0 : GNUNET_PQ_make_prepare (
4587 : "select_kyc_relevant_aggregation_events",
4588 : "SELECT"
4589 : " amount_val"
4590 : ",amount_frac"
4591 : ",execution_date AS date"
4592 : " FROM wire_out"
4593 : " WHERE wire_target_h_payto=$1"
4594 : " AND execution_date >= $2"
4595 : " ORDER BY execution_date DESC",
4596 : 2),
4597 :
4598 : /* Used in #postgres_select_merge_amounts_for_kyc_check (
4599 : () */
4600 0 : GNUNET_PQ_make_prepare (
4601 : "select_kyc_relevant_merge_events",
4602 : "SELECT"
4603 : " amount_with_fee_val AS amount_val"
4604 : ",amount_with_fee_frac AS amount_frac"
4605 : ",merge_timestamp AS date"
4606 : " FROM account_merges"
4607 : " JOIN purse_merges USING (purse_pub)"
4608 : " JOIN purse_requests USING (purse_pub)"
4609 : " WHERE wallet_h_payto=$1"
4610 : " AND merge_timestamp >= $2"
4611 : " AND finished"
4612 : " ORDER BY merge_timestamp DESC",
4613 : 2),
4614 :
4615 : GNUNET_PQ_PREPARED_STATEMENT_END
4616 : };
4617 :
4618 0 : ret = GNUNET_PQ_prepare_statements (pg->conn,
4619 : ps);
4620 0 : if (GNUNET_OK != ret)
4621 0 : return ret;
4622 0 : pg->init = true;
4623 0 : return GNUNET_OK;
4624 : }
4625 :
4626 :
4627 : /**
4628 : * Connect to the database if the connection does not exist yet.
4629 : *
4630 : * @param pg the plugin-specific state
4631 : * @param skip_prepare true if we should skip prepared statement setup
4632 : * @return #GNUNET_OK on success
4633 : */
4634 : static enum GNUNET_GenericReturnValue
4635 21 : internal_setup (struct PostgresClosure *pg,
4636 : bool skip_prepare)
4637 : {
4638 21 : if (NULL == pg->conn)
4639 : {
4640 : #if AUTO_EXPLAIN
4641 : /* Enable verbose logging to see where queries do not
4642 : properly use indices */
4643 21 : struct GNUNET_PQ_ExecuteStatement es[] = {
4644 21 : GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
4645 21 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
4646 21 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
4647 21 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
4648 : /* https://wiki.postgresql.org/wiki/Serializable suggests to really
4649 : force the default to 'serializable' if SSI is to be used. */
4650 21 : GNUNET_PQ_make_try_execute (
4651 : "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
4652 21 : GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
4653 21 : GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
4654 21 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
4655 : GNUNET_PQ_EXECUTE_STATEMENT_END
4656 : };
4657 : #else
4658 : struct GNUNET_PQ_ExecuteStatement es[] = {
4659 : GNUNET_PQ_make_try_execute (
4660 : "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
4661 : GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
4662 : GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
4663 : GNUNET_PQ_make_try_execute ("SET autocommit=OFF;"),
4664 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
4665 : GNUNET_PQ_EXECUTE_STATEMENT_END
4666 : };
4667 : #endif
4668 : struct GNUNET_PQ_Context *db_conn;
4669 :
4670 21 : db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
4671 : "exchangedb-postgres",
4672 : NULL,
4673 : es,
4674 : NULL);
4675 21 : if (NULL == db_conn)
4676 21 : return GNUNET_SYSERR;
4677 0 : pg->conn = db_conn;
4678 : }
4679 0 : if (NULL == pg->transaction_name)
4680 0 : GNUNET_PQ_reconnect_if_down (pg->conn);
4681 0 : if (pg->init)
4682 0 : return GNUNET_OK;
4683 0 : if (skip_prepare)
4684 0 : return GNUNET_OK;
4685 0 : return prepare_statements (pg);
4686 : }
4687 :
4688 :
4689 : /**
4690 : * Do a pre-flight check that we are not in an uncommitted transaction.
4691 : * If we are, try to commit the previous transaction and output a warning.
4692 : * Does not return anything, as we will continue regardless of the outcome.
4693 : *
4694 : * @param cls the `struct PostgresClosure` with the plugin-specific state
4695 : * @return #GNUNET_OK if everything is fine
4696 : * #GNUNET_NO if a transaction was rolled back
4697 : * #GNUNET_SYSERR on hard errors
4698 : */
4699 : static enum GNUNET_GenericReturnValue
4700 0 : postgres_preflight (void *cls)
4701 : {
4702 0 : struct PostgresClosure *pg = cls;
4703 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
4704 0 : GNUNET_PQ_make_execute ("ROLLBACK"),
4705 : GNUNET_PQ_EXECUTE_STATEMENT_END
4706 : };
4707 :
4708 0 : if (! pg->init)
4709 : {
4710 0 : if (GNUNET_OK !=
4711 0 : internal_setup (pg,
4712 : false))
4713 0 : return GNUNET_SYSERR;
4714 : }
4715 0 : if (NULL == pg->transaction_name)
4716 0 : return GNUNET_OK; /* all good */
4717 0 : if (GNUNET_OK ==
4718 0 : GNUNET_PQ_exec_statements (pg->conn,
4719 : es))
4720 : {
4721 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4722 : "BUG: Preflight check rolled back transaction `%s'!\n",
4723 : pg->transaction_name);
4724 : }
4725 : else
4726 : {
4727 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4728 : "BUG: Preflight check failed to rollback transaction `%s'!\n",
4729 : pg->transaction_name);
4730 : }
4731 0 : pg->transaction_name = NULL;
4732 0 : return GNUNET_NO;
4733 : }
4734 :
4735 :
4736 : /**
4737 : * Start a transaction.
4738 : *
4739 : * @param cls the `struct PostgresClosure` with the plugin-specific state
4740 : * @param name unique name identifying the transaction (for debugging)
4741 : * must point to a constant
4742 : * @return #GNUNET_OK on success
4743 : */
4744 : static enum GNUNET_GenericReturnValue
4745 0 : postgres_start (void *cls,
4746 : const char *name)
4747 : {
4748 0 : struct PostgresClosure *pg = cls;
4749 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
4750 0 : GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
4751 : GNUNET_PQ_EXECUTE_STATEMENT_END
4752 : };
4753 :
4754 0 : GNUNET_assert (NULL != name);
4755 0 : if (GNUNET_SYSERR ==
4756 0 : postgres_preflight (pg))
4757 0 : return GNUNET_SYSERR;
4758 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4759 : "Starting transaction `%s'\n",
4760 : name);
4761 0 : if (GNUNET_OK !=
4762 0 : GNUNET_PQ_exec_statements (pg->conn,
4763 : es))
4764 : {
4765 0 : TALER_LOG_ERROR ("Failed to start transaction\n");
4766 0 : GNUNET_break (0);
4767 0 : return GNUNET_SYSERR;
4768 : }
4769 0 : pg->transaction_name = name;
4770 0 : return GNUNET_OK;
4771 : }
4772 :
4773 :
4774 : /**
4775 : * Start a READ COMMITTED transaction.
4776 : *
4777 : * @param cls the `struct PostgresClosure` with the plugin-specific state
4778 : * @param name unique name identifying the transaction (for debugging)
4779 : * must point to a constant
4780 : * @return #GNUNET_OK on success
4781 : */
4782 : static enum GNUNET_GenericReturnValue
4783 0 : postgres_start_read_committed (void *cls,
4784 : const char *name)
4785 : {
4786 0 : struct PostgresClosure *pg = cls;
4787 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
4788 0 : GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL READ COMMITTED"),
4789 : GNUNET_PQ_EXECUTE_STATEMENT_END
4790 : };
4791 :
4792 0 : GNUNET_assert (NULL != name);
4793 0 : if (GNUNET_SYSERR ==
4794 0 : postgres_preflight (pg))
4795 0 : return GNUNET_SYSERR;
4796 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4797 : "Starting READ COMMITTED transaction `%s`\n",
4798 : name);
4799 0 : if (GNUNET_OK !=
4800 0 : GNUNET_PQ_exec_statements (pg->conn,
4801 : es))
4802 : {
4803 0 : TALER_LOG_ERROR ("Failed to start transaction\n");
4804 0 : GNUNET_break (0);
4805 0 : return GNUNET_SYSERR;
4806 : }
4807 0 : pg->transaction_name = name;
4808 0 : return GNUNET_OK;
4809 : }
4810 :
4811 :
4812 : /**
4813 : * Start a READ ONLY serializable transaction.
4814 : *
4815 : * @param cls the `struct PostgresClosure` with the plugin-specific state
4816 : * @param name unique name identifying the transaction (for debugging)
4817 : * must point to a constant
4818 : * @return #GNUNET_OK on success
4819 : */
4820 : static enum GNUNET_GenericReturnValue
4821 0 : postgres_start_read_only (void *cls,
4822 : const char *name)
4823 : {
4824 0 : struct PostgresClosure *pg = cls;
4825 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
4826 0 : GNUNET_PQ_make_execute (
4827 : "START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY"),
4828 : GNUNET_PQ_EXECUTE_STATEMENT_END
4829 : };
4830 :
4831 0 : GNUNET_assert (NULL != name);
4832 0 : if (GNUNET_SYSERR ==
4833 0 : postgres_preflight (pg))
4834 0 : return GNUNET_SYSERR;
4835 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4836 : "Starting READ ONLY transaction `%s`\n",
4837 : name);
4838 0 : if (GNUNET_OK !=
4839 0 : GNUNET_PQ_exec_statements (pg->conn,
4840 : es))
4841 : {
4842 0 : TALER_LOG_ERROR ("Failed to start transaction\n");
4843 0 : GNUNET_break (0);
4844 0 : return GNUNET_SYSERR;
4845 : }
4846 0 : pg->transaction_name = name;
4847 0 : return GNUNET_OK;
4848 : }
4849 :
4850 :
4851 : /**
4852 : * Roll back the current transaction of a database connection.
4853 : *
4854 : * @param cls the `struct PostgresClosure` with the plugin-specific state
4855 : */
4856 : static void
4857 0 : postgres_rollback (void *cls)
4858 : {
4859 0 : struct PostgresClosure *pg = cls;
4860 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
4861 0 : GNUNET_PQ_make_execute ("ROLLBACK"),
4862 : GNUNET_PQ_EXECUTE_STATEMENT_END
4863 : };
4864 :
4865 0 : if (NULL == pg->transaction_name)
4866 : {
4867 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4868 : "Skipping rollback, no transaction active\n");
4869 0 : return;
4870 : }
4871 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4872 : "Rolling back transaction\n");
4873 0 : GNUNET_break (GNUNET_OK ==
4874 : GNUNET_PQ_exec_statements (pg->conn,
4875 : es));
4876 0 : pg->transaction_name = NULL;
4877 : }
4878 :
4879 :
4880 : /**
4881 : * Commit the current transaction of a database connection.
4882 : *
4883 : * @param cls the `struct PostgresClosure` with the plugin-specific state
4884 : * @return final transaction status
4885 : */
4886 : static enum GNUNET_DB_QueryStatus
4887 0 : postgres_commit (void *cls)
4888 : {
4889 0 : struct PostgresClosure *pg = cls;
4890 0 : struct GNUNET_PQ_QueryParam params[] = {
4891 : GNUNET_PQ_query_param_end
4892 : };
4893 : enum GNUNET_DB_QueryStatus qs;
4894 :
4895 0 : GNUNET_break (NULL != pg->transaction_name);
4896 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4897 : "Committing transaction `%s'\n",
4898 : pg->transaction_name);
4899 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
4900 : "do_commit",
4901 : params);
4902 0 : pg->transaction_name = NULL;
4903 0 : return qs;
4904 : }
4905 :
4906 :
4907 : /**
4908 : * Register callback to be invoked on events of type @a es.
4909 : *
4910 : * @param cls database context to use
4911 : * @param timeout how long until to generate a timeout event
4912 : * @param es specification of the event to listen for
4913 : * @param cb function to call when the event happens, possibly
4914 : * multiple times (until cancel is invoked)
4915 : * @param cb_cls closure for @a cb
4916 : * @return handle useful to cancel the listener
4917 : */
4918 : static struct GNUNET_DB_EventHandler *
4919 0 : postgres_event_listen (void *cls,
4920 : struct GNUNET_TIME_Relative timeout,
4921 : const struct GNUNET_DB_EventHeaderP *es,
4922 : GNUNET_DB_EventCallback cb,
4923 : void *cb_cls)
4924 : {
4925 0 : struct PostgresClosure *pg = cls;
4926 :
4927 0 : return GNUNET_PQ_event_listen (pg->conn,
4928 : es,
4929 : timeout,
4930 : cb,
4931 : cb_cls);
4932 : }
4933 :
4934 :
4935 : /**
4936 : * Stop notifications.
4937 : *
4938 : * @param cls the plugin's `struct PostgresClosure`
4939 : * @param eh handle to unregister.
4940 : */
4941 : static void
4942 0 : postgres_event_listen_cancel (void *cls,
4943 : struct GNUNET_DB_EventHandler *eh)
4944 : {
4945 : (void) cls;
4946 0 : GNUNET_PQ_event_listen_cancel (eh);
4947 0 : }
4948 :
4949 :
4950 : /**
4951 : * Notify all that listen on @a es of an event.
4952 : *
4953 : * @param cls database context to use
4954 : * @param es specification of the event to generate
4955 : * @param extra additional event data provided
4956 : * @param extra_size number of bytes in @a extra
4957 : */
4958 : static void
4959 0 : postgres_event_notify (void *cls,
4960 : const struct GNUNET_DB_EventHeaderP *es,
4961 : const void *extra,
4962 : size_t extra_size)
4963 : {
4964 0 : struct PostgresClosure *pg = cls;
4965 :
4966 0 : GNUNET_PQ_event_notify (pg->conn,
4967 : es,
4968 : extra,
4969 : extra_size);
4970 0 : }
4971 :
4972 :
4973 : /**
4974 : * Insert a denomination key's public information into the database for
4975 : * reference by auditors and other consistency checks.
4976 : *
4977 : * @param cls the @e cls of this struct with the plugin-specific state
4978 : * @param denom_pub the public key used for signing coins of this denomination
4979 : * @param issue issuing information with value, fees and other info about the coin
4980 : * @return status of the query
4981 : */
4982 : static enum GNUNET_DB_QueryStatus
4983 0 : postgres_insert_denomination_info (
4984 : void *cls,
4985 : const struct TALER_DenominationPublicKey *denom_pub,
4986 : const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
4987 : {
4988 0 : struct PostgresClosure *pg = cls;
4989 : struct TALER_DenominationHashP denom_hash;
4990 0 : struct GNUNET_PQ_QueryParam params[] = {
4991 0 : GNUNET_PQ_query_param_auto_from_type (&issue->denom_hash),
4992 0 : TALER_PQ_query_param_denom_pub (denom_pub),
4993 0 : GNUNET_PQ_query_param_auto_from_type (&issue->signature),
4994 0 : GNUNET_PQ_query_param_timestamp (&issue->start),
4995 0 : GNUNET_PQ_query_param_timestamp (&issue->expire_withdraw),
4996 0 : GNUNET_PQ_query_param_timestamp (&issue->expire_deposit),
4997 0 : GNUNET_PQ_query_param_timestamp (&issue->expire_legal),
4998 0 : TALER_PQ_query_param_amount (&issue->value),
4999 0 : TALER_PQ_query_param_amount (&issue->fees.withdraw),
5000 0 : TALER_PQ_query_param_amount (&issue->fees.deposit),
5001 0 : TALER_PQ_query_param_amount (&issue->fees.refresh),
5002 0 : TALER_PQ_query_param_amount (&issue->fees.refund),
5003 0 : GNUNET_PQ_query_param_uint32 (&denom_pub->age_mask.bits),
5004 : GNUNET_PQ_query_param_end
5005 : };
5006 :
5007 0 : GNUNET_assert (denom_pub->age_mask.bits ==
5008 : issue->age_mask.bits);
5009 0 : TALER_denom_pub_hash (denom_pub,
5010 : &denom_hash);
5011 0 : GNUNET_assert (0 ==
5012 : GNUNET_memcmp (&denom_hash,
5013 : &issue->denom_hash));
5014 0 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
5015 : issue->start.abs_time));
5016 0 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
5017 : issue->expire_withdraw.abs_time));
5018 0 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
5019 : issue->expire_deposit.abs_time));
5020 0 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
5021 : issue->expire_legal.abs_time));
5022 : /* check fees match denomination currency */
5023 0 : GNUNET_assert (GNUNET_YES ==
5024 : TALER_denom_fee_check_currency (
5025 : issue->value.currency,
5026 : &issue->fees));
5027 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
5028 : "denomination_insert",
5029 : params);
5030 : }
5031 :
5032 :
5033 : /**
5034 : * Fetch information about a denomination key.
5035 : *
5036 : * @param cls the @e cls of this struct with the plugin-specific state
5037 : * @param denom_pub_hash hash of the public key used for signing coins of this denomination
5038 : * @param[out] issue set to issue information with value, fees and other info about the coin
5039 : * @return transaction status code
5040 : */
5041 : static enum GNUNET_DB_QueryStatus
5042 0 : postgres_get_denomination_info (
5043 : void *cls,
5044 : const struct TALER_DenominationHashP *denom_pub_hash,
5045 : struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
5046 : {
5047 0 : struct PostgresClosure *pg = cls;
5048 : enum GNUNET_DB_QueryStatus qs;
5049 0 : struct GNUNET_PQ_QueryParam params[] = {
5050 0 : GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
5051 : GNUNET_PQ_query_param_end
5052 : };
5053 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5054 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
5055 : &issue->signature),
5056 0 : GNUNET_PQ_result_spec_timestamp ("valid_from",
5057 : &issue->start),
5058 0 : GNUNET_PQ_result_spec_timestamp ("expire_withdraw",
5059 : &issue->expire_withdraw),
5060 0 : GNUNET_PQ_result_spec_timestamp ("expire_deposit",
5061 : &issue->expire_deposit),
5062 0 : GNUNET_PQ_result_spec_timestamp ("expire_legal",
5063 : &issue->expire_legal),
5064 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("coin",
5065 : &issue->value),
5066 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
5067 : &issue->fees.withdraw),
5068 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
5069 : &issue->fees.deposit),
5070 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
5071 : &issue->fees.refresh),
5072 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
5073 : &issue->fees.refund),
5074 0 : GNUNET_PQ_result_spec_uint32 ("age_mask",
5075 : &issue->age_mask.bits),
5076 : GNUNET_PQ_result_spec_end
5077 : };
5078 :
5079 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
5080 : "denomination_get",
5081 : params,
5082 : rs);
5083 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
5084 0 : return qs;
5085 0 : issue->denom_hash = *denom_pub_hash;
5086 0 : return qs;
5087 : }
5088 :
5089 :
5090 : /**
5091 : * Closure for #domination_cb_helper()
5092 : */
5093 : struct DenomIteratorContext
5094 : {
5095 : /**
5096 : * Function to call with the results.
5097 : */
5098 : TALER_EXCHANGEDB_DenominationCallback cb;
5099 :
5100 : /**
5101 : * Closure to pass to @e cb
5102 : */
5103 : void *cb_cls;
5104 :
5105 : /**
5106 : * Plugin context.
5107 : */
5108 : struct PostgresClosure *pg;
5109 : };
5110 :
5111 :
5112 : /**
5113 : * Helper function for #postgres_iterate_denomination_info().
5114 : * Calls the callback with each denomination key.
5115 : *
5116 : * @param cls a `struct DenomIteratorContext`
5117 : * @param result db results
5118 : * @param num_results number of results in @a result
5119 : */
5120 : static void
5121 0 : domination_cb_helper (void *cls,
5122 : PGresult *result,
5123 : unsigned int num_results)
5124 : {
5125 0 : struct DenomIteratorContext *dic = cls;
5126 0 : struct PostgresClosure *pg = dic->pg;
5127 :
5128 0 : for (unsigned int i = 0; i<num_results; i++)
5129 : {
5130 : struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
5131 : struct TALER_DenominationPublicKey denom_pub;
5132 : struct TALER_DenominationHashP denom_hash;
5133 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5134 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
5135 : &issue.signature),
5136 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
5137 : &denom_hash),
5138 0 : GNUNET_PQ_result_spec_timestamp ("valid_from",
5139 : &issue.start),
5140 0 : GNUNET_PQ_result_spec_timestamp ("expire_withdraw",
5141 : &issue.expire_withdraw),
5142 0 : GNUNET_PQ_result_spec_timestamp ("expire_deposit",
5143 : &issue.expire_deposit),
5144 0 : GNUNET_PQ_result_spec_timestamp ("expire_legal",
5145 : &issue.expire_legal),
5146 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("coin",
5147 : &issue.value),
5148 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
5149 : &issue.fees.withdraw),
5150 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
5151 : &issue.fees.deposit),
5152 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
5153 : &issue.fees.refresh),
5154 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
5155 : &issue.fees.refund),
5156 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
5157 : &denom_pub),
5158 0 : GNUNET_PQ_result_spec_uint32 ("age_mask",
5159 : &issue.age_mask.bits),
5160 : GNUNET_PQ_result_spec_end
5161 : };
5162 :
5163 0 : if (GNUNET_OK !=
5164 0 : GNUNET_PQ_extract_result (result,
5165 : rs,
5166 : i))
5167 : {
5168 0 : GNUNET_break (0);
5169 0 : return;
5170 : }
5171 :
5172 : /* Unfortunately we have to carry the age mask in both, the
5173 : * TALER_DenominationPublicKey and
5174 : * TALER_EXCHANGEDB_DenominationKeyInformation at different times.
5175 : * Here we use _both_ so let's make sure the values are the same. */
5176 0 : denom_pub.age_mask = issue.age_mask;
5177 0 : TALER_denom_pub_hash (&denom_pub,
5178 : &issue.denom_hash);
5179 0 : if (0 !=
5180 0 : GNUNET_memcmp (&issue.denom_hash,
5181 : &denom_hash))
5182 : {
5183 0 : GNUNET_break (0);
5184 : }
5185 : else
5186 : {
5187 0 : dic->cb (dic->cb_cls,
5188 : &denom_pub,
5189 : &issue);
5190 : }
5191 0 : TALER_denom_pub_free (&denom_pub);
5192 : }
5193 : }
5194 :
5195 :
5196 : /**
5197 : * Fetch information about all known denomination keys.
5198 : *
5199 : * @param cls the @e cls of this struct with the plugin-specific state
5200 : * @param cb function to call on each denomination key
5201 : * @param cb_cls closure for @a cb
5202 : * @return transaction status code
5203 : */
5204 : static enum GNUNET_DB_QueryStatus
5205 0 : postgres_iterate_denomination_info (void *cls,
5206 : TALER_EXCHANGEDB_DenominationCallback cb,
5207 : void *cb_cls)
5208 : {
5209 0 : struct PostgresClosure *pg = cls;
5210 0 : struct GNUNET_PQ_QueryParam params[] = {
5211 : GNUNET_PQ_query_param_end
5212 : };
5213 0 : struct DenomIteratorContext dic = {
5214 : .cb = cb,
5215 : .cb_cls = cb_cls,
5216 : .pg = pg
5217 : };
5218 :
5219 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
5220 : "denomination_iterate",
5221 : params,
5222 : &domination_cb_helper,
5223 : &dic);
5224 : }
5225 :
5226 :
5227 : /**
5228 : * Closure for #dominations_cb_helper()
5229 : */
5230 : struct DenomsIteratorContext
5231 : {
5232 : /**
5233 : * Function to call with the results.
5234 : */
5235 : TALER_EXCHANGEDB_DenominationsCallback cb;
5236 :
5237 : /**
5238 : * Closure to pass to @e cb
5239 : */
5240 : void *cb_cls;
5241 :
5242 : /**
5243 : * Plugin context.
5244 : */
5245 : struct PostgresClosure *pg;
5246 : };
5247 :
5248 :
5249 : /**
5250 : * Helper function for #postgres_iterate_denominations().
5251 : * Calls the callback with each denomination key.
5252 : *
5253 : * @param cls a `struct DenomsIteratorContext`
5254 : * @param result db results
5255 : * @param num_results number of results in @a result
5256 : */
5257 : static void
5258 0 : dominations_cb_helper (void *cls,
5259 : PGresult *result,
5260 : unsigned int num_results)
5261 : {
5262 0 : struct DenomsIteratorContext *dic = cls;
5263 0 : struct PostgresClosure *pg = dic->pg;
5264 :
5265 0 : for (unsigned int i = 0; i<num_results; i++)
5266 : {
5267 0 : struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
5268 0 : struct TALER_DenominationPublicKey denom_pub = {0};
5269 0 : struct TALER_MasterSignatureP master_sig = {0};
5270 0 : struct TALER_DenominationHashP h_denom_pub = {0};
5271 : bool revoked;
5272 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5273 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
5274 : &master_sig),
5275 0 : GNUNET_PQ_result_spec_bool ("revoked",
5276 : &revoked),
5277 0 : GNUNET_PQ_result_spec_timestamp ("valid_from",
5278 : &meta.start),
5279 0 : GNUNET_PQ_result_spec_timestamp ("expire_withdraw",
5280 : &meta.expire_withdraw),
5281 0 : GNUNET_PQ_result_spec_timestamp ("expire_deposit",
5282 : &meta.expire_deposit),
5283 0 : GNUNET_PQ_result_spec_timestamp ("expire_legal",
5284 : &meta.expire_legal),
5285 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("coin",
5286 : &meta.value),
5287 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
5288 : &meta.fees.withdraw),
5289 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
5290 : &meta.fees.deposit),
5291 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
5292 : &meta.fees.refresh),
5293 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
5294 : &meta.fees.refund),
5295 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
5296 : &denom_pub),
5297 0 : GNUNET_PQ_result_spec_uint32 ("age_mask",
5298 : &meta.age_mask.bits),
5299 : GNUNET_PQ_result_spec_end
5300 : };
5301 :
5302 0 : if (GNUNET_OK !=
5303 0 : GNUNET_PQ_extract_result (result,
5304 : rs,
5305 : i))
5306 : {
5307 0 : GNUNET_break (0);
5308 0 : return;
5309 : }
5310 :
5311 : /* make sure the mask information is the same */
5312 0 : denom_pub.age_mask = meta.age_mask;
5313 :
5314 0 : TALER_denom_pub_hash (&denom_pub,
5315 : &h_denom_pub);
5316 0 : dic->cb (dic->cb_cls,
5317 : &denom_pub,
5318 : &h_denom_pub,
5319 : &meta,
5320 : &master_sig,
5321 : revoked);
5322 0 : GNUNET_PQ_cleanup_result (rs);
5323 : }
5324 : }
5325 :
5326 :
5327 : /**
5328 : * Function called to invoke @a cb on every known denomination key (revoked
5329 : * and non-revoked) that has been signed by the master key. Runs in its own
5330 : * read-only transaction.
5331 : *
5332 : *
5333 : * @param cls the @e cls of this struct with the plugin-specific state
5334 : * @param cb function to call on each denomination key
5335 : * @param cb_cls closure for @a cb
5336 : * @return transaction status code
5337 : */
5338 : static enum GNUNET_DB_QueryStatus
5339 0 : postgres_iterate_denominations (void *cls,
5340 : TALER_EXCHANGEDB_DenominationsCallback cb,
5341 : void *cb_cls)
5342 : {
5343 0 : struct PostgresClosure *pg = cls;
5344 0 : struct GNUNET_PQ_QueryParam params[] = {
5345 : GNUNET_PQ_query_param_end
5346 : };
5347 0 : struct DenomsIteratorContext dic = {
5348 : .cb = cb,
5349 : .cb_cls = cb_cls,
5350 : .pg = pg
5351 : };
5352 :
5353 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
5354 : "select_denominations",
5355 : params,
5356 : &dominations_cb_helper,
5357 : &dic);
5358 : }
5359 :
5360 :
5361 : /**
5362 : * Closure for #signkeys_cb_helper()
5363 : */
5364 : struct SignkeysIteratorContext
5365 : {
5366 : /**
5367 : * Function to call with the results.
5368 : */
5369 : TALER_EXCHANGEDB_ActiveSignkeysCallback cb;
5370 :
5371 : /**
5372 : * Closure to pass to @e cb
5373 : */
5374 : void *cb_cls;
5375 :
5376 : };
5377 :
5378 :
5379 : /**
5380 : * Helper function for #postgres_iterate_active_signkeys().
5381 : * Calls the callback with each signkey.
5382 : *
5383 : * @param cls a `struct SignkeysIteratorContext`
5384 : * @param result db results
5385 : * @param num_results number of results in @a result
5386 : */
5387 : static void
5388 0 : signkeys_cb_helper (void *cls,
5389 : PGresult *result,
5390 : unsigned int num_results)
5391 : {
5392 0 : struct SignkeysIteratorContext *dic = cls;
5393 :
5394 0 : for (unsigned int i = 0; i<num_results; i++)
5395 : {
5396 : struct TALER_EXCHANGEDB_SignkeyMetaData meta;
5397 : struct TALER_ExchangePublicKeyP exchange_pub;
5398 : struct TALER_MasterSignatureP master_sig;
5399 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5400 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
5401 : &master_sig),
5402 0 : GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
5403 : &exchange_pub),
5404 0 : GNUNET_PQ_result_spec_timestamp ("valid_from",
5405 : &meta.start),
5406 0 : GNUNET_PQ_result_spec_timestamp ("expire_sign",
5407 : &meta.expire_sign),
5408 0 : GNUNET_PQ_result_spec_timestamp ("expire_legal",
5409 : &meta.expire_legal),
5410 : GNUNET_PQ_result_spec_end
5411 : };
5412 :
5413 0 : if (GNUNET_OK !=
5414 0 : GNUNET_PQ_extract_result (result,
5415 : rs,
5416 : i))
5417 : {
5418 0 : GNUNET_break (0);
5419 0 : return;
5420 : }
5421 0 : dic->cb (dic->cb_cls,
5422 : &exchange_pub,
5423 : &meta,
5424 : &master_sig);
5425 : }
5426 : }
5427 :
5428 :
5429 : /**
5430 : * Function called to invoke @a cb on every non-revoked exchange signing key
5431 : * that has been signed by the master key. Revoked and (for signing!)
5432 : * expired keys are skipped. Runs in its own read-only transaction.
5433 : *
5434 : * @param cls the @e cls of this struct with the plugin-specific state
5435 : * @param cb function to call on each signing key
5436 : * @param cb_cls closure for @a cb
5437 : * @return transaction status code
5438 : */
5439 : static enum GNUNET_DB_QueryStatus
5440 0 : postgres_iterate_active_signkeys (void *cls,
5441 : TALER_EXCHANGEDB_ActiveSignkeysCallback cb,
5442 : void *cb_cls)
5443 : {
5444 0 : struct PostgresClosure *pg = cls;
5445 0 : struct GNUNET_TIME_Absolute now = {0};
5446 0 : struct GNUNET_PQ_QueryParam params[] = {
5447 0 : GNUNET_PQ_query_param_absolute_time (&now),
5448 : GNUNET_PQ_query_param_end
5449 : };
5450 0 : struct SignkeysIteratorContext dic = {
5451 : .cb = cb,
5452 : .cb_cls = cb_cls,
5453 : };
5454 :
5455 0 : now = GNUNET_TIME_absolute_get ();
5456 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
5457 : "select_signkeys",
5458 : params,
5459 : &signkeys_cb_helper,
5460 : &dic);
5461 : }
5462 :
5463 :
5464 : /**
5465 : * Closure for #auditors_cb_helper()
5466 : */
5467 : struct AuditorsIteratorContext
5468 : {
5469 : /**
5470 : * Function to call with the results.
5471 : */
5472 : TALER_EXCHANGEDB_AuditorsCallback cb;
5473 :
5474 : /**
5475 : * Closure to pass to @e cb
5476 : */
5477 : void *cb_cls;
5478 :
5479 : };
5480 :
5481 :
5482 : /**
5483 : * Helper function for #postgres_iterate_active_auditors().
5484 : * Calls the callback with each auditor.
5485 : *
5486 : * @param cls a `struct SignkeysIteratorContext`
5487 : * @param result db results
5488 : * @param num_results number of results in @a result
5489 : */
5490 : static void
5491 0 : auditors_cb_helper (void *cls,
5492 : PGresult *result,
5493 : unsigned int num_results)
5494 : {
5495 0 : struct AuditorsIteratorContext *dic = cls;
5496 :
5497 0 : for (unsigned int i = 0; i<num_results; i++)
5498 : {
5499 : struct TALER_AuditorPublicKeyP auditor_pub;
5500 : char *auditor_url;
5501 : char *auditor_name;
5502 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5503 0 : GNUNET_PQ_result_spec_auto_from_type ("auditor_pub",
5504 : &auditor_pub),
5505 0 : GNUNET_PQ_result_spec_string ("auditor_url",
5506 : &auditor_url),
5507 0 : GNUNET_PQ_result_spec_string ("auditor_name",
5508 : &auditor_name),
5509 : GNUNET_PQ_result_spec_end
5510 : };
5511 :
5512 0 : if (GNUNET_OK !=
5513 0 : GNUNET_PQ_extract_result (result,
5514 : rs,
5515 : i))
5516 : {
5517 0 : GNUNET_break (0);
5518 0 : return;
5519 : }
5520 0 : dic->cb (dic->cb_cls,
5521 : &auditor_pub,
5522 : auditor_url,
5523 : auditor_name);
5524 0 : GNUNET_PQ_cleanup_result (rs);
5525 : }
5526 : }
5527 :
5528 :
5529 : /**
5530 : * Function called to invoke @a cb on every active auditor. Disabled
5531 : * auditors are skipped. Runs in its own read-only transaction.
5532 : *
5533 : * @param cls the @e cls of this struct with the plugin-specific state
5534 : * @param cb function to call on each active auditor
5535 : * @param cb_cls closure for @a cb
5536 : * @return transaction status code
5537 : */
5538 : static enum GNUNET_DB_QueryStatus
5539 0 : postgres_iterate_active_auditors (void *cls,
5540 : TALER_EXCHANGEDB_AuditorsCallback cb,
5541 : void *cb_cls)
5542 : {
5543 0 : struct PostgresClosure *pg = cls;
5544 0 : struct GNUNET_PQ_QueryParam params[] = {
5545 : GNUNET_PQ_query_param_end
5546 : };
5547 0 : struct AuditorsIteratorContext dic = {
5548 : .cb = cb,
5549 : .cb_cls = cb_cls,
5550 : };
5551 :
5552 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
5553 : "select_auditors",
5554 : params,
5555 : &auditors_cb_helper,
5556 : &dic);
5557 : }
5558 :
5559 :
5560 : /**
5561 : * Closure for #auditor_denoms_cb_helper()
5562 : */
5563 : struct AuditorDenomsIteratorContext
5564 : {
5565 : /**
5566 : * Function to call with the results.
5567 : */
5568 : TALER_EXCHANGEDB_AuditorDenominationsCallback cb;
5569 :
5570 : /**
5571 : * Closure to pass to @e cb
5572 : */
5573 : void *cb_cls;
5574 : };
5575 :
5576 :
5577 : /**
5578 : * Helper function for #postgres_iterate_auditor_denominations().
5579 : * Calls the callback with each auditor and denomination pair.
5580 : *
5581 : * @param cls a `struct AuditorDenomsIteratorContext`
5582 : * @param result db results
5583 : * @param num_results number of results in @a result
5584 : */
5585 : static void
5586 0 : auditor_denoms_cb_helper (void *cls,
5587 : PGresult *result,
5588 : unsigned int num_results)
5589 : {
5590 0 : struct AuditorDenomsIteratorContext *dic = cls;
5591 :
5592 0 : for (unsigned int i = 0; i<num_results; i++)
5593 : {
5594 : struct TALER_AuditorPublicKeyP auditor_pub;
5595 : struct TALER_DenominationHashP h_denom_pub;
5596 : struct TALER_AuditorSignatureP auditor_sig;
5597 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5598 0 : GNUNET_PQ_result_spec_auto_from_type ("auditor_pub",
5599 : &auditor_pub),
5600 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
5601 : &h_denom_pub),
5602 0 : GNUNET_PQ_result_spec_auto_from_type ("auditor_sig",
5603 : &auditor_sig),
5604 : GNUNET_PQ_result_spec_end
5605 : };
5606 :
5607 0 : if (GNUNET_OK !=
5608 0 : GNUNET_PQ_extract_result (result,
5609 : rs,
5610 : i))
5611 : {
5612 0 : GNUNET_break (0);
5613 0 : return;
5614 : }
5615 0 : dic->cb (dic->cb_cls,
5616 : &auditor_pub,
5617 : &h_denom_pub,
5618 : &auditor_sig);
5619 : }
5620 : }
5621 :
5622 :
5623 : /**
5624 : * Function called to invoke @a cb on every denomination with an active
5625 : * auditor. Disabled auditors and denominations without auditor are
5626 : * skipped. Runs in its own read-only transaction.
5627 : *
5628 : * @param cls the @e cls of this struct with the plugin-specific state
5629 : * @param cb function to call on each active auditor
5630 : * @param cb_cls closure for @a cb
5631 : * @return transaction status code
5632 : */
5633 : static enum GNUNET_DB_QueryStatus
5634 0 : postgres_iterate_auditor_denominations (
5635 : void *cls,
5636 : TALER_EXCHANGEDB_AuditorDenominationsCallback cb,
5637 : void *cb_cls)
5638 : {
5639 0 : struct PostgresClosure *pg = cls;
5640 0 : struct GNUNET_PQ_QueryParam params[] = {
5641 : GNUNET_PQ_query_param_end
5642 : };
5643 0 : struct AuditorDenomsIteratorContext dic = {
5644 : .cb = cb,
5645 : .cb_cls = cb_cls,
5646 : };
5647 :
5648 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
5649 : "select_auditor_denoms",
5650 : params,
5651 : &auditor_denoms_cb_helper,
5652 : &dic);
5653 : }
5654 :
5655 :
5656 : /**
5657 : * Get the summary of a reserve.
5658 : *
5659 : * @param cls the `struct PostgresClosure` with the plugin-specific state
5660 : * @param[in,out] reserve the reserve data. The public key of the reserve should be
5661 : * set in this structure; it is used to query the database. The balance
5662 : * and expiration are then filled accordingly.
5663 : * @return transaction status
5664 : */
5665 : static enum GNUNET_DB_QueryStatus
5666 0 : postgres_reserves_get (void *cls,
5667 : struct TALER_EXCHANGEDB_Reserve *reserve)
5668 : {
5669 0 : struct PostgresClosure *pg = cls;
5670 0 : struct GNUNET_PQ_QueryParam params[] = {
5671 0 : GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
5672 : GNUNET_PQ_query_param_end
5673 : };
5674 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5675 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
5676 : &reserve->balance),
5677 0 : GNUNET_PQ_result_spec_timestamp ("expiration_date",
5678 : &reserve->expiry),
5679 0 : GNUNET_PQ_result_spec_timestamp ("gc_date",
5680 : &reserve->gc),
5681 : GNUNET_PQ_result_spec_end
5682 : };
5683 :
5684 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
5685 : "reserves_get",
5686 : params,
5687 : rs);
5688 : }
5689 :
5690 :
5691 : /**
5692 : * Get the origin of funds of a reserve.
5693 : *
5694 : * @param cls the `struct PostgresClosure` with the plugin-specific state
5695 : * @param reserve_pub public key of the reserve
5696 : * @param[out] h_payto set to hash of the wire source payto://-URI
5697 : * @return transaction status
5698 : */
5699 : static enum GNUNET_DB_QueryStatus
5700 0 : postgres_reserves_get_origin (
5701 : void *cls,
5702 : const struct TALER_ReservePublicKeyP *reserve_pub,
5703 : struct TALER_PaytoHashP *h_payto)
5704 : {
5705 0 : struct PostgresClosure *pg = cls;
5706 0 : struct GNUNET_PQ_QueryParam params[] = {
5707 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
5708 : GNUNET_PQ_query_param_end
5709 : };
5710 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5711 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_source_h_payto",
5712 : h_payto),
5713 : GNUNET_PQ_result_spec_end
5714 : };
5715 :
5716 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
5717 : "get_h_wire_source_of_reserve",
5718 : params,
5719 : rs);
5720 : }
5721 :
5722 :
5723 : /**
5724 : * Extract next KYC alert. Deletes the alert.
5725 : *
5726 : * @param cls the @e cls of this struct with the plugin-specific state
5727 : * @param trigger_type which type of alert to drain
5728 : * @param[out] h_payto set to hash of payto-URI where KYC status changed
5729 : * @return transaction status
5730 : */
5731 : static enum GNUNET_DB_QueryStatus
5732 0 : postgres_drain_kyc_alert (void *cls,
5733 : uint32_t trigger_type,
5734 : struct TALER_PaytoHashP *h_payto)
5735 : {
5736 0 : struct PostgresClosure *pg = cls;
5737 0 : struct GNUNET_PQ_QueryParam params[] = {
5738 0 : GNUNET_PQ_query_param_uint32 (&trigger_type),
5739 : GNUNET_PQ_query_param_end
5740 : };
5741 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5742 0 : GNUNET_PQ_result_spec_auto_from_type ("h_payto",
5743 : h_payto),
5744 : GNUNET_PQ_result_spec_end
5745 : };
5746 :
5747 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
5748 : "drain_kyc_alert",
5749 : params,
5750 : rs);
5751 : }
5752 :
5753 :
5754 : /**
5755 : * Updates a reserve with the data from the given reserve structure.
5756 : *
5757 : * @param cls the `struct PostgresClosure` with the plugin-specific state
5758 : * @param reserve the reserve structure whose data will be used to update the
5759 : * corresponding record in the database.
5760 : * @return transaction status
5761 : */
5762 : static enum GNUNET_DB_QueryStatus
5763 0 : reserves_update (void *cls,
5764 : const struct TALER_EXCHANGEDB_Reserve *reserve)
5765 : {
5766 0 : struct PostgresClosure *pg = cls;
5767 0 : struct GNUNET_PQ_QueryParam params[] = {
5768 0 : GNUNET_PQ_query_param_timestamp (&reserve->expiry),
5769 0 : GNUNET_PQ_query_param_timestamp (&reserve->gc),
5770 0 : TALER_PQ_query_param_amount (&reserve->balance),
5771 0 : GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
5772 : GNUNET_PQ_query_param_end
5773 : };
5774 :
5775 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
5776 : "reserve_update",
5777 : params);
5778 : }
5779 :
5780 :
5781 : /**
5782 : * Setup new wire target for @a payto_uri.
5783 : *
5784 : * @param pg the plugin-specific state
5785 : * @param payto_uri the payto URI to check
5786 : * @param[out] h_payto set to the hash of @a payto_uri
5787 : * @return transaction status
5788 : */
5789 : static enum GNUNET_DB_QueryStatus
5790 0 : setup_wire_target (
5791 : struct PostgresClosure *pg,
5792 : const char *payto_uri,
5793 : struct TALER_PaytoHashP *h_payto)
5794 : {
5795 0 : struct GNUNET_PQ_QueryParam iparams[] = {
5796 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
5797 0 : GNUNET_PQ_query_param_string (payto_uri),
5798 : GNUNET_PQ_query_param_end
5799 : };
5800 :
5801 0 : TALER_payto_hash (payto_uri,
5802 : h_payto);
5803 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
5804 : "insert_kyc_status",
5805 : iparams);
5806 : }
5807 :
5808 :
5809 : /**
5810 : * Generate event notification for the reserve
5811 : * change.
5812 : *
5813 : * @param pg plugin state
5814 : * @param reserve_pub reserve to notfiy on
5815 : */
5816 : static void
5817 0 : notify_on_reserve (struct PostgresClosure *pg,
5818 : const struct TALER_ReservePublicKeyP *reserve_pub)
5819 : {
5820 0 : struct TALER_ReserveEventP rep = {
5821 0 : .header.size = htons (sizeof (rep)),
5822 0 : .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
5823 : .reserve_pub = *reserve_pub
5824 : };
5825 :
5826 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5827 : "Notifying on reserve!\n");
5828 0 : postgres_event_notify (pg,
5829 : &rep.header,
5830 : NULL,
5831 : 0);
5832 0 : }
5833 :
5834 :
5835 : /**
5836 : * Insert an incoming transaction into reserves. New reserves are also
5837 : * created through this function. Started within the scope of an ongoing
5838 : * transaction.
5839 : *
5840 : * @param cls the `struct PostgresClosure` with the plugin-specific state
5841 : * @param reserve_pub public key of the reserve
5842 : * @param balance the amount that has to be added to the reserve
5843 : * @param execution_time when was the amount added
5844 : * @param sender_account_details account information for the sender (payto://-URL)
5845 : * @param exchange_account_section name of the section in the configuration for the exchange's
5846 : * account into which the deposit was made
5847 : * @param wire_ref unique reference identifying the wire transfer
5848 : * @return transaction status code
5849 : */
5850 : static enum GNUNET_DB_QueryStatus
5851 0 : postgres_reserves_in_insert (void *cls,
5852 : const struct TALER_ReservePublicKeyP *reserve_pub,
5853 : const struct TALER_Amount *balance,
5854 : struct GNUNET_TIME_Timestamp execution_time,
5855 : const char *sender_account_details,
5856 : const char *exchange_account_section,
5857 : uint64_t wire_ref)
5858 : {
5859 0 : struct PostgresClosure *pg = cls;
5860 : enum GNUNET_DB_QueryStatus qs1;
5861 : struct TALER_EXCHANGEDB_Reserve reserve;
5862 : struct GNUNET_TIME_Timestamp expiry;
5863 : struct GNUNET_TIME_Timestamp gc;
5864 : uint64_t reserve_uuid;
5865 :
5866 0 : reserve.pub = *reserve_pub;
5867 0 : expiry = GNUNET_TIME_absolute_to_timestamp (
5868 : GNUNET_TIME_absolute_add (execution_time.abs_time,
5869 : pg->idle_reserve_expiration_time));
5870 0 : gc = GNUNET_TIME_absolute_to_timestamp (
5871 : GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
5872 : pg->legal_reserve_expiration_time));
5873 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5874 : "Creating reserve %s with expiration in %s\n",
5875 : TALER_B2S (reserve_pub),
5876 : GNUNET_STRINGS_relative_time_to_string (
5877 : pg->idle_reserve_expiration_time,
5878 : GNUNET_NO));
5879 : /* Optimistically assume this is a new reserve, create balance for the first
5880 : time; we do this before adding the actual transaction to "reserves_in",
5881 : as for a new reserve it can't be a duplicate 'add' operation, and as
5882 : the 'add' operation needs the reserve entry as a foreign key. */
5883 : {
5884 0 : struct GNUNET_PQ_QueryParam params[] = {
5885 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
5886 0 : TALER_PQ_query_param_amount (balance),
5887 0 : GNUNET_PQ_query_param_timestamp (&expiry),
5888 0 : GNUNET_PQ_query_param_timestamp (&gc),
5889 : GNUNET_PQ_query_param_end
5890 : };
5891 0 : struct GNUNET_PQ_ResultSpec rs[] = {
5892 0 : GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
5893 : &reserve_uuid),
5894 : GNUNET_PQ_result_spec_end
5895 : };
5896 :
5897 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5898 : "Reserve does not exist; creating a new one\n");
5899 : /* Note: query uses 'on conflict do nothing' */
5900 0 : qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
5901 : "reserve_create",
5902 : params,
5903 : rs);
5904 0 : if (qs1 < 0)
5905 0 : return qs1;
5906 : }
5907 :
5908 : /* Create new incoming transaction, "ON CONFLICT DO NOTHING"
5909 : is again used to guard against duplicates. */
5910 : {
5911 : enum GNUNET_DB_QueryStatus qs2;
5912 : enum GNUNET_DB_QueryStatus qs3;
5913 : struct TALER_PaytoHashP h_payto;
5914 :
5915 0 : qs3 = setup_wire_target (pg,
5916 : sender_account_details,
5917 : &h_payto);
5918 0 : if (qs3 < 0)
5919 0 : return qs3;
5920 : /* We do not have the UUID, so insert by public key */
5921 0 : struct GNUNET_PQ_QueryParam params[] = {
5922 0 : GNUNET_PQ_query_param_auto_from_type (&reserve.pub),
5923 0 : GNUNET_PQ_query_param_uint64 (&wire_ref),
5924 0 : TALER_PQ_query_param_amount (balance),
5925 0 : GNUNET_PQ_query_param_string (exchange_account_section),
5926 0 : GNUNET_PQ_query_param_auto_from_type (&h_payto),
5927 0 : GNUNET_PQ_query_param_timestamp (&execution_time),
5928 : GNUNET_PQ_query_param_end
5929 : };
5930 :
5931 0 : qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
5932 : "reserves_in_add_transaction",
5933 : params);
5934 : /* qs2 could be 0 as statement used 'ON CONFLICT DO NOTHING' */
5935 0 : if (0 >= qs2)
5936 : {
5937 0 : if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs2) &&
5938 : (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1) )
5939 : {
5940 : /* Conflict for the transaction, but the reserve was
5941 : just now created, that should be impossible. */
5942 0 : GNUNET_break (0); /* should be impossible: reserve was fresh,
5943 : but transaction already known */
5944 0 : return GNUNET_DB_STATUS_HARD_ERROR;
5945 : }
5946 : /* Transaction was already known or error. We are finished. */
5947 0 : return qs2;
5948 : }
5949 : }
5950 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs1)
5951 : {
5952 : /* New reserve, we are finished */
5953 0 : notify_on_reserve (pg,
5954 : reserve_pub);
5955 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
5956 : }
5957 :
5958 : /* we were wrong with our optimistic assumption:
5959 : reserve did already exist, need to do an update instead */
5960 : {
5961 : /* We need to move away from 'read committed' to serializable.
5962 : Also, we know that it should be safe to commit at this point.
5963 : (We are only run in a larger transaction for performance.) */
5964 : enum GNUNET_DB_QueryStatus cs;
5965 :
5966 0 : cs = postgres_commit (pg);
5967 0 : if (cs < 0)
5968 0 : return cs;
5969 0 : if (GNUNET_OK !=
5970 0 : postgres_start (pg,
5971 : "reserve-update-serializable"))
5972 : {
5973 0 : GNUNET_break (0);
5974 0 : return GNUNET_DB_STATUS_HARD_ERROR;
5975 : }
5976 : }
5977 : {
5978 : enum GNUNET_DB_QueryStatus reserve_exists;
5979 :
5980 0 : reserve_exists = postgres_reserves_get (pg,
5981 : &reserve);
5982 0 : switch (reserve_exists)
5983 : {
5984 0 : case GNUNET_DB_STATUS_HARD_ERROR:
5985 0 : GNUNET_break (0);
5986 0 : return reserve_exists;
5987 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
5988 0 : return reserve_exists;
5989 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
5990 : /* First we got a conflict, but then we cannot select? Very strange. */
5991 0 : GNUNET_break (0);
5992 0 : return GNUNET_DB_STATUS_SOFT_ERROR;
5993 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
5994 : /* continued below */
5995 0 : break;
5996 : }
5997 0 : }
5998 :
5999 : {
6000 : struct TALER_EXCHANGEDB_Reserve updated_reserve;
6001 : enum GNUNET_DB_QueryStatus qs3;
6002 :
6003 : /* If the reserve already existed, we need to still update the
6004 : balance; we do this after checking for duplication, as
6005 : otherwise we might have to actually pay the cost to roll this
6006 : back for duplicate transactions; like this, we should virtually
6007 : never actually have to rollback anything. */
6008 0 : updated_reserve.pub = reserve.pub;
6009 0 : if (0 >
6010 0 : TALER_amount_add (&updated_reserve.balance,
6011 : &reserve.balance,
6012 : balance))
6013 : {
6014 : /* currency overflow or incompatible currency */
6015 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6016 : "Attempt to deposit incompatible amount into reserve\n");
6017 0 : return GNUNET_DB_STATUS_HARD_ERROR;
6018 : }
6019 0 : updated_reserve.expiry = GNUNET_TIME_timestamp_max (expiry,
6020 : reserve.expiry);
6021 0 : updated_reserve.gc = GNUNET_TIME_timestamp_max (gc,
6022 : reserve.gc);
6023 0 : qs3 = reserves_update (pg,
6024 : &updated_reserve);
6025 0 : switch (qs3)
6026 : {
6027 0 : case GNUNET_DB_STATUS_HARD_ERROR:
6028 0 : GNUNET_break (0);
6029 0 : return qs3;
6030 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
6031 0 : return qs3;
6032 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
6033 : /* How can the UPDATE not work here? Very strange. */
6034 0 : GNUNET_break (0);
6035 0 : return GNUNET_DB_STATUS_HARD_ERROR;
6036 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
6037 : /* continued below */
6038 0 : break;
6039 : }
6040 0 : }
6041 0 : notify_on_reserve (pg,
6042 : reserve_pub);
6043 : /* Go back to original transaction mode */
6044 : {
6045 : enum GNUNET_DB_QueryStatus cs;
6046 :
6047 0 : cs = postgres_commit (pg);
6048 0 : if (cs < 0)
6049 0 : return cs;
6050 0 : if (GNUNET_OK !=
6051 0 : postgres_start_read_committed (pg,
6052 : "reserve-insert-continued"))
6053 : {
6054 0 : GNUNET_break (0);
6055 0 : return GNUNET_DB_STATUS_HARD_ERROR;
6056 : }
6057 : }
6058 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
6059 : }
6060 :
6061 :
6062 : /**
6063 : * Locate the response for a /reserve/withdraw request under the
6064 : * key of the hash of the blinded message.
6065 : *
6066 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6067 : * @param bch hash that uniquely identifies the withdraw operation
6068 : * @param collectable corresponding collectable coin (blind signature)
6069 : * if a coin is found
6070 : * @return statement execution status
6071 : */
6072 : static enum GNUNET_DB_QueryStatus
6073 0 : postgres_get_withdraw_info (
6074 : void *cls,
6075 : const struct TALER_BlindedCoinHashP *bch,
6076 : struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
6077 : {
6078 0 : struct PostgresClosure *pg = cls;
6079 0 : struct GNUNET_PQ_QueryParam params[] = {
6080 0 : GNUNET_PQ_query_param_auto_from_type (bch),
6081 : GNUNET_PQ_query_param_end
6082 : };
6083 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6084 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
6085 : &collectable->denom_pub_hash),
6086 0 : TALER_PQ_result_spec_blinded_denom_sig ("denom_sig",
6087 : &collectable->sig),
6088 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
6089 : &collectable->reserve_sig),
6090 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
6091 : &collectable->reserve_pub),
6092 0 : GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
6093 : &collectable->h_coin_envelope),
6094 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
6095 : &collectable->amount_with_fee),
6096 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
6097 : &collectable->withdraw_fee),
6098 : GNUNET_PQ_result_spec_end
6099 : };
6100 :
6101 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6102 : "get_withdraw_info",
6103 : params,
6104 : rs);
6105 : }
6106 :
6107 :
6108 : /**
6109 : * Perform withdraw operation, checking for sufficient balance
6110 : * and possibly persisting the withdrawal details.
6111 : *
6112 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6113 : * @param nonce client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
6114 : * @param[in,out] collectable corresponding collectable coin (blind signature) if a coin is found; possibly updated if a (different) signature exists already
6115 : * @param now current time (rounded)
6116 : * @param[out] found set to true if the reserve was found
6117 : * @param[out] balance_ok set to true if the balance was sufficient
6118 : * @param[out] nonce_ok set to false if the nonce was reused
6119 : * @param[out] ruuid set to the reserve's UUID (reserves table row)
6120 : * @return query execution status
6121 : */
6122 : static enum GNUNET_DB_QueryStatus
6123 0 : postgres_do_withdraw (
6124 : void *cls,
6125 : const struct TALER_CsNonce *nonce,
6126 : const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
6127 : struct GNUNET_TIME_Timestamp now,
6128 : bool *found,
6129 : bool *balance_ok,
6130 : bool *nonce_ok,
6131 : uint64_t *ruuid)
6132 : {
6133 0 : struct PostgresClosure *pg = cls;
6134 : struct GNUNET_TIME_Timestamp gc;
6135 0 : struct GNUNET_PQ_QueryParam params[] = {
6136 : NULL == nonce
6137 0 : ? GNUNET_PQ_query_param_null ()
6138 0 : : GNUNET_PQ_query_param_auto_from_type (nonce),
6139 0 : TALER_PQ_query_param_amount (&collectable->amount_with_fee),
6140 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
6141 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
6142 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
6143 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
6144 0 : TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
6145 0 : GNUNET_PQ_query_param_timestamp (&now),
6146 0 : GNUNET_PQ_query_param_timestamp (&gc),
6147 : GNUNET_PQ_query_param_end
6148 : };
6149 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6150 0 : GNUNET_PQ_result_spec_bool ("reserve_found",
6151 : found),
6152 0 : GNUNET_PQ_result_spec_bool ("balance_ok",
6153 : balance_ok),
6154 0 : GNUNET_PQ_result_spec_bool ("nonce_ok",
6155 : nonce_ok),
6156 0 : GNUNET_PQ_result_spec_uint64 ("ruuid",
6157 : ruuid),
6158 : GNUNET_PQ_result_spec_end
6159 : };
6160 :
6161 0 : gc = GNUNET_TIME_absolute_to_timestamp (
6162 : GNUNET_TIME_absolute_add (now.abs_time,
6163 : pg->legal_reserve_expiration_time));
6164 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6165 : "call_withdraw",
6166 : params,
6167 : rs);
6168 : }
6169 :
6170 :
6171 : /**
6172 : * Perform reserve update as part of a batch withdraw operation, checking
6173 : * for sufficient balance. Persisting the withdrawal details is done
6174 : * separately!
6175 : *
6176 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6177 : * @param now current time (rounded)
6178 : * @param reserve_pub public key of the reserve to debit
6179 : * @param amount total amount to withdraw
6180 : * @param[out] found set to true if the reserve was found
6181 : * @param[out] balance_ok set to true if the balance was sufficient
6182 : * @param[out] ruuid set to the reserve's UUID (reserves table row)
6183 : * @return query execution status
6184 : */
6185 : static enum GNUNET_DB_QueryStatus
6186 0 : postgres_do_batch_withdraw (
6187 : void *cls,
6188 : struct GNUNET_TIME_Timestamp now,
6189 : const struct TALER_ReservePublicKeyP *reserve_pub,
6190 : const struct TALER_Amount *amount,
6191 : bool *found,
6192 : bool *balance_ok,
6193 : uint64_t *ruuid)
6194 : {
6195 0 : struct PostgresClosure *pg = cls;
6196 : struct GNUNET_TIME_Timestamp gc;
6197 0 : struct GNUNET_PQ_QueryParam params[] = {
6198 0 : TALER_PQ_query_param_amount (amount),
6199 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
6200 0 : GNUNET_PQ_query_param_timestamp (&now),
6201 0 : GNUNET_PQ_query_param_timestamp (&gc),
6202 : GNUNET_PQ_query_param_end
6203 : };
6204 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6205 0 : GNUNET_PQ_result_spec_bool ("reserve_found",
6206 : found),
6207 0 : GNUNET_PQ_result_spec_bool ("balance_ok",
6208 : balance_ok),
6209 0 : GNUNET_PQ_result_spec_uint64 ("ruuid",
6210 : ruuid),
6211 : GNUNET_PQ_result_spec_end
6212 : };
6213 :
6214 0 : gc = GNUNET_TIME_absolute_to_timestamp (
6215 : GNUNET_TIME_absolute_add (now.abs_time,
6216 : pg->legal_reserve_expiration_time));
6217 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6218 : "call_batch_withdraw",
6219 : params,
6220 : rs);
6221 : }
6222 :
6223 :
6224 : /**
6225 : * Perform insert as part of a batch withdraw operation, and persisting the
6226 : * withdrawal details.
6227 : *
6228 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6229 : * @param nonce client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
6230 : * @param collectable corresponding collectable coin (blind signature)
6231 : * @param now current time (rounded)
6232 : * @param ruuid reserve UUID
6233 : * @param[out] denom_unknown set if the denomination is unknown in the DB
6234 : * @param[out] conflict if the envelope was already in the DB
6235 : * @param[out] nonce_reuse if @a nonce was non-NULL and reused
6236 : * @return query execution status
6237 : */
6238 : static enum GNUNET_DB_QueryStatus
6239 0 : postgres_do_batch_withdraw_insert (
6240 : void *cls,
6241 : const struct TALER_CsNonce *nonce,
6242 : const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
6243 : struct GNUNET_TIME_Timestamp now,
6244 : uint64_t ruuid,
6245 : bool *denom_unknown,
6246 : bool *conflict,
6247 : bool *nonce_reuse)
6248 : {
6249 0 : struct PostgresClosure *pg = cls;
6250 0 : struct GNUNET_PQ_QueryParam params[] = {
6251 : NULL == nonce
6252 0 : ? GNUNET_PQ_query_param_null ()
6253 0 : : GNUNET_PQ_query_param_auto_from_type (nonce),
6254 0 : TALER_PQ_query_param_amount (&collectable->amount_with_fee),
6255 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
6256 0 : GNUNET_PQ_query_param_uint64 (&ruuid),
6257 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
6258 0 : GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
6259 0 : TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
6260 0 : GNUNET_PQ_query_param_timestamp (&now),
6261 : GNUNET_PQ_query_param_end
6262 : };
6263 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6264 0 : GNUNET_PQ_result_spec_bool ("denom_unknown",
6265 : denom_unknown),
6266 0 : GNUNET_PQ_result_spec_bool ("conflict",
6267 : conflict),
6268 0 : GNUNET_PQ_result_spec_bool ("nonce_reuse",
6269 : nonce_reuse),
6270 : GNUNET_PQ_result_spec_end
6271 : };
6272 :
6273 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6274 : "call_batch_withdraw_insert",
6275 : params,
6276 : rs);
6277 : }
6278 :
6279 :
6280 : /**
6281 : * Compute the shard number of a given @a merchant_pub.
6282 : *
6283 : * @param merchant_pub merchant public key to compute shard for
6284 : * @return shard number
6285 : */
6286 : static uint64_t
6287 0 : compute_shard (const struct TALER_MerchantPublicKeyP *merchant_pub)
6288 : {
6289 : uint32_t res;
6290 :
6291 0 : GNUNET_assert (GNUNET_YES ==
6292 : GNUNET_CRYPTO_kdf (&res,
6293 : sizeof (res),
6294 : merchant_pub,
6295 : sizeof (*merchant_pub),
6296 : "VOID",
6297 : 4,
6298 : NULL, 0));
6299 : /* interpret hash result as NBO for platform independence,
6300 : convert to HBO and map to [0..2^31-1] range */
6301 0 : res = ntohl (res);
6302 0 : if (res > INT32_MAX)
6303 0 : res += INT32_MIN;
6304 0 : GNUNET_assert (res <= INT32_MAX);
6305 0 : return (uint64_t) res;
6306 : }
6307 :
6308 :
6309 : /**
6310 : * Perform deposit operation, checking for sufficient balance
6311 : * of the coin and possibly persisting the deposit details.
6312 : *
6313 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6314 : * @param deposit deposit operation details
6315 : * @param known_coin_id row of the coin in the known_coins table
6316 : * @param h_payto hash of the merchant's bank account details
6317 : * @param extension_blocked true if an extension is blocking the wire transfer
6318 : * @param[in,out] exchange_timestamp time to use for the deposit (possibly updated)
6319 : * @param[out] balance_ok set to true if the balance was sufficient
6320 : * @param[out] in_conflict set to true if the deposit conflicted
6321 : * @return query execution status
6322 : */
6323 : static enum GNUNET_DB_QueryStatus
6324 0 : postgres_do_deposit (
6325 : void *cls,
6326 : const struct TALER_EXCHANGEDB_Deposit *deposit,
6327 : uint64_t known_coin_id,
6328 : const struct TALER_PaytoHashP *h_payto,
6329 : bool extension_blocked,
6330 : struct GNUNET_TIME_Timestamp *exchange_timestamp,
6331 : bool *balance_ok,
6332 : bool *in_conflict)
6333 : {
6334 0 : struct PostgresClosure *pg = cls;
6335 0 : uint64_t deposit_shard = compute_shard (&deposit->merchant_pub);
6336 0 : struct GNUNET_PQ_QueryParam params[] = {
6337 0 : TALER_PQ_query_param_amount (&deposit->amount_with_fee),
6338 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
6339 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->wire_salt),
6340 0 : GNUNET_PQ_query_param_timestamp (&deposit->timestamp),
6341 0 : GNUNET_PQ_query_param_timestamp (exchange_timestamp),
6342 0 : GNUNET_PQ_query_param_timestamp (&deposit->refund_deadline),
6343 0 : GNUNET_PQ_query_param_timestamp (&deposit->wire_deadline),
6344 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
6345 0 : GNUNET_PQ_query_param_string (deposit->receiver_wire_account),
6346 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
6347 0 : GNUNET_PQ_query_param_uint64 (&known_coin_id),
6348 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
6349 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
6350 0 : GNUNET_PQ_query_param_uint64 (&deposit_shard),
6351 0 : GNUNET_PQ_query_param_bool (extension_blocked),
6352 0 : (NULL == deposit->extension_details)
6353 0 : ? GNUNET_PQ_query_param_null ()
6354 0 : : TALER_PQ_query_param_json (deposit->extension_details),
6355 : GNUNET_PQ_query_param_end
6356 : };
6357 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6358 0 : GNUNET_PQ_result_spec_bool ("balance_ok",
6359 : balance_ok),
6360 0 : GNUNET_PQ_result_spec_bool ("conflicted",
6361 : in_conflict),
6362 0 : GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
6363 : exchange_timestamp),
6364 : GNUNET_PQ_result_spec_end
6365 : };
6366 :
6367 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6368 : "call_deposit",
6369 : params,
6370 : rs);
6371 : }
6372 :
6373 :
6374 : /**
6375 : * Perform melt operation, checking for sufficient balance
6376 : * of the coin and possibly persisting the melt details.
6377 : *
6378 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6379 : * @param rms client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
6380 : * @param[in,out] refresh refresh operation details; the noreveal_index
6381 : * is set in case the coin was already melted before
6382 : * @param known_coin_id row of the coin in the known_coins table
6383 : * @param[in,out] zombie_required true if the melt must only succeed if the coin is a zombie, set to false if the requirement was satisfied
6384 : * @param[out] balance_ok set to true if the balance was sufficient
6385 : * @return query execution status
6386 : */
6387 : static enum GNUNET_DB_QueryStatus
6388 0 : postgres_do_melt (
6389 : void *cls,
6390 : const struct TALER_RefreshMasterSecretP *rms,
6391 : struct TALER_EXCHANGEDB_Refresh *refresh,
6392 : uint64_t known_coin_id,
6393 : bool *zombie_required,
6394 : bool *balance_ok)
6395 : {
6396 0 : struct PostgresClosure *pg = cls;
6397 0 : struct GNUNET_PQ_QueryParam params[] = {
6398 : NULL == rms
6399 0 : ? GNUNET_PQ_query_param_null ()
6400 0 : : GNUNET_PQ_query_param_auto_from_type (rms),
6401 0 : TALER_PQ_query_param_amount (&refresh->amount_with_fee),
6402 0 : GNUNET_PQ_query_param_auto_from_type (&refresh->rc),
6403 0 : GNUNET_PQ_query_param_auto_from_type (&refresh->coin.coin_pub),
6404 0 : GNUNET_PQ_query_param_auto_from_type (&refresh->coin_sig),
6405 0 : GNUNET_PQ_query_param_uint64 (&known_coin_id),
6406 0 : GNUNET_PQ_query_param_uint32 (&refresh->noreveal_index),
6407 0 : GNUNET_PQ_query_param_bool (*zombie_required),
6408 : GNUNET_PQ_query_param_end
6409 : };
6410 : bool is_null;
6411 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6412 0 : GNUNET_PQ_result_spec_bool ("balance_ok",
6413 : balance_ok),
6414 0 : GNUNET_PQ_result_spec_bool ("zombie_required",
6415 : zombie_required),
6416 0 : GNUNET_PQ_result_spec_allow_null (
6417 : GNUNET_PQ_result_spec_uint32 ("noreveal_index",
6418 : &refresh->noreveal_index),
6419 : &is_null),
6420 : GNUNET_PQ_result_spec_end
6421 : };
6422 : enum GNUNET_DB_QueryStatus qs;
6423 :
6424 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6425 : "call_melt",
6426 : params,
6427 : rs);
6428 0 : if (is_null)
6429 0 : refresh->noreveal_index = UINT32_MAX; /* set to very invalid value */
6430 0 : return qs;
6431 : }
6432 :
6433 :
6434 : /**
6435 : * Perform refund operation, checking for sufficient deposits
6436 : * of the coin and possibly persisting the refund details.
6437 : *
6438 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6439 : * @param refund refund operation details
6440 : * @param deposit_fee deposit fee applicable for the coin, possibly refunded
6441 : * @param known_coin_id row of the coin in the known_coins table
6442 : * @param[out] not_found set if the deposit was not found
6443 : * @param[out] refund_ok set if the refund succeeded (below deposit amount)
6444 : * @param[out] gone if the merchant was already paid
6445 : * @param[out] conflict set if the refund ID was re-used
6446 : * @return query execution status
6447 : */
6448 : static enum GNUNET_DB_QueryStatus
6449 0 : postgres_do_refund (
6450 : void *cls,
6451 : const struct TALER_EXCHANGEDB_Refund *refund,
6452 : const struct TALER_Amount *deposit_fee,
6453 : uint64_t known_coin_id,
6454 : bool *not_found,
6455 : bool *refund_ok,
6456 : bool *gone,
6457 : bool *conflict)
6458 : {
6459 0 : struct PostgresClosure *pg = cls;
6460 0 : uint64_t deposit_shard = compute_shard (&refund->details.merchant_pub);
6461 : struct TALER_Amount amount_without_fee;
6462 0 : struct GNUNET_PQ_QueryParam params[] = {
6463 0 : TALER_PQ_query_param_amount (&refund->details.refund_amount),
6464 0 : TALER_PQ_query_param_amount (&amount_without_fee),
6465 0 : TALER_PQ_query_param_amount (deposit_fee),
6466 0 : GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms),
6467 0 : GNUNET_PQ_query_param_uint64 (&refund->details.rtransaction_id),
6468 0 : GNUNET_PQ_query_param_uint64 (&deposit_shard),
6469 0 : GNUNET_PQ_query_param_uint64 (&known_coin_id),
6470 0 : GNUNET_PQ_query_param_auto_from_type (&refund->coin.coin_pub),
6471 0 : GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_pub),
6472 0 : GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_sig),
6473 : GNUNET_PQ_query_param_end
6474 : };
6475 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6476 0 : GNUNET_PQ_result_spec_bool ("not_found",
6477 : not_found),
6478 0 : GNUNET_PQ_result_spec_bool ("refund_ok",
6479 : refund_ok),
6480 0 : GNUNET_PQ_result_spec_bool ("gone",
6481 : gone),
6482 0 : GNUNET_PQ_result_spec_bool ("conflict",
6483 : conflict),
6484 : GNUNET_PQ_result_spec_end
6485 : };
6486 :
6487 0 : if (0 >
6488 0 : TALER_amount_subtract (&amount_without_fee,
6489 : &refund->details.refund_amount,
6490 : &refund->details.refund_fee))
6491 : {
6492 0 : GNUNET_break (0);
6493 0 : return GNUNET_DB_STATUS_HARD_ERROR;
6494 : }
6495 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6496 : "call_refund",
6497 : params,
6498 : rs);
6499 : }
6500 :
6501 :
6502 : /**
6503 : * Perform recoup operation, checking for sufficient deposits
6504 : * of the coin and possibly persisting the recoup details.
6505 : *
6506 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6507 : * @param reserve_pub public key of the reserve to credit
6508 : * @param reserve_out_serial_id row in the reserves_out table justifying the recoup
6509 : * @param coin_bks coin blinding key secret to persist
6510 : * @param coin_pub public key of the coin being recouped
6511 : * @param known_coin_id row of the @a coin_pub in the known_coins table
6512 : * @param coin_sig signature of the coin requesting the recoup
6513 : * @param[in,out] recoup_timestamp recoup timestamp, set if recoup existed
6514 : * @param[out] recoup_ok set if the recoup succeeded (balance ok)
6515 : * @param[out] internal_failure set on internal failures
6516 : * @return query execution status
6517 : */
6518 : static enum GNUNET_DB_QueryStatus
6519 0 : postgres_do_recoup (
6520 : void *cls,
6521 : const struct TALER_ReservePublicKeyP *reserve_pub,
6522 : uint64_t reserve_out_serial_id,
6523 : const union TALER_DenominationBlindingKeyP *coin_bks,
6524 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
6525 : uint64_t known_coin_id,
6526 : const struct TALER_CoinSpendSignatureP *coin_sig,
6527 : struct GNUNET_TIME_Timestamp *recoup_timestamp,
6528 : bool *recoup_ok,
6529 : bool *internal_failure)
6530 : {
6531 0 : struct PostgresClosure *pg = cls;
6532 : struct GNUNET_TIME_Timestamp reserve_gc
6533 0 : = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time);
6534 : struct GNUNET_TIME_Timestamp reserve_expiration
6535 0 : = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time);
6536 0 : struct GNUNET_PQ_QueryParam params[] = {
6537 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
6538 0 : GNUNET_PQ_query_param_uint64 (&reserve_out_serial_id),
6539 0 : GNUNET_PQ_query_param_auto_from_type (coin_bks),
6540 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
6541 0 : GNUNET_PQ_query_param_uint64 (&known_coin_id),
6542 0 : GNUNET_PQ_query_param_auto_from_type (coin_sig),
6543 0 : GNUNET_PQ_query_param_timestamp (&reserve_gc),
6544 0 : GNUNET_PQ_query_param_timestamp (&reserve_expiration),
6545 0 : GNUNET_PQ_query_param_timestamp (recoup_timestamp),
6546 : GNUNET_PQ_query_param_end
6547 : };
6548 : bool is_null;
6549 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6550 0 : GNUNET_PQ_result_spec_allow_null (
6551 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
6552 : recoup_timestamp),
6553 : &is_null),
6554 0 : GNUNET_PQ_result_spec_bool ("recoup_ok",
6555 : recoup_ok),
6556 0 : GNUNET_PQ_result_spec_bool ("internal_failure",
6557 : internal_failure),
6558 : GNUNET_PQ_result_spec_end
6559 : };
6560 :
6561 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6562 : "call_recoup",
6563 : params,
6564 : rs);
6565 : }
6566 :
6567 :
6568 : /**
6569 : * Perform recoup-refresh operation, checking for sufficient deposits of the
6570 : * coin and possibly persisting the recoup-refresh details.
6571 : *
6572 : * @param cls the `struct PostgresClosure` with the plugin-specific state
6573 : * @param old_coin_pub public key of the old coin to credit
6574 : * @param rrc_serial row in the refresh_revealed_coins table justifying the recoup-refresh
6575 : * @param coin_bks coin blinding key secret to persist
6576 : * @param coin_pub public key of the coin being recouped
6577 : * @param known_coin_id row of the @a coin_pub in the known_coins table
6578 : * @param coin_sig signature of the coin requesting the recoup
6579 : * @param[in,out] recoup_timestamp recoup timestamp, set if recoup existed
6580 : * @param[out] recoup_ok set if the recoup-refresh succeeded (balance ok)
6581 : * @param[out] internal_failure set on internal failures
6582 : * @return query execution status
6583 : */
6584 : static enum GNUNET_DB_QueryStatus
6585 0 : postgres_do_recoup_refresh (
6586 : void *cls,
6587 : const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
6588 : uint64_t rrc_serial,
6589 : const union TALER_DenominationBlindingKeyP *coin_bks,
6590 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
6591 : uint64_t known_coin_id,
6592 : const struct TALER_CoinSpendSignatureP *coin_sig,
6593 : struct GNUNET_TIME_Timestamp *recoup_timestamp,
6594 : bool *recoup_ok,
6595 : bool *internal_failure)
6596 : {
6597 0 : struct PostgresClosure *pg = cls;
6598 0 : struct GNUNET_PQ_QueryParam params[] = {
6599 0 : GNUNET_PQ_query_param_auto_from_type (old_coin_pub),
6600 0 : GNUNET_PQ_query_param_uint64 (&rrc_serial),
6601 0 : GNUNET_PQ_query_param_auto_from_type (coin_bks),
6602 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
6603 0 : GNUNET_PQ_query_param_uint64 (&known_coin_id),
6604 0 : GNUNET_PQ_query_param_auto_from_type (coin_sig),
6605 0 : GNUNET_PQ_query_param_timestamp (recoup_timestamp),
6606 : GNUNET_PQ_query_param_end
6607 : };
6608 : bool is_null;
6609 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6610 0 : GNUNET_PQ_result_spec_allow_null (
6611 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
6612 : recoup_timestamp),
6613 : &is_null),
6614 0 : GNUNET_PQ_result_spec_bool ("recoup_ok",
6615 : recoup_ok),
6616 0 : GNUNET_PQ_result_spec_bool ("internal_failure",
6617 : internal_failure),
6618 : GNUNET_PQ_result_spec_end
6619 : };
6620 :
6621 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
6622 : "call_recoup_refresh",
6623 : params,
6624 : rs);
6625 : }
6626 :
6627 :
6628 : /**
6629 : * Closure for callbacks invoked via #postgres_get_reserve_history.
6630 : */
6631 : struct ReserveHistoryContext
6632 : {
6633 :
6634 : /**
6635 : * Which reserve are we building the history for?
6636 : */
6637 : const struct TALER_ReservePublicKeyP *reserve_pub;
6638 :
6639 : /**
6640 : * Where we build the history.
6641 : */
6642 : struct TALER_EXCHANGEDB_ReserveHistory *rh;
6643 :
6644 : /**
6645 : * Tail of @e rh list.
6646 : */
6647 : struct TALER_EXCHANGEDB_ReserveHistory *rh_tail;
6648 :
6649 : /**
6650 : * Plugin context.
6651 : */
6652 : struct PostgresClosure *pg;
6653 :
6654 : /**
6655 : * Sum of all credit transactions.
6656 : */
6657 : struct TALER_Amount balance_in;
6658 :
6659 : /**
6660 : * Sum of all debit transactions.
6661 : */
6662 : struct TALER_Amount balance_out;
6663 :
6664 : /**
6665 : * Set to #GNUNET_SYSERR on serious internal errors during
6666 : * the callbacks.
6667 : */
6668 : enum GNUNET_GenericReturnValue status;
6669 : };
6670 :
6671 :
6672 : /**
6673 : * Append and return a fresh element to the reserve
6674 : * history kept in @a rhc.
6675 : *
6676 : * @param rhc where the history is kept
6677 : * @return the fresh element that was added
6678 : */
6679 : static struct TALER_EXCHANGEDB_ReserveHistory *
6680 0 : append_rh (struct ReserveHistoryContext *rhc)
6681 : {
6682 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
6683 :
6684 0 : tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
6685 0 : if (NULL != rhc->rh_tail)
6686 : {
6687 0 : rhc->rh_tail->next = tail;
6688 0 : rhc->rh_tail = tail;
6689 : }
6690 : else
6691 : {
6692 0 : rhc->rh_tail = tail;
6693 0 : rhc->rh = tail;
6694 : }
6695 0 : return tail;
6696 : }
6697 :
6698 :
6699 : /**
6700 : * Add bank transfers to result set for #postgres_get_reserve_history.
6701 : *
6702 : * @param cls a `struct ReserveHistoryContext *`
6703 : * @param result SQL result
6704 : * @param num_results number of rows in @a result
6705 : */
6706 : static void
6707 0 : add_bank_to_exchange (void *cls,
6708 : PGresult *result,
6709 : unsigned int num_results)
6710 : {
6711 0 : struct ReserveHistoryContext *rhc = cls;
6712 0 : struct PostgresClosure *pg = rhc->pg;
6713 :
6714 0 : while (0 < num_results)
6715 : {
6716 : struct TALER_EXCHANGEDB_BankTransfer *bt;
6717 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
6718 :
6719 0 : bt = GNUNET_new (struct TALER_EXCHANGEDB_BankTransfer);
6720 : {
6721 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6722 0 : GNUNET_PQ_result_spec_uint64 ("wire_reference",
6723 : &bt->wire_reference),
6724 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("credit",
6725 : &bt->amount),
6726 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
6727 : &bt->execution_date),
6728 0 : GNUNET_PQ_result_spec_string ("sender_account_details",
6729 : &bt->sender_account_details),
6730 : GNUNET_PQ_result_spec_end
6731 : };
6732 :
6733 0 : if (GNUNET_OK !=
6734 0 : GNUNET_PQ_extract_result (result,
6735 : rs,
6736 : --num_results))
6737 : {
6738 0 : GNUNET_break (0);
6739 0 : GNUNET_free (bt);
6740 0 : rhc->status = GNUNET_SYSERR;
6741 0 : return;
6742 : }
6743 : }
6744 0 : GNUNET_assert (0 <=
6745 : TALER_amount_add (&rhc->balance_in,
6746 : &rhc->balance_in,
6747 : &bt->amount));
6748 0 : bt->reserve_pub = *rhc->reserve_pub;
6749 0 : tail = append_rh (rhc);
6750 0 : tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
6751 0 : tail->details.bank = bt;
6752 : } /* end of 'while (0 < rows)' */
6753 : }
6754 :
6755 :
6756 : /**
6757 : * Add coin withdrawals to result set for #postgres_get_reserve_history.
6758 : *
6759 : * @param cls a `struct ReserveHistoryContext *`
6760 : * @param result SQL result
6761 : * @param num_results number of rows in @a result
6762 : */
6763 : static void
6764 0 : add_withdraw_coin (void *cls,
6765 : PGresult *result,
6766 : unsigned int num_results)
6767 : {
6768 0 : struct ReserveHistoryContext *rhc = cls;
6769 0 : struct PostgresClosure *pg = rhc->pg;
6770 :
6771 0 : while (0 < num_results)
6772 : {
6773 : struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc;
6774 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
6775 :
6776 0 : cbc = GNUNET_new (struct TALER_EXCHANGEDB_CollectableBlindcoin);
6777 : {
6778 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6779 0 : GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
6780 : &cbc->h_coin_envelope),
6781 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
6782 : &cbc->denom_pub_hash),
6783 0 : TALER_PQ_result_spec_blinded_denom_sig ("denom_sig",
6784 : &cbc->sig),
6785 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
6786 : &cbc->reserve_sig),
6787 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
6788 : &cbc->amount_with_fee),
6789 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
6790 : &cbc->withdraw_fee),
6791 : GNUNET_PQ_result_spec_end
6792 : };
6793 :
6794 0 : if (GNUNET_OK !=
6795 0 : GNUNET_PQ_extract_result (result,
6796 : rs,
6797 : --num_results))
6798 : {
6799 0 : GNUNET_break (0);
6800 0 : GNUNET_free (cbc);
6801 0 : rhc->status = GNUNET_SYSERR;
6802 0 : return;
6803 : }
6804 : }
6805 0 : GNUNET_assert (0 <=
6806 : TALER_amount_add (&rhc->balance_out,
6807 : &rhc->balance_out,
6808 : &cbc->amount_with_fee));
6809 0 : cbc->reserve_pub = *rhc->reserve_pub;
6810 0 : tail = append_rh (rhc);
6811 0 : tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
6812 0 : tail->details.withdraw = cbc;
6813 : }
6814 : }
6815 :
6816 :
6817 : /**
6818 : * Add recoups to result set for #postgres_get_reserve_history.
6819 : *
6820 : * @param cls a `struct ReserveHistoryContext *`
6821 : * @param result SQL result
6822 : * @param num_results number of rows in @a result
6823 : */
6824 : static void
6825 0 : add_recoup (void *cls,
6826 : PGresult *result,
6827 : unsigned int num_results)
6828 : {
6829 0 : struct ReserveHistoryContext *rhc = cls;
6830 0 : struct PostgresClosure *pg = rhc->pg;
6831 :
6832 0 : while (0 < num_results)
6833 : {
6834 : struct TALER_EXCHANGEDB_Recoup *recoup;
6835 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
6836 :
6837 0 : recoup = GNUNET_new (struct TALER_EXCHANGEDB_Recoup);
6838 : {
6839 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6840 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
6841 : &recoup->value),
6842 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
6843 : &recoup->coin.coin_pub),
6844 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
6845 : &recoup->coin_blind),
6846 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
6847 : &recoup->coin_sig),
6848 0 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
6849 : &recoup->timestamp),
6850 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
6851 : &recoup->coin.denom_pub_hash),
6852 0 : TALER_PQ_result_spec_denom_sig (
6853 : "denom_sig",
6854 : &recoup->coin.denom_sig),
6855 : GNUNET_PQ_result_spec_end
6856 : };
6857 :
6858 0 : if (GNUNET_OK !=
6859 0 : GNUNET_PQ_extract_result (result,
6860 : rs,
6861 : --num_results))
6862 : {
6863 0 : GNUNET_break (0);
6864 0 : GNUNET_free (recoup);
6865 0 : rhc->status = GNUNET_SYSERR;
6866 0 : return;
6867 : }
6868 : }
6869 0 : GNUNET_assert (0 <=
6870 : TALER_amount_add (&rhc->balance_in,
6871 : &rhc->balance_in,
6872 : &recoup->value));
6873 0 : recoup->reserve_pub = *rhc->reserve_pub;
6874 0 : tail = append_rh (rhc);
6875 0 : tail->type = TALER_EXCHANGEDB_RO_RECOUP_COIN;
6876 0 : tail->details.recoup = recoup;
6877 : } /* end of 'while (0 < rows)' */
6878 : }
6879 :
6880 :
6881 : /**
6882 : * Add exchange-to-bank transfers to result set for
6883 : * #postgres_get_reserve_history.
6884 : *
6885 : * @param cls a `struct ReserveHistoryContext *`
6886 : * @param result SQL result
6887 : * @param num_results number of rows in @a result
6888 : */
6889 : static void
6890 0 : add_exchange_to_bank (void *cls,
6891 : PGresult *result,
6892 : unsigned int num_results)
6893 : {
6894 0 : struct ReserveHistoryContext *rhc = cls;
6895 0 : struct PostgresClosure *pg = rhc->pg;
6896 :
6897 0 : while (0 < num_results)
6898 : {
6899 : struct TALER_EXCHANGEDB_ClosingTransfer *closing;
6900 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
6901 :
6902 0 : closing = GNUNET_new (struct TALER_EXCHANGEDB_ClosingTransfer);
6903 : {
6904 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6905 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
6906 : &closing->amount),
6907 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
6908 : &closing->closing_fee),
6909 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
6910 : &closing->execution_date),
6911 0 : GNUNET_PQ_result_spec_string ("receiver_account",
6912 : &closing->receiver_account_details),
6913 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid",
6914 : &closing->wtid),
6915 : GNUNET_PQ_result_spec_end
6916 : };
6917 :
6918 0 : if (GNUNET_OK !=
6919 0 : GNUNET_PQ_extract_result (result,
6920 : rs,
6921 : --num_results))
6922 : {
6923 0 : GNUNET_break (0);
6924 0 : GNUNET_free (closing);
6925 0 : rhc->status = GNUNET_SYSERR;
6926 0 : return;
6927 : }
6928 : }
6929 0 : GNUNET_assert (0 <=
6930 : TALER_amount_add (&rhc->balance_out,
6931 : &rhc->balance_out,
6932 : &closing->amount));
6933 0 : closing->reserve_pub = *rhc->reserve_pub;
6934 0 : tail = append_rh (rhc);
6935 0 : tail->type = TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK;
6936 0 : tail->details.closing = closing;
6937 : } /* end of 'while (0 < rows)' */
6938 : }
6939 :
6940 :
6941 : /**
6942 : * Add purse merge transfers to result set for
6943 : * #postgres_get_reserve_history.
6944 : *
6945 : * @param cls a `struct ReserveHistoryContext *`
6946 : * @param result SQL result
6947 : * @param num_results number of rows in @a result
6948 : */
6949 : static void
6950 0 : add_p2p_merge (void *cls,
6951 : PGresult *result,
6952 : unsigned int num_results)
6953 : {
6954 0 : struct ReserveHistoryContext *rhc = cls;
6955 0 : struct PostgresClosure *pg = rhc->pg;
6956 :
6957 0 : while (0 < num_results)
6958 : {
6959 : struct TALER_EXCHANGEDB_PurseMerge *merge;
6960 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
6961 :
6962 0 : merge = GNUNET_new (struct TALER_EXCHANGEDB_PurseMerge);
6963 : {
6964 : uint32_t flags32;
6965 : struct TALER_Amount balance;
6966 0 : struct GNUNET_PQ_ResultSpec rs[] = {
6967 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
6968 : &merge->purse_fee),
6969 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
6970 : &balance),
6971 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
6972 : &merge->amount_with_fee),
6973 0 : GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
6974 : &merge->merge_timestamp),
6975 0 : GNUNET_PQ_result_spec_timestamp ("purse_expiration",
6976 : &merge->purse_expiration),
6977 0 : GNUNET_PQ_result_spec_uint32 ("age_limit",
6978 : &merge->min_age),
6979 0 : GNUNET_PQ_result_spec_uint32 ("flags",
6980 : &flags32),
6981 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
6982 : &merge->h_contract_terms),
6983 0 : GNUNET_PQ_result_spec_auto_from_type ("merge_pub",
6984 : &merge->merge_pub),
6985 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
6986 : &merge->purse_pub),
6987 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
6988 : &merge->reserve_sig),
6989 : GNUNET_PQ_result_spec_end
6990 : };
6991 :
6992 0 : if (GNUNET_OK !=
6993 0 : GNUNET_PQ_extract_result (result,
6994 : rs,
6995 : --num_results))
6996 : {
6997 0 : GNUNET_break (0);
6998 0 : GNUNET_free (merge);
6999 0 : rhc->status = GNUNET_SYSERR;
7000 0 : return;
7001 : }
7002 0 : merge->flags = (enum TALER_WalletAccountMergeFlags) flags32;
7003 0 : if ( (! GNUNET_TIME_absolute_is_future (
7004 0 : merge->merge_timestamp.abs_time)) &&
7005 0 : (-1 != TALER_amount_cmp (&balance,
7006 0 : &merge->amount_with_fee)) )
7007 0 : merge->merged = true;
7008 : }
7009 0 : if (merge->merged)
7010 0 : GNUNET_assert (0 <=
7011 : TALER_amount_add (&rhc->balance_in,
7012 : &rhc->balance_in,
7013 : &merge->amount_with_fee));
7014 0 : GNUNET_assert (0 <=
7015 : TALER_amount_add (&rhc->balance_out,
7016 : &rhc->balance_out,
7017 : &merge->purse_fee));
7018 0 : merge->reserve_pub = *rhc->reserve_pub;
7019 0 : tail = append_rh (rhc);
7020 0 : tail->type = TALER_EXCHANGEDB_RO_PURSE_MERGE;
7021 0 : tail->details.merge = merge;
7022 : }
7023 : }
7024 :
7025 :
7026 : /**
7027 : * Add paid for history requests to result set for
7028 : * #postgres_get_reserve_history.
7029 : *
7030 : * @param cls a `struct ReserveHistoryContext *`
7031 : * @param result SQL result
7032 : * @param num_results number of rows in @a result
7033 : */
7034 : static void
7035 0 : add_history_requests (void *cls,
7036 : PGresult *result,
7037 : unsigned int num_results)
7038 : {
7039 0 : struct ReserveHistoryContext *rhc = cls;
7040 0 : struct PostgresClosure *pg = rhc->pg;
7041 :
7042 0 : while (0 < num_results)
7043 : {
7044 : struct TALER_EXCHANGEDB_HistoryRequest *history;
7045 : struct TALER_EXCHANGEDB_ReserveHistory *tail;
7046 :
7047 0 : history = GNUNET_new (struct TALER_EXCHANGEDB_HistoryRequest);
7048 : {
7049 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7050 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
7051 : &history->history_fee),
7052 0 : GNUNET_PQ_result_spec_timestamp ("request_timestamp",
7053 : &history->request_timestamp),
7054 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
7055 : &history->reserve_sig),
7056 : GNUNET_PQ_result_spec_end
7057 : };
7058 :
7059 0 : if (GNUNET_OK !=
7060 0 : GNUNET_PQ_extract_result (result,
7061 : rs,
7062 : --num_results))
7063 : {
7064 0 : GNUNET_break (0);
7065 0 : GNUNET_free (history);
7066 0 : rhc->status = GNUNET_SYSERR;
7067 0 : return;
7068 : }
7069 : }
7070 0 : GNUNET_assert (0 <=
7071 : TALER_amount_add (&rhc->balance_out,
7072 : &rhc->balance_out,
7073 : &history->history_fee));
7074 0 : history->reserve_pub = *rhc->reserve_pub;
7075 0 : tail = append_rh (rhc);
7076 0 : tail->type = TALER_EXCHANGEDB_RO_HISTORY_REQUEST;
7077 0 : tail->details.history = history;
7078 : }
7079 : }
7080 :
7081 :
7082 : /**
7083 : * Get all of the transaction history associated with the specified
7084 : * reserve.
7085 : *
7086 : * @param cls the `struct PostgresClosure` with the plugin-specific state
7087 : * @param reserve_pub public key of the reserve
7088 : * @param[out] balance set to the reserve balance
7089 : * @param[out] rhp set to known transaction history (NULL if reserve is unknown)
7090 : * @return transaction status
7091 : */
7092 : static enum GNUNET_DB_QueryStatus
7093 0 : postgres_get_reserve_history (void *cls,
7094 : const struct TALER_ReservePublicKeyP *reserve_pub,
7095 : struct TALER_Amount *balance,
7096 : struct TALER_EXCHANGEDB_ReserveHistory **rhp)
7097 : {
7098 0 : struct PostgresClosure *pg = cls;
7099 : struct ReserveHistoryContext rhc;
7100 : struct
7101 : {
7102 : /**
7103 : * Name of the prepared statement to run.
7104 : */
7105 : const char *statement;
7106 : /**
7107 : * Function to use to process the results.
7108 : */
7109 : GNUNET_PQ_PostgresResultHandler cb;
7110 0 : } work[] = {
7111 : /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
7112 : { "reserves_in_get_transactions",
7113 : add_bank_to_exchange },
7114 : /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
7115 : { "get_reserves_out",
7116 : &add_withdraw_coin },
7117 : /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */
7118 : { "recoup_by_reserve",
7119 : &add_recoup },
7120 : /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
7121 : { "close_by_reserve",
7122 : &add_exchange_to_bank },
7123 : /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */
7124 : { "merge_by_reserve",
7125 : &add_p2p_merge },
7126 : /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */
7127 : { "history_by_reserve",
7128 : &add_history_requests },
7129 : /* List terminator */
7130 : { NULL,
7131 : NULL }
7132 : };
7133 : enum GNUNET_DB_QueryStatus qs;
7134 0 : struct GNUNET_PQ_QueryParam params[] = {
7135 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
7136 : GNUNET_PQ_query_param_end
7137 : };
7138 :
7139 0 : rhc.reserve_pub = reserve_pub;
7140 0 : rhc.rh = NULL;
7141 0 : rhc.rh_tail = NULL;
7142 0 : rhc.pg = pg;
7143 0 : rhc.status = GNUNET_OK;
7144 0 : GNUNET_assert (GNUNET_OK ==
7145 : TALER_amount_set_zero (pg->currency,
7146 : &rhc.balance_in));
7147 0 : GNUNET_assert (GNUNET_OK ==
7148 : TALER_amount_set_zero (pg->currency,
7149 : &rhc.balance_out));
7150 0 : qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
7151 0 : for (unsigned int i = 0; NULL != work[i].cb; i++)
7152 : {
7153 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
7154 : work[i].statement,
7155 : params,
7156 : work[i].cb,
7157 : &rhc);
7158 0 : if ( (0 > qs) ||
7159 0 : (GNUNET_OK != rhc.status) )
7160 : break;
7161 : }
7162 0 : if ( (qs < 0) ||
7163 0 : (rhc.status != GNUNET_OK) )
7164 : {
7165 0 : common_free_reserve_history (cls,
7166 : rhc.rh);
7167 0 : rhc.rh = NULL;
7168 0 : if (qs >= 0)
7169 : {
7170 : /* status == SYSERR is a very hard error... */
7171 0 : qs = GNUNET_DB_STATUS_HARD_ERROR;
7172 : }
7173 : }
7174 0 : *rhp = rhc.rh;
7175 0 : GNUNET_assert (0 <=
7176 : TALER_amount_subtract (balance,
7177 : &rhc.balance_in,
7178 : &rhc.balance_out));
7179 0 : return qs;
7180 : }
7181 :
7182 :
7183 : /**
7184 : * Get a truncated transaction history associated with the specified
7185 : * reserve.
7186 : *
7187 : * @param cls the `struct PostgresClosure` with the plugin-specific state
7188 : * @param reserve_pub public key of the reserve
7189 : * @param[out] balance_in set to the total of inbound
7190 : * transactions in the returned history
7191 : * @param[out] balance_out set to the total of outbound
7192 : * transactions in the returned history
7193 : * @param[out] rhp set to known transaction history (NULL if reserve is unknown)
7194 : * @return transaction status
7195 : */
7196 : static enum GNUNET_DB_QueryStatus
7197 0 : postgres_get_reserve_status (void *cls,
7198 : const struct TALER_ReservePublicKeyP *reserve_pub,
7199 : struct TALER_Amount *balance_in,
7200 : struct TALER_Amount *balance_out,
7201 : struct TALER_EXCHANGEDB_ReserveHistory **rhp)
7202 : {
7203 0 : struct PostgresClosure *pg = cls;
7204 : struct ReserveHistoryContext rhc;
7205 : struct
7206 : {
7207 : /**
7208 : * Name of the prepared statement to run.
7209 : */
7210 : const char *statement;
7211 : /**
7212 : * Function to use to process the results.
7213 : */
7214 : GNUNET_PQ_PostgresResultHandler cb;
7215 0 : } work[] = {
7216 : /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
7217 : { "reserves_in_get_transactions_truncated",
7218 : add_bank_to_exchange },
7219 : /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
7220 : { "get_reserves_out_truncated",
7221 : &add_withdraw_coin },
7222 : /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */
7223 : { "recoup_by_reserve_truncated",
7224 : &add_recoup },
7225 : /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
7226 : { "close_by_reserve_truncated",
7227 : &add_exchange_to_bank },
7228 : /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */
7229 : { "merge_by_reserve_truncated",
7230 : &add_p2p_merge },
7231 : /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */
7232 : { "history_by_reserve_truncated",
7233 : &add_history_requests },
7234 : /* List terminator */
7235 : { NULL,
7236 : NULL }
7237 : };
7238 : enum GNUNET_DB_QueryStatus qs;
7239 : struct GNUNET_TIME_Absolute timelimit;
7240 0 : struct GNUNET_PQ_QueryParam params[] = {
7241 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
7242 0 : GNUNET_PQ_query_param_absolute_time (&timelimit),
7243 : GNUNET_PQ_query_param_end
7244 : };
7245 :
7246 0 : timelimit = GNUNET_TIME_absolute_subtract (
7247 : GNUNET_TIME_absolute_get (),
7248 : GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS,
7249 : 5));
7250 0 : rhc.reserve_pub = reserve_pub;
7251 0 : rhc.rh = NULL;
7252 0 : rhc.rh_tail = NULL;
7253 0 : rhc.pg = pg;
7254 0 : rhc.status = GNUNET_OK;
7255 0 : GNUNET_assert (GNUNET_OK ==
7256 : TALER_amount_set_zero (pg->currency,
7257 : &rhc.balance_in));
7258 0 : GNUNET_assert (GNUNET_OK ==
7259 : TALER_amount_set_zero (pg->currency,
7260 : &rhc.balance_out));
7261 0 : qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
7262 0 : for (unsigned int i = 0; NULL != work[i].cb; i++)
7263 : {
7264 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
7265 : work[i].statement,
7266 : params,
7267 : work[i].cb,
7268 : &rhc);
7269 0 : if ( (0 > qs) ||
7270 0 : (GNUNET_OK != rhc.status) )
7271 : break;
7272 : }
7273 0 : if ( (qs < 0) ||
7274 0 : (rhc.status != GNUNET_OK) )
7275 : {
7276 0 : common_free_reserve_history (cls,
7277 : rhc.rh);
7278 0 : rhc.rh = NULL;
7279 0 : if (qs >= 0)
7280 : {
7281 : /* status == SYSERR is a very hard error... */
7282 0 : qs = GNUNET_DB_STATUS_HARD_ERROR;
7283 : }
7284 : }
7285 0 : *rhp = rhc.rh;
7286 0 : *balance_in = rhc.balance_in;
7287 0 : *balance_out = rhc.balance_out;
7288 0 : return qs;
7289 : }
7290 :
7291 :
7292 : /**
7293 : * Get the balance of the specified reserve.
7294 : *
7295 : * @param cls the `struct PostgresClosure` with the plugin-specific state
7296 : * @param reserve_pub public key of the reserve
7297 : * @param[out] balance set to the reserve balance
7298 : * @return transaction status
7299 : */
7300 : static enum GNUNET_DB_QueryStatus
7301 0 : postgres_get_reserve_balance (void *cls,
7302 : const struct TALER_ReservePublicKeyP *reserve_pub,
7303 : struct TALER_Amount *balance)
7304 : {
7305 0 : struct PostgresClosure *pg = cls;
7306 0 : struct GNUNET_PQ_QueryParam params[] = {
7307 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
7308 : GNUNET_PQ_query_param_end
7309 : };
7310 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7311 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
7312 : balance),
7313 : GNUNET_PQ_result_spec_end
7314 : };
7315 :
7316 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7317 : "get_reserve_balance",
7318 : params,
7319 : rs);
7320 : }
7321 :
7322 :
7323 : /**
7324 : * Check if we have the specified deposit already in the database.
7325 : *
7326 : * @param cls the `struct PostgresClosure` with the plugin-specific state
7327 : * @param h_contract_terms contract to check for
7328 : * @param h_wire wire hash to check for
7329 : * @param coin_pub public key of the coin to check for
7330 : * @param merchant merchant public key to check for
7331 : * @param refund_deadline expected refund deadline
7332 : * @param[out] deposit_fee set to the deposit fee the exchange charged
7333 : * @param[out] exchange_timestamp set to the time when the exchange received the deposit
7334 : * @return 1 if we know this operation,
7335 : * 0 if this exact deposit is unknown to us,
7336 : * otherwise transaction error status
7337 : */
7338 : static enum GNUNET_DB_QueryStatus
7339 0 : postgres_have_deposit2 (
7340 : void *cls,
7341 : const struct TALER_PrivateContractHashP *h_contract_terms,
7342 : const struct TALER_MerchantWireHashP *h_wire,
7343 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
7344 : const struct TALER_MerchantPublicKeyP *merchant,
7345 : struct GNUNET_TIME_Timestamp refund_deadline,
7346 : struct TALER_Amount *deposit_fee,
7347 : struct GNUNET_TIME_Timestamp *exchange_timestamp)
7348 : {
7349 0 : struct PostgresClosure *pg = cls;
7350 0 : struct GNUNET_PQ_QueryParam params[] = {
7351 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
7352 0 : GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
7353 0 : GNUNET_PQ_query_param_auto_from_type (merchant),
7354 : GNUNET_PQ_query_param_end
7355 : };
7356 : struct TALER_EXCHANGEDB_Deposit deposit2;
7357 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7358 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
7359 : &deposit2.amount_with_fee),
7360 0 : GNUNET_PQ_result_spec_timestamp ("wallet_timestamp",
7361 : &deposit2.timestamp),
7362 0 : GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
7363 : exchange_timestamp),
7364 0 : GNUNET_PQ_result_spec_timestamp ("refund_deadline",
7365 : &deposit2.refund_deadline),
7366 0 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
7367 : &deposit2.wire_deadline),
7368 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
7369 : deposit_fee),
7370 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
7371 : &deposit2.wire_salt),
7372 0 : GNUNET_PQ_result_spec_string ("receiver_wire_account",
7373 : &deposit2.receiver_wire_account),
7374 : GNUNET_PQ_result_spec_end
7375 : };
7376 : enum GNUNET_DB_QueryStatus qs;
7377 : struct TALER_MerchantWireHashP h_wire2;
7378 :
7379 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7380 : "Getting deposits for coin %s\n",
7381 : TALER_B2S (coin_pub));
7382 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7383 : "get_deposit",
7384 : params,
7385 : rs);
7386 0 : if (0 >= qs)
7387 0 : return qs;
7388 0 : TALER_merchant_wire_signature_hash (deposit2.receiver_wire_account,
7389 : &deposit2.wire_salt,
7390 : &h_wire2);
7391 0 : GNUNET_free (deposit2.receiver_wire_account);
7392 : /* Now we check that the other information in @a deposit
7393 : also matches, and if not report inconsistencies. */
7394 0 : if ( (GNUNET_TIME_timestamp_cmp (refund_deadline,
7395 : !=,
7396 0 : deposit2.refund_deadline)) ||
7397 0 : (0 != GNUNET_memcmp (h_wire,
7398 : &h_wire2) ) )
7399 : {
7400 : /* Inconsistencies detected! Does not match! */
7401 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
7402 : }
7403 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
7404 : }
7405 :
7406 :
7407 : /**
7408 : * Aggregate all matching deposits for @a h_payto and
7409 : * @a merchant_pub, returning the total amounts.
7410 : *
7411 : * @param cls the @e cls of this struct with the plugin-specific state
7412 : * @param h_payto destination of the wire transfer
7413 : * @param merchant_pub public key of the merchant
7414 : * @param wtid wire transfer ID to set for the aggregate
7415 : * @param[out] total set to the sum of the total deposits minus applicable deposit fees and refunds
7416 : * @return transaction status
7417 : */
7418 : static enum GNUNET_DB_QueryStatus
7419 0 : postgres_aggregate (
7420 : void *cls,
7421 : const struct TALER_PaytoHashP *h_payto,
7422 : const struct TALER_MerchantPublicKeyP *merchant_pub,
7423 : const struct TALER_WireTransferIdentifierRawP *wtid,
7424 : struct TALER_Amount *total)
7425 : {
7426 0 : struct PostgresClosure *pg = cls;
7427 0 : struct GNUNET_TIME_Absolute now = {0};
7428 0 : struct GNUNET_PQ_QueryParam params[] = {
7429 0 : GNUNET_PQ_query_param_absolute_time (&now),
7430 0 : GNUNET_PQ_query_param_auto_from_type (merchant_pub),
7431 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
7432 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
7433 : GNUNET_PQ_query_param_end
7434 : };
7435 : uint64_t sum_deposit_value;
7436 : uint64_t sum_deposit_frac;
7437 : uint64_t sum_refund_value;
7438 : uint64_t sum_refund_frac;
7439 : uint64_t sum_fee_value;
7440 : uint64_t sum_fee_frac;
7441 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7442 0 : GNUNET_PQ_result_spec_uint64 ("sum_deposit_value",
7443 : &sum_deposit_value),
7444 0 : GNUNET_PQ_result_spec_uint64 ("sum_deposit_fraction",
7445 : &sum_deposit_frac),
7446 0 : GNUNET_PQ_result_spec_uint64 ("sum_refund_value",
7447 : &sum_refund_value),
7448 0 : GNUNET_PQ_result_spec_uint64 ("sum_refund_fraction",
7449 : &sum_refund_frac),
7450 0 : GNUNET_PQ_result_spec_uint64 ("sum_fee_value",
7451 : &sum_fee_value),
7452 0 : GNUNET_PQ_result_spec_uint64 ("sum_fee_fraction",
7453 : &sum_fee_frac),
7454 : GNUNET_PQ_result_spec_end
7455 : };
7456 : enum GNUNET_DB_QueryStatus qs;
7457 : struct TALER_Amount sum_deposit;
7458 : struct TALER_Amount sum_refund;
7459 : struct TALER_Amount sum_fee;
7460 : struct TALER_Amount delta;
7461 :
7462 0 : now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (),
7463 : pg->aggregator_shift);
7464 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7465 : "aggregate",
7466 : params,
7467 : rs);
7468 0 : if (qs < 0)
7469 : {
7470 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
7471 0 : return qs;
7472 : }
7473 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
7474 : {
7475 0 : GNUNET_assert (GNUNET_OK ==
7476 : TALER_amount_set_zero (pg->currency,
7477 : total));
7478 0 : return qs;
7479 : }
7480 0 : GNUNET_assert (GNUNET_OK ==
7481 : TALER_amount_set_zero (pg->currency,
7482 : &sum_deposit));
7483 0 : GNUNET_assert (GNUNET_OK ==
7484 : TALER_amount_set_zero (pg->currency,
7485 : &sum_refund));
7486 0 : GNUNET_assert (GNUNET_OK ==
7487 : TALER_amount_set_zero (pg->currency,
7488 : &sum_fee));
7489 0 : sum_deposit.value = sum_deposit_frac / TALER_AMOUNT_FRAC_BASE
7490 0 : + sum_deposit_value;
7491 0 : sum_deposit.fraction = sum_deposit_frac % TALER_AMOUNT_FRAC_BASE;
7492 0 : sum_refund.value = sum_refund_frac / TALER_AMOUNT_FRAC_BASE
7493 0 : + sum_refund_value;
7494 0 : sum_refund.fraction = sum_refund_frac % TALER_AMOUNT_FRAC_BASE;
7495 0 : sum_fee.value = sum_fee_frac / TALER_AMOUNT_FRAC_BASE
7496 0 : + sum_fee_value;
7497 0 : sum_fee.fraction = sum_fee_frac % TALER_AMOUNT_FRAC_BASE; \
7498 0 : GNUNET_assert (0 <=
7499 : TALER_amount_subtract (&delta,
7500 : &sum_deposit,
7501 : &sum_refund));
7502 0 : GNUNET_assert (0 <=
7503 : TALER_amount_subtract (total,
7504 : &delta,
7505 : &sum_fee));
7506 0 : return qs;
7507 : }
7508 :
7509 :
7510 : /**
7511 : * Create a new entry in the transient aggregation table.
7512 : *
7513 : * @param cls the @e cls of this struct with the plugin-specific state
7514 : * @param h_payto destination of the wire transfer
7515 : * @param exchange_account_section exchange account to use
7516 : * @param merchant_pub public key of the merchant receiving the transfer
7517 : * @param wtid the raw wire transfer identifier to be used
7518 : * @param kyc_requirement_row row in legitimization_requirements that need to be satisfied to continue, or 0 for none
7519 : * @param total amount to be wired in the future
7520 : * @return transaction status
7521 : */
7522 : static enum GNUNET_DB_QueryStatus
7523 0 : postgres_create_aggregation_transient (
7524 : void *cls,
7525 : const struct TALER_PaytoHashP *h_payto,
7526 : const char *exchange_account_section,
7527 : const struct TALER_MerchantPublicKeyP *merchant_pub,
7528 : const struct TALER_WireTransferIdentifierRawP *wtid,
7529 : uint64_t kyc_requirement_row,
7530 : const struct TALER_Amount *total)
7531 : {
7532 0 : struct PostgresClosure *pg = cls;
7533 0 : struct GNUNET_PQ_QueryParam params[] = {
7534 0 : TALER_PQ_query_param_amount (total),
7535 0 : GNUNET_PQ_query_param_auto_from_type (merchant_pub),
7536 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
7537 0 : GNUNET_PQ_query_param_uint64 (&kyc_requirement_row),
7538 0 : GNUNET_PQ_query_param_string (exchange_account_section),
7539 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
7540 : GNUNET_PQ_query_param_end
7541 : };
7542 :
7543 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
7544 : "create_aggregation_transient",
7545 : params);
7546 : }
7547 :
7548 :
7549 : /**
7550 : * Find existing entry in the transient aggregation table.
7551 : *
7552 : * @param cls the @e cls of this struct with the plugin-specific state
7553 : * @param h_payto destination of the wire transfer
7554 : * @param merchant_pub public key of the merchant receiving the transfer
7555 : * @param exchange_account_section exchange account to use
7556 : * @param[out] wtid set to the raw wire transfer identifier to be used
7557 : * @param[out] total existing amount to be wired in the future
7558 : * @return transaction status
7559 : */
7560 : static enum GNUNET_DB_QueryStatus
7561 0 : postgres_select_aggregation_transient (
7562 : void *cls,
7563 : const struct TALER_PaytoHashP *h_payto,
7564 : const struct TALER_MerchantPublicKeyP *merchant_pub,
7565 : const char *exchange_account_section,
7566 : struct TALER_WireTransferIdentifierRawP *wtid,
7567 : struct TALER_Amount *total)
7568 : {
7569 0 : struct PostgresClosure *pg = cls;
7570 0 : struct GNUNET_PQ_QueryParam params[] = {
7571 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
7572 0 : GNUNET_PQ_query_param_auto_from_type (merchant_pub),
7573 0 : GNUNET_PQ_query_param_string (exchange_account_section),
7574 : GNUNET_PQ_query_param_end
7575 : };
7576 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7577 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
7578 : total),
7579 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
7580 : wtid),
7581 : GNUNET_PQ_result_spec_end
7582 : };
7583 :
7584 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7585 : "select_aggregation_transient",
7586 : params,
7587 : rs);
7588 : }
7589 :
7590 :
7591 : /**
7592 : * Closure for #get_refunds_cb().
7593 : */
7594 : struct FindAggregationTransientContext
7595 : {
7596 : /**
7597 : * Function to call on each result.
7598 : */
7599 : TALER_EXCHANGEDB_TransientAggregationCallback cb;
7600 :
7601 : /**
7602 : * Closure for @a cb.
7603 : */
7604 : void *cb_cls;
7605 :
7606 : /**
7607 : * Plugin context.
7608 : */
7609 : struct PostgresClosure *pg;
7610 :
7611 : /**
7612 : * Set to #GNUNET_SYSERR on error.
7613 : */
7614 : enum GNUNET_GenericReturnValue status;
7615 : };
7616 :
7617 :
7618 : /**
7619 : * Function to be called with the results of a SELECT statement
7620 : * that has returned @a num_results results.
7621 : *
7622 : * @param cls closure of type `struct SelectRefundContext *`
7623 : * @param result the postgres result
7624 : * @param num_results the number of results in @a result
7625 : */
7626 : static void
7627 0 : get_transients_cb (void *cls,
7628 : PGresult *result,
7629 : unsigned int num_results)
7630 : {
7631 0 : struct FindAggregationTransientContext *srctx = cls;
7632 0 : struct PostgresClosure *pg = srctx->pg;
7633 :
7634 0 : for (unsigned int i = 0; i<num_results; i++)
7635 : {
7636 : struct TALER_Amount amount;
7637 : char *payto_uri;
7638 : struct TALER_WireTransferIdentifierRawP wtid;
7639 : struct TALER_MerchantPublicKeyP merchant_pub;
7640 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7641 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
7642 : &merchant_pub),
7643 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
7644 : &wtid),
7645 0 : GNUNET_PQ_result_spec_string ("payto_uri",
7646 : &payto_uri),
7647 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
7648 : &amount),
7649 : GNUNET_PQ_result_spec_end
7650 : };
7651 : bool cont;
7652 :
7653 0 : if (GNUNET_OK !=
7654 0 : GNUNET_PQ_extract_result (result,
7655 : rs,
7656 : i))
7657 : {
7658 0 : GNUNET_break (0);
7659 0 : srctx->status = GNUNET_SYSERR;
7660 0 : return;
7661 : }
7662 0 : cont = srctx->cb (srctx->cb_cls,
7663 : payto_uri,
7664 : &wtid,
7665 : &merchant_pub,
7666 : &amount);
7667 0 : GNUNET_free (payto_uri);
7668 0 : if (! cont)
7669 0 : break;
7670 : }
7671 : }
7672 :
7673 :
7674 : /**
7675 : * Find existing entry in the transient aggregation table.
7676 : *
7677 : * @param cls the @e cls of this struct with the plugin-specific state
7678 : * @param h_payto destination of the wire transfer
7679 : * @param cb function to call on each matching entry
7680 : * @param cb_cls closure for @a cb
7681 : * @return transaction status
7682 : */
7683 : static enum GNUNET_DB_QueryStatus
7684 0 : postgres_find_aggregation_transient (
7685 : void *cls,
7686 : const struct TALER_PaytoHashP *h_payto,
7687 : TALER_EXCHANGEDB_TransientAggregationCallback cb,
7688 : void *cb_cls)
7689 : {
7690 0 : struct PostgresClosure *pg = cls;
7691 : enum GNUNET_DB_QueryStatus qs;
7692 0 : struct GNUNET_PQ_QueryParam params[] = {
7693 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
7694 : GNUNET_PQ_query_param_end
7695 : };
7696 0 : struct FindAggregationTransientContext srctx = {
7697 : .cb = cb,
7698 : .cb_cls = cb_cls,
7699 : .pg = pg,
7700 : .status = GNUNET_OK
7701 : };
7702 :
7703 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
7704 : "find_transient_aggregations",
7705 : params,
7706 : &get_transients_cb,
7707 : &srctx);
7708 0 : if (GNUNET_SYSERR == srctx.status)
7709 0 : return GNUNET_DB_STATUS_HARD_ERROR;
7710 0 : return qs;
7711 : }
7712 :
7713 :
7714 : /**
7715 : * Update existing entry in the transient aggregation table.
7716 : * @a h_payto is only needed for query performance.
7717 : *
7718 : * @param cls the @e cls of this struct with the plugin-specific state
7719 : * @param h_payto destination of the wire transfer
7720 : * @param wtid the raw wire transfer identifier to update
7721 : * @param kyc_requirement_row row in legitimization_requirements that need to be satisfied to continue, or 0 for none
7722 : * @param total new total amount to be wired in the future
7723 : * @return transaction status
7724 : */
7725 : static enum GNUNET_DB_QueryStatus
7726 0 : postgres_update_aggregation_transient (
7727 : void *cls,
7728 : const struct TALER_PaytoHashP *h_payto,
7729 : const struct TALER_WireTransferIdentifierRawP *wtid,
7730 : uint64_t kyc_requirement_row,
7731 : const struct TALER_Amount *total)
7732 : {
7733 0 : struct PostgresClosure *pg = cls;
7734 0 : struct GNUNET_PQ_QueryParam params[] = {
7735 0 : TALER_PQ_query_param_amount (total),
7736 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
7737 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
7738 0 : GNUNET_PQ_query_param_uint64 (&kyc_requirement_row),
7739 : GNUNET_PQ_query_param_end
7740 : };
7741 :
7742 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
7743 : "update_aggregation_transient",
7744 : params);
7745 : }
7746 :
7747 :
7748 : /**
7749 : * Delete existing entry in the transient aggregation table.
7750 : * @a h_payto is only needed for query performance.
7751 : *
7752 : * @param cls the @e cls of this struct with the plugin-specific state
7753 : * @param h_payto destination of the wire transfer
7754 : * @param wtid the raw wire transfer identifier to update
7755 : * @return transaction status
7756 : */
7757 : static enum GNUNET_DB_QueryStatus
7758 0 : postgres_delete_aggregation_transient (
7759 : void *cls,
7760 : const struct TALER_PaytoHashP *h_payto,
7761 : const struct TALER_WireTransferIdentifierRawP *wtid)
7762 : {
7763 0 : struct PostgresClosure *pg = cls;
7764 0 : struct GNUNET_PQ_QueryParam params[] = {
7765 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
7766 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
7767 : GNUNET_PQ_query_param_end
7768 : };
7769 :
7770 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
7771 : "delete_aggregation_transient",
7772 : params);
7773 : }
7774 :
7775 :
7776 : /**
7777 : * Obtain information about deposits that are ready to be executed. Such
7778 : * deposits must not be marked as "done", the execution time must be
7779 : * in the past, and the KYC status must be 'ok'.
7780 : *
7781 : * @param cls the @e cls of this struct with the plugin-specific state
7782 : * @param start_shard_row minimum shard row to select
7783 : * @param end_shard_row maximum shard row to select (inclusive)
7784 : * @param[out] merchant_pub set to the public key of a merchant with a ready deposit
7785 : * @param[out] payto_uri set to the account of the merchant, to be freed by caller
7786 : * @return transaction status code
7787 : */
7788 : static enum GNUNET_DB_QueryStatus
7789 0 : postgres_get_ready_deposit (void *cls,
7790 : uint64_t start_shard_row,
7791 : uint64_t end_shard_row,
7792 : struct TALER_MerchantPublicKeyP *merchant_pub,
7793 : char **payto_uri)
7794 : {
7795 0 : struct PostgresClosure *pg = cls;
7796 0 : struct GNUNET_TIME_Absolute now = {0};
7797 0 : struct GNUNET_PQ_QueryParam params[] = {
7798 0 : GNUNET_PQ_query_param_absolute_time (&now),
7799 0 : GNUNET_PQ_query_param_uint64 (&start_shard_row),
7800 0 : GNUNET_PQ_query_param_uint64 (&end_shard_row),
7801 : GNUNET_PQ_query_param_end
7802 : };
7803 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7804 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
7805 : merchant_pub),
7806 0 : GNUNET_PQ_result_spec_string ("payto_uri",
7807 : payto_uri),
7808 : GNUNET_PQ_result_spec_end
7809 : };
7810 :
7811 0 : now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (),
7812 : pg->aggregator_shift);
7813 0 : GNUNET_assert (start_shard_row < end_shard_row);
7814 0 : GNUNET_assert (end_shard_row <= INT32_MAX);
7815 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7816 : "Finding ready deposits by deadline %s (%llu)\n",
7817 : GNUNET_TIME_absolute2s (now),
7818 : (unsigned long long) now.abs_value_us);
7819 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7820 : "deposits_get_ready",
7821 : params,
7822 : rs);
7823 : }
7824 :
7825 :
7826 : /**
7827 : * Retrieve the record for a known coin.
7828 : *
7829 : * @param cls the plugin closure
7830 : * @param coin_pub the public key of the coin to search for
7831 : * @param coin_info place holder for the returned coin information object
7832 : * @return transaction status code
7833 : */
7834 : static enum GNUNET_DB_QueryStatus
7835 0 : postgres_get_known_coin (void *cls,
7836 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
7837 : struct TALER_CoinPublicInfo *coin_info)
7838 : {
7839 0 : struct PostgresClosure *pg = cls;
7840 0 : struct GNUNET_PQ_QueryParam params[] = {
7841 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
7842 : GNUNET_PQ_query_param_end
7843 : };
7844 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7845 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
7846 : &coin_info->denom_pub_hash),
7847 0 : GNUNET_PQ_result_spec_allow_null (
7848 0 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
7849 : &coin_info->h_age_commitment),
7850 : &coin_info->no_age_commitment),
7851 0 : TALER_PQ_result_spec_denom_sig ("denom_sig",
7852 : &coin_info->denom_sig),
7853 : GNUNET_PQ_result_spec_end
7854 : };
7855 :
7856 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7857 : "Getting known coin data for coin %s\n",
7858 : TALER_B2S (coin_pub));
7859 0 : coin_info->coin_pub = *coin_pub;
7860 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7861 : "get_known_coin",
7862 : params,
7863 : rs);
7864 : }
7865 :
7866 :
7867 : /**
7868 : * Retrieve the denomination of a known coin.
7869 : *
7870 : * @param cls the plugin closure
7871 : * @param coin_pub the public key of the coin to search for
7872 : * @param[out] known_coin_id set to the ID of the coin in the known_coins table
7873 : * @param[out] denom_hash where to store the hash of the coins denomination
7874 : * @return transaction status code
7875 : */
7876 : static enum GNUNET_DB_QueryStatus
7877 0 : postgres_get_coin_denomination (
7878 : void *cls,
7879 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
7880 : uint64_t *known_coin_id,
7881 : struct TALER_DenominationHashP *denom_hash)
7882 : {
7883 0 : struct PostgresClosure *pg = cls;
7884 0 : struct GNUNET_PQ_QueryParam params[] = {
7885 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
7886 : GNUNET_PQ_query_param_end
7887 : };
7888 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7889 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
7890 : denom_hash),
7891 0 : GNUNET_PQ_result_spec_uint64 ("known_coin_id",
7892 : known_coin_id),
7893 : GNUNET_PQ_result_spec_end
7894 : };
7895 :
7896 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7897 : "Getting coin denomination of coin %s\n",
7898 : TALER_B2S (coin_pub));
7899 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7900 : "get_coin_denomination",
7901 : params,
7902 : rs);
7903 : }
7904 :
7905 :
7906 : /**
7907 : * Count the number of known coins by denomination.
7908 : *
7909 : * @param cls database connection plugin state
7910 : * @param denom_pub_hash denomination to count by
7911 : * @return number of coins if non-negative, otherwise an `enum GNUNET_DB_QueryStatus`
7912 : */
7913 : static long long
7914 0 : postgres_count_known_coins (void *cls,
7915 : const struct
7916 : TALER_DenominationHashP *denom_pub_hash)
7917 : {
7918 0 : struct PostgresClosure *pg = cls;
7919 : uint64_t count;
7920 0 : struct GNUNET_PQ_QueryParam params[] = {
7921 0 : GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
7922 : GNUNET_PQ_query_param_end
7923 : };
7924 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7925 0 : GNUNET_PQ_result_spec_uint64 ("count",
7926 : &count),
7927 : GNUNET_PQ_result_spec_end
7928 : };
7929 : enum GNUNET_DB_QueryStatus qs;
7930 :
7931 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7932 : "count_known_coins",
7933 : params,
7934 : rs);
7935 0 : if (0 > qs)
7936 0 : return (long long) qs;
7937 0 : return (long long) count;
7938 : }
7939 :
7940 :
7941 : /**
7942 : * Make sure the given @a coin is known to the database.
7943 : *
7944 : * @param cls database connection plugin state
7945 : * @param coin the coin that must be made known
7946 : * @param[out] known_coin_id set to the unique row of the coin
7947 : * @param[out] denom_hash set to the denomination hash of the existing
7948 : * coin (for conflict error reporting)
7949 : * @param[out] h_age_commitment set to the conflicting age commitment hash on conflict
7950 : * @return database transaction status, non-negative on success
7951 : */
7952 : static enum TALER_EXCHANGEDB_CoinKnownStatus
7953 0 : postgres_ensure_coin_known (void *cls,
7954 : const struct TALER_CoinPublicInfo *coin,
7955 : uint64_t *known_coin_id,
7956 : struct TALER_DenominationHashP *denom_hash,
7957 : struct TALER_AgeCommitmentHash *h_age_commitment)
7958 : {
7959 0 : struct PostgresClosure *pg = cls;
7960 : enum GNUNET_DB_QueryStatus qs;
7961 : bool existed;
7962 0 : bool is_denom_pub_hash_null = false;
7963 0 : bool is_age_hash_null = false;
7964 0 : struct GNUNET_PQ_QueryParam params[] = {
7965 0 : GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
7966 0 : GNUNET_PQ_query_param_auto_from_type (&coin->denom_pub_hash),
7967 0 : GNUNET_PQ_query_param_auto_from_type (&coin->h_age_commitment),
7968 0 : TALER_PQ_query_param_denom_sig (&coin->denom_sig),
7969 : GNUNET_PQ_query_param_end
7970 : };
7971 0 : struct GNUNET_PQ_ResultSpec rs[] = {
7972 0 : GNUNET_PQ_result_spec_bool ("existed",
7973 : &existed),
7974 0 : GNUNET_PQ_result_spec_uint64 ("known_coin_id",
7975 : known_coin_id),
7976 0 : GNUNET_PQ_result_spec_allow_null (
7977 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
7978 : denom_hash),
7979 : &is_denom_pub_hash_null),
7980 0 : GNUNET_PQ_result_spec_allow_null (
7981 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
7982 : h_age_commitment),
7983 : &is_age_hash_null),
7984 : GNUNET_PQ_result_spec_end
7985 : };
7986 :
7987 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
7988 : "insert_known_coin",
7989 : params,
7990 : rs);
7991 0 : switch (qs)
7992 : {
7993 0 : case GNUNET_DB_STATUS_HARD_ERROR:
7994 0 : GNUNET_break (0);
7995 0 : return TALER_EXCHANGEDB_CKS_HARD_FAIL;
7996 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
7997 0 : return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
7998 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
7999 0 : GNUNET_break (0); /* should be impossible */
8000 0 : return TALER_EXCHANGEDB_CKS_HARD_FAIL;
8001 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
8002 0 : if (! existed)
8003 0 : return TALER_EXCHANGEDB_CKS_ADDED;
8004 0 : break; /* continued below */
8005 : }
8006 :
8007 0 : if ( (! is_denom_pub_hash_null) &&
8008 0 : (0 != GNUNET_memcmp (&denom_hash->hash,
8009 : &coin->denom_pub_hash.hash)) )
8010 : {
8011 0 : GNUNET_break_op (0);
8012 0 : return TALER_EXCHANGEDB_CKS_DENOM_CONFLICT;
8013 : }
8014 :
8015 0 : if ( (! is_age_hash_null) &&
8016 0 : (0 != GNUNET_memcmp (h_age_commitment,
8017 : &coin->h_age_commitment)) )
8018 : {
8019 0 : GNUNET_break (GNUNET_is_zero (h_age_commitment));
8020 0 : GNUNET_break_op (0);
8021 0 : return TALER_EXCHANGEDB_CKS_AGE_CONFLICT;
8022 : }
8023 :
8024 0 : return TALER_EXCHANGEDB_CKS_PRESENT;
8025 : }
8026 :
8027 :
8028 : /**
8029 : * Insert information about deposited coin into the database.
8030 : *
8031 : * @param cls the `struct PostgresClosure` with the plugin-specific state
8032 : * @param exchange_timestamp time the exchange received the deposit request
8033 : * @param deposit deposit information to store
8034 : * @return query result status
8035 : */
8036 : static enum GNUNET_DB_QueryStatus
8037 0 : postgres_insert_deposit (void *cls,
8038 : struct GNUNET_TIME_Timestamp exchange_timestamp,
8039 : const struct TALER_EXCHANGEDB_Deposit *deposit)
8040 : {
8041 0 : struct PostgresClosure *pg = cls;
8042 : struct TALER_PaytoHashP h_payto;
8043 : enum GNUNET_DB_QueryStatus qs;
8044 :
8045 0 : qs = setup_wire_target (pg,
8046 0 : deposit->receiver_wire_account,
8047 : &h_payto);
8048 0 : if (qs < 0)
8049 0 : return qs;
8050 0 : if (GNUNET_TIME_timestamp_cmp (deposit->wire_deadline,
8051 : <,
8052 : deposit->refund_deadline))
8053 : {
8054 0 : GNUNET_break (0);
8055 : }
8056 : {
8057 0 : uint64_t shard = compute_shard (&deposit->merchant_pub);
8058 0 : struct GNUNET_PQ_QueryParam params[] = {
8059 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
8060 0 : TALER_PQ_query_param_amount (&deposit->amount_with_fee),
8061 0 : GNUNET_PQ_query_param_timestamp (&deposit->timestamp),
8062 0 : GNUNET_PQ_query_param_timestamp (&deposit->refund_deadline),
8063 0 : GNUNET_PQ_query_param_timestamp (&deposit->wire_deadline),
8064 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
8065 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
8066 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->wire_salt),
8067 0 : GNUNET_PQ_query_param_auto_from_type (&h_payto),
8068 0 : GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
8069 0 : GNUNET_PQ_query_param_timestamp (&exchange_timestamp),
8070 0 : GNUNET_PQ_query_param_uint64 (&shard),
8071 : GNUNET_PQ_query_param_end
8072 : };
8073 :
8074 0 : GNUNET_assert (shard <= INT32_MAX);
8075 0 : GNUNET_log (
8076 : GNUNET_ERROR_TYPE_INFO,
8077 : "Inserting deposit to be executed at %s (%llu/%llu)\n",
8078 : GNUNET_TIME_timestamp2s (deposit->wire_deadline),
8079 : (unsigned long long) deposit->wire_deadline.abs_time.abs_value_us,
8080 : (unsigned long long) deposit->refund_deadline.abs_time.abs_value_us);
8081 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
8082 : "insert_deposit",
8083 : params);
8084 : }
8085 : }
8086 :
8087 :
8088 : /**
8089 : * Insert information about refunded coin into the database.
8090 : *
8091 : * @param cls the @e cls of this struct with the plugin-specific state
8092 : * @param refund refund information to store
8093 : * @return query result status
8094 : */
8095 : static enum GNUNET_DB_QueryStatus
8096 0 : postgres_insert_refund (void *cls,
8097 : const struct TALER_EXCHANGEDB_Refund *refund)
8098 : {
8099 0 : struct PostgresClosure *pg = cls;
8100 0 : struct GNUNET_PQ_QueryParam params[] = {
8101 0 : GNUNET_PQ_query_param_auto_from_type (&refund->coin.coin_pub),
8102 0 : GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_pub),
8103 0 : GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_sig),
8104 0 : GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms),
8105 0 : GNUNET_PQ_query_param_uint64 (&refund->details.rtransaction_id),
8106 0 : TALER_PQ_query_param_amount (&refund->details.refund_amount),
8107 : GNUNET_PQ_query_param_end
8108 : };
8109 :
8110 0 : GNUNET_assert (GNUNET_YES ==
8111 : TALER_amount_cmp_currency (&refund->details.refund_amount,
8112 : &refund->details.refund_fee));
8113 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
8114 : "insert_refund",
8115 : params);
8116 : }
8117 :
8118 :
8119 : /**
8120 : * Closure for #get_refunds_cb().
8121 : */
8122 : struct SelectRefundContext
8123 : {
8124 : /**
8125 : * Function to call on each result.
8126 : */
8127 : TALER_EXCHANGEDB_RefundCoinCallback cb;
8128 :
8129 : /**
8130 : * Closure for @a cb.
8131 : */
8132 : void *cb_cls;
8133 :
8134 : /**
8135 : * Plugin context.
8136 : */
8137 : struct PostgresClosure *pg;
8138 :
8139 : /**
8140 : * Set to #GNUNET_SYSERR on error.
8141 : */
8142 : int status;
8143 : };
8144 :
8145 :
8146 : /**
8147 : * Function to be called with the results of a SELECT statement
8148 : * that has returned @a num_results results.
8149 : *
8150 : * @param cls closure of type `struct SelectRefundContext *`
8151 : * @param result the postgres result
8152 : * @param num_results the number of results in @a result
8153 : */
8154 : static void
8155 0 : get_refunds_cb (void *cls,
8156 : PGresult *result,
8157 : unsigned int num_results)
8158 : {
8159 0 : struct SelectRefundContext *srctx = cls;
8160 0 : struct PostgresClosure *pg = srctx->pg;
8161 :
8162 0 : for (unsigned int i = 0; i<num_results; i++)
8163 : {
8164 : struct TALER_Amount amount_with_fee;
8165 0 : struct GNUNET_PQ_ResultSpec rs[] = {
8166 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
8167 : &amount_with_fee),
8168 : GNUNET_PQ_result_spec_end
8169 : };
8170 :
8171 0 : if (GNUNET_OK !=
8172 0 : GNUNET_PQ_extract_result (result,
8173 : rs,
8174 : i))
8175 : {
8176 0 : GNUNET_break (0);
8177 0 : srctx->status = GNUNET_SYSERR;
8178 0 : return;
8179 : }
8180 0 : if (GNUNET_OK !=
8181 0 : srctx->cb (srctx->cb_cls,
8182 : &amount_with_fee))
8183 0 : return;
8184 : }
8185 : }
8186 :
8187 :
8188 : /**
8189 : * Select refunds by @a coin_pub, @a merchant_pub and @a h_contract.
8190 : *
8191 : * @param cls closure of plugin
8192 : * @param coin_pub coin to get refunds for
8193 : * @param merchant_pub merchant to get refunds for
8194 : * @param h_contract contract (hash) to get refunds for
8195 : * @param cb function to call for each refund found
8196 : * @param cb_cls closure for @a cb
8197 : * @return query result status
8198 : */
8199 : static enum GNUNET_DB_QueryStatus
8200 0 : postgres_select_refunds_by_coin (
8201 : void *cls,
8202 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
8203 : const struct TALER_MerchantPublicKeyP *merchant_pub,
8204 : const struct TALER_PrivateContractHashP *h_contract,
8205 : TALER_EXCHANGEDB_RefundCoinCallback cb,
8206 : void *cb_cls)
8207 : {
8208 0 : struct PostgresClosure *pg = cls;
8209 : enum GNUNET_DB_QueryStatus qs;
8210 0 : struct GNUNET_PQ_QueryParam params[] = {
8211 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
8212 0 : GNUNET_PQ_query_param_auto_from_type (merchant_pub),
8213 0 : GNUNET_PQ_query_param_auto_from_type (h_contract),
8214 : GNUNET_PQ_query_param_end
8215 : };
8216 0 : struct SelectRefundContext srctx = {
8217 : .cb = cb,
8218 : .cb_cls = cb_cls,
8219 : .pg = pg,
8220 : .status = GNUNET_OK
8221 : };
8222 :
8223 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
8224 : "get_refunds_by_coin_and_contract",
8225 : params,
8226 : &get_refunds_cb,
8227 : &srctx);
8228 0 : if (GNUNET_SYSERR == srctx.status)
8229 0 : return GNUNET_DB_STATUS_HARD_ERROR;
8230 0 : return qs;
8231 : }
8232 :
8233 :
8234 : /**
8235 : * Lookup refresh melt commitment data under the given @a rc.
8236 : *
8237 : * @param cls the `struct PostgresClosure` with the plugin-specific state
8238 : * @param rc commitment hash to use to locate the operation
8239 : * @param[out] melt where to store the result; note that
8240 : * melt->session.coin.denom_sig will be set to NULL
8241 : * and is not fetched by this routine (as it is not needed by the client)
8242 : * @param[out] melt_serial_id set to the row ID of @a rc in the refresh_commitments table
8243 : * @return transaction status
8244 : */
8245 : static enum GNUNET_DB_QueryStatus
8246 0 : postgres_get_melt (void *cls,
8247 : const struct TALER_RefreshCommitmentP *rc,
8248 : struct TALER_EXCHANGEDB_Melt *melt,
8249 : uint64_t *melt_serial_id)
8250 : {
8251 0 : struct PostgresClosure *pg = cls;
8252 : bool h_age_commitment_is_null;
8253 0 : struct GNUNET_PQ_QueryParam params[] = {
8254 0 : GNUNET_PQ_query_param_auto_from_type (rc),
8255 : GNUNET_PQ_query_param_end
8256 : };
8257 0 : struct GNUNET_PQ_ResultSpec rs[] = {
8258 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
8259 : &melt->session.coin.
8260 : denom_pub_hash),
8261 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
8262 : &melt->melt_fee),
8263 0 : GNUNET_PQ_result_spec_uint32 ("noreveal_index",
8264 : &melt->session.noreveal_index),
8265 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
8266 : &melt->session.coin.coin_pub),
8267 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
8268 : &melt->session.coin_sig),
8269 0 : GNUNET_PQ_result_spec_allow_null (
8270 0 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
8271 : &melt->session.coin.h_age_commitment),
8272 : &h_age_commitment_is_null),
8273 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
8274 : &melt->session.amount_with_fee),
8275 0 : GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
8276 : melt_serial_id),
8277 : GNUNET_PQ_result_spec_end
8278 : };
8279 : enum GNUNET_DB_QueryStatus qs;
8280 :
8281 0 : memset (&melt->session.coin.denom_sig,
8282 : 0,
8283 : sizeof (melt->session.coin.denom_sig));
8284 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
8285 : "get_melt",
8286 : params,
8287 : rs);
8288 0 : if (h_age_commitment_is_null)
8289 0 : memset (&melt->session.coin.h_age_commitment,
8290 : 0,
8291 : sizeof(melt->session.coin.h_age_commitment));
8292 :
8293 0 : melt->session.rc = *rc;
8294 0 : return qs;
8295 : }
8296 :
8297 :
8298 : /**
8299 : * Store in the database which coin(s) the wallet wanted to create
8300 : * in a given refresh operation and all of the other information
8301 : * we learned or created in the /refresh/reveal step.
8302 : *
8303 : * @param cls the @e cls of this struct with the plugin-specific state
8304 : * @param melt_serial_id row ID of the commitment / melt operation in refresh_commitments
8305 : * @param num_rrcs number of coins to generate, size of the @a rrcs array
8306 : * @param rrcs information about the new coins
8307 : * @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
8308 : * @param tprivs transfer private keys to store
8309 : * @param tp public key to store
8310 : * @return query status for the transaction
8311 : */
8312 : static enum GNUNET_DB_QueryStatus
8313 0 : postgres_insert_refresh_reveal (
8314 : void *cls,
8315 : uint64_t melt_serial_id,
8316 : uint32_t num_rrcs,
8317 : const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
8318 : unsigned int num_tprivs,
8319 : const struct TALER_TransferPrivateKeyP *tprivs,
8320 : const struct TALER_TransferPublicKeyP *tp)
8321 : {
8322 0 : struct PostgresClosure *pg = cls;
8323 :
8324 0 : if (TALER_CNC_KAPPA != num_tprivs + 1)
8325 : {
8326 0 : GNUNET_break (0);
8327 0 : return GNUNET_DB_STATUS_HARD_ERROR;
8328 : }
8329 0 : for (uint32_t i = 0; i<num_rrcs; i++)
8330 : {
8331 0 : const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
8332 0 : struct GNUNET_PQ_QueryParam params[] = {
8333 0 : GNUNET_PQ_query_param_uint64 (&melt_serial_id),
8334 0 : GNUNET_PQ_query_param_uint32 (&i),
8335 0 : GNUNET_PQ_query_param_auto_from_type (&rrc->orig_coin_link_sig),
8336 0 : GNUNET_PQ_query_param_auto_from_type (&rrc->h_denom_pub),
8337 0 : TALER_PQ_query_param_blinded_planchet (&rrc->blinded_planchet),
8338 0 : TALER_PQ_query_param_exchange_withdraw_values (&rrc->exchange_vals),
8339 0 : GNUNET_PQ_query_param_auto_from_type (&rrc->coin_envelope_hash),
8340 0 : TALER_PQ_query_param_blinded_denom_sig (&rrc->coin_sig),
8341 : GNUNET_PQ_query_param_end
8342 : };
8343 : enum GNUNET_DB_QueryStatus qs;
8344 :
8345 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
8346 : "insert_refresh_revealed_coin",
8347 : params);
8348 0 : if (0 > qs)
8349 0 : return qs;
8350 : }
8351 :
8352 : {
8353 0 : struct GNUNET_PQ_QueryParam params[] = {
8354 0 : GNUNET_PQ_query_param_uint64 (&melt_serial_id),
8355 0 : GNUNET_PQ_query_param_auto_from_type (tp),
8356 0 : GNUNET_PQ_query_param_fixed_size (
8357 : tprivs,
8358 : num_tprivs * sizeof (struct TALER_TransferPrivateKeyP)),
8359 : GNUNET_PQ_query_param_end
8360 : };
8361 :
8362 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
8363 : "insert_refresh_transfer_keys",
8364 : params);
8365 : }
8366 : }
8367 :
8368 :
8369 : /**
8370 : * Context where we aggregate data from the database.
8371 : * Closure for #add_revealed_coins().
8372 : */
8373 : struct GetRevealContext
8374 : {
8375 : /**
8376 : * Array of revealed coins we obtained from the DB.
8377 : */
8378 : struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs;
8379 :
8380 : /**
8381 : * Length of the @a rrcs array.
8382 : */
8383 : unsigned int rrcs_len;
8384 :
8385 : /**
8386 : * Set to an error code if we ran into trouble.
8387 : */
8388 : enum GNUNET_DB_QueryStatus qs;
8389 : };
8390 :
8391 :
8392 : /**
8393 : * Function to be called with the results of a SELECT statement
8394 : * that has returned @a num_results results.
8395 : *
8396 : * @param cls closure of type `struct GetRevealContext`
8397 : * @param result the postgres result
8398 : * @param num_results the number of results in @a result
8399 : */
8400 : static void
8401 0 : add_revealed_coins (void *cls,
8402 : PGresult *result,
8403 : unsigned int num_results)
8404 : {
8405 0 : struct GetRevealContext *grctx = cls;
8406 :
8407 0 : if (0 == num_results)
8408 0 : return;
8409 0 : grctx->rrcs = GNUNET_new_array (num_results,
8410 : struct TALER_EXCHANGEDB_RefreshRevealedCoin);
8411 0 : grctx->rrcs_len = num_results;
8412 0 : for (unsigned int i = 0; i < num_results; i++)
8413 : {
8414 : uint32_t off;
8415 0 : struct GNUNET_PQ_ResultSpec rso[] = {
8416 0 : GNUNET_PQ_result_spec_uint32 ("freshcoin_index",
8417 : &off),
8418 : GNUNET_PQ_result_spec_end
8419 : };
8420 :
8421 0 : if (GNUNET_OK !=
8422 0 : GNUNET_PQ_extract_result (result,
8423 : rso,
8424 : i))
8425 : {
8426 0 : GNUNET_break (0);
8427 0 : grctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
8428 0 : return;
8429 : }
8430 0 : if (off >= num_results)
8431 : {
8432 0 : GNUNET_break (0);
8433 0 : grctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
8434 0 : return;
8435 : }
8436 : {
8437 0 : struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &grctx->rrcs[off];
8438 0 : struct GNUNET_PQ_ResultSpec rsi[] = {
8439 : /* NOTE: freshcoin_index selected and discarded here... */
8440 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
8441 : &rrc->h_denom_pub),
8442 0 : GNUNET_PQ_result_spec_auto_from_type ("link_sig",
8443 : &rrc->orig_coin_link_sig),
8444 0 : GNUNET_PQ_result_spec_auto_from_type ("h_coin_ev",
8445 : &rrc->coin_envelope_hash),
8446 0 : TALER_PQ_result_spec_blinded_planchet ("coin_ev",
8447 : &rrc->blinded_planchet),
8448 0 : TALER_PQ_result_spec_exchange_withdraw_values ("ewv",
8449 : &rrc->exchange_vals),
8450 0 : TALER_PQ_result_spec_blinded_denom_sig ("ev_sig",
8451 : &rrc->coin_sig),
8452 : GNUNET_PQ_result_spec_end
8453 : };
8454 :
8455 0 : if (TALER_DENOMINATION_INVALID != rrc->blinded_planchet.cipher)
8456 : {
8457 : /* duplicate offset, not allowed */
8458 0 : GNUNET_break (0);
8459 0 : grctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
8460 0 : return;
8461 : }
8462 0 : if (GNUNET_OK !=
8463 0 : GNUNET_PQ_extract_result (result,
8464 : rsi,
8465 : i))
8466 : {
8467 0 : GNUNET_break (0);
8468 0 : grctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
8469 0 : return;
8470 : }
8471 : }
8472 : }
8473 : }
8474 :
8475 :
8476 : /**
8477 : * Lookup in the database the coins that we want to
8478 : * create in the given refresh operation.
8479 : *
8480 : * @param cls the `struct PostgresClosure` with the plugin-specific state
8481 : * @param rc identify commitment and thus refresh operation
8482 : * @param cb function to call with the results
8483 : * @param cb_cls closure for @a cb
8484 : * @return transaction status
8485 : */
8486 : static enum GNUNET_DB_QueryStatus
8487 0 : postgres_get_refresh_reveal (void *cls,
8488 : const struct TALER_RefreshCommitmentP *rc,
8489 : TALER_EXCHANGEDB_RefreshCallback cb,
8490 : void *cb_cls)
8491 : {
8492 0 : struct PostgresClosure *pg = cls;
8493 : struct GetRevealContext grctx;
8494 : enum GNUNET_DB_QueryStatus qs;
8495 0 : struct GNUNET_PQ_QueryParam params[] = {
8496 0 : GNUNET_PQ_query_param_auto_from_type (rc),
8497 : GNUNET_PQ_query_param_end
8498 : };
8499 :
8500 0 : memset (&grctx,
8501 : 0,
8502 : sizeof (grctx));
8503 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
8504 : "get_refresh_revealed_coins",
8505 : params,
8506 : &add_revealed_coins,
8507 : &grctx);
8508 0 : switch (qs)
8509 : {
8510 0 : case GNUNET_DB_STATUS_HARD_ERROR:
8511 : case GNUNET_DB_STATUS_SOFT_ERROR:
8512 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
8513 0 : goto cleanup;
8514 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
8515 : default: /* can have more than one result */
8516 0 : break;
8517 : }
8518 0 : switch (grctx.qs)
8519 : {
8520 0 : case GNUNET_DB_STATUS_HARD_ERROR:
8521 : case GNUNET_DB_STATUS_SOFT_ERROR:
8522 0 : goto cleanup;
8523 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
8524 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: /* should be impossible */
8525 0 : break;
8526 : }
8527 :
8528 : /* Pass result back to application */
8529 0 : cb (cb_cls,
8530 : grctx.rrcs_len,
8531 0 : grctx.rrcs);
8532 0 : cleanup:
8533 0 : for (unsigned int i = 0; i < grctx.rrcs_len; i++)
8534 : {
8535 0 : struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &grctx.rrcs[i];
8536 :
8537 0 : TALER_blinded_denom_sig_free (&rrc->coin_sig);
8538 0 : TALER_blinded_planchet_free (&rrc->blinded_planchet);
8539 : }
8540 0 : GNUNET_free (grctx.rrcs);
8541 0 : return qs;
8542 : }
8543 :
8544 :
8545 : /**
8546 : * Closure for #add_ldl().
8547 : */
8548 : struct LinkDataContext
8549 : {
8550 : /**
8551 : * Function to call on each result.
8552 : */
8553 : TALER_EXCHANGEDB_LinkCallback ldc;
8554 :
8555 : /**
8556 : * Closure for @e ldc.
8557 : */
8558 : void *ldc_cls;
8559 :
8560 : /**
8561 : * Last transfer public key for which we have information in @e last.
8562 : * Only valid if @e last is non-NULL.
8563 : */
8564 : struct TALER_TransferPublicKeyP transfer_pub;
8565 :
8566 : /**
8567 : * Link data for @e transfer_pub
8568 : */
8569 : struct TALER_EXCHANGEDB_LinkList *last;
8570 :
8571 : /**
8572 : * Status, set to #GNUNET_SYSERR on errors,
8573 : */
8574 : int status;
8575 : };
8576 :
8577 :
8578 : /**
8579 : * Free memory of the link data list.
8580 : *
8581 : * @param cls the @e cls of this struct with the plugin-specific state (unused)
8582 : * @param ldl link data list to release
8583 : */
8584 : static void
8585 0 : free_link_data_list (void *cls,
8586 : struct TALER_EXCHANGEDB_LinkList *ldl)
8587 : {
8588 : struct TALER_EXCHANGEDB_LinkList *next;
8589 :
8590 : (void) cls;
8591 0 : while (NULL != ldl)
8592 : {
8593 0 : next = ldl->next;
8594 0 : TALER_denom_pub_free (&ldl->denom_pub);
8595 0 : TALER_blinded_denom_sig_free (&ldl->ev_sig);
8596 0 : GNUNET_free (ldl);
8597 0 : ldl = next;
8598 : }
8599 0 : }
8600 :
8601 :
8602 : /**
8603 : * Function to be called with the results of a SELECT statement
8604 : * that has returned @a num_results results.
8605 : *
8606 : * @param cls closure of type `struct LinkDataContext *`
8607 : * @param result the postgres result
8608 : * @param num_results the number of results in @a result
8609 : */
8610 : static void
8611 0 : add_ldl (void *cls,
8612 : PGresult *result,
8613 : unsigned int num_results)
8614 : {
8615 0 : struct LinkDataContext *ldctx = cls;
8616 :
8617 0 : for (int i = num_results - 1; i >= 0; i--)
8618 : {
8619 : struct TALER_EXCHANGEDB_LinkList *pos;
8620 : struct TALER_TransferPublicKeyP transfer_pub;
8621 :
8622 0 : pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkList);
8623 : {
8624 : struct TALER_BlindedPlanchet bp;
8625 0 : struct GNUNET_PQ_ResultSpec rs[] = {
8626 0 : GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
8627 : &transfer_pub),
8628 0 : GNUNET_PQ_result_spec_auto_from_type ("link_sig",
8629 : &pos->orig_coin_link_sig),
8630 0 : TALER_PQ_result_spec_blinded_denom_sig ("ev_sig",
8631 : &pos->ev_sig),
8632 0 : GNUNET_PQ_result_spec_uint32 ("freshcoin_index",
8633 : &pos->coin_refresh_offset),
8634 0 : TALER_PQ_result_spec_exchange_withdraw_values ("ewv",
8635 : &pos->alg_values),
8636 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
8637 : &pos->denom_pub),
8638 0 : TALER_PQ_result_spec_blinded_planchet ("coin_ev",
8639 : &bp),
8640 : GNUNET_PQ_result_spec_end
8641 : };
8642 :
8643 0 : if (GNUNET_OK !=
8644 0 : GNUNET_PQ_extract_result (result,
8645 : rs,
8646 : i))
8647 : {
8648 0 : GNUNET_break (0);
8649 0 : GNUNET_free (pos);
8650 0 : ldctx->status = GNUNET_SYSERR;
8651 0 : return;
8652 : }
8653 0 : if (TALER_DENOMINATION_CS == bp.cipher)
8654 : {
8655 0 : pos->nonce = bp.details.cs_blinded_planchet.nonce;
8656 0 : pos->have_nonce = true;
8657 : }
8658 0 : TALER_blinded_planchet_free (&bp);
8659 : }
8660 0 : if ( (NULL != ldctx->last) &&
8661 0 : (0 == GNUNET_memcmp (&transfer_pub,
8662 : &ldctx->transfer_pub)) )
8663 : {
8664 0 : pos->next = ldctx->last;
8665 : }
8666 : else
8667 : {
8668 0 : if (NULL != ldctx->last)
8669 : {
8670 0 : ldctx->ldc (ldctx->ldc_cls,
8671 0 : &ldctx->transfer_pub,
8672 0 : ldctx->last);
8673 0 : free_link_data_list (cls,
8674 : ldctx->last);
8675 : }
8676 0 : ldctx->transfer_pub = transfer_pub;
8677 : }
8678 0 : ldctx->last = pos;
8679 : }
8680 : }
8681 :
8682 :
8683 : /**
8684 : * Obtain the link data of a coin, that is the encrypted link
8685 : * information, the denomination keys and the signatures.
8686 : *
8687 : * @param cls the `struct PostgresClosure` with the plugin-specific state
8688 : * @param coin_pub public key of the coin
8689 : * @param ldc function to call for each session the coin was melted into
8690 : * @param ldc_cls closure for @a tdc
8691 : * @return transaction status code
8692 : */
8693 : static enum GNUNET_DB_QueryStatus
8694 0 : postgres_get_link_data (void *cls,
8695 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
8696 : TALER_EXCHANGEDB_LinkCallback ldc,
8697 : void *ldc_cls)
8698 : {
8699 0 : struct PostgresClosure *pg = cls;
8700 0 : struct GNUNET_PQ_QueryParam params[] = {
8701 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
8702 : GNUNET_PQ_query_param_end
8703 : };
8704 : enum GNUNET_DB_QueryStatus qs;
8705 : struct LinkDataContext ldctx;
8706 :
8707 0 : ldctx.ldc = ldc;
8708 0 : ldctx.ldc_cls = ldc_cls;
8709 0 : ldctx.last = NULL;
8710 0 : ldctx.status = GNUNET_OK;
8711 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
8712 : "get_link",
8713 : params,
8714 : &add_ldl,
8715 : &ldctx);
8716 0 : if (NULL != ldctx.last)
8717 : {
8718 0 : if (GNUNET_OK == ldctx.status)
8719 : {
8720 : /* call callback one more time! */
8721 0 : ldc (ldc_cls,
8722 : &ldctx.transfer_pub,
8723 0 : ldctx.last);
8724 : }
8725 0 : free_link_data_list (cls,
8726 : ldctx.last);
8727 0 : ldctx.last = NULL;
8728 : }
8729 0 : if (GNUNET_OK != ldctx.status)
8730 0 : return GNUNET_DB_STATUS_HARD_ERROR;
8731 0 : return qs;
8732 : }
8733 :
8734 :
8735 : /**
8736 : * Closure for callbacks called from #postgres_get_coin_transactions()
8737 : */
8738 : struct CoinHistoryContext
8739 : {
8740 : /**
8741 : * Head of the coin's history list.
8742 : */
8743 : struct TALER_EXCHANGEDB_TransactionList *head;
8744 :
8745 : /**
8746 : * Public key of the coin we are building the history for.
8747 : */
8748 : const struct TALER_CoinSpendPublicKeyP *coin_pub;
8749 :
8750 : /**
8751 : * Closure for all callbacks of this database plugin.
8752 : */
8753 : void *db_cls;
8754 :
8755 : /**
8756 : * Plugin context.
8757 : */
8758 : struct PostgresClosure *pg;
8759 :
8760 : /**
8761 : * Set to 'true' if the transaction failed.
8762 : */
8763 : bool failed;
8764 :
8765 : /**
8766 : * Set to 'true' if we found a deposit or melt (for invariant check).
8767 : */
8768 : bool have_deposit_or_melt;
8769 : };
8770 :
8771 :
8772 : /**
8773 : * Function to be called with the results of a SELECT statement
8774 : * that has returned @a num_results results.
8775 : *
8776 : * @param cls closure of type `struct CoinHistoryContext`
8777 : * @param result the postgres result
8778 : * @param num_results the number of results in @a result
8779 : */
8780 : static void
8781 0 : add_coin_deposit (void *cls,
8782 : PGresult *result,
8783 : unsigned int num_results)
8784 : {
8785 0 : struct CoinHistoryContext *chc = cls;
8786 0 : struct PostgresClosure *pg = chc->pg;
8787 :
8788 0 : for (unsigned int i = 0; i < num_results; i++)
8789 : {
8790 : struct TALER_EXCHANGEDB_DepositListEntry *deposit;
8791 : struct TALER_EXCHANGEDB_TransactionList *tl;
8792 : uint64_t serial_id;
8793 :
8794 0 : chc->have_deposit_or_melt = true;
8795 0 : deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
8796 : {
8797 0 : struct GNUNET_PQ_ResultSpec rs[] = {
8798 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
8799 : &deposit->amount_with_fee),
8800 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
8801 : &deposit->deposit_fee),
8802 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
8803 : &deposit->h_denom_pub),
8804 0 : GNUNET_PQ_result_spec_allow_null (
8805 0 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
8806 : &deposit->h_age_commitment),
8807 : &deposit->no_age_commitment),
8808 0 : GNUNET_PQ_result_spec_timestamp ("wallet_timestamp",
8809 : &deposit->timestamp),
8810 0 : GNUNET_PQ_result_spec_timestamp ("refund_deadline",
8811 : &deposit->refund_deadline),
8812 0 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
8813 : &deposit->wire_deadline),
8814 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
8815 : &deposit->merchant_pub),
8816 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
8817 : &deposit->h_contract_terms),
8818 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
8819 : &deposit->wire_salt),
8820 0 : GNUNET_PQ_result_spec_string ("payto_uri",
8821 : &deposit->receiver_wire_account),
8822 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
8823 : &deposit->csig),
8824 0 : GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
8825 : &serial_id),
8826 0 : GNUNET_PQ_result_spec_auto_from_type ("done",
8827 : &deposit->done),
8828 : GNUNET_PQ_result_spec_end
8829 : };
8830 :
8831 0 : if (GNUNET_OK !=
8832 0 : GNUNET_PQ_extract_result (result,
8833 : rs,
8834 : i))
8835 : {
8836 0 : GNUNET_break (0);
8837 0 : GNUNET_free (deposit);
8838 0 : chc->failed = true;
8839 0 : return;
8840 : }
8841 : }
8842 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
8843 0 : tl->next = chc->head;
8844 0 : tl->type = TALER_EXCHANGEDB_TT_DEPOSIT;
8845 0 : tl->details.deposit = deposit;
8846 0 : tl->serial_id = serial_id;
8847 0 : chc->head = tl;
8848 : }
8849 : }
8850 :
8851 :
8852 : /**
8853 : * Function to be called with the results of a SELECT statement
8854 : * that has returned @a num_results results.
8855 : *
8856 : * @param cls closure of type `struct CoinHistoryContext`
8857 : * @param result the postgres result
8858 : * @param num_results the number of results in @a result
8859 : */
8860 : static void
8861 0 : add_coin_purse_deposit (void *cls,
8862 : PGresult *result,
8863 : unsigned int num_results)
8864 : {
8865 0 : struct CoinHistoryContext *chc = cls;
8866 0 : struct PostgresClosure *pg = chc->pg;
8867 :
8868 0 : for (unsigned int i = 0; i < num_results; i++)
8869 : {
8870 : struct TALER_EXCHANGEDB_PurseDepositListEntry *deposit;
8871 : struct TALER_EXCHANGEDB_TransactionList *tl;
8872 : uint64_t serial_id;
8873 :
8874 0 : chc->have_deposit_or_melt = true;
8875 0 : deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry);
8876 : {
8877 0 : struct GNUNET_PQ_ResultSpec rs[] = {
8878 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
8879 : &deposit->amount),
8880 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
8881 : &deposit->deposit_fee),
8882 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
8883 : &deposit->purse_pub),
8884 0 : GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
8885 : &serial_id),
8886 0 : GNUNET_PQ_result_spec_allow_null (
8887 : GNUNET_PQ_result_spec_string ("partner_base_url",
8888 : &deposit->exchange_base_url),
8889 : NULL),
8890 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
8891 : &deposit->coin_sig),
8892 0 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
8893 : &deposit->h_age_commitment),
8894 0 : GNUNET_PQ_result_spec_bool ("refunded",
8895 : &deposit->refunded),
8896 : GNUNET_PQ_result_spec_end
8897 : };
8898 :
8899 0 : if (GNUNET_OK !=
8900 0 : GNUNET_PQ_extract_result (result,
8901 : rs,
8902 : i))
8903 : {
8904 0 : GNUNET_break (0);
8905 0 : GNUNET_free (deposit);
8906 0 : chc->failed = true;
8907 0 : return;
8908 : }
8909 0 : deposit->no_age_commitment = GNUNET_is_zero (&deposit->h_age_commitment);
8910 : }
8911 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
8912 0 : tl->next = chc->head;
8913 0 : tl->type = TALER_EXCHANGEDB_TT_PURSE_DEPOSIT;
8914 0 : tl->details.purse_deposit = deposit;
8915 0 : tl->serial_id = serial_id;
8916 0 : chc->head = tl;
8917 : }
8918 : }
8919 :
8920 :
8921 : /**
8922 : * Function to be called with the results of a SELECT statement
8923 : * that has returned @a num_results results.
8924 : *
8925 : * @param cls closure of type `struct CoinHistoryContext`
8926 : * @param result the postgres result
8927 : * @param num_results the number of results in @a result
8928 : */
8929 : static void
8930 0 : add_coin_melt (void *cls,
8931 : PGresult *result,
8932 : unsigned int num_results)
8933 : {
8934 0 : struct CoinHistoryContext *chc = cls;
8935 0 : struct PostgresClosure *pg = chc->pg;
8936 :
8937 0 : for (unsigned int i = 0; i<num_results; i++)
8938 : {
8939 : struct TALER_EXCHANGEDB_MeltListEntry *melt;
8940 : struct TALER_EXCHANGEDB_TransactionList *tl;
8941 : uint64_t serial_id;
8942 :
8943 0 : chc->have_deposit_or_melt = true;
8944 0 : melt = GNUNET_new (struct TALER_EXCHANGEDB_MeltListEntry);
8945 : {
8946 0 : struct GNUNET_PQ_ResultSpec rs[] = {
8947 0 : GNUNET_PQ_result_spec_auto_from_type ("rc",
8948 : &melt->rc),
8949 : /* oldcoin_index not needed */
8950 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
8951 : &melt->h_denom_pub),
8952 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
8953 : &melt->coin_sig),
8954 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
8955 : &melt->amount_with_fee),
8956 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
8957 : &melt->melt_fee),
8958 0 : GNUNET_PQ_result_spec_allow_null (
8959 0 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
8960 : &melt->h_age_commitment),
8961 : &melt->no_age_commitment),
8962 0 : GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
8963 : &serial_id),
8964 : GNUNET_PQ_result_spec_end
8965 : };
8966 :
8967 0 : if (GNUNET_OK !=
8968 0 : GNUNET_PQ_extract_result (result,
8969 : rs,
8970 : i))
8971 : {
8972 0 : GNUNET_break (0);
8973 0 : GNUNET_free (melt);
8974 0 : chc->failed = true;
8975 0 : return;
8976 : }
8977 : }
8978 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
8979 0 : tl->next = chc->head;
8980 0 : tl->type = TALER_EXCHANGEDB_TT_MELT;
8981 0 : tl->details.melt = melt;
8982 0 : tl->serial_id = serial_id;
8983 0 : chc->head = tl;
8984 : }
8985 : }
8986 :
8987 :
8988 : /**
8989 : * Function to be called with the results of a SELECT statement
8990 : * that has returned @a num_results results.
8991 : *
8992 : * @param cls closure of type `struct CoinHistoryContext`
8993 : * @param result the postgres result
8994 : * @param num_results the number of results in @a result
8995 : */
8996 : static void
8997 0 : add_coin_refund (void *cls,
8998 : PGresult *result,
8999 : unsigned int num_results)
9000 : {
9001 0 : struct CoinHistoryContext *chc = cls;
9002 0 : struct PostgresClosure *pg = chc->pg;
9003 :
9004 0 : for (unsigned int i = 0; i<num_results; i++)
9005 : {
9006 : struct TALER_EXCHANGEDB_RefundListEntry *refund;
9007 : struct TALER_EXCHANGEDB_TransactionList *tl;
9008 : uint64_t serial_id;
9009 :
9010 0 : refund = GNUNET_new (struct TALER_EXCHANGEDB_RefundListEntry);
9011 : {
9012 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9013 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
9014 : &refund->merchant_pub),
9015 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_sig",
9016 : &refund->merchant_sig),
9017 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
9018 : &refund->h_contract_terms),
9019 0 : GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
9020 : &refund->rtransaction_id),
9021 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
9022 : &refund->refund_amount),
9023 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
9024 : &refund->refund_fee),
9025 0 : GNUNET_PQ_result_spec_uint64 ("refund_serial_id",
9026 : &serial_id),
9027 : GNUNET_PQ_result_spec_end
9028 : };
9029 :
9030 0 : if (GNUNET_OK !=
9031 0 : GNUNET_PQ_extract_result (result,
9032 : rs,
9033 : i))
9034 : {
9035 0 : GNUNET_break (0);
9036 0 : GNUNET_free (refund);
9037 0 : chc->failed = true;
9038 0 : return;
9039 : }
9040 : }
9041 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
9042 0 : tl->next = chc->head;
9043 0 : tl->type = TALER_EXCHANGEDB_TT_REFUND;
9044 0 : tl->details.refund = refund;
9045 0 : tl->serial_id = serial_id;
9046 0 : chc->head = tl;
9047 : }
9048 : }
9049 :
9050 :
9051 : /**
9052 : * Function to be called with the results of a SELECT statement
9053 : * that has returned @a num_results results.
9054 : *
9055 : * @param cls closure of type `struct CoinHistoryContext`
9056 : * @param result the postgres result
9057 : * @param num_results the number of results in @a result
9058 : */
9059 : static void
9060 0 : add_old_coin_recoup (void *cls,
9061 : PGresult *result,
9062 : unsigned int num_results)
9063 : {
9064 0 : struct CoinHistoryContext *chc = cls;
9065 0 : struct PostgresClosure *pg = chc->pg;
9066 :
9067 0 : for (unsigned int i = 0; i<num_results; i++)
9068 : {
9069 : struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
9070 : struct TALER_EXCHANGEDB_TransactionList *tl;
9071 : uint64_t serial_id;
9072 :
9073 0 : recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
9074 : {
9075 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9076 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
9077 : &recoup->coin.coin_pub),
9078 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
9079 : &recoup->coin_sig),
9080 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
9081 : &recoup->coin_blind),
9082 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
9083 : &recoup->value),
9084 0 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
9085 : &recoup->timestamp),
9086 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
9087 : &recoup->coin.denom_pub_hash),
9088 0 : TALER_PQ_result_spec_denom_sig ("denom_sig",
9089 : &recoup->coin.denom_sig),
9090 0 : GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
9091 : &serial_id),
9092 : GNUNET_PQ_result_spec_end
9093 : };
9094 :
9095 0 : if (GNUNET_OK !=
9096 0 : GNUNET_PQ_extract_result (result,
9097 : rs,
9098 : i))
9099 : {
9100 0 : GNUNET_break (0);
9101 0 : GNUNET_free (recoup);
9102 0 : chc->failed = true;
9103 0 : return;
9104 : }
9105 0 : recoup->old_coin_pub = *chc->coin_pub;
9106 : }
9107 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
9108 0 : tl->next = chc->head;
9109 0 : tl->type = TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP;
9110 0 : tl->details.old_coin_recoup = recoup;
9111 0 : tl->serial_id = serial_id;
9112 0 : chc->head = tl;
9113 : }
9114 : }
9115 :
9116 :
9117 : /**
9118 : * Function to be called with the results of a SELECT statement
9119 : * that has returned @a num_results results.
9120 : *
9121 : * @param cls closure of type `struct CoinHistoryContext`
9122 : * @param result the postgres result
9123 : * @param num_results the number of results in @a result
9124 : */
9125 : static void
9126 0 : add_coin_recoup (void *cls,
9127 : PGresult *result,
9128 : unsigned int num_results)
9129 : {
9130 0 : struct CoinHistoryContext *chc = cls;
9131 0 : struct PostgresClosure *pg = chc->pg;
9132 :
9133 0 : for (unsigned int i = 0; i<num_results; i++)
9134 : {
9135 : struct TALER_EXCHANGEDB_RecoupListEntry *recoup;
9136 : struct TALER_EXCHANGEDB_TransactionList *tl;
9137 : uint64_t serial_id;
9138 :
9139 0 : recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupListEntry);
9140 : {
9141 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9142 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
9143 : &recoup->reserve_pub),
9144 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
9145 : &recoup->coin_sig),
9146 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
9147 : &recoup->h_denom_pub),
9148 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
9149 : &recoup->coin_blind),
9150 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
9151 : &recoup->value),
9152 0 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
9153 : &recoup->timestamp),
9154 0 : GNUNET_PQ_result_spec_uint64 ("recoup_uuid",
9155 : &serial_id),
9156 : GNUNET_PQ_result_spec_end
9157 : };
9158 :
9159 0 : if (GNUNET_OK !=
9160 0 : GNUNET_PQ_extract_result (result,
9161 : rs,
9162 : i))
9163 : {
9164 0 : GNUNET_break (0);
9165 0 : GNUNET_free (recoup);
9166 0 : chc->failed = true;
9167 0 : return;
9168 : }
9169 : }
9170 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
9171 0 : tl->next = chc->head;
9172 0 : tl->type = TALER_EXCHANGEDB_TT_RECOUP;
9173 0 : tl->details.recoup = recoup;
9174 0 : tl->serial_id = serial_id;
9175 0 : chc->head = tl;
9176 : }
9177 : }
9178 :
9179 :
9180 : /**
9181 : * Function to be called with the results of a SELECT statement
9182 : * that has returned @a num_results results.
9183 : *
9184 : * @param cls closure of type `struct CoinHistoryContext`
9185 : * @param result the postgres result
9186 : * @param num_results the number of results in @a result
9187 : */
9188 : static void
9189 0 : add_coin_recoup_refresh (void *cls,
9190 : PGresult *result,
9191 : unsigned int num_results)
9192 : {
9193 0 : struct CoinHistoryContext *chc = cls;
9194 0 : struct PostgresClosure *pg = chc->pg;
9195 :
9196 0 : for (unsigned int i = 0; i<num_results; i++)
9197 : {
9198 : struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
9199 : struct TALER_EXCHANGEDB_TransactionList *tl;
9200 : uint64_t serial_id;
9201 :
9202 0 : recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
9203 : {
9204 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9205 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
9206 : &recoup->old_coin_pub),
9207 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
9208 : &recoup->coin_sig),
9209 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
9210 : &recoup->coin_blind),
9211 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
9212 : &recoup->value),
9213 0 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
9214 : &recoup->timestamp),
9215 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
9216 : &recoup->coin.denom_pub_hash),
9217 0 : TALER_PQ_result_spec_denom_sig ("denom_sig",
9218 : &recoup->coin.denom_sig),
9219 0 : GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
9220 : &serial_id),
9221 : GNUNET_PQ_result_spec_end
9222 : };
9223 :
9224 0 : if (GNUNET_OK !=
9225 0 : GNUNET_PQ_extract_result (result,
9226 : rs,
9227 : i))
9228 : {
9229 0 : GNUNET_break (0);
9230 0 : GNUNET_free (recoup);
9231 0 : chc->failed = true;
9232 0 : return;
9233 : }
9234 0 : recoup->coin.coin_pub = *chc->coin_pub;
9235 : }
9236 0 : tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
9237 0 : tl->next = chc->head;
9238 0 : tl->type = TALER_EXCHANGEDB_TT_RECOUP_REFRESH;
9239 0 : tl->details.recoup_refresh = recoup;
9240 0 : tl->serial_id = serial_id;
9241 0 : chc->head = tl;
9242 : }
9243 : }
9244 :
9245 :
9246 : /**
9247 : * Work we need to do.
9248 : */
9249 : struct Work
9250 : {
9251 : /**
9252 : * SQL prepared statement name.
9253 : */
9254 : const char *statement;
9255 :
9256 : /**
9257 : * Function to call to handle the result(s).
9258 : */
9259 : GNUNET_PQ_PostgresResultHandler cb;
9260 : };
9261 :
9262 :
9263 : /**
9264 : * Compile a list of all (historic) transactions performed with the given coin
9265 : * (/refresh/melt, /deposit, /refund and /recoup operations).
9266 : *
9267 : * @param cls the `struct PostgresClosure` with the plugin-specific state
9268 : * @param coin_pub coin to investigate
9269 : * @param[out] tlp set to list of transactions, NULL if coin is fresh
9270 : * @return database transaction status
9271 : */
9272 : static enum GNUNET_DB_QueryStatus
9273 0 : postgres_get_coin_transactions (
9274 : void *cls,
9275 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
9276 : struct TALER_EXCHANGEDB_TransactionList **tlp)
9277 : {
9278 0 : struct PostgresClosure *pg = cls;
9279 : static const struct Work work[] = {
9280 : /** #TALER_EXCHANGEDB_TT_DEPOSIT */
9281 : { "get_deposit_with_coin_pub",
9282 : &add_coin_deposit },
9283 : /** #TALER_EXCHANGEDB_TT_MELT */
9284 : { "get_refresh_session_by_coin",
9285 : &add_coin_melt },
9286 : /** #TALER_EXCHANGEDB_TT_PURSE_DEPOSIT */
9287 : { "get_purse_deposit_by_coin_pub",
9288 : &add_coin_purse_deposit },
9289 : /** #TALER_EXCHANGEDB_TT_REFUND */
9290 : { "get_refunds_by_coin",
9291 : &add_coin_refund },
9292 : /** #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP */
9293 : { "recoup_by_old_coin",
9294 : &add_old_coin_recoup },
9295 : /** #TALER_EXCHANGEDB_TT_RECOUP */
9296 : { "recoup_by_coin",
9297 : &add_coin_recoup },
9298 : /** #TALER_EXCHANGEDB_TT_RECOUP_REFRESH */
9299 : { "recoup_by_refreshed_coin",
9300 : &add_coin_recoup_refresh },
9301 : { NULL, NULL }
9302 : };
9303 0 : struct GNUNET_PQ_QueryParam params[] = {
9304 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
9305 : GNUNET_PQ_query_param_end
9306 : };
9307 : enum GNUNET_DB_QueryStatus qs;
9308 0 : struct CoinHistoryContext chc = {
9309 : .head = NULL,
9310 : .coin_pub = coin_pub,
9311 : .pg = pg,
9312 : .db_cls = cls
9313 : };
9314 :
9315 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9316 : "Getting transactions for coin %s\n",
9317 : TALER_B2S (coin_pub));
9318 0 : for (unsigned int i = 0; NULL != work[i].statement; i++)
9319 : {
9320 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
9321 : work[i].statement,
9322 : params,
9323 : work[i].cb,
9324 : &chc);
9325 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9326 : "Coin %s yielded %d transactions of type %s\n",
9327 : TALER_B2S (coin_pub),
9328 : qs,
9329 : work[i].statement);
9330 0 : if ( (0 > qs) ||
9331 0 : (chc.failed) )
9332 : {
9333 0 : if (NULL != chc.head)
9334 0 : common_free_coin_transaction_list (cls,
9335 : chc.head);
9336 0 : *tlp = NULL;
9337 0 : if (chc.failed)
9338 0 : qs = GNUNET_DB_STATUS_HARD_ERROR;
9339 0 : return qs;
9340 : }
9341 : }
9342 0 : *tlp = chc.head;
9343 0 : if (NULL == chc.head)
9344 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
9345 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
9346 : }
9347 :
9348 :
9349 : /**
9350 : * Closure for #handle_wt_result.
9351 : */
9352 : struct WireTransferResultContext
9353 : {
9354 : /**
9355 : * Function to call on each result.
9356 : */
9357 : TALER_EXCHANGEDB_AggregationDataCallback cb;
9358 :
9359 : /**
9360 : * Closure for @e cb.
9361 : */
9362 : void *cb_cls;
9363 :
9364 : /**
9365 : * Plugin context.
9366 : */
9367 : struct PostgresClosure *pg;
9368 :
9369 : /**
9370 : * Set to #GNUNET_SYSERR on serious errors.
9371 : */
9372 : int status;
9373 : };
9374 :
9375 :
9376 : /**
9377 : * Function to be called with the results of a SELECT statement
9378 : * that has returned @a num_results results. Helper function
9379 : * for #postgres_lookup_wire_transfer().
9380 : *
9381 : * @param cls closure of type `struct WireTransferResultContext *`
9382 : * @param result the postgres result
9383 : * @param num_results the number of results in @a result
9384 : */
9385 : static void
9386 0 : handle_wt_result (void *cls,
9387 : PGresult *result,
9388 : unsigned int num_results)
9389 : {
9390 0 : struct WireTransferResultContext *ctx = cls;
9391 0 : struct PostgresClosure *pg = ctx->pg;
9392 :
9393 0 : for (unsigned int i = 0; i<num_results; i++)
9394 : {
9395 : uint64_t rowid;
9396 : struct TALER_PrivateContractHashP h_contract_terms;
9397 : struct TALER_CoinSpendPublicKeyP coin_pub;
9398 : struct TALER_PaytoHashP h_payto;
9399 : struct TALER_MerchantPublicKeyP merchant_pub;
9400 : struct GNUNET_TIME_Timestamp exec_time;
9401 : struct TALER_Amount amount_with_fee;
9402 : struct TALER_Amount deposit_fee;
9403 : struct TALER_DenominationPublicKey denom_pub;
9404 : char *payto_uri;
9405 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9406 0 : GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id", &rowid),
9407 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
9408 : &h_contract_terms),
9409 0 : GNUNET_PQ_result_spec_string ("payto_uri",
9410 : &payto_uri),
9411 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_target_h_payto",
9412 : &h_payto),
9413 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
9414 : &denom_pub),
9415 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
9416 : &coin_pub),
9417 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
9418 : &merchant_pub),
9419 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
9420 : &exec_time),
9421 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
9422 : &amount_with_fee),
9423 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
9424 : &deposit_fee),
9425 : GNUNET_PQ_result_spec_end
9426 : };
9427 :
9428 0 : if (GNUNET_OK !=
9429 0 : GNUNET_PQ_extract_result (result,
9430 : rs,
9431 : i))
9432 : {
9433 0 : GNUNET_break (0);
9434 0 : ctx->status = GNUNET_SYSERR;
9435 0 : return;
9436 : }
9437 0 : ctx->cb (ctx->cb_cls,
9438 : rowid,
9439 : &merchant_pub,
9440 : payto_uri,
9441 : &h_payto,
9442 : exec_time,
9443 : &h_contract_terms,
9444 : &denom_pub,
9445 : &coin_pub,
9446 : &amount_with_fee,
9447 : &deposit_fee);
9448 0 : GNUNET_PQ_cleanup_result (rs);
9449 : }
9450 : }
9451 :
9452 :
9453 : /**
9454 : * Lookup the list of Taler transactions that were aggregated
9455 : * into a wire transfer by the respective @a wtid.
9456 : *
9457 : * @param cls closure
9458 : * @param wtid the raw wire transfer identifier we used
9459 : * @param cb function to call on each transaction found
9460 : * @param cb_cls closure for @a cb
9461 : * @return query status of the transaction
9462 : */
9463 : static enum GNUNET_DB_QueryStatus
9464 0 : postgres_lookup_wire_transfer (
9465 : void *cls,
9466 : const struct TALER_WireTransferIdentifierRawP *wtid,
9467 : TALER_EXCHANGEDB_AggregationDataCallback cb,
9468 : void *cb_cls)
9469 : {
9470 0 : struct PostgresClosure *pg = cls;
9471 0 : struct GNUNET_PQ_QueryParam params[] = {
9472 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
9473 : GNUNET_PQ_query_param_end
9474 : };
9475 : struct WireTransferResultContext ctx;
9476 : enum GNUNET_DB_QueryStatus qs;
9477 :
9478 0 : ctx.cb = cb;
9479 0 : ctx.cb_cls = cb_cls;
9480 0 : ctx.pg = pg;
9481 0 : ctx.status = GNUNET_OK;
9482 : /* check if the melt record exists and get it */
9483 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
9484 : "lookup_transactions",
9485 : params,
9486 : &handle_wt_result,
9487 : &ctx);
9488 0 : if (GNUNET_OK != ctx.status)
9489 0 : return GNUNET_DB_STATUS_HARD_ERROR;
9490 0 : return qs;
9491 : }
9492 :
9493 :
9494 : /**
9495 : * Try to find the wire transfer details for a deposit operation.
9496 : * If we did not execute the deposit yet, return when it is supposed
9497 : * to be executed.
9498 : *
9499 : * @param cls closure
9500 : * @param h_contract_terms hash of the proposal data
9501 : * @param h_wire hash of merchant wire details
9502 : * @param coin_pub public key of deposited coin
9503 : * @param merchant_pub merchant public key
9504 : * @param[out] pending set to true if the transaction is still pending
9505 : * @param[out] wtid wire transfer identifier, only set if @a pending is false
9506 : * @param[out] exec_time when was the transaction done, or
9507 : * when we expect it to be done (if @a pending is false)
9508 : * @param[out] amount_with_fee set to the total deposited amount
9509 : * @param[out] deposit_fee set to how much the exchange did charge for the deposit
9510 : * @param[out] kyc set to the kyc status of the receiver (if @a pending)
9511 : * @return transaction status code
9512 : */
9513 : static enum GNUNET_DB_QueryStatus
9514 0 : postgres_lookup_transfer_by_deposit (
9515 : void *cls,
9516 : const struct TALER_PrivateContractHashP *h_contract_terms,
9517 : const struct TALER_MerchantWireHashP *h_wire,
9518 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
9519 : const struct TALER_MerchantPublicKeyP *merchant_pub,
9520 : bool *pending,
9521 : struct TALER_WireTransferIdentifierRawP *wtid,
9522 : struct GNUNET_TIME_Timestamp *exec_time,
9523 : struct TALER_Amount *amount_with_fee,
9524 : struct TALER_Amount *deposit_fee,
9525 : struct TALER_EXCHANGEDB_KycStatus *kyc)
9526 : {
9527 0 : struct PostgresClosure *pg = cls;
9528 : enum GNUNET_DB_QueryStatus qs;
9529 0 : struct GNUNET_PQ_QueryParam params[] = {
9530 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
9531 0 : GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
9532 0 : GNUNET_PQ_query_param_auto_from_type (merchant_pub),
9533 : GNUNET_PQ_query_param_end
9534 : };
9535 : char *payto_uri;
9536 : struct TALER_WireSaltP wire_salt;
9537 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9538 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
9539 : wtid),
9540 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
9541 : &wire_salt),
9542 0 : GNUNET_PQ_result_spec_string ("payto_uri",
9543 : &payto_uri),
9544 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
9545 : exec_time),
9546 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
9547 : amount_with_fee),
9548 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
9549 : deposit_fee),
9550 : GNUNET_PQ_result_spec_end
9551 : };
9552 :
9553 0 : memset (kyc,
9554 : 0,
9555 : sizeof (*kyc));
9556 : /* check if the aggregation record exists and get it */
9557 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
9558 : "lookup_deposit_wtid",
9559 : params,
9560 : rs);
9561 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
9562 : {
9563 : struct TALER_MerchantWireHashP wh;
9564 :
9565 0 : TALER_merchant_wire_signature_hash (payto_uri,
9566 : &wire_salt,
9567 : &wh);
9568 0 : GNUNET_PQ_cleanup_result (rs);
9569 0 : if (0 ==
9570 0 : GNUNET_memcmp (&wh,
9571 : h_wire))
9572 : {
9573 0 : *pending = false;
9574 0 : kyc->ok = true;
9575 0 : return qs;
9576 : }
9577 0 : qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
9578 : }
9579 0 : if (0 > qs)
9580 0 : return qs;
9581 0 : *pending = true;
9582 0 : memset (wtid,
9583 : 0,
9584 : sizeof (*wtid));
9585 0 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
9586 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9587 : "lookup_deposit_wtid returned 0 matching rows\n");
9588 : {
9589 : /* Check if transaction exists in deposits, so that we just
9590 : do not have a WTID yet. In that case, return without wtid
9591 : (by setting 'pending' true). */
9592 0 : struct GNUNET_PQ_ResultSpec rs2[] = {
9593 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
9594 : &wire_salt),
9595 0 : GNUNET_PQ_result_spec_string ("payto_uri",
9596 : &payto_uri),
9597 0 : GNUNET_PQ_result_spec_allow_null (
9598 : GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
9599 : &kyc->requirement_row),
9600 : NULL),
9601 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
9602 : amount_with_fee),
9603 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
9604 : deposit_fee),
9605 0 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
9606 : exec_time),
9607 : GNUNET_PQ_result_spec_end
9608 : };
9609 :
9610 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
9611 : "get_deposit_without_wtid",
9612 : params,
9613 : rs2);
9614 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
9615 : {
9616 : struct TALER_MerchantWireHashP wh;
9617 :
9618 0 : if (0 == kyc->requirement_row)
9619 0 : kyc->ok = true; /* technically: unknown */
9620 0 : TALER_merchant_wire_signature_hash (payto_uri,
9621 : &wire_salt,
9622 : &wh);
9623 0 : GNUNET_PQ_cleanup_result (rs);
9624 0 : if (0 !=
9625 0 : GNUNET_memcmp (&wh,
9626 : h_wire))
9627 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
9628 : }
9629 0 : return qs;
9630 : }
9631 : }
9632 :
9633 :
9634 : /**
9635 : * Function called to insert aggregation information into the DB.
9636 : *
9637 : * @param cls closure
9638 : * @param wtid the raw wire transfer identifier we used
9639 : * @param deposit_serial_id row in the deposits table for which this is aggregation data
9640 : * @return transaction status code
9641 : */
9642 : static enum GNUNET_DB_QueryStatus
9643 0 : postgres_insert_aggregation_tracking (
9644 : void *cls,
9645 : const struct TALER_WireTransferIdentifierRawP *wtid,
9646 : unsigned long long deposit_serial_id)
9647 : {
9648 0 : struct PostgresClosure *pg = cls;
9649 0 : uint64_t rid = deposit_serial_id;
9650 0 : struct GNUNET_PQ_QueryParam params[] = {
9651 0 : GNUNET_PQ_query_param_uint64 (&rid),
9652 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
9653 : GNUNET_PQ_query_param_end
9654 : };
9655 :
9656 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
9657 : "insert_aggregation_tracking",
9658 : params);
9659 : }
9660 :
9661 :
9662 : /**
9663 : * Obtain wire fee from database.
9664 : *
9665 : * @param cls closure
9666 : * @param type type of wire transfer the fee applies for
9667 : * @param date for which date do we want the fee?
9668 : * @param[out] start_date when does the fee go into effect
9669 : * @param[out] end_date when does the fee end being valid
9670 : * @param[out] fees how high are the wire fees
9671 : * @param[out] master_sig signature over the above by the exchange master key
9672 : * @return status of the transaction
9673 : */
9674 : static enum GNUNET_DB_QueryStatus
9675 0 : postgres_get_wire_fee (void *cls,
9676 : const char *type,
9677 : struct GNUNET_TIME_Timestamp date,
9678 : struct GNUNET_TIME_Timestamp *start_date,
9679 : struct GNUNET_TIME_Timestamp *end_date,
9680 : struct TALER_WireFeeSet *fees,
9681 : struct TALER_MasterSignatureP *master_sig)
9682 : {
9683 0 : struct PostgresClosure *pg = cls;
9684 0 : struct GNUNET_PQ_QueryParam params[] = {
9685 0 : GNUNET_PQ_query_param_string (type),
9686 0 : GNUNET_PQ_query_param_timestamp (&date),
9687 : GNUNET_PQ_query_param_end
9688 : };
9689 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9690 0 : GNUNET_PQ_result_spec_timestamp ("start_date",
9691 : start_date),
9692 0 : GNUNET_PQ_result_spec_timestamp ("end_date",
9693 : end_date),
9694 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
9695 : &fees->wire),
9696 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("wad_fee",
9697 : &fees->wad),
9698 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
9699 : &fees->closing),
9700 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
9701 : master_sig),
9702 : GNUNET_PQ_result_spec_end
9703 : };
9704 :
9705 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
9706 : "get_wire_fee",
9707 : params,
9708 : rs);
9709 : }
9710 :
9711 :
9712 : /**
9713 : * Obtain global fees from database.
9714 : *
9715 : * @param cls closure
9716 : * @param date for which date do we want the fee?
9717 : * @param[out] start_date when does the fee go into effect
9718 : * @param[out] end_date when does the fee end being valid
9719 : * @param[out] fees how high are the wire fees
9720 : * @param[out] purse_timeout set to how long we keep unmerged purses
9721 : * @param[out] kyc_timeout set to how long we keep accounts without KYC
9722 : * @param[out] history_expiration set to how long we keep account histories
9723 : * @param[out] purse_account_limit set to the number of free purses per account
9724 : * @param[out] master_sig signature over the above by the exchange master key
9725 : * @return status of the transaction
9726 : */
9727 : static enum GNUNET_DB_QueryStatus
9728 0 : postgres_get_global_fee (void *cls,
9729 : struct GNUNET_TIME_Timestamp date,
9730 : struct GNUNET_TIME_Timestamp *start_date,
9731 : struct GNUNET_TIME_Timestamp *end_date,
9732 : struct TALER_GlobalFeeSet *fees,
9733 : struct GNUNET_TIME_Relative *purse_timeout,
9734 : struct GNUNET_TIME_Relative *kyc_timeout,
9735 : struct GNUNET_TIME_Relative *history_expiration,
9736 : uint32_t *purse_account_limit,
9737 : struct TALER_MasterSignatureP *master_sig)
9738 : {
9739 0 : struct PostgresClosure *pg = cls;
9740 0 : struct GNUNET_PQ_QueryParam params[] = {
9741 0 : GNUNET_PQ_query_param_timestamp (&date),
9742 : GNUNET_PQ_query_param_end
9743 : };
9744 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9745 0 : GNUNET_PQ_result_spec_timestamp ("start_date",
9746 : start_date),
9747 0 : GNUNET_PQ_result_spec_timestamp ("end_date",
9748 : end_date),
9749 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
9750 : &fees->history),
9751 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("kyc_fee",
9752 : &fees->kyc),
9753 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee",
9754 : &fees->account),
9755 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
9756 : &fees->purse),
9757 0 : GNUNET_PQ_result_spec_relative_time ("purse_timeout",
9758 : purse_timeout),
9759 0 : GNUNET_PQ_result_spec_relative_time ("kyc_timeout",
9760 : kyc_timeout),
9761 0 : GNUNET_PQ_result_spec_relative_time ("history_expiration",
9762 : history_expiration),
9763 0 : GNUNET_PQ_result_spec_uint32 ("purse_account_limit",
9764 : purse_account_limit),
9765 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
9766 : master_sig),
9767 : GNUNET_PQ_result_spec_end
9768 : };
9769 :
9770 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
9771 : "get_global_fee",
9772 : params,
9773 : rs);
9774 : }
9775 :
9776 :
9777 : /**
9778 : * Closure for #global_fees_cb().
9779 : */
9780 : struct GlobalFeeContext
9781 : {
9782 : /**
9783 : * Function to call for each global fee block.
9784 : */
9785 : TALER_EXCHANGEDB_GlobalFeeCallback cb;
9786 :
9787 : /**
9788 : * Closure to give to @e rec.
9789 : */
9790 : void *cb_cls;
9791 :
9792 : /**
9793 : * Plugin context.
9794 : */
9795 : struct PostgresClosure *pg;
9796 :
9797 : /**
9798 : * Set to #GNUNET_SYSERR on error.
9799 : */
9800 : enum GNUNET_GenericReturnValue status;
9801 : };
9802 :
9803 :
9804 : /**
9805 : * Function to be called with the results of a SELECT statement
9806 : * that has returned @a num_results results.
9807 : *
9808 : * @param cls closure
9809 : * @param result the postgres result
9810 : * @param num_results the number of results in @a result
9811 : */
9812 : static void
9813 0 : global_fees_cb (void *cls,
9814 : PGresult *result,
9815 : unsigned int num_results)
9816 : {
9817 0 : struct GlobalFeeContext *gctx = cls;
9818 0 : struct PostgresClosure *pg = gctx->pg;
9819 :
9820 0 : for (unsigned int i = 0; i<num_results; i++)
9821 : {
9822 : struct TALER_GlobalFeeSet fees;
9823 : struct GNUNET_TIME_Relative purse_timeout;
9824 : struct GNUNET_TIME_Relative kyc_timeout;
9825 : struct GNUNET_TIME_Relative history_expiration;
9826 : uint32_t purse_account_limit;
9827 : struct GNUNET_TIME_Timestamp start_date;
9828 : struct GNUNET_TIME_Timestamp end_date;
9829 : struct TALER_MasterSignatureP master_sig;
9830 0 : struct GNUNET_PQ_ResultSpec rs[] = {
9831 0 : GNUNET_PQ_result_spec_timestamp ("start_date",
9832 : &start_date),
9833 0 : GNUNET_PQ_result_spec_timestamp ("end_date",
9834 : &end_date),
9835 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
9836 : &fees.history),
9837 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("kyc_fee",
9838 : &fees.kyc),
9839 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee",
9840 : &fees.account),
9841 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
9842 : &fees.purse),
9843 0 : GNUNET_PQ_result_spec_relative_time ("purse_timeout",
9844 : &purse_timeout),
9845 0 : GNUNET_PQ_result_spec_relative_time ("kyc_timeout",
9846 : &kyc_timeout),
9847 0 : GNUNET_PQ_result_spec_relative_time ("history_expiration",
9848 : &history_expiration),
9849 0 : GNUNET_PQ_result_spec_uint32 ("purse_account_limit",
9850 : &purse_account_limit),
9851 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
9852 : &master_sig),
9853 : GNUNET_PQ_result_spec_end
9854 : };
9855 0 : if (GNUNET_OK !=
9856 0 : GNUNET_PQ_extract_result (result,
9857 : rs,
9858 : i))
9859 : {
9860 0 : GNUNET_break (0);
9861 0 : gctx->status = GNUNET_SYSERR;
9862 0 : break;
9863 : }
9864 0 : gctx->cb (gctx->cb_cls,
9865 : &fees,
9866 : purse_timeout,
9867 : kyc_timeout,
9868 : history_expiration,
9869 : purse_account_limit,
9870 : start_date,
9871 : end_date,
9872 : &master_sig);
9873 0 : GNUNET_PQ_cleanup_result (rs);
9874 : }
9875 0 : }
9876 :
9877 :
9878 : /**
9879 : * Obtain global fees from database.
9880 : *
9881 : * @param cls closure
9882 : * @param cb function to call on each fee entry
9883 : * @param cb_cls closure for @a cb
9884 : * @return status of the transaction
9885 : */
9886 : static enum GNUNET_DB_QueryStatus
9887 0 : postgres_get_global_fees (void *cls,
9888 : TALER_EXCHANGEDB_GlobalFeeCallback cb,
9889 : void *cb_cls)
9890 : {
9891 0 : struct PostgresClosure *pg = cls;
9892 : struct GNUNET_TIME_Timestamp date
9893 0 : = GNUNET_TIME_absolute_to_timestamp (
9894 : GNUNET_TIME_absolute_subtract (
9895 : GNUNET_TIME_absolute_get (),
9896 : GNUNET_TIME_UNIT_YEARS));
9897 0 : struct GNUNET_PQ_QueryParam params[] = {
9898 0 : GNUNET_PQ_query_param_timestamp (&date),
9899 : GNUNET_PQ_query_param_end
9900 : };
9901 0 : struct GlobalFeeContext gctx = {
9902 : .cb = cb,
9903 : .cb_cls = cb_cls,
9904 : .pg = pg,
9905 : .status = GNUNET_OK
9906 : };
9907 :
9908 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
9909 : "get_global_fees",
9910 : params,
9911 : &global_fees_cb,
9912 : &gctx);
9913 : }
9914 :
9915 :
9916 : /**
9917 : * Insert wire transfer fee into database.
9918 : *
9919 : * @param cls closure
9920 : * @param type type of wire transfer this fee applies for
9921 : * @param start_date when does the fee go into effect
9922 : * @param end_date when does the fee end being valid
9923 : * @param fees how high are the wire fees
9924 : * @param master_sig signature over the above by the exchange master key
9925 : * @return transaction status code
9926 : */
9927 : static enum GNUNET_DB_QueryStatus
9928 0 : postgres_insert_wire_fee (void *cls,
9929 : const char *type,
9930 : struct GNUNET_TIME_Timestamp start_date,
9931 : struct GNUNET_TIME_Timestamp end_date,
9932 : const struct TALER_WireFeeSet *fees,
9933 : const struct TALER_MasterSignatureP *master_sig)
9934 : {
9935 0 : struct PostgresClosure *pg = cls;
9936 0 : struct GNUNET_PQ_QueryParam params[] = {
9937 0 : GNUNET_PQ_query_param_string (type),
9938 0 : GNUNET_PQ_query_param_timestamp (&start_date),
9939 0 : GNUNET_PQ_query_param_timestamp (&end_date),
9940 0 : TALER_PQ_query_param_amount (&fees->wire),
9941 0 : TALER_PQ_query_param_amount (&fees->closing),
9942 0 : TALER_PQ_query_param_amount (&fees->wad),
9943 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
9944 : GNUNET_PQ_query_param_end
9945 : };
9946 : struct TALER_WireFeeSet wx;
9947 : struct TALER_MasterSignatureP sig;
9948 : struct GNUNET_TIME_Timestamp sd;
9949 : struct GNUNET_TIME_Timestamp ed;
9950 : enum GNUNET_DB_QueryStatus qs;
9951 :
9952 0 : qs = postgres_get_wire_fee (pg,
9953 : type,
9954 : start_date,
9955 : &sd,
9956 : &ed,
9957 : &wx,
9958 : &sig);
9959 0 : if (qs < 0)
9960 0 : return qs;
9961 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
9962 : {
9963 0 : if (0 != GNUNET_memcmp (&sig,
9964 : master_sig))
9965 : {
9966 0 : GNUNET_break (0);
9967 0 : return GNUNET_DB_STATUS_HARD_ERROR;
9968 : }
9969 0 : if (0 !=
9970 0 : TALER_wire_fee_set_cmp (fees,
9971 : &wx))
9972 : {
9973 0 : GNUNET_break (0);
9974 0 : return GNUNET_DB_STATUS_HARD_ERROR;
9975 : }
9976 0 : if ( (GNUNET_TIME_timestamp_cmp (sd,
9977 : !=,
9978 0 : start_date)) ||
9979 0 : (GNUNET_TIME_timestamp_cmp (ed,
9980 : !=,
9981 : end_date)) )
9982 : {
9983 0 : GNUNET_break (0);
9984 0 : return GNUNET_DB_STATUS_HARD_ERROR;
9985 : }
9986 : /* equal record already exists */
9987 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
9988 : }
9989 :
9990 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
9991 : "insert_wire_fee",
9992 : params);
9993 : }
9994 :
9995 :
9996 : /**
9997 : * Insert global fee data into database.
9998 : *
9999 : * @param cls closure
10000 : * @param start_date when does the fees go into effect
10001 : * @param end_date when does the fees end being valid
10002 : * @param fees how high is are the global fees
10003 : * @param purse_timeout when do purses time out
10004 : * @param kyc_timeout when do reserves without KYC time out
10005 : * @param history_expiration how long are account histories preserved
10006 : * @param purse_account_limit how many purses are free per account
10007 : * @param master_sig signature over the above by the exchange master key
10008 : * @return transaction status code
10009 : */
10010 : static enum GNUNET_DB_QueryStatus
10011 0 : postgres_insert_global_fee (void *cls,
10012 : struct GNUNET_TIME_Timestamp start_date,
10013 : struct GNUNET_TIME_Timestamp end_date,
10014 : const struct TALER_GlobalFeeSet *fees,
10015 : struct GNUNET_TIME_Relative purse_timeout,
10016 : struct GNUNET_TIME_Relative kyc_timeout,
10017 : struct GNUNET_TIME_Relative history_expiration,
10018 : uint32_t purse_account_limit,
10019 : const struct TALER_MasterSignatureP *master_sig)
10020 : {
10021 0 : struct PostgresClosure *pg = cls;
10022 0 : struct GNUNET_PQ_QueryParam params[] = {
10023 0 : GNUNET_PQ_query_param_timestamp (&start_date),
10024 0 : GNUNET_PQ_query_param_timestamp (&end_date),
10025 0 : TALER_PQ_query_param_amount (&fees->history),
10026 0 : TALER_PQ_query_param_amount (&fees->kyc),
10027 0 : TALER_PQ_query_param_amount (&fees->account),
10028 0 : TALER_PQ_query_param_amount (&fees->purse),
10029 0 : GNUNET_PQ_query_param_relative_time (&purse_timeout),
10030 0 : GNUNET_PQ_query_param_relative_time (&kyc_timeout),
10031 0 : GNUNET_PQ_query_param_relative_time (&history_expiration),
10032 0 : GNUNET_PQ_query_param_uint32 (&purse_account_limit),
10033 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
10034 : GNUNET_PQ_query_param_end
10035 : };
10036 : struct TALER_GlobalFeeSet wx;
10037 : struct TALER_MasterSignatureP sig;
10038 : struct GNUNET_TIME_Timestamp sd;
10039 : struct GNUNET_TIME_Timestamp ed;
10040 : enum GNUNET_DB_QueryStatus qs;
10041 : struct GNUNET_TIME_Relative pt;
10042 : struct GNUNET_TIME_Relative kt;
10043 : struct GNUNET_TIME_Relative he;
10044 : uint32_t pal;
10045 :
10046 0 : qs = postgres_get_global_fee (pg,
10047 : start_date,
10048 : &sd,
10049 : &ed,
10050 : &wx,
10051 : &pt,
10052 : &kt,
10053 : &he,
10054 : &pal,
10055 : &sig);
10056 0 : if (qs < 0)
10057 0 : return qs;
10058 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
10059 : {
10060 0 : if (0 != GNUNET_memcmp (&sig,
10061 : master_sig))
10062 : {
10063 0 : GNUNET_break (0);
10064 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10065 : }
10066 0 : if (0 !=
10067 0 : TALER_global_fee_set_cmp (fees,
10068 : &wx))
10069 : {
10070 0 : GNUNET_break (0);
10071 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10072 : }
10073 0 : if ( (GNUNET_TIME_timestamp_cmp (sd,
10074 : !=,
10075 0 : start_date)) ||
10076 0 : (GNUNET_TIME_timestamp_cmp (ed,
10077 : !=,
10078 : end_date)) )
10079 : {
10080 0 : GNUNET_break (0);
10081 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10082 : }
10083 0 : if ( (GNUNET_TIME_relative_cmp (purse_timeout,
10084 : !=,
10085 0 : pt)) ||
10086 0 : (GNUNET_TIME_relative_cmp (kyc_timeout,
10087 : !=,
10088 0 : kt)) ||
10089 0 : (GNUNET_TIME_relative_cmp (history_expiration,
10090 : !=,
10091 : he)) )
10092 : {
10093 0 : GNUNET_break (0);
10094 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10095 : }
10096 0 : if (purse_account_limit != pal)
10097 : {
10098 0 : GNUNET_break (0);
10099 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10100 : }
10101 : /* equal record already exists */
10102 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
10103 : }
10104 :
10105 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
10106 : "insert_global_fee",
10107 : params);
10108 : }
10109 :
10110 :
10111 : /**
10112 : * Closure for #reserve_expired_cb().
10113 : */
10114 : struct ExpiredReserveContext
10115 : {
10116 : /**
10117 : * Function to call for each expired reserve.
10118 : */
10119 : TALER_EXCHANGEDB_ReserveExpiredCallback rec;
10120 :
10121 : /**
10122 : * Closure to give to @e rec.
10123 : */
10124 : void *rec_cls;
10125 :
10126 : /**
10127 : * Plugin context.
10128 : */
10129 : struct PostgresClosure *pg;
10130 :
10131 : /**
10132 : * Set to #GNUNET_SYSERR on error.
10133 : */
10134 : enum GNUNET_GenericReturnValue status;
10135 : };
10136 :
10137 :
10138 : /**
10139 : * Function to be called with the results of a SELECT statement
10140 : * that has returned @a num_results results.
10141 : *
10142 : * @param cls closure
10143 : * @param result the postgres result
10144 : * @param num_results the number of results in @a result
10145 : */
10146 : static void
10147 0 : reserve_expired_cb (void *cls,
10148 : PGresult *result,
10149 : unsigned int num_results)
10150 : {
10151 0 : struct ExpiredReserveContext *erc = cls;
10152 0 : struct PostgresClosure *pg = erc->pg;
10153 : enum GNUNET_GenericReturnValue ret;
10154 :
10155 0 : ret = GNUNET_OK;
10156 0 : for (unsigned int i = 0; i<num_results; i++)
10157 : {
10158 : struct GNUNET_TIME_Timestamp exp_date;
10159 : char *account_details;
10160 : struct TALER_ReservePublicKeyP reserve_pub;
10161 : struct TALER_Amount remaining_balance;
10162 0 : struct GNUNET_PQ_ResultSpec rs[] = {
10163 0 : GNUNET_PQ_result_spec_timestamp ("expiration_date",
10164 : &exp_date),
10165 0 : GNUNET_PQ_result_spec_string ("account_details",
10166 : &account_details),
10167 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
10168 : &reserve_pub),
10169 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
10170 : &remaining_balance),
10171 : GNUNET_PQ_result_spec_end
10172 : };
10173 :
10174 0 : if (GNUNET_OK !=
10175 0 : GNUNET_PQ_extract_result (result,
10176 : rs,
10177 : i))
10178 : {
10179 0 : GNUNET_break (0);
10180 0 : ret = GNUNET_SYSERR;
10181 0 : break;
10182 : }
10183 0 : ret = erc->rec (erc->rec_cls,
10184 : &reserve_pub,
10185 : &remaining_balance,
10186 : account_details,
10187 : exp_date);
10188 0 : GNUNET_PQ_cleanup_result (rs);
10189 0 : if (GNUNET_OK != ret)
10190 0 : break;
10191 : }
10192 0 : erc->status = ret;
10193 0 : }
10194 :
10195 :
10196 : /**
10197 : * Obtain information about expired reserves and their
10198 : * remaining balances.
10199 : *
10200 : * @param cls closure of the plugin
10201 : * @param now timestamp based on which we decide expiration
10202 : * @param rec function to call on expired reserves
10203 : * @param rec_cls closure for @a rec
10204 : * @return transaction status
10205 : */
10206 : static enum GNUNET_DB_QueryStatus
10207 0 : postgres_get_expired_reserves (void *cls,
10208 : struct GNUNET_TIME_Timestamp now,
10209 : TALER_EXCHANGEDB_ReserveExpiredCallback rec,
10210 : void *rec_cls)
10211 : {
10212 0 : struct PostgresClosure *pg = cls;
10213 0 : struct GNUNET_PQ_QueryParam params[] = {
10214 0 : GNUNET_PQ_query_param_timestamp (&now),
10215 : GNUNET_PQ_query_param_end
10216 : };
10217 0 : struct ExpiredReserveContext ectx = {
10218 : .rec = rec,
10219 : .rec_cls = rec_cls,
10220 : .pg = pg,
10221 : .status = GNUNET_OK
10222 : };
10223 : enum GNUNET_DB_QueryStatus qs;
10224 :
10225 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
10226 : "get_expired_reserves",
10227 : params,
10228 : &reserve_expired_cb,
10229 : &ectx);
10230 0 : switch (ectx.status)
10231 : {
10232 0 : case GNUNET_SYSERR:
10233 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10234 0 : case GNUNET_NO:
10235 0 : return GNUNET_DB_STATUS_SOFT_ERROR;
10236 0 : case GNUNET_OK:
10237 0 : break;
10238 : }
10239 0 : return qs;
10240 : }
10241 :
10242 :
10243 : /**
10244 : * Insert reserve close operation into database.
10245 : *
10246 : * @param cls closure
10247 : * @param reserve_pub which reserve is this about?
10248 : * @param execution_date when did we perform the transfer?
10249 : * @param receiver_account to which account do we transfer?
10250 : * @param wtid wire transfer details
10251 : * @param amount_with_fee amount we charged to the reserve
10252 : * @param closing_fee how high is the closing fee
10253 : * @return transaction status code
10254 : */
10255 : static enum GNUNET_DB_QueryStatus
10256 0 : postgres_insert_reserve_closed (
10257 : void *cls,
10258 : const struct TALER_ReservePublicKeyP *reserve_pub,
10259 : struct GNUNET_TIME_Timestamp execution_date,
10260 : const char *receiver_account,
10261 : const struct TALER_WireTransferIdentifierRawP *wtid,
10262 : const struct TALER_Amount *amount_with_fee,
10263 : const struct TALER_Amount *closing_fee)
10264 : {
10265 0 : struct PostgresClosure *pg = cls;
10266 : struct TALER_EXCHANGEDB_Reserve reserve;
10267 : enum GNUNET_DB_QueryStatus qs;
10268 : struct TALER_PaytoHashP h_payto;
10269 :
10270 0 : TALER_payto_hash (receiver_account,
10271 : &h_payto);
10272 : {
10273 0 : struct GNUNET_PQ_QueryParam params[] = {
10274 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
10275 0 : GNUNET_PQ_query_param_timestamp (&execution_date),
10276 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
10277 0 : GNUNET_PQ_query_param_auto_from_type (&h_payto),
10278 0 : TALER_PQ_query_param_amount (amount_with_fee),
10279 0 : TALER_PQ_query_param_amount (closing_fee),
10280 : GNUNET_PQ_query_param_end
10281 : };
10282 :
10283 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
10284 : "reserves_close_insert",
10285 : params);
10286 : }
10287 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
10288 0 : return qs;
10289 :
10290 : /* update reserve balance */
10291 0 : reserve.pub = *reserve_pub;
10292 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
10293 0 : (qs = postgres_reserves_get (cls,
10294 : &reserve)))
10295 : {
10296 : /* Existence should have been checked before we got here... */
10297 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
10298 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
10299 0 : qs = GNUNET_DB_STATUS_HARD_ERROR;
10300 0 : return qs;
10301 : }
10302 : {
10303 : enum TALER_AmountArithmeticResult ret;
10304 :
10305 0 : ret = TALER_amount_subtract (&reserve.balance,
10306 : &reserve.balance,
10307 : amount_with_fee);
10308 0 : if (ret < 0)
10309 : {
10310 : /* The reserve history was checked to make sure there is enough of a balance
10311 : left before we tried this; however, concurrent operations may have changed
10312 : the situation by now. We should re-try the transaction. */
10313 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
10314 : "Closing of reserve `%s' refused due to balance mismatch. Retrying.\n",
10315 : TALER_B2S (reserve_pub));
10316 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10317 : }
10318 0 : GNUNET_break (TALER_AAR_RESULT_ZERO == ret);
10319 : }
10320 0 : return reserves_update (cls,
10321 : &reserve);
10322 : }
10323 :
10324 :
10325 : /**
10326 : * Function called to insert wire transfer commit data into the DB.
10327 : *
10328 : * @param cls closure
10329 : * @param type type of the wire transfer (i.e. "iban")
10330 : * @param buf buffer with wire transfer preparation data
10331 : * @param buf_size number of bytes in @a buf
10332 : * @return query status code
10333 : */
10334 : static enum GNUNET_DB_QueryStatus
10335 0 : postgres_wire_prepare_data_insert (void *cls,
10336 : const char *type,
10337 : const char *buf,
10338 : size_t buf_size)
10339 : {
10340 0 : struct PostgresClosure *pg = cls;
10341 0 : struct GNUNET_PQ_QueryParam params[] = {
10342 0 : GNUNET_PQ_query_param_string (type),
10343 0 : GNUNET_PQ_query_param_fixed_size (buf, buf_size),
10344 : GNUNET_PQ_query_param_end
10345 : };
10346 :
10347 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
10348 : "wire_prepare_data_insert",
10349 : params);
10350 : }
10351 :
10352 :
10353 : /**
10354 : * Function called to mark wire transfer commit data as finished.
10355 : *
10356 : * @param cls closure
10357 : * @param rowid which entry to mark as finished
10358 : * @return transaction status code
10359 : */
10360 : static enum GNUNET_DB_QueryStatus
10361 0 : postgres_wire_prepare_data_mark_finished (
10362 : void *cls,
10363 : uint64_t rowid)
10364 : {
10365 0 : struct PostgresClosure *pg = cls;
10366 0 : struct GNUNET_PQ_QueryParam params[] = {
10367 0 : GNUNET_PQ_query_param_uint64 (&rowid),
10368 : GNUNET_PQ_query_param_end
10369 : };
10370 :
10371 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
10372 : "wire_prepare_data_mark_done",
10373 : params);
10374 : }
10375 :
10376 :
10377 : /**
10378 : * Function called to mark wire transfer commit data as failed.
10379 : *
10380 : * @param cls closure
10381 : * @param rowid which entry to mark as failed
10382 : * @return transaction status code
10383 : */
10384 : static enum GNUNET_DB_QueryStatus
10385 0 : postgres_wire_prepare_data_mark_failed (
10386 : void *cls,
10387 : uint64_t rowid)
10388 : {
10389 0 : struct PostgresClosure *pg = cls;
10390 0 : struct GNUNET_PQ_QueryParam params[] = {
10391 0 : GNUNET_PQ_query_param_uint64 (&rowid),
10392 : GNUNET_PQ_query_param_end
10393 : };
10394 :
10395 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
10396 : "wire_prepare_data_mark_failed",
10397 : params);
10398 : }
10399 :
10400 :
10401 : /**
10402 : * Closure for #prewire_cb().
10403 : */
10404 : struct PrewireContext
10405 : {
10406 : /**
10407 : * Function to call on each result.
10408 : */
10409 : TALER_EXCHANGEDB_WirePreparationIterator cb;
10410 :
10411 : /**
10412 : * Closure for @a cb.
10413 : */
10414 : void *cb_cls;
10415 :
10416 : /**
10417 : * #GNUNET_OK if everything went fine.
10418 : */
10419 : enum GNUNET_GenericReturnValue status;
10420 : };
10421 :
10422 :
10423 : /**
10424 : * Invoke the callback for each result.
10425 : *
10426 : * @param cls a `struct MissingWireContext *`
10427 : * @param result SQL result
10428 : * @param num_results number of rows in @a result
10429 : */
10430 : static void
10431 0 : prewire_cb (void *cls,
10432 : PGresult *result,
10433 : unsigned int num_results)
10434 : {
10435 0 : struct PrewireContext *pc = cls;
10436 :
10437 0 : for (unsigned int i = 0; i < num_results; i++)
10438 : {
10439 : uint64_t prewire_uuid;
10440 : char *wire_method;
10441 0 : void *buf = NULL;
10442 : size_t buf_size;
10443 0 : struct GNUNET_PQ_ResultSpec rs[] = {
10444 0 : GNUNET_PQ_result_spec_uint64 ("prewire_uuid",
10445 : &prewire_uuid),
10446 0 : GNUNET_PQ_result_spec_string ("wire_method",
10447 : &wire_method),
10448 0 : GNUNET_PQ_result_spec_variable_size ("buf",
10449 : &buf,
10450 : &buf_size),
10451 : GNUNET_PQ_result_spec_end
10452 : };
10453 :
10454 0 : if (GNUNET_OK !=
10455 0 : GNUNET_PQ_extract_result (result,
10456 : rs,
10457 : i))
10458 : {
10459 0 : GNUNET_break (0);
10460 0 : pc->status = GNUNET_SYSERR;
10461 0 : return;
10462 : }
10463 0 : pc->cb (pc->cb_cls,
10464 : prewire_uuid,
10465 : wire_method,
10466 : buf,
10467 : buf_size);
10468 0 : GNUNET_PQ_cleanup_result (rs);
10469 : }
10470 : }
10471 :
10472 :
10473 : /**
10474 : * Function called to get an unfinished wire transfer
10475 : * preparation data. Fetches at most one item.
10476 : *
10477 : * @param cls closure
10478 : * @param start_row offset to query table at
10479 : * @param limit maximum number of results to return
10480 : * @param cb function to call for ONE unfinished item
10481 : * @param cb_cls closure for @a cb
10482 : * @return transaction status code
10483 : */
10484 : static enum GNUNET_DB_QueryStatus
10485 0 : postgres_wire_prepare_data_get (void *cls,
10486 : uint64_t start_row,
10487 : uint64_t limit,
10488 : TALER_EXCHANGEDB_WirePreparationIterator cb,
10489 : void *cb_cls)
10490 : {
10491 0 : struct PostgresClosure *pg = cls;
10492 0 : struct GNUNET_PQ_QueryParam params[] = {
10493 0 : GNUNET_PQ_query_param_uint64 (&start_row),
10494 0 : GNUNET_PQ_query_param_uint64 (&limit),
10495 : GNUNET_PQ_query_param_end
10496 : };
10497 0 : struct PrewireContext pc = {
10498 : .cb = cb,
10499 : .cb_cls = cb_cls,
10500 : .status = GNUNET_OK
10501 : };
10502 : enum GNUNET_DB_QueryStatus qs;
10503 :
10504 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
10505 : "wire_prepare_data_get",
10506 : params,
10507 : &prewire_cb,
10508 : &pc);
10509 0 : if (GNUNET_OK != pc.status)
10510 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10511 0 : return qs;
10512 : }
10513 :
10514 :
10515 : /**
10516 : * Starts a READ COMMITTED transaction where we transiently violate the foreign
10517 : * constraints on the "wire_out" table as we insert aggregations
10518 : * and only add the wire transfer out at the end.
10519 : *
10520 : * @param cls the @e cls of this struct with the plugin-specific state
10521 : * @return #GNUNET_OK on success
10522 : */
10523 : static enum GNUNET_GenericReturnValue
10524 0 : postgres_start_deferred_wire_out (void *cls)
10525 : {
10526 0 : struct PostgresClosure *pg = cls;
10527 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
10528 0 : GNUNET_PQ_make_execute (
10529 : "START TRANSACTION ISOLATION LEVEL READ COMMITTED;"),
10530 0 : GNUNET_PQ_make_execute ("SET CONSTRAINTS ALL DEFERRED;"),
10531 : GNUNET_PQ_EXECUTE_STATEMENT_END
10532 : };
10533 :
10534 0 : if (GNUNET_SYSERR ==
10535 0 : postgres_preflight (pg))
10536 0 : return GNUNET_SYSERR;
10537 0 : if (GNUNET_OK !=
10538 0 : GNUNET_PQ_exec_statements (pg->conn,
10539 : es))
10540 : {
10541 0 : TALER_LOG_ERROR (
10542 : "Failed to defer wire_out_ref constraint on transaction\n");
10543 0 : GNUNET_break (0);
10544 0 : postgres_rollback (pg);
10545 0 : return GNUNET_SYSERR;
10546 : }
10547 0 : pg->transaction_name = "deferred wire out";
10548 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10549 : "Starting READ COMMITTED DEFERRED transaction `%s'\n",
10550 : pg->transaction_name);
10551 0 : return GNUNET_OK;
10552 : }
10553 :
10554 :
10555 : /**
10556 : * Store information about an outgoing wire transfer that was executed.
10557 : *
10558 : * @param cls closure
10559 : * @param date time of the wire transfer
10560 : * @param wtid subject of the wire transfer
10561 : * @param h_payto identifies the receiver account of the wire transfer
10562 : * @param exchange_account_section configuration section of the exchange specifying the
10563 : * exchange's bank account being used
10564 : * @param amount amount that was transmitted
10565 : * @return transaction status code
10566 : */
10567 : static enum GNUNET_DB_QueryStatus
10568 0 : postgres_store_wire_transfer_out (
10569 : void *cls,
10570 : struct GNUNET_TIME_Timestamp date,
10571 : const struct TALER_WireTransferIdentifierRawP *wtid,
10572 : const struct TALER_PaytoHashP *h_payto,
10573 : const char *exchange_account_section,
10574 : const struct TALER_Amount *amount)
10575 : {
10576 0 : struct PostgresClosure *pg = cls;
10577 0 : struct GNUNET_PQ_QueryParam params[] = {
10578 0 : GNUNET_PQ_query_param_timestamp (&date),
10579 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
10580 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
10581 0 : GNUNET_PQ_query_param_string (exchange_account_section),
10582 0 : TALER_PQ_query_param_amount (amount),
10583 : GNUNET_PQ_query_param_end
10584 : };
10585 :
10586 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
10587 : "insert_wire_out",
10588 : params);
10589 : }
10590 :
10591 :
10592 : /**
10593 : * Function called to perform "garbage collection" on the
10594 : * database, expiring records we no longer require.
10595 : *
10596 : * @param cls closure
10597 : * @return #GNUNET_OK on success,
10598 : * #GNUNET_SYSERR on DB errors
10599 : */
10600 : static enum GNUNET_GenericReturnValue
10601 0 : postgres_gc (void *cls)
10602 : {
10603 0 : struct PostgresClosure *pg = cls;
10604 0 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
10605 : struct GNUNET_TIME_Absolute long_ago;
10606 0 : struct GNUNET_PQ_QueryParam params[] = {
10607 0 : GNUNET_PQ_query_param_absolute_time (&long_ago),
10608 0 : GNUNET_PQ_query_param_absolute_time (&now),
10609 : GNUNET_PQ_query_param_end
10610 : };
10611 : struct GNUNET_PQ_Context *conn;
10612 : enum GNUNET_GenericReturnValue ret;
10613 :
10614 : /* Keep wire fees for 10 years, that should always
10615 : be enough _and_ they are tiny so it does not
10616 : matter to make this tight */
10617 0 : long_ago = GNUNET_TIME_absolute_subtract (
10618 : now,
10619 : GNUNET_TIME_relative_multiply (
10620 : GNUNET_TIME_UNIT_YEARS,
10621 : 10));
10622 : {
10623 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
10624 0 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
10625 : GNUNET_PQ_EXECUTE_STATEMENT_END
10626 : };
10627 0 : struct GNUNET_PQ_PreparedStatement ps[] = {
10628 : /* Used in #postgres_gc() */
10629 0 : GNUNET_PQ_make_prepare ("run_gc",
10630 : "CALL"
10631 : " exchange_do_gc"
10632 : " ($1,$2);",
10633 : 2),
10634 : GNUNET_PQ_PREPARED_STATEMENT_END
10635 : };
10636 :
10637 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
10638 : "exchangedb-postgres",
10639 : NULL,
10640 : es,
10641 : ps);
10642 : }
10643 0 : if (NULL == conn)
10644 0 : return GNUNET_SYSERR;
10645 0 : ret = GNUNET_OK;
10646 0 : if (0 > GNUNET_PQ_eval_prepared_non_select (conn,
10647 : "run_gc",
10648 : params))
10649 0 : ret = GNUNET_SYSERR;
10650 0 : GNUNET_PQ_disconnect (conn);
10651 0 : return ret;
10652 : }
10653 :
10654 :
10655 : /**
10656 : * Closure for #deposit_serial_helper_cb().
10657 : */
10658 : struct DepositSerialContext
10659 : {
10660 :
10661 : /**
10662 : * Callback to call.
10663 : */
10664 : TALER_EXCHANGEDB_DepositCallback cb;
10665 :
10666 : /**
10667 : * Closure for @e cb.
10668 : */
10669 : void *cb_cls;
10670 :
10671 : /**
10672 : * Plugin context.
10673 : */
10674 : struct PostgresClosure *pg;
10675 :
10676 : /**
10677 : * Status code, set to #GNUNET_SYSERR on hard errors.
10678 : */
10679 : enum GNUNET_GenericReturnValue status;
10680 : };
10681 :
10682 :
10683 : /**
10684 : * Helper function to be called with the results of a SELECT statement
10685 : * that has returned @a num_results results.
10686 : *
10687 : * @param cls closure of type `struct DepositSerialContext`
10688 : * @param result the postgres result
10689 : * @param num_results the number of results in @a result
10690 : */
10691 : static void
10692 0 : deposit_serial_helper_cb (void *cls,
10693 : PGresult *result,
10694 : unsigned int num_results)
10695 : {
10696 0 : struct DepositSerialContext *dsc = cls;
10697 0 : struct PostgresClosure *pg = dsc->pg;
10698 :
10699 0 : for (unsigned int i = 0; i<num_results; i++)
10700 : {
10701 : struct TALER_EXCHANGEDB_Deposit deposit;
10702 : struct GNUNET_TIME_Timestamp exchange_timestamp;
10703 : struct TALER_DenominationPublicKey denom_pub;
10704 : bool done;
10705 : uint64_t rowid;
10706 0 : struct GNUNET_PQ_ResultSpec rs[] = {
10707 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
10708 : &deposit.amount_with_fee),
10709 0 : GNUNET_PQ_result_spec_timestamp ("wallet_timestamp",
10710 : &deposit.timestamp),
10711 0 : GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
10712 : &exchange_timestamp),
10713 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
10714 : &deposit.merchant_pub),
10715 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
10716 : &denom_pub),
10717 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
10718 : &deposit.coin.coin_pub),
10719 0 : GNUNET_PQ_result_spec_allow_null (
10720 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
10721 : &deposit.coin.h_age_commitment),
10722 : &deposit.coin.no_age_commitment),
10723 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
10724 : &deposit.csig),
10725 0 : GNUNET_PQ_result_spec_timestamp ("refund_deadline",
10726 : &deposit.refund_deadline),
10727 0 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
10728 : &deposit.wire_deadline),
10729 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
10730 : &deposit.h_contract_terms),
10731 0 : GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
10732 : &deposit.wire_salt),
10733 0 : GNUNET_PQ_result_spec_string ("receiver_wire_account",
10734 : &deposit.receiver_wire_account),
10735 0 : GNUNET_PQ_result_spec_bool ("done",
10736 : &done),
10737 0 : GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
10738 : &rowid),
10739 : GNUNET_PQ_result_spec_end
10740 : };
10741 : enum GNUNET_GenericReturnValue ret;
10742 :
10743 0 : memset (&deposit,
10744 : 0,
10745 : sizeof (deposit));
10746 0 : if (GNUNET_OK !=
10747 0 : GNUNET_PQ_extract_result (result,
10748 : rs,
10749 : i))
10750 : {
10751 0 : GNUNET_break (0);
10752 0 : dsc->status = GNUNET_SYSERR;
10753 0 : return;
10754 : }
10755 0 : ret = dsc->cb (dsc->cb_cls,
10756 : rowid,
10757 : exchange_timestamp,
10758 : &deposit,
10759 : &denom_pub,
10760 : done);
10761 0 : GNUNET_PQ_cleanup_result (rs);
10762 0 : if (GNUNET_OK != ret)
10763 0 : break;
10764 : }
10765 : }
10766 :
10767 :
10768 : /**
10769 : * Select deposits above @a serial_id in monotonically increasing
10770 : * order.
10771 : *
10772 : * @param cls closure
10773 : * @param serial_id highest serial ID to exclude (select strictly larger)
10774 : * @param cb function to call on each result
10775 : * @param cb_cls closure for @a cb
10776 : * @return transaction status code
10777 : */
10778 : static enum GNUNET_DB_QueryStatus
10779 0 : postgres_select_deposits_above_serial_id (
10780 : void *cls,
10781 : uint64_t serial_id,
10782 : TALER_EXCHANGEDB_DepositCallback cb,
10783 : void *cb_cls)
10784 : {
10785 0 : struct PostgresClosure *pg = cls;
10786 0 : struct GNUNET_PQ_QueryParam params[] = {
10787 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
10788 : GNUNET_PQ_query_param_end
10789 : };
10790 0 : struct DepositSerialContext dsc = {
10791 : .cb = cb,
10792 : .cb_cls = cb_cls,
10793 : .pg = pg,
10794 : .status = GNUNET_OK
10795 : };
10796 : enum GNUNET_DB_QueryStatus qs;
10797 :
10798 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
10799 : "audit_get_deposits_incr",
10800 : params,
10801 : &deposit_serial_helper_cb,
10802 : &dsc);
10803 0 : if (GNUNET_OK != dsc.status)
10804 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10805 0 : return qs;
10806 : }
10807 :
10808 :
10809 : /**
10810 : * Closure for #purse_deposit_serial_helper_cb().
10811 : */
10812 : struct PurseDepositSerialContext
10813 : {
10814 :
10815 : /**
10816 : * Callback to call.
10817 : */
10818 : TALER_EXCHANGEDB_PurseDepositCallback cb;
10819 :
10820 : /**
10821 : * Closure for @e cb.
10822 : */
10823 : void *cb_cls;
10824 :
10825 : /**
10826 : * Plugin context.
10827 : */
10828 : struct PostgresClosure *pg;
10829 :
10830 : /**
10831 : * Status code, set to #GNUNET_SYSERR on hard errors.
10832 : */
10833 : enum GNUNET_GenericReturnValue status;
10834 : };
10835 :
10836 :
10837 : /**
10838 : * Helper function to be called with the results of a SELECT statement
10839 : * that has returned @a num_results results.
10840 : *
10841 : * @param cls closure of type `struct DepositSerialContext`
10842 : * @param result the postgres result
10843 : * @param num_results the number of results in @a result
10844 : */
10845 : static void
10846 0 : purse_deposit_serial_helper_cb (void *cls,
10847 : PGresult *result,
10848 : unsigned int num_results)
10849 : {
10850 0 : struct PurseDepositSerialContext *dsc = cls;
10851 0 : struct PostgresClosure *pg = dsc->pg;
10852 :
10853 0 : for (unsigned int i = 0; i<num_results; i++)
10854 : {
10855 0 : struct TALER_EXCHANGEDB_PurseDeposit deposit = {
10856 : .exchange_base_url = NULL
10857 : };
10858 : struct TALER_DenominationPublicKey denom_pub;
10859 : uint64_t rowid;
10860 : uint32_t flags32;
10861 : struct TALER_ReservePublicKeyP reserve_pub;
10862 0 : bool not_merged = false;
10863 : struct TALER_Amount purse_balance;
10864 : struct TALER_Amount purse_total;
10865 0 : struct GNUNET_PQ_ResultSpec rs[] = {
10866 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
10867 : &deposit.amount),
10868 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
10869 : &purse_balance),
10870 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("total",
10871 : &purse_total),
10872 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
10873 : &deposit.deposit_fee),
10874 0 : GNUNET_PQ_result_spec_allow_null (
10875 : GNUNET_PQ_result_spec_string ("partner_base_url",
10876 : &deposit.exchange_base_url),
10877 : NULL),
10878 0 : GNUNET_PQ_result_spec_allow_null (
10879 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
10880 : &reserve_pub),
10881 : ¬_merged),
10882 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
10883 : &denom_pub),
10884 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
10885 : &deposit.purse_pub),
10886 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
10887 : &deposit.coin_sig),
10888 0 : GNUNET_PQ_result_spec_uint32 ("flags",
10889 : &flags32),
10890 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
10891 : &deposit.coin_pub),
10892 0 : GNUNET_PQ_result_spec_allow_null (
10893 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
10894 : &deposit.h_age_commitment),
10895 : &deposit.no_age_commitment),
10896 0 : GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
10897 : &rowid),
10898 : GNUNET_PQ_result_spec_end
10899 : };
10900 : enum GNUNET_GenericReturnValue ret;
10901 :
10902 0 : memset (&deposit,
10903 : 0,
10904 : sizeof (deposit));
10905 0 : if (GNUNET_OK !=
10906 0 : GNUNET_PQ_extract_result (result,
10907 : rs,
10908 : i))
10909 : {
10910 0 : GNUNET_break (0);
10911 0 : dsc->status = GNUNET_SYSERR;
10912 0 : return;
10913 : }
10914 0 : ret = dsc->cb (dsc->cb_cls,
10915 : rowid,
10916 : &deposit,
10917 : not_merged ? NULL : &reserve_pub,
10918 : (enum TALER_WalletAccountMergeFlags) flags32,
10919 : &purse_balance,
10920 : &purse_total,
10921 : &denom_pub);
10922 0 : GNUNET_PQ_cleanup_result (rs);
10923 0 : if (GNUNET_OK != ret)
10924 0 : break;
10925 : }
10926 : }
10927 :
10928 :
10929 : /**
10930 : * Select deposits above @a serial_id in monotonically increasing
10931 : * order.
10932 : *
10933 : * @param cls closure
10934 : * @param serial_id highest serial ID to exclude (select strictly larger)
10935 : * @param cb function to call on each result
10936 : * @param cb_cls closure for @a cb
10937 : * @return transaction status code
10938 : */
10939 : static enum GNUNET_DB_QueryStatus
10940 0 : postgres_select_purse_deposits_above_serial_id (
10941 : void *cls,
10942 : uint64_t serial_id,
10943 : TALER_EXCHANGEDB_PurseDepositCallback cb,
10944 : void *cb_cls)
10945 : {
10946 0 : struct PostgresClosure *pg = cls;
10947 0 : struct GNUNET_PQ_QueryParam params[] = {
10948 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
10949 : GNUNET_PQ_query_param_end
10950 : };
10951 0 : struct PurseDepositSerialContext dsc = {
10952 : .cb = cb,
10953 : .cb_cls = cb_cls,
10954 : .pg = pg,
10955 : .status = GNUNET_OK
10956 : };
10957 : enum GNUNET_DB_QueryStatus qs;
10958 :
10959 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
10960 : "audit_get_purse_deposits_incr",
10961 : params,
10962 : &purse_deposit_serial_helper_cb,
10963 : &dsc);
10964 0 : if (GNUNET_OK != dsc.status)
10965 0 : return GNUNET_DB_STATUS_HARD_ERROR;
10966 0 : return qs;
10967 : }
10968 :
10969 :
10970 : /**
10971 : * Closure for #account_merge_serial_helper_cb().
10972 : */
10973 : struct AccountMergeSerialContext
10974 : {
10975 :
10976 : /**
10977 : * Callback to call.
10978 : */
10979 : TALER_EXCHANGEDB_AccountMergeCallback cb;
10980 :
10981 : /**
10982 : * Closure for @e cb.
10983 : */
10984 : void *cb_cls;
10985 :
10986 : /**
10987 : * Plugin context.
10988 : */
10989 : struct PostgresClosure *pg;
10990 :
10991 : /**
10992 : * Status code, set to #GNUNET_SYSERR on hard errors.
10993 : */
10994 : enum GNUNET_GenericReturnValue status;
10995 : };
10996 :
10997 :
10998 : /**
10999 : * Helper function to be called with the results of a SELECT statement
11000 : * that has returned @a num_results results.
11001 : *
11002 : * @param cls closure of type `struct AccountMergeSerialContext`
11003 : * @param result the postgres result
11004 : * @param num_results the number of results in @a result
11005 : */
11006 : static void
11007 0 : account_merge_serial_helper_cb (void *cls,
11008 : PGresult *result,
11009 : unsigned int num_results)
11010 : {
11011 0 : struct AccountMergeSerialContext *dsc = cls;
11012 0 : struct PostgresClosure *pg = dsc->pg;
11013 :
11014 0 : for (unsigned int i = 0; i<num_results; i++)
11015 : {
11016 : struct TALER_ReservePublicKeyP reserve_pub;
11017 : struct TALER_PurseContractPublicKeyP purse_pub;
11018 : struct TALER_PrivateContractHashP h_contract_terms;
11019 : struct GNUNET_TIME_Timestamp purse_expiration;
11020 : struct TALER_Amount amount;
11021 : uint32_t min_age;
11022 : uint32_t flags32;
11023 : enum TALER_WalletAccountMergeFlags flags;
11024 : struct TALER_Amount purse_fee;
11025 : struct GNUNET_TIME_Timestamp merge_timestamp;
11026 : struct TALER_ReserveSignatureP reserve_sig;
11027 : uint64_t rowid;
11028 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11029 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
11030 : &amount),
11031 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
11032 : &purse_fee),
11033 0 : GNUNET_PQ_result_spec_uint32 ("flags",
11034 : &flags32),
11035 0 : GNUNET_PQ_result_spec_uint32 ("age_limit",
11036 : &min_age),
11037 0 : GNUNET_PQ_result_spec_timestamp ("purse_expiration",
11038 : &purse_expiration),
11039 0 : GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
11040 : &merge_timestamp),
11041 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
11042 : &h_contract_terms),
11043 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
11044 : &purse_pub),
11045 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
11046 : &reserve_sig),
11047 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
11048 : &reserve_pub),
11049 0 : GNUNET_PQ_result_spec_uint64 ("account_merge_request_serial_id",
11050 : &rowid),
11051 : GNUNET_PQ_result_spec_end
11052 : };
11053 : enum GNUNET_GenericReturnValue ret;
11054 :
11055 0 : if (GNUNET_OK !=
11056 0 : GNUNET_PQ_extract_result (result,
11057 : rs,
11058 : i))
11059 : {
11060 0 : GNUNET_break (0);
11061 0 : dsc->status = GNUNET_SYSERR;
11062 0 : return;
11063 : }
11064 0 : flags = (enum TALER_WalletAccountMergeFlags) flags32;
11065 0 : ret = dsc->cb (dsc->cb_cls,
11066 : rowid,
11067 : &reserve_pub,
11068 : &purse_pub,
11069 : &h_contract_terms,
11070 : purse_expiration,
11071 : &amount,
11072 : min_age,
11073 : flags,
11074 : &purse_fee,
11075 : merge_timestamp,
11076 : &reserve_sig);
11077 0 : GNUNET_PQ_cleanup_result (rs);
11078 0 : if (GNUNET_OK != ret)
11079 0 : break;
11080 : }
11081 : }
11082 :
11083 :
11084 : /**
11085 : * Select account merges above @a serial_id in monotonically increasing
11086 : * order.
11087 : *
11088 : * @param cls closure
11089 : * @param serial_id highest serial ID to exclude (select strictly larger)
11090 : * @param cb function to call on each result
11091 : * @param cb_cls closure for @a cb
11092 : * @return transaction status code
11093 : */
11094 : static enum GNUNET_DB_QueryStatus
11095 0 : postgres_select_account_merges_above_serial_id (
11096 : void *cls,
11097 : uint64_t serial_id,
11098 : TALER_EXCHANGEDB_AccountMergeCallback cb,
11099 : void *cb_cls)
11100 : {
11101 0 : struct PostgresClosure *pg = cls;
11102 0 : struct GNUNET_PQ_QueryParam params[] = {
11103 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
11104 : GNUNET_PQ_query_param_end
11105 : };
11106 0 : struct AccountMergeSerialContext dsc = {
11107 : .cb = cb,
11108 : .cb_cls = cb_cls,
11109 : .pg = pg,
11110 : .status = GNUNET_OK
11111 : };
11112 : enum GNUNET_DB_QueryStatus qs;
11113 :
11114 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11115 : "audit_get_account_merge_incr",
11116 : params,
11117 : &account_merge_serial_helper_cb,
11118 : &dsc);
11119 0 : if (GNUNET_OK != dsc.status)
11120 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11121 0 : return qs;
11122 : }
11123 :
11124 :
11125 : /**
11126 : * Closure for #purse_deposit_serial_helper_cb().
11127 : */
11128 : struct PurseMergeSerialContext
11129 : {
11130 :
11131 : /**
11132 : * Callback to call.
11133 : */
11134 : TALER_EXCHANGEDB_PurseMergeCallback cb;
11135 :
11136 : /**
11137 : * Closure for @e cb.
11138 : */
11139 : void *cb_cls;
11140 :
11141 : /**
11142 : * Plugin context.
11143 : */
11144 : struct PostgresClosure *pg;
11145 :
11146 : /**
11147 : * Status code, set to #GNUNET_SYSERR on hard errors.
11148 : */
11149 : enum GNUNET_GenericReturnValue status;
11150 : };
11151 :
11152 :
11153 : /**
11154 : * Helper function to be called with the results of a SELECT statement
11155 : * that has returned @a num_results results.
11156 : *
11157 : * @param cls closure of type `struct PurseMergeSerialContext`
11158 : * @param result the postgres result
11159 : * @param num_results the number of results in @a result
11160 : */
11161 : static void
11162 0 : purse_merges_serial_helper_cb (void *cls,
11163 : PGresult *result,
11164 : unsigned int num_results)
11165 : {
11166 0 : struct PurseMergeSerialContext *dsc = cls;
11167 0 : struct PostgresClosure *pg = dsc->pg;
11168 :
11169 0 : for (unsigned int i = 0; i<num_results; i++)
11170 : {
11171 : uint64_t rowid;
11172 0 : char *partner_base_url = NULL;
11173 : struct TALER_Amount amount;
11174 : struct TALER_Amount balance;
11175 : uint32_t flags32;
11176 : enum TALER_WalletAccountMergeFlags flags;
11177 : struct TALER_PurseMergePublicKeyP merge_pub;
11178 : struct TALER_ReservePublicKeyP reserve_pub;
11179 : struct TALER_PurseMergeSignatureP merge_sig;
11180 : struct TALER_PurseContractPublicKeyP purse_pub;
11181 : struct GNUNET_TIME_Timestamp merge_timestamp;
11182 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11183 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
11184 : &amount),
11185 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
11186 : &balance),
11187 0 : GNUNET_PQ_result_spec_allow_null (
11188 : GNUNET_PQ_result_spec_string ("partner_base_url",
11189 : &partner_base_url),
11190 : NULL),
11191 0 : GNUNET_PQ_result_spec_uint32 ("flags",
11192 : &flags32),
11193 0 : GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
11194 : &merge_timestamp),
11195 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
11196 : &purse_pub),
11197 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
11198 : &reserve_pub),
11199 0 : GNUNET_PQ_result_spec_auto_from_type ("merge_sig",
11200 : &merge_sig),
11201 0 : GNUNET_PQ_result_spec_auto_from_type ("merge_pub",
11202 : &merge_pub),
11203 0 : GNUNET_PQ_result_spec_uint64 ("purse_merge_request_serial_id",
11204 : &rowid),
11205 : GNUNET_PQ_result_spec_end
11206 : };
11207 : enum GNUNET_GenericReturnValue ret;
11208 :
11209 0 : if (GNUNET_OK !=
11210 0 : GNUNET_PQ_extract_result (result,
11211 : rs,
11212 : i))
11213 : {
11214 0 : GNUNET_break (0);
11215 0 : dsc->status = GNUNET_SYSERR;
11216 0 : return;
11217 : }
11218 0 : flags = (enum TALER_WalletAccountMergeFlags) flags32;
11219 0 : ret = dsc->cb (dsc->cb_cls,
11220 : rowid,
11221 : partner_base_url,
11222 : &amount,
11223 : &balance,
11224 : flags,
11225 : &merge_pub,
11226 : &reserve_pub,
11227 : &merge_sig,
11228 : &purse_pub,
11229 : merge_timestamp);
11230 0 : GNUNET_PQ_cleanup_result (rs);
11231 0 : if (GNUNET_OK != ret)
11232 0 : break;
11233 : }
11234 : }
11235 :
11236 :
11237 : /**
11238 : * Select purse merges deposits above @a serial_id in monotonically increasing
11239 : * order.
11240 : *
11241 : * @param cls closure
11242 : * @param serial_id highest serial ID to exclude (select strictly larger)
11243 : * @param cb function to call on each result
11244 : * @param cb_cls closure for @a cb
11245 : * @return transaction status code
11246 : */
11247 : static enum GNUNET_DB_QueryStatus
11248 0 : postgres_select_purse_merges_above_serial_id (
11249 : void *cls,
11250 : uint64_t serial_id,
11251 : TALER_EXCHANGEDB_PurseMergeCallback cb,
11252 : void *cb_cls)
11253 : {
11254 0 : struct PostgresClosure *pg = cls;
11255 0 : struct GNUNET_PQ_QueryParam params[] = {
11256 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
11257 : GNUNET_PQ_query_param_end
11258 : };
11259 0 : struct PurseMergeSerialContext dsc = {
11260 : .cb = cb,
11261 : .cb_cls = cb_cls,
11262 : .pg = pg,
11263 : .status = GNUNET_OK
11264 : };
11265 : enum GNUNET_DB_QueryStatus qs;
11266 :
11267 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11268 : "audit_get_purse_merge_incr",
11269 : params,
11270 : &purse_merges_serial_helper_cb,
11271 : &dsc);
11272 0 : if (GNUNET_OK != dsc.status)
11273 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11274 0 : return qs;
11275 : }
11276 :
11277 :
11278 : /**
11279 : * Closure for #purse_deposit_serial_helper_cb().
11280 : */
11281 : struct HistoryRequestSerialContext
11282 : {
11283 :
11284 : /**
11285 : * Callback to call.
11286 : */
11287 : TALER_EXCHANGEDB_HistoryRequestCallback cb;
11288 :
11289 : /**
11290 : * Closure for @e cb.
11291 : */
11292 : void *cb_cls;
11293 :
11294 : /**
11295 : * Plugin context.
11296 : */
11297 : struct PostgresClosure *pg;
11298 :
11299 : /**
11300 : * Status code, set to #GNUNET_SYSERR on hard errors.
11301 : */
11302 : enum GNUNET_GenericReturnValue status;
11303 : };
11304 :
11305 :
11306 : /**
11307 : * Helper function to be called with the results of a SELECT statement
11308 : * that has returned @a num_results results.
11309 : *
11310 : * @param cls closure of type `struct HistoryRequestSerialContext`
11311 : * @param result the postgres result
11312 : * @param num_results the number of results in @a result
11313 : */
11314 : static void
11315 0 : history_request_serial_helper_cb (void *cls,
11316 : PGresult *result,
11317 : unsigned int num_results)
11318 : {
11319 0 : struct HistoryRequestSerialContext *dsc = cls;
11320 0 : struct PostgresClosure *pg = dsc->pg;
11321 :
11322 0 : for (unsigned int i = 0; i<num_results; i++)
11323 : {
11324 : uint64_t rowid;
11325 : struct TALER_Amount history_fee;
11326 : struct GNUNET_TIME_Timestamp ts;
11327 : struct TALER_ReservePublicKeyP reserve_pub;
11328 : struct TALER_ReserveSignatureP reserve_sig;
11329 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11330 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
11331 : &history_fee),
11332 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
11333 : &reserve_pub),
11334 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
11335 : &reserve_sig),
11336 0 : GNUNET_PQ_result_spec_uint64 ("history_request_serial_id",
11337 : &rowid),
11338 0 : GNUNET_PQ_result_spec_timestamp ("request_timestamp",
11339 : &ts),
11340 : GNUNET_PQ_result_spec_end
11341 : };
11342 : enum GNUNET_GenericReturnValue ret;
11343 :
11344 0 : if (GNUNET_OK !=
11345 0 : GNUNET_PQ_extract_result (result,
11346 : rs,
11347 : i))
11348 : {
11349 0 : GNUNET_break (0);
11350 0 : dsc->status = GNUNET_SYSERR;
11351 0 : return;
11352 : }
11353 0 : ret = dsc->cb (dsc->cb_cls,
11354 : rowid,
11355 : &history_fee,
11356 : ts,
11357 : &reserve_pub,
11358 : &reserve_sig);
11359 0 : GNUNET_PQ_cleanup_result (rs);
11360 0 : if (GNUNET_OK != ret)
11361 0 : break;
11362 : }
11363 : }
11364 :
11365 :
11366 : /**
11367 : * Select history requests above @a serial_id in monotonically increasing
11368 : * order.
11369 : *
11370 : * @param cls closure
11371 : * @param serial_id highest serial ID to exclude (select strictly larger)
11372 : * @param cb function to call on each result
11373 : * @param cb_cls closure for @a cb
11374 : * @return transaction status code
11375 : */
11376 : static enum GNUNET_DB_QueryStatus
11377 0 : postgres_select_history_requests_above_serial_id (
11378 : void *cls,
11379 : uint64_t serial_id,
11380 : TALER_EXCHANGEDB_HistoryRequestCallback cb,
11381 : void *cb_cls)
11382 : {
11383 0 : struct PostgresClosure *pg = cls;
11384 0 : struct GNUNET_PQ_QueryParam params[] = {
11385 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
11386 : GNUNET_PQ_query_param_end
11387 : };
11388 0 : struct HistoryRequestSerialContext dsc = {
11389 : .cb = cb,
11390 : .cb_cls = cb_cls,
11391 : .pg = pg,
11392 : .status = GNUNET_OK
11393 : };
11394 : enum GNUNET_DB_QueryStatus qs;
11395 :
11396 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11397 : "audit_get_history_requests_incr",
11398 : params,
11399 : &history_request_serial_helper_cb,
11400 : &dsc);
11401 0 : if (GNUNET_OK != dsc.status)
11402 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11403 0 : return qs;
11404 : }
11405 :
11406 :
11407 : /**
11408 : * Closure for #purse_refund_serial_helper_cb().
11409 : */
11410 : struct PurseRefundSerialContext
11411 : {
11412 :
11413 : /**
11414 : * Callback to call.
11415 : */
11416 : TALER_EXCHANGEDB_PurseRefundCallback cb;
11417 :
11418 : /**
11419 : * Closure for @e cb.
11420 : */
11421 : void *cb_cls;
11422 :
11423 : /**
11424 : * Plugin context.
11425 : */
11426 : struct PostgresClosure *pg;
11427 :
11428 : /**
11429 : * Status code, set to #GNUNET_SYSERR on hard errors.
11430 : */
11431 : enum GNUNET_GenericReturnValue status;
11432 : };
11433 :
11434 :
11435 : /**
11436 : * Helper function to be called with the results of a SELECT statement
11437 : * that has returned @a num_results results.
11438 : *
11439 : * @param cls closure of type `struct PurseRefundSerialContext`
11440 : * @param result the postgres result
11441 : * @param num_results the number of results in @a result
11442 : */
11443 : static void
11444 0 : purse_refund_serial_helper_cb (void *cls,
11445 : PGresult *result,
11446 : unsigned int num_results)
11447 : {
11448 0 : struct PurseRefundSerialContext *dsc = cls;
11449 :
11450 0 : for (unsigned int i = 0; i<num_results; i++)
11451 : {
11452 : struct TALER_PurseContractPublicKeyP purse_pub;
11453 : uint64_t rowid;
11454 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11455 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
11456 : &purse_pub),
11457 0 : GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
11458 : &rowid),
11459 : GNUNET_PQ_result_spec_end
11460 : };
11461 : enum GNUNET_GenericReturnValue ret;
11462 :
11463 0 : if (GNUNET_OK !=
11464 0 : GNUNET_PQ_extract_result (result,
11465 : rs,
11466 : i))
11467 : {
11468 0 : GNUNET_break (0);
11469 0 : dsc->status = GNUNET_SYSERR;
11470 0 : return;
11471 : }
11472 0 : ret = dsc->cb (dsc->cb_cls,
11473 : rowid,
11474 : &purse_pub);
11475 0 : GNUNET_PQ_cleanup_result (rs);
11476 0 : if (GNUNET_OK != ret)
11477 0 : break;
11478 : }
11479 : }
11480 :
11481 :
11482 : /**
11483 : * Select purse refunds above @a serial_id in monotonically increasing
11484 : * order.
11485 : *
11486 : * @param cls closure
11487 : * @param serial_id highest serial ID to exclude (select strictly larger)
11488 : * @param cb function to call on each result
11489 : * @param cb_cls closure for @a cb
11490 : * @return transaction status code
11491 : */
11492 : static enum GNUNET_DB_QueryStatus
11493 0 : postgres_select_purse_refunds_above_serial_id (
11494 : void *cls,
11495 : uint64_t serial_id,
11496 : TALER_EXCHANGEDB_PurseRefundCallback cb,
11497 : void *cb_cls)
11498 : {
11499 0 : struct PostgresClosure *pg = cls;
11500 0 : struct GNUNET_PQ_QueryParam params[] = {
11501 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
11502 : GNUNET_PQ_query_param_end
11503 : };
11504 0 : struct PurseRefundSerialContext dsc = {
11505 : .cb = cb,
11506 : .cb_cls = cb_cls,
11507 : .pg = pg,
11508 : .status = GNUNET_OK
11509 : };
11510 : enum GNUNET_DB_QueryStatus qs;
11511 :
11512 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11513 : "audit_get_purse_refunds_incr",
11514 : params,
11515 : &purse_refund_serial_helper_cb,
11516 : &dsc);
11517 0 : if (GNUNET_OK != dsc.status)
11518 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11519 0 : return qs;
11520 : }
11521 :
11522 :
11523 : /**
11524 : * Closure for #purse_refund_coin_helper_cb().
11525 : */
11526 : struct PurseRefundCoinContext
11527 : {
11528 :
11529 : /**
11530 : * Callback to call.
11531 : */
11532 : TALER_EXCHANGEDB_PurseRefundCoinCallback cb;
11533 :
11534 : /**
11535 : * Closure for @e cb.
11536 : */
11537 : void *cb_cls;
11538 :
11539 : /**
11540 : * Plugin context.
11541 : */
11542 : struct PostgresClosure *pg;
11543 :
11544 : /**
11545 : * Status code, set to #GNUNET_SYSERR on hard errors.
11546 : */
11547 : enum GNUNET_GenericReturnValue status;
11548 : };
11549 :
11550 :
11551 : /**
11552 : * Helper function to be called with the results of a SELECT statement
11553 : * that has returned @a num_results results.
11554 : *
11555 : * @param cls closure of type `struct PurseRefundCoinContext`
11556 : * @param result the postgres result
11557 : * @param num_results the number of results in @a result
11558 : */
11559 : static void
11560 0 : purse_refund_coin_helper_cb (void *cls,
11561 : PGresult *result,
11562 : unsigned int num_results)
11563 : {
11564 0 : struct PurseRefundCoinContext *dsc = cls;
11565 0 : struct PostgresClosure *pg = dsc->pg;
11566 :
11567 0 : for (unsigned int i = 0; i<num_results; i++)
11568 : {
11569 : struct TALER_Amount amount_with_fee;
11570 : struct TALER_CoinSpendPublicKeyP coin_pub;
11571 : struct TALER_DenominationPublicKey denom_pub;
11572 : uint64_t rowid;
11573 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11574 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
11575 : &denom_pub),
11576 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
11577 : &amount_with_fee),
11578 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
11579 : &coin_pub),
11580 0 : GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
11581 : &rowid),
11582 : GNUNET_PQ_result_spec_end
11583 : };
11584 : enum GNUNET_GenericReturnValue ret;
11585 :
11586 0 : if (GNUNET_OK !=
11587 0 : GNUNET_PQ_extract_result (result,
11588 : rs,
11589 : i))
11590 : {
11591 0 : GNUNET_break (0);
11592 0 : dsc->status = GNUNET_SYSERR;
11593 0 : return;
11594 : }
11595 0 : ret = dsc->cb (dsc->cb_cls,
11596 : rowid,
11597 : &amount_with_fee,
11598 : &coin_pub,
11599 : &denom_pub);
11600 0 : GNUNET_PQ_cleanup_result (rs);
11601 0 : if (GNUNET_OK != ret)
11602 0 : break;
11603 : }
11604 : }
11605 :
11606 :
11607 : /**
11608 : * Select coin affected by purse refund.
11609 : *
11610 : * @param cls closure
11611 : * @param purse_pub purse that was refunded
11612 : * @param cb function to call on each result
11613 : * @param cb_cls closure for @a cb
11614 : * @return transaction status code
11615 : */
11616 : static enum GNUNET_DB_QueryStatus
11617 0 : postgres_select_purse_deposits_by_purse (
11618 : void *cls,
11619 : const struct TALER_PurseContractPublicKeyP *purse_pub,
11620 : TALER_EXCHANGEDB_PurseRefundCoinCallback cb,
11621 : void *cb_cls)
11622 : {
11623 0 : struct PostgresClosure *pg = cls;
11624 0 : struct GNUNET_PQ_QueryParam params[] = {
11625 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
11626 : GNUNET_PQ_query_param_end
11627 : };
11628 0 : struct PurseRefundCoinContext dsc = {
11629 : .cb = cb,
11630 : .cb_cls = cb_cls,
11631 : .pg = pg,
11632 : .status = GNUNET_OK
11633 : };
11634 : enum GNUNET_DB_QueryStatus qs;
11635 :
11636 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11637 : "audit_get_purse_deposits_by_purse",
11638 : params,
11639 : &purse_refund_coin_helper_cb,
11640 : &dsc);
11641 0 : if (GNUNET_OK != dsc.status)
11642 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11643 0 : return qs;
11644 : }
11645 :
11646 :
11647 : /**
11648 : * Closure for #refreshs_serial_helper_cb().
11649 : */
11650 : struct RefreshsSerialContext
11651 : {
11652 :
11653 : /**
11654 : * Callback to call.
11655 : */
11656 : TALER_EXCHANGEDB_RefreshesCallback cb;
11657 :
11658 : /**
11659 : * Closure for @e cb.
11660 : */
11661 : void *cb_cls;
11662 :
11663 : /**
11664 : * Plugin context.
11665 : */
11666 : struct PostgresClosure *pg;
11667 :
11668 : /**
11669 : * Status code, set to #GNUNET_SYSERR on hard errors.
11670 : */
11671 : enum GNUNET_GenericReturnValue status;
11672 : };
11673 :
11674 :
11675 : /**
11676 : * Helper function to be called with the results of a SELECT statement
11677 : * that has returned @a num_results results.
11678 : *
11679 : * @param cls closure of type `struct RefreshsSerialContext`
11680 : * @param result the postgres result
11681 : * @param num_results the number of results in @a result
11682 : */
11683 : static void
11684 0 : refreshs_serial_helper_cb (void *cls,
11685 : PGresult *result,
11686 : unsigned int num_results)
11687 : {
11688 0 : struct RefreshsSerialContext *rsc = cls;
11689 0 : struct PostgresClosure *pg = rsc->pg;
11690 :
11691 0 : for (unsigned int i = 0; i<num_results; i++)
11692 : {
11693 : struct TALER_DenominationPublicKey denom_pub;
11694 : struct TALER_CoinSpendPublicKeyP coin_pub;
11695 : struct TALER_CoinSpendSignatureP coin_sig;
11696 : struct TALER_AgeCommitmentHash h_age_commitment;
11697 : bool ac_isnull;
11698 : struct TALER_Amount amount_with_fee;
11699 : uint32_t noreveal_index;
11700 : uint64_t rowid;
11701 : struct TALER_RefreshCommitmentP rc;
11702 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11703 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
11704 : &denom_pub),
11705 0 : GNUNET_PQ_result_spec_allow_null (
11706 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
11707 : &h_age_commitment),
11708 : &ac_isnull),
11709 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
11710 : &coin_pub),
11711 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
11712 : &coin_sig),
11713 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
11714 : &amount_with_fee),
11715 0 : GNUNET_PQ_result_spec_uint32 ("noreveal_index",
11716 : &noreveal_index),
11717 0 : GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
11718 : &rowid),
11719 0 : GNUNET_PQ_result_spec_auto_from_type ("rc",
11720 : &rc),
11721 : GNUNET_PQ_result_spec_end
11722 : };
11723 : enum GNUNET_GenericReturnValue ret;
11724 :
11725 0 : if (GNUNET_OK !=
11726 0 : GNUNET_PQ_extract_result (result,
11727 : rs,
11728 : i))
11729 : {
11730 0 : GNUNET_break (0);
11731 0 : rsc->status = GNUNET_SYSERR;
11732 0 : return;
11733 : }
11734 :
11735 0 : ret = rsc->cb (rsc->cb_cls,
11736 : rowid,
11737 : &denom_pub,
11738 : ac_isnull ? NULL : &h_age_commitment,
11739 : &coin_pub,
11740 : &coin_sig,
11741 : &amount_with_fee,
11742 : noreveal_index,
11743 : &rc);
11744 0 : GNUNET_PQ_cleanup_result (rs);
11745 0 : if (GNUNET_OK != ret)
11746 0 : break;
11747 : }
11748 : }
11749 :
11750 :
11751 : /**
11752 : * Select refresh sessions above @a serial_id in monotonically increasing
11753 : * order.
11754 : *
11755 : * @param cls closure
11756 : * @param serial_id highest serial ID to exclude (select strictly larger)
11757 : * @param cb function to call on each result
11758 : * @param cb_cls closure for @a cb
11759 : * @return transaction status code
11760 : */
11761 : static enum GNUNET_DB_QueryStatus
11762 0 : postgres_select_refreshes_above_serial_id (
11763 : void *cls,
11764 : uint64_t serial_id,
11765 : TALER_EXCHANGEDB_RefreshesCallback cb,
11766 : void *cb_cls)
11767 : {
11768 0 : struct PostgresClosure *pg = cls;
11769 0 : struct GNUNET_PQ_QueryParam params[] = {
11770 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
11771 : GNUNET_PQ_query_param_end
11772 : };
11773 0 : struct RefreshsSerialContext rsc = {
11774 : .cb = cb,
11775 : .cb_cls = cb_cls,
11776 : .pg = pg,
11777 : .status = GNUNET_OK
11778 : };
11779 : enum GNUNET_DB_QueryStatus qs;
11780 :
11781 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11782 : "audit_get_refresh_commitments_incr",
11783 : params,
11784 : &refreshs_serial_helper_cb,
11785 : &rsc);
11786 0 : if (GNUNET_OK != rsc.status)
11787 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11788 0 : return qs;
11789 : }
11790 :
11791 :
11792 : /**
11793 : * Closure for #refunds_serial_helper_cb().
11794 : */
11795 : struct RefundsSerialContext
11796 : {
11797 :
11798 : /**
11799 : * Callback to call.
11800 : */
11801 : TALER_EXCHANGEDB_RefundCallback cb;
11802 :
11803 : /**
11804 : * Closure for @e cb.
11805 : */
11806 : void *cb_cls;
11807 :
11808 : /**
11809 : * Plugin context.
11810 : */
11811 : struct PostgresClosure *pg;
11812 :
11813 : /**
11814 : * Status code, set to #GNUNET_SYSERR on hard errors.
11815 : */
11816 : enum GNUNET_GenericReturnValue status;
11817 : };
11818 :
11819 :
11820 : /**
11821 : * Helper function to be called with the results of a SELECT statement
11822 : * that has returned @a num_results results.
11823 : *
11824 : * @param cls closure of type `struct RefundsSerialContext`
11825 : * @param result the postgres result
11826 : * @param num_results the number of results in @a result
11827 : */
11828 : static void
11829 0 : refunds_serial_helper_cb (void *cls,
11830 : PGresult *result,
11831 : unsigned int num_results)
11832 : {
11833 0 : struct RefundsSerialContext *rsc = cls;
11834 0 : struct PostgresClosure *pg = rsc->pg;
11835 :
11836 0 : for (unsigned int i = 0; i<num_results; i++)
11837 : {
11838 : struct TALER_EXCHANGEDB_Refund refund;
11839 : struct TALER_DenominationPublicKey denom_pub;
11840 : uint64_t rowid;
11841 : bool full_refund;
11842 0 : struct GNUNET_PQ_ResultSpec rs[] = {
11843 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
11844 : &refund.details.merchant_pub),
11845 0 : GNUNET_PQ_result_spec_auto_from_type ("merchant_sig",
11846 : &refund.details.merchant_sig),
11847 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
11848 : &refund.details.h_contract_terms),
11849 0 : GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
11850 : &refund.details.rtransaction_id),
11851 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
11852 : &denom_pub),
11853 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
11854 : &refund.coin.coin_pub),
11855 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
11856 : &refund.details.refund_amount),
11857 0 : GNUNET_PQ_result_spec_uint64 ("refund_serial_id",
11858 : &rowid),
11859 : GNUNET_PQ_result_spec_end
11860 : };
11861 : enum GNUNET_GenericReturnValue ret;
11862 :
11863 0 : if (GNUNET_OK !=
11864 0 : GNUNET_PQ_extract_result (result,
11865 : rs,
11866 : i))
11867 : {
11868 0 : GNUNET_break (0);
11869 0 : rsc->status = GNUNET_SYSERR;
11870 0 : return;
11871 : }
11872 : {
11873 0 : struct GNUNET_PQ_QueryParam params[] = {
11874 0 : GNUNET_PQ_query_param_uint64 (&rowid),
11875 : GNUNET_PQ_query_param_end
11876 : };
11877 : struct TALER_Amount amount_with_fee;
11878 : uint64_t s_f;
11879 : uint64_t s_v;
11880 0 : struct GNUNET_PQ_ResultSpec rs2[] = {
11881 0 : GNUNET_PQ_result_spec_uint64 ("s_v",
11882 : &s_v),
11883 0 : GNUNET_PQ_result_spec_uint64 ("s_f",
11884 : &s_f),
11885 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
11886 : &amount_with_fee),
11887 : GNUNET_PQ_result_spec_end
11888 : };
11889 : enum GNUNET_DB_QueryStatus qs;
11890 :
11891 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (
11892 : pg->conn,
11893 : "test_refund_full",
11894 : params,
11895 : rs2);
11896 0 : if (qs <= 0)
11897 : {
11898 0 : GNUNET_break (0);
11899 0 : rsc->status = GNUNET_SYSERR;
11900 0 : return;
11901 : }
11902 : /* normalize */
11903 0 : s_v += s_f / TALER_AMOUNT_FRAC_BASE;
11904 0 : s_f %= TALER_AMOUNT_FRAC_BASE;
11905 0 : full_refund = (s_v >= amount_with_fee.value) &&
11906 0 : (s_f >= amount_with_fee.fraction);
11907 : }
11908 0 : ret = rsc->cb (rsc->cb_cls,
11909 : rowid,
11910 : &denom_pub,
11911 : &refund.coin.coin_pub,
11912 : &refund.details.merchant_pub,
11913 : &refund.details.merchant_sig,
11914 : &refund.details.h_contract_terms,
11915 : refund.details.rtransaction_id,
11916 : full_refund,
11917 : &refund.details.refund_amount);
11918 0 : GNUNET_PQ_cleanup_result (rs);
11919 0 : if (GNUNET_OK != ret)
11920 0 : break;
11921 : }
11922 : }
11923 :
11924 :
11925 : /**
11926 : * Select refunds above @a serial_id in monotonically increasing
11927 : * order.
11928 : *
11929 : * @param cls closure
11930 : * @param serial_id highest serial ID to exclude (select strictly larger)
11931 : * @param cb function to call on each result
11932 : * @param cb_cls closure for @a cb
11933 : * @return transaction status code
11934 : */
11935 : static enum GNUNET_DB_QueryStatus
11936 0 : postgres_select_refunds_above_serial_id (
11937 : void *cls,
11938 : uint64_t serial_id,
11939 : TALER_EXCHANGEDB_RefundCallback cb,
11940 : void *cb_cls)
11941 : {
11942 0 : struct PostgresClosure *pg = cls;
11943 0 : struct GNUNET_PQ_QueryParam params[] = {
11944 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
11945 : GNUNET_PQ_query_param_end
11946 : };
11947 0 : struct RefundsSerialContext rsc = {
11948 : .cb = cb,
11949 : .cb_cls = cb_cls,
11950 : .pg = pg,
11951 : .status = GNUNET_OK
11952 : };
11953 : enum GNUNET_DB_QueryStatus qs;
11954 :
11955 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
11956 : "audit_get_refunds_incr",
11957 : params,
11958 : &refunds_serial_helper_cb,
11959 : &rsc);
11960 0 : if (GNUNET_OK != rsc.status)
11961 0 : return GNUNET_DB_STATUS_HARD_ERROR;
11962 0 : return qs;
11963 : }
11964 :
11965 :
11966 : /**
11967 : * Closure for #reserves_in_serial_helper_cb().
11968 : */
11969 : struct ReservesInSerialContext
11970 : {
11971 :
11972 : /**
11973 : * Callback to call.
11974 : */
11975 : TALER_EXCHANGEDB_ReserveInCallback cb;
11976 :
11977 : /**
11978 : * Closure for @e cb.
11979 : */
11980 : void *cb_cls;
11981 :
11982 : /**
11983 : * Plugin context.
11984 : */
11985 : struct PostgresClosure *pg;
11986 :
11987 : /**
11988 : * Status code, set to #GNUNET_SYSERR on hard errors.
11989 : */
11990 : enum GNUNET_GenericReturnValue status;
11991 : };
11992 :
11993 :
11994 : /**
11995 : * Helper function to be called with the results of a SELECT statement
11996 : * that has returned @a num_results results.
11997 : *
11998 : * @param cls closure of type `struct ReservesInSerialContext`
11999 : * @param result the postgres result
12000 : * @param num_results the number of results in @a result
12001 : */
12002 : static void
12003 0 : reserves_in_serial_helper_cb (void *cls,
12004 : PGresult *result,
12005 : unsigned int num_results)
12006 : {
12007 0 : struct ReservesInSerialContext *risc = cls;
12008 0 : struct PostgresClosure *pg = risc->pg;
12009 :
12010 0 : for (unsigned int i = 0; i<num_results; i++)
12011 : {
12012 : struct TALER_ReservePublicKeyP reserve_pub;
12013 : struct TALER_Amount credit;
12014 : char *sender_account_details;
12015 : struct GNUNET_TIME_Timestamp execution_date;
12016 : uint64_t rowid;
12017 : uint64_t wire_reference;
12018 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12019 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
12020 : &reserve_pub),
12021 0 : GNUNET_PQ_result_spec_uint64 ("wire_reference",
12022 : &wire_reference),
12023 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("credit",
12024 : &credit),
12025 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
12026 : &execution_date),
12027 0 : GNUNET_PQ_result_spec_string ("sender_account_details",
12028 : &sender_account_details),
12029 0 : GNUNET_PQ_result_spec_uint64 ("reserve_in_serial_id",
12030 : &rowid),
12031 : GNUNET_PQ_result_spec_end
12032 : };
12033 : enum GNUNET_GenericReturnValue ret;
12034 :
12035 0 : if (GNUNET_OK !=
12036 0 : GNUNET_PQ_extract_result (result,
12037 : rs,
12038 : i))
12039 : {
12040 0 : GNUNET_break (0);
12041 0 : risc->status = GNUNET_SYSERR;
12042 0 : return;
12043 : }
12044 0 : ret = risc->cb (risc->cb_cls,
12045 : rowid,
12046 : &reserve_pub,
12047 : &credit,
12048 : sender_account_details,
12049 : wire_reference,
12050 : execution_date);
12051 0 : GNUNET_PQ_cleanup_result (rs);
12052 0 : if (GNUNET_OK != ret)
12053 0 : break;
12054 : }
12055 : }
12056 :
12057 :
12058 : /**
12059 : * Select inbound wire transfers into reserves_in above @a serial_id
12060 : * in monotonically increasing order.
12061 : *
12062 : * @param cls closure
12063 : * @param serial_id highest serial ID to exclude (select strictly larger)
12064 : * @param cb function to call on each result
12065 : * @param cb_cls closure for @a cb
12066 : * @return transaction status code
12067 : */
12068 : static enum GNUNET_DB_QueryStatus
12069 0 : postgres_select_reserves_in_above_serial_id (
12070 : void *cls,
12071 : uint64_t serial_id,
12072 : TALER_EXCHANGEDB_ReserveInCallback cb,
12073 : void *cb_cls)
12074 : {
12075 0 : struct PostgresClosure *pg = cls;
12076 0 : struct GNUNET_PQ_QueryParam params[] = {
12077 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12078 : GNUNET_PQ_query_param_end
12079 : };
12080 0 : struct ReservesInSerialContext risc = {
12081 : .cb = cb,
12082 : .cb_cls = cb_cls,
12083 : .pg = pg,
12084 : .status = GNUNET_OK
12085 : };
12086 : enum GNUNET_DB_QueryStatus qs;
12087 :
12088 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12089 : "audit_reserves_in_get_transactions_incr",
12090 : params,
12091 : &reserves_in_serial_helper_cb,
12092 : &risc);
12093 0 : if (GNUNET_OK != risc.status)
12094 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12095 0 : return qs;
12096 : }
12097 :
12098 :
12099 : /**
12100 : * Select inbound wire transfers into reserves_in above @a serial_id
12101 : * in monotonically increasing order by account.
12102 : *
12103 : * @param cls closure
12104 : * @param account_name name of the account to select by
12105 : * @param serial_id highest serial ID to exclude (select strictly larger)
12106 : * @param cb function to call on each result
12107 : * @param cb_cls closure for @a cb
12108 : * @return transaction status code
12109 : */
12110 : static enum GNUNET_DB_QueryStatus
12111 0 : postgres_select_reserves_in_above_serial_id_by_account (
12112 : void *cls,
12113 : const char *account_name,
12114 : uint64_t serial_id,
12115 : TALER_EXCHANGEDB_ReserveInCallback cb,
12116 : void *cb_cls)
12117 : {
12118 0 : struct PostgresClosure *pg = cls;
12119 0 : struct GNUNET_PQ_QueryParam params[] = {
12120 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12121 0 : GNUNET_PQ_query_param_string (account_name),
12122 : GNUNET_PQ_query_param_end
12123 : };
12124 0 : struct ReservesInSerialContext risc = {
12125 : .cb = cb,
12126 : .cb_cls = cb_cls,
12127 : .pg = pg,
12128 : .status = GNUNET_OK
12129 : };
12130 : enum GNUNET_DB_QueryStatus qs;
12131 :
12132 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12133 : "audit_reserves_in_get_transactions_incr_by_account",
12134 : params,
12135 : &reserves_in_serial_helper_cb,
12136 : &risc);
12137 0 : if (GNUNET_OK != risc.status)
12138 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12139 0 : return qs;
12140 : }
12141 :
12142 :
12143 : /**
12144 : * Closure for #reserves_out_serial_helper_cb().
12145 : */
12146 : struct ReservesOutSerialContext
12147 : {
12148 :
12149 : /**
12150 : * Callback to call.
12151 : */
12152 : TALER_EXCHANGEDB_WithdrawCallback cb;
12153 :
12154 : /**
12155 : * Closure for @e cb.
12156 : */
12157 : void *cb_cls;
12158 :
12159 : /**
12160 : * Plugin context.
12161 : */
12162 : struct PostgresClosure *pg;
12163 :
12164 : /**
12165 : * Status code, set to #GNUNET_SYSERR on hard errors.
12166 : */
12167 : enum GNUNET_GenericReturnValue status;
12168 : };
12169 :
12170 :
12171 : /**
12172 : * Helper function to be called with the results of a SELECT statement
12173 : * that has returned @a num_results results.
12174 : *
12175 : * @param cls closure of type `struct ReservesOutSerialContext`
12176 : * @param result the postgres result
12177 : * @param num_results the number of results in @a result
12178 : */
12179 : static void
12180 0 : reserves_out_serial_helper_cb (void *cls,
12181 : PGresult *result,
12182 : unsigned int num_results)
12183 : {
12184 0 : struct ReservesOutSerialContext *rosc = cls;
12185 0 : struct PostgresClosure *pg = rosc->pg;
12186 :
12187 0 : for (unsigned int i = 0; i<num_results; i++)
12188 : {
12189 : struct TALER_BlindedCoinHashP h_blind_ev;
12190 : struct TALER_DenominationPublicKey denom_pub;
12191 : struct TALER_ReservePublicKeyP reserve_pub;
12192 : struct TALER_ReserveSignatureP reserve_sig;
12193 : struct GNUNET_TIME_Timestamp execution_date;
12194 : struct TALER_Amount amount_with_fee;
12195 : uint64_t rowid;
12196 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12197 0 : GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
12198 : &h_blind_ev),
12199 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
12200 : &denom_pub),
12201 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
12202 : &reserve_pub),
12203 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
12204 : &reserve_sig),
12205 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
12206 : &execution_date),
12207 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
12208 : &amount_with_fee),
12209 0 : GNUNET_PQ_result_spec_uint64 ("reserve_out_serial_id",
12210 : &rowid),
12211 : GNUNET_PQ_result_spec_end
12212 : };
12213 : enum GNUNET_GenericReturnValue ret;
12214 :
12215 0 : if (GNUNET_OK !=
12216 0 : GNUNET_PQ_extract_result (result,
12217 : rs,
12218 : i))
12219 : {
12220 0 : GNUNET_break (0);
12221 0 : rosc->status = GNUNET_SYSERR;
12222 0 : return;
12223 : }
12224 0 : ret = rosc->cb (rosc->cb_cls,
12225 : rowid,
12226 : &h_blind_ev,
12227 : &denom_pub,
12228 : &reserve_pub,
12229 : &reserve_sig,
12230 : execution_date,
12231 : &amount_with_fee);
12232 0 : GNUNET_PQ_cleanup_result (rs);
12233 0 : if (GNUNET_OK != ret)
12234 0 : break;
12235 : }
12236 : }
12237 :
12238 :
12239 : /**
12240 : * Select withdraw operations from reserves_out above @a serial_id
12241 : * in monotonically increasing order.
12242 : *
12243 : * @param cls closure
12244 : * @param serial_id highest serial ID to exclude (select strictly larger)
12245 : * @param cb function to call on each result
12246 : * @param cb_cls closure for @a cb
12247 : * @return transaction status code
12248 : */
12249 : static enum GNUNET_DB_QueryStatus
12250 0 : postgres_select_withdrawals_above_serial_id (
12251 : void *cls,
12252 : uint64_t serial_id,
12253 : TALER_EXCHANGEDB_WithdrawCallback cb,
12254 : void *cb_cls)
12255 : {
12256 0 : struct PostgresClosure *pg = cls;
12257 0 : struct GNUNET_PQ_QueryParam params[] = {
12258 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12259 : GNUNET_PQ_query_param_end
12260 : };
12261 0 : struct ReservesOutSerialContext rosc = {
12262 : .cb = cb,
12263 : .cb_cls = cb_cls,
12264 : .pg = pg,
12265 : .status = GNUNET_OK
12266 : };
12267 : enum GNUNET_DB_QueryStatus qs;
12268 :
12269 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12270 : "audit_get_reserves_out_incr",
12271 : params,
12272 : &reserves_out_serial_helper_cb,
12273 : &rosc);
12274 0 : if (GNUNET_OK != rosc.status)
12275 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12276 0 : return qs;
12277 : }
12278 :
12279 :
12280 : /**
12281 : * Closure for #wire_out_serial_helper_cb().
12282 : */
12283 : struct WireOutSerialContext
12284 : {
12285 :
12286 : /**
12287 : * Callback to call.
12288 : */
12289 : TALER_EXCHANGEDB_WireTransferOutCallback cb;
12290 :
12291 : /**
12292 : * Closure for @e cb.
12293 : */
12294 : void *cb_cls;
12295 :
12296 : /**
12297 : * Plugin context.
12298 : */
12299 : struct PostgresClosure *pg;
12300 :
12301 : /**
12302 : * Status code, set to #GNUNET_SYSERR on hard errors.
12303 : */
12304 : int status;
12305 : };
12306 :
12307 :
12308 : /**
12309 : * Helper function to be called with the results of a SELECT statement
12310 : * that has returned @a num_results results.
12311 : *
12312 : * @param cls closure of type `struct WireOutSerialContext`
12313 : * @param result the postgres result
12314 : * @param num_results the number of results in @a result
12315 : */
12316 : static void
12317 0 : wire_out_serial_helper_cb (void *cls,
12318 : PGresult *result,
12319 : unsigned int num_results)
12320 : {
12321 0 : struct WireOutSerialContext *wosc = cls;
12322 0 : struct PostgresClosure *pg = wosc->pg;
12323 :
12324 0 : for (unsigned int i = 0; i<num_results; i++)
12325 : {
12326 : uint64_t rowid;
12327 : struct GNUNET_TIME_Timestamp date;
12328 : struct TALER_WireTransferIdentifierRawP wtid;
12329 : char *payto_uri;
12330 : struct TALER_Amount amount;
12331 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12332 0 : GNUNET_PQ_result_spec_uint64 ("wireout_uuid",
12333 : &rowid),
12334 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
12335 : &date),
12336 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
12337 : &wtid),
12338 0 : GNUNET_PQ_result_spec_string ("payto_uri",
12339 : &payto_uri),
12340 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
12341 : &amount),
12342 : GNUNET_PQ_result_spec_end
12343 : };
12344 : int ret;
12345 :
12346 0 : if (GNUNET_OK !=
12347 0 : GNUNET_PQ_extract_result (result,
12348 : rs,
12349 : i))
12350 : {
12351 0 : GNUNET_break (0);
12352 0 : wosc->status = GNUNET_SYSERR;
12353 0 : return;
12354 : }
12355 0 : ret = wosc->cb (wosc->cb_cls,
12356 : rowid,
12357 : date,
12358 : &wtid,
12359 : payto_uri,
12360 : &amount);
12361 0 : GNUNET_PQ_cleanup_result (rs);
12362 0 : if (GNUNET_OK != ret)
12363 0 : break;
12364 : }
12365 : }
12366 :
12367 :
12368 : /**
12369 : * Function called to select all wire transfers the exchange
12370 : * executed.
12371 : *
12372 : * @param cls closure
12373 : * @param serial_id highest serial ID to exclude (select strictly larger)
12374 : * @param cb function to call for ONE unfinished item
12375 : * @param cb_cls closure for @a cb
12376 : * @return transaction status code
12377 : */
12378 : static enum GNUNET_DB_QueryStatus
12379 0 : postgres_select_wire_out_above_serial_id (
12380 : void *cls,
12381 : uint64_t serial_id,
12382 : TALER_EXCHANGEDB_WireTransferOutCallback cb,
12383 : void *cb_cls)
12384 : {
12385 0 : struct PostgresClosure *pg = cls;
12386 0 : struct GNUNET_PQ_QueryParam params[] = {
12387 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12388 : GNUNET_PQ_query_param_end
12389 : };
12390 0 : struct WireOutSerialContext wosc = {
12391 : .cb = cb,
12392 : .cb_cls = cb_cls,
12393 : .pg = pg,
12394 : .status = GNUNET_OK
12395 : };
12396 : enum GNUNET_DB_QueryStatus qs;
12397 :
12398 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12399 : "audit_get_wire_incr",
12400 : params,
12401 : &wire_out_serial_helper_cb,
12402 : &wosc);
12403 0 : if (GNUNET_OK != wosc.status)
12404 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12405 0 : return qs;
12406 : }
12407 :
12408 :
12409 : /**
12410 : * Function called to select all wire transfers the exchange
12411 : * executed by account.
12412 : *
12413 : * @param cls closure
12414 : * @param account_name account to select
12415 : * @param serial_id highest serial ID to exclude (select strictly larger)
12416 : * @param cb function to call for ONE unfinished item
12417 : * @param cb_cls closure for @a cb
12418 : * @return transaction status code
12419 : */
12420 : static enum GNUNET_DB_QueryStatus
12421 0 : postgres_select_wire_out_above_serial_id_by_account (
12422 : void *cls,
12423 : const char *account_name,
12424 : uint64_t serial_id,
12425 : TALER_EXCHANGEDB_WireTransferOutCallback cb,
12426 : void *cb_cls)
12427 : {
12428 0 : struct PostgresClosure *pg = cls;
12429 0 : struct GNUNET_PQ_QueryParam params[] = {
12430 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12431 0 : GNUNET_PQ_query_param_string (account_name),
12432 : GNUNET_PQ_query_param_end
12433 : };
12434 0 : struct WireOutSerialContext wosc = {
12435 : .cb = cb,
12436 : .cb_cls = cb_cls,
12437 : .pg = pg,
12438 : .status = GNUNET_OK
12439 : };
12440 : enum GNUNET_DB_QueryStatus qs;
12441 :
12442 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12443 : "audit_get_wire_incr_by_account",
12444 : params,
12445 : &wire_out_serial_helper_cb,
12446 : &wosc);
12447 0 : if (GNUNET_OK != wosc.status)
12448 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12449 0 : return qs;
12450 : }
12451 :
12452 :
12453 : /**
12454 : * Closure for #recoup_serial_helper_cb().
12455 : */
12456 : struct RecoupSerialContext
12457 : {
12458 :
12459 : /**
12460 : * Callback to call.
12461 : */
12462 : TALER_EXCHANGEDB_RecoupCallback cb;
12463 :
12464 : /**
12465 : * Closure for @e cb.
12466 : */
12467 : void *cb_cls;
12468 :
12469 : /**
12470 : * Plugin context.
12471 : */
12472 : struct PostgresClosure *pg;
12473 :
12474 : /**
12475 : * Status code, set to #GNUNET_SYSERR on hard errors.
12476 : */
12477 : enum GNUNET_GenericReturnValue status;
12478 : };
12479 :
12480 :
12481 : /**
12482 : * Helper function to be called with the results of a SELECT statement
12483 : * that has returned @a num_results results.
12484 : *
12485 : * @param cls closure of type `struct RecoupSerialContext`
12486 : * @param result the postgres result
12487 : * @param num_results the number of results in @a result
12488 : */
12489 : static void
12490 0 : recoup_serial_helper_cb (void *cls,
12491 : PGresult *result,
12492 : unsigned int num_results)
12493 : {
12494 0 : struct RecoupSerialContext *psc = cls;
12495 0 : struct PostgresClosure *pg = psc->pg;
12496 :
12497 0 : for (unsigned int i = 0; i<num_results; i++)
12498 : {
12499 : uint64_t rowid;
12500 : struct TALER_ReservePublicKeyP reserve_pub;
12501 : struct TALER_CoinPublicInfo coin;
12502 : struct TALER_CoinSpendSignatureP coin_sig;
12503 : union TALER_DenominationBlindingKeyP coin_blind;
12504 : struct TALER_Amount amount;
12505 : struct TALER_DenominationPublicKey denom_pub;
12506 : struct TALER_BlindedCoinHashP h_blind_ev;
12507 : struct GNUNET_TIME_Timestamp timestamp;
12508 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12509 0 : GNUNET_PQ_result_spec_uint64 ("recoup_uuid",
12510 : &rowid),
12511 0 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
12512 : ×tamp),
12513 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
12514 : &reserve_pub),
12515 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
12516 : &coin.coin_pub),
12517 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
12518 : &denom_pub),
12519 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
12520 : &coin_sig),
12521 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
12522 : &coin_blind),
12523 0 : GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
12524 : &h_blind_ev),
12525 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
12526 : &coin.denom_pub_hash),
12527 0 : GNUNET_PQ_result_spec_allow_null (
12528 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
12529 : &coin.h_age_commitment),
12530 : &coin.no_age_commitment),
12531 0 : TALER_PQ_result_spec_denom_sig ("denom_sig",
12532 : &coin.denom_sig),
12533 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
12534 : &amount),
12535 : GNUNET_PQ_result_spec_end
12536 : };
12537 : int ret;
12538 :
12539 0 : if (GNUNET_OK !=
12540 0 : GNUNET_PQ_extract_result (result,
12541 : rs,
12542 : i))
12543 : {
12544 0 : GNUNET_break (0);
12545 0 : psc->status = GNUNET_SYSERR;
12546 0 : return;
12547 : }
12548 0 : ret = psc->cb (psc->cb_cls,
12549 : rowid,
12550 : timestamp,
12551 : &amount,
12552 : &reserve_pub,
12553 : &coin,
12554 : &denom_pub,
12555 : &coin_sig,
12556 : &coin_blind);
12557 0 : GNUNET_PQ_cleanup_result (rs);
12558 0 : if (GNUNET_OK != ret)
12559 0 : break;
12560 : }
12561 : }
12562 :
12563 :
12564 : /**
12565 : * Function called to select recoup requests the exchange
12566 : * received, ordered by serial ID (monotonically increasing).
12567 : *
12568 : * @param cls closure
12569 : * @param serial_id lowest serial ID to include (select larger or equal)
12570 : * @param cb function to call for ONE unfinished item
12571 : * @param cb_cls closure for @a cb
12572 : * @return transaction status code
12573 : */
12574 : static enum GNUNET_DB_QueryStatus
12575 0 : postgres_select_recoup_above_serial_id (
12576 : void *cls,
12577 : uint64_t serial_id,
12578 : TALER_EXCHANGEDB_RecoupCallback cb,
12579 : void *cb_cls)
12580 : {
12581 0 : struct PostgresClosure *pg = cls;
12582 0 : struct GNUNET_PQ_QueryParam params[] = {
12583 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12584 : GNUNET_PQ_query_param_end
12585 : };
12586 0 : struct RecoupSerialContext psc = {
12587 : .cb = cb,
12588 : .cb_cls = cb_cls,
12589 : .pg = pg,
12590 : .status = GNUNET_OK
12591 : };
12592 : enum GNUNET_DB_QueryStatus qs;
12593 :
12594 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12595 : "recoup_get_incr",
12596 : params,
12597 : &recoup_serial_helper_cb,
12598 : &psc);
12599 0 : if (GNUNET_OK != psc.status)
12600 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12601 0 : return qs;
12602 : }
12603 :
12604 :
12605 : /**
12606 : * Closure for #recoup_refresh_serial_helper_cb().
12607 : */
12608 : struct RecoupRefreshSerialContext
12609 : {
12610 :
12611 : /**
12612 : * Callback to call.
12613 : */
12614 : TALER_EXCHANGEDB_RecoupRefreshCallback cb;
12615 :
12616 : /**
12617 : * Closure for @e cb.
12618 : */
12619 : void *cb_cls;
12620 :
12621 : /**
12622 : * Plugin context.
12623 : */
12624 : struct PostgresClosure *pg;
12625 :
12626 : /**
12627 : * Status code, set to #GNUNET_SYSERR on hard errors.
12628 : */
12629 : enum GNUNET_GenericReturnValue status;
12630 : };
12631 :
12632 :
12633 : /**
12634 : * Helper function to be called with the results of a SELECT statement
12635 : * that has returned @a num_results results.
12636 : *
12637 : * @param cls closure of type `struct RecoupRefreshSerialContext`
12638 : * @param result the postgres result
12639 : * @param num_results the number of results in @a result
12640 : */
12641 : static void
12642 0 : recoup_refresh_serial_helper_cb (void *cls,
12643 : PGresult *result,
12644 : unsigned int num_results)
12645 : {
12646 0 : struct RecoupRefreshSerialContext *psc = cls;
12647 0 : struct PostgresClosure *pg = psc->pg;
12648 :
12649 0 : for (unsigned int i = 0; i<num_results; i++)
12650 : {
12651 : uint64_t rowid;
12652 : struct TALER_CoinSpendPublicKeyP old_coin_pub;
12653 : struct TALER_CoinPublicInfo coin;
12654 : struct TALER_CoinSpendSignatureP coin_sig;
12655 : union TALER_DenominationBlindingKeyP coin_blind;
12656 : struct TALER_DenominationPublicKey denom_pub;
12657 : struct TALER_DenominationHashP old_denom_pub_hash;
12658 : struct TALER_Amount amount;
12659 : struct TALER_BlindedCoinHashP h_blind_ev;
12660 : struct GNUNET_TIME_Timestamp timestamp;
12661 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12662 0 : GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
12663 : &rowid),
12664 0 : GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
12665 : ×tamp),
12666 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
12667 : &old_coin_pub),
12668 0 : GNUNET_PQ_result_spec_auto_from_type ("old_denom_pub_hash",
12669 : &old_denom_pub_hash),
12670 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
12671 : &coin.coin_pub),
12672 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
12673 : &coin_sig),
12674 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
12675 : &coin_blind),
12676 0 : TALER_PQ_result_spec_denom_pub ("denom_pub",
12677 : &denom_pub),
12678 0 : GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
12679 : &h_blind_ev),
12680 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
12681 : &coin.denom_pub_hash),
12682 0 : GNUNET_PQ_result_spec_allow_null (
12683 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
12684 : &coin.h_age_commitment),
12685 : &coin.no_age_commitment),
12686 0 : TALER_PQ_result_spec_denom_sig ("denom_sig",
12687 : &coin.denom_sig),
12688 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
12689 : &amount),
12690 : GNUNET_PQ_result_spec_end
12691 : };
12692 : enum GNUNET_GenericReturnValue ret;
12693 :
12694 0 : if (GNUNET_OK !=
12695 0 : GNUNET_PQ_extract_result (result,
12696 : rs,
12697 : i))
12698 : {
12699 0 : GNUNET_break (0);
12700 0 : psc->status = GNUNET_SYSERR;
12701 0 : return;
12702 : }
12703 0 : ret = psc->cb (psc->cb_cls,
12704 : rowid,
12705 : timestamp,
12706 : &amount,
12707 : &old_coin_pub,
12708 : &old_denom_pub_hash,
12709 : &coin,
12710 : &denom_pub,
12711 : &coin_sig,
12712 : &coin_blind);
12713 0 : GNUNET_PQ_cleanup_result (rs);
12714 0 : if (GNUNET_OK != ret)
12715 0 : break;
12716 : }
12717 : }
12718 :
12719 :
12720 : /**
12721 : * Function called to select recoup requests the exchange received for
12722 : * refreshed coins, ordered by serial ID (monotonically increasing).
12723 : *
12724 : * @param cls closure
12725 : * @param serial_id lowest serial ID to include (select larger or equal)
12726 : * @param cb function to call for ONE unfinished item
12727 : * @param cb_cls closure for @a cb
12728 : * @return transaction status code
12729 : */
12730 : static enum GNUNET_DB_QueryStatus
12731 0 : postgres_select_recoup_refresh_above_serial_id (
12732 : void *cls,
12733 : uint64_t serial_id,
12734 : TALER_EXCHANGEDB_RecoupRefreshCallback cb,
12735 : void *cb_cls)
12736 : {
12737 0 : struct PostgresClosure *pg = cls;
12738 0 : struct GNUNET_PQ_QueryParam params[] = {
12739 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12740 : GNUNET_PQ_query_param_end
12741 : };
12742 0 : struct RecoupRefreshSerialContext psc = {
12743 : .cb = cb,
12744 : .cb_cls = cb_cls,
12745 : .pg = pg,
12746 : .status = GNUNET_OK
12747 : };
12748 : enum GNUNET_DB_QueryStatus qs;
12749 :
12750 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12751 : "recoup_refresh_get_incr",
12752 : params,
12753 : &recoup_refresh_serial_helper_cb,
12754 : &psc);
12755 0 : if (GNUNET_OK != psc.status)
12756 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12757 0 : return qs;
12758 : }
12759 :
12760 :
12761 : /**
12762 : * Closure for #reserve_closed_serial_helper_cb().
12763 : */
12764 : struct ReserveClosedSerialContext
12765 : {
12766 :
12767 : /**
12768 : * Callback to call.
12769 : */
12770 : TALER_EXCHANGEDB_ReserveClosedCallback cb;
12771 :
12772 : /**
12773 : * Closure for @e cb.
12774 : */
12775 : void *cb_cls;
12776 :
12777 : /**
12778 : * Plugin's context.
12779 : */
12780 : struct PostgresClosure *pg;
12781 :
12782 : /**
12783 : * Status code, set to #GNUNET_SYSERR on hard errors.
12784 : */
12785 : enum GNUNET_GenericReturnValue status;
12786 : };
12787 :
12788 :
12789 : /**
12790 : * Helper function to be called with the results of a SELECT statement
12791 : * that has returned @a num_results results.
12792 : *
12793 : * @param cls closure of type `struct ReserveClosedSerialContext`
12794 : * @param result the postgres result
12795 : * @param num_results the number of results in @a result
12796 : */
12797 : static void
12798 0 : reserve_closed_serial_helper_cb (void *cls,
12799 : PGresult *result,
12800 : unsigned int num_results)
12801 : {
12802 0 : struct ReserveClosedSerialContext *rcsc = cls;
12803 0 : struct PostgresClosure *pg = rcsc->pg;
12804 :
12805 0 : for (unsigned int i = 0; i<num_results; i++)
12806 : {
12807 : uint64_t rowid;
12808 : struct TALER_ReservePublicKeyP reserve_pub;
12809 : char *receiver_account;
12810 : struct TALER_WireTransferIdentifierRawP wtid;
12811 : struct TALER_Amount amount_with_fee;
12812 : struct TALER_Amount closing_fee;
12813 : struct GNUNET_TIME_Timestamp execution_date;
12814 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12815 0 : GNUNET_PQ_result_spec_uint64 ("close_uuid",
12816 : &rowid),
12817 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
12818 : &reserve_pub),
12819 0 : GNUNET_PQ_result_spec_timestamp ("execution_date",
12820 : &execution_date),
12821 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid",
12822 : &wtid),
12823 0 : GNUNET_PQ_result_spec_string ("receiver_account",
12824 : &receiver_account),
12825 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
12826 : &amount_with_fee),
12827 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
12828 : &closing_fee),
12829 : GNUNET_PQ_result_spec_end
12830 : };
12831 : enum GNUNET_GenericReturnValue ret;
12832 :
12833 0 : if (GNUNET_OK !=
12834 0 : GNUNET_PQ_extract_result (result,
12835 : rs,
12836 : i))
12837 : {
12838 0 : GNUNET_break (0);
12839 0 : rcsc->status = GNUNET_SYSERR;
12840 0 : return;
12841 : }
12842 0 : ret = rcsc->cb (rcsc->cb_cls,
12843 : rowid,
12844 : execution_date,
12845 : &amount_with_fee,
12846 : &closing_fee,
12847 : &reserve_pub,
12848 : receiver_account,
12849 : &wtid);
12850 0 : GNUNET_PQ_cleanup_result (rs);
12851 0 : if (GNUNET_OK != ret)
12852 0 : break;
12853 : }
12854 : }
12855 :
12856 :
12857 : /**
12858 : * Function called to select reserve close operations the aggregator
12859 : * triggered, ordered by serial ID (monotonically increasing).
12860 : *
12861 : * @param cls closure
12862 : * @param serial_id lowest serial ID to include (select larger or equal)
12863 : * @param cb function to call for ONE unfinished item
12864 : * @param cb_cls closure for @a cb
12865 : * @return transaction status code
12866 : */
12867 : static enum GNUNET_DB_QueryStatus
12868 0 : postgres_select_reserve_closed_above_serial_id (
12869 : void *cls,
12870 : uint64_t serial_id,
12871 : TALER_EXCHANGEDB_ReserveClosedCallback cb,
12872 : void *cb_cls)
12873 : {
12874 0 : struct PostgresClosure *pg = cls;
12875 0 : struct GNUNET_PQ_QueryParam params[] = {
12876 0 : GNUNET_PQ_query_param_uint64 (&serial_id),
12877 : GNUNET_PQ_query_param_end
12878 : };
12879 0 : struct ReserveClosedSerialContext rcsc = {
12880 : .cb = cb,
12881 : .cb_cls = cb_cls,
12882 : .pg = pg,
12883 : .status = GNUNET_OK
12884 : };
12885 : enum GNUNET_DB_QueryStatus qs;
12886 :
12887 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
12888 : "reserves_close_get_incr",
12889 : params,
12890 : &reserve_closed_serial_helper_cb,
12891 : &rcsc);
12892 0 : if (GNUNET_OK != rcsc.status)
12893 0 : return GNUNET_DB_STATUS_HARD_ERROR;
12894 0 : return qs;
12895 : }
12896 :
12897 :
12898 : /**
12899 : * Obtain information about which reserve a coin was generated
12900 : * from given the hash of the blinded coin.
12901 : *
12902 : * @param cls closure
12903 : * @param bch hash that uniquely identifies the withdraw request
12904 : * @param[out] reserve_pub set to information about the reserve (on success only)
12905 : * @param[out] reserve_out_serial_id set to row of the @a h_blind_ev in reserves_out
12906 : * @return transaction status code
12907 : */
12908 : static enum GNUNET_DB_QueryStatus
12909 0 : postgres_get_reserve_by_h_blind (
12910 : void *cls,
12911 : const struct TALER_BlindedCoinHashP *bch,
12912 : struct TALER_ReservePublicKeyP *reserve_pub,
12913 : uint64_t *reserve_out_serial_id)
12914 : {
12915 0 : struct PostgresClosure *pg = cls;
12916 0 : struct GNUNET_PQ_QueryParam params[] = {
12917 0 : GNUNET_PQ_query_param_auto_from_type (bch),
12918 : GNUNET_PQ_query_param_end
12919 : };
12920 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12921 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
12922 : reserve_pub),
12923 0 : GNUNET_PQ_result_spec_uint64 ("reserve_out_serial_id",
12924 : reserve_out_serial_id),
12925 : GNUNET_PQ_result_spec_end
12926 : };
12927 :
12928 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
12929 : "reserve_by_h_blind",
12930 : params,
12931 : rs);
12932 : }
12933 :
12934 :
12935 : /**
12936 : * Obtain information about which old coin a coin was refreshed
12937 : * given the hash of the blinded (fresh) coin.
12938 : *
12939 : * @param cls closure
12940 : * @param h_blind_ev hash of the blinded coin
12941 : * @param[out] old_coin_pub set to information about the old coin (on success only)
12942 : * @param[out] rrc_serial set to serial number of the entry in the database
12943 : * @return transaction status code
12944 : */
12945 : static enum GNUNET_DB_QueryStatus
12946 0 : postgres_get_old_coin_by_h_blind (
12947 : void *cls,
12948 : const struct TALER_BlindedCoinHashP *h_blind_ev,
12949 : struct TALER_CoinSpendPublicKeyP *old_coin_pub,
12950 : uint64_t *rrc_serial)
12951 : {
12952 0 : struct PostgresClosure *pg = cls;
12953 0 : struct GNUNET_PQ_QueryParam params[] = {
12954 0 : GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
12955 : GNUNET_PQ_query_param_end
12956 : };
12957 0 : struct GNUNET_PQ_ResultSpec rs[] = {
12958 0 : GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
12959 : old_coin_pub),
12960 0 : GNUNET_PQ_result_spec_uint64 ("rrc_serial",
12961 : rrc_serial),
12962 : GNUNET_PQ_result_spec_end
12963 : };
12964 :
12965 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
12966 : "old_coin_by_h_blind",
12967 : params,
12968 : rs);
12969 : }
12970 :
12971 :
12972 : /**
12973 : * Store information that a denomination key was revoked
12974 : * in the database.
12975 : *
12976 : * @param cls closure
12977 : * @param denom_pub_hash hash of the revoked denomination key
12978 : * @param master_sig signature affirming the revocation
12979 : * @return transaction status code
12980 : */
12981 : static enum GNUNET_DB_QueryStatus
12982 0 : postgres_insert_denomination_revocation (
12983 : void *cls,
12984 : const struct TALER_DenominationHashP *denom_pub_hash,
12985 : const struct TALER_MasterSignatureP *master_sig)
12986 : {
12987 0 : struct PostgresClosure *pg = cls;
12988 0 : struct GNUNET_PQ_QueryParam params[] = {
12989 0 : GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
12990 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
12991 : GNUNET_PQ_query_param_end
12992 : };
12993 :
12994 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
12995 : "denomination_revocation_insert",
12996 : params);
12997 : }
12998 :
12999 :
13000 : /**
13001 : * Obtain information about a denomination key's revocation from
13002 : * the database.
13003 : *
13004 : * @param cls closure
13005 : * @param denom_pub_hash hash of the revoked denomination key
13006 : * @param[out] master_sig signature affirming the revocation
13007 : * @param[out] rowid row where the information is stored
13008 : * @return transaction status code
13009 : */
13010 : static enum GNUNET_DB_QueryStatus
13011 0 : postgres_get_denomination_revocation (
13012 : void *cls,
13013 : const struct TALER_DenominationHashP *denom_pub_hash,
13014 : struct TALER_MasterSignatureP *master_sig,
13015 : uint64_t *rowid)
13016 : {
13017 0 : struct PostgresClosure *pg = cls;
13018 0 : struct GNUNET_PQ_QueryParam params[] = {
13019 0 : GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
13020 : GNUNET_PQ_query_param_end
13021 : };
13022 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13023 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
13024 : master_sig),
13025 0 : GNUNET_PQ_result_spec_uint64 ("denom_revocations_serial_id",
13026 : rowid),
13027 : GNUNET_PQ_result_spec_end
13028 : };
13029 :
13030 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13031 : "denomination_revocation_get",
13032 : params,
13033 : rs);
13034 : }
13035 :
13036 :
13037 : /**
13038 : * Closure for #missing_wire_cb().
13039 : */
13040 : struct MissingWireContext
13041 : {
13042 : /**
13043 : * Function to call per result.
13044 : */
13045 : TALER_EXCHANGEDB_WireMissingCallback cb;
13046 :
13047 : /**
13048 : * Closure for @e cb.
13049 : */
13050 : void *cb_cls;
13051 :
13052 : /**
13053 : * Plugin context.
13054 : */
13055 : struct PostgresClosure *pg;
13056 :
13057 : /**
13058 : * Set to #GNUNET_SYSERR on error.
13059 : */
13060 : enum GNUNET_GenericReturnValue status;
13061 : };
13062 :
13063 :
13064 : /**
13065 : * Invoke the callback for each result.
13066 : *
13067 : * @param cls a `struct MissingWireContext *`
13068 : * @param result SQL result
13069 : * @param num_results number of rows in @a result
13070 : */
13071 : static void
13072 0 : missing_wire_cb (void *cls,
13073 : PGresult *result,
13074 : unsigned int num_results)
13075 : {
13076 0 : struct MissingWireContext *mwc = cls;
13077 0 : struct PostgresClosure *pg = mwc->pg;
13078 :
13079 0 : while (0 < num_results)
13080 : {
13081 : uint64_t rowid;
13082 : struct TALER_CoinSpendPublicKeyP coin_pub;
13083 : struct TALER_Amount amount;
13084 : char *payto_uri;
13085 : struct GNUNET_TIME_Timestamp deadline;
13086 : bool done;
13087 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13088 0 : GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
13089 : &rowid),
13090 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
13091 : &coin_pub),
13092 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
13093 : &amount),
13094 0 : GNUNET_PQ_result_spec_string ("payto_uri",
13095 : &payto_uri),
13096 0 : GNUNET_PQ_result_spec_timestamp ("wire_deadline",
13097 : &deadline),
13098 0 : GNUNET_PQ_result_spec_bool ("done",
13099 : &done),
13100 : GNUNET_PQ_result_spec_end
13101 : };
13102 :
13103 0 : if (GNUNET_OK !=
13104 0 : GNUNET_PQ_extract_result (result,
13105 : rs,
13106 : --num_results))
13107 : {
13108 0 : GNUNET_break (0);
13109 0 : mwc->status = GNUNET_SYSERR;
13110 0 : return;
13111 : }
13112 0 : mwc->cb (mwc->cb_cls,
13113 : rowid,
13114 : &coin_pub,
13115 : &amount,
13116 : payto_uri,
13117 : deadline,
13118 : done);
13119 0 : GNUNET_PQ_cleanup_result (rs);
13120 : }
13121 : }
13122 :
13123 :
13124 : /**
13125 : * Select all of those deposits in the database for which we do
13126 : * not have a wire transfer (or a refund) and which should have
13127 : * been deposited between @a start_date and @a end_date.
13128 : *
13129 : * @param cls closure
13130 : * @param start_date lower bound on the requested wire execution date
13131 : * @param end_date upper bound on the requested wire execution date
13132 : * @param cb function to call on all such deposits
13133 : * @param cb_cls closure for @a cb
13134 : * @return transaction status code
13135 : */
13136 : static enum GNUNET_DB_QueryStatus
13137 0 : postgres_select_deposits_missing_wire (void *cls,
13138 : struct GNUNET_TIME_Timestamp start_date,
13139 : struct GNUNET_TIME_Timestamp end_date,
13140 : TALER_EXCHANGEDB_WireMissingCallback cb,
13141 : void *cb_cls)
13142 : {
13143 0 : struct PostgresClosure *pg = cls;
13144 0 : struct GNUNET_PQ_QueryParam params[] = {
13145 0 : GNUNET_PQ_query_param_timestamp (&start_date),
13146 0 : GNUNET_PQ_query_param_timestamp (&end_date),
13147 : GNUNET_PQ_query_param_end
13148 : };
13149 0 : struct MissingWireContext mwc = {
13150 : .cb = cb,
13151 : .cb_cls = cb_cls,
13152 : .pg = pg,
13153 : .status = GNUNET_OK
13154 : };
13155 : enum GNUNET_DB_QueryStatus qs;
13156 :
13157 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
13158 : "deposits_get_overdue",
13159 : params,
13160 : &missing_wire_cb,
13161 : &mwc);
13162 0 : if (GNUNET_OK != mwc.status)
13163 0 : return GNUNET_DB_STATUS_HARD_ERROR;
13164 0 : return qs;
13165 : }
13166 :
13167 :
13168 : /**
13169 : * Check the last date an auditor was modified.
13170 : *
13171 : * @param cls closure
13172 : * @param auditor_pub key to look up information for
13173 : * @param[out] last_date last modification date to auditor status
13174 : * @return transaction status code
13175 : */
13176 : static enum GNUNET_DB_QueryStatus
13177 0 : postgres_lookup_auditor_timestamp (
13178 : void *cls,
13179 : const struct TALER_AuditorPublicKeyP *auditor_pub,
13180 : struct GNUNET_TIME_Timestamp *last_date)
13181 : {
13182 0 : struct PostgresClosure *pg = cls;
13183 0 : struct GNUNET_PQ_QueryParam params[] = {
13184 0 : GNUNET_PQ_query_param_auto_from_type (auditor_pub),
13185 : GNUNET_PQ_query_param_end
13186 : };
13187 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13188 0 : GNUNET_PQ_result_spec_timestamp ("last_change",
13189 : last_date),
13190 : GNUNET_PQ_result_spec_end
13191 : };
13192 :
13193 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13194 : "lookup_auditor_timestamp",
13195 : params,
13196 : rs);
13197 : }
13198 :
13199 :
13200 : /**
13201 : * Lookup current state of an auditor.
13202 : *
13203 : * @param cls closure
13204 : * @param auditor_pub key to look up information for
13205 : * @param[out] auditor_url set to the base URL of the auditor's REST API; memory to be
13206 : * released by the caller!
13207 : * @param[out] enabled set if the auditor is currently in use
13208 : * @return transaction status code
13209 : */
13210 : static enum GNUNET_DB_QueryStatus
13211 0 : postgres_lookup_auditor_status (
13212 : void *cls,
13213 : const struct TALER_AuditorPublicKeyP *auditor_pub,
13214 : char **auditor_url,
13215 : bool *enabled)
13216 : {
13217 0 : struct PostgresClosure *pg = cls;
13218 0 : struct GNUNET_PQ_QueryParam params[] = {
13219 0 : GNUNET_PQ_query_param_auto_from_type (auditor_pub),
13220 : GNUNET_PQ_query_param_end
13221 : };
13222 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13223 0 : GNUNET_PQ_result_spec_string ("auditor_url",
13224 : auditor_url),
13225 0 : GNUNET_PQ_result_spec_bool ("is_active",
13226 : enabled),
13227 : GNUNET_PQ_result_spec_end
13228 : };
13229 :
13230 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13231 : "lookup_auditor_status",
13232 : params,
13233 : rs);
13234 : }
13235 :
13236 :
13237 : /**
13238 : * Insert information about an auditor that will audit this exchange.
13239 : *
13240 : * @param cls closure
13241 : * @param auditor_pub key of the auditor
13242 : * @param auditor_url base URL of the auditor's REST service
13243 : * @param auditor_name name of the auditor (for humans)
13244 : * @param start_date date when the auditor was added by the offline system
13245 : * (only to be used for replay detection)
13246 : * @return transaction status code
13247 : */
13248 : static enum GNUNET_DB_QueryStatus
13249 0 : postgres_insert_auditor (void *cls,
13250 : const struct TALER_AuditorPublicKeyP *auditor_pub,
13251 : const char *auditor_url,
13252 : const char *auditor_name,
13253 : struct GNUNET_TIME_Timestamp start_date)
13254 : {
13255 0 : struct PostgresClosure *pg = cls;
13256 0 : struct GNUNET_PQ_QueryParam params[] = {
13257 0 : GNUNET_PQ_query_param_auto_from_type (auditor_pub),
13258 0 : GNUNET_PQ_query_param_string (auditor_name),
13259 0 : GNUNET_PQ_query_param_string (auditor_url),
13260 0 : GNUNET_PQ_query_param_timestamp (&start_date),
13261 : GNUNET_PQ_query_param_end
13262 : };
13263 :
13264 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13265 : "insert_auditor",
13266 : params);
13267 : }
13268 :
13269 :
13270 : /**
13271 : * Update information about an auditor that will audit this exchange.
13272 : *
13273 : * @param cls closure
13274 : * @param auditor_pub key of the auditor (primary key for the existing record)
13275 : * @param auditor_url base URL of the auditor's REST service, to be updated
13276 : * @param auditor_name name of the auditor (for humans)
13277 : * @param change_date date when the auditor status was last changed
13278 : * (only to be used for replay detection)
13279 : * @param enabled true to enable, false to disable
13280 : * @return transaction status code
13281 : */
13282 : static enum GNUNET_DB_QueryStatus
13283 0 : postgres_update_auditor (void *cls,
13284 : const struct TALER_AuditorPublicKeyP *auditor_pub,
13285 : const char *auditor_url,
13286 : const char *auditor_name,
13287 : struct GNUNET_TIME_Timestamp change_date,
13288 : bool enabled)
13289 : {
13290 0 : struct PostgresClosure *pg = cls;
13291 0 : struct GNUNET_PQ_QueryParam params[] = {
13292 0 : GNUNET_PQ_query_param_auto_from_type (auditor_pub),
13293 0 : GNUNET_PQ_query_param_string (auditor_url),
13294 0 : GNUNET_PQ_query_param_string (auditor_name),
13295 0 : GNUNET_PQ_query_param_bool (enabled),
13296 0 : GNUNET_PQ_query_param_timestamp (&change_date),
13297 : GNUNET_PQ_query_param_end
13298 : };
13299 :
13300 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13301 : "update_auditor",
13302 : params);
13303 : }
13304 :
13305 :
13306 : /**
13307 : * Check the last date an exchange wire account was modified.
13308 : *
13309 : * @param cls closure
13310 : * @param payto_uri key to look up information for
13311 : * @param[out] last_date last modification date to auditor status
13312 : * @return transaction status code
13313 : */
13314 : static enum GNUNET_DB_QueryStatus
13315 0 : postgres_lookup_wire_timestamp (void *cls,
13316 : const char *payto_uri,
13317 : struct GNUNET_TIME_Timestamp *last_date)
13318 : {
13319 0 : struct PostgresClosure *pg = cls;
13320 0 : struct GNUNET_PQ_QueryParam params[] = {
13321 0 : GNUNET_PQ_query_param_string (payto_uri),
13322 : GNUNET_PQ_query_param_end
13323 : };
13324 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13325 0 : GNUNET_PQ_result_spec_timestamp ("last_change",
13326 : last_date),
13327 : GNUNET_PQ_result_spec_end
13328 : };
13329 :
13330 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13331 : "lookup_wire_timestamp",
13332 : params,
13333 : rs);
13334 : }
13335 :
13336 :
13337 : /**
13338 : * Insert information about an wire account used by this exchange.
13339 : *
13340 : * @param cls closure
13341 : * @param payto_uri wire account of the exchange
13342 : * @param start_date date when the account was added by the offline system
13343 : * (only to be used for replay detection)
13344 : * @param master_sig public signature affirming the existence of the account,
13345 : * must be of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS
13346 : * @return transaction status code
13347 : */
13348 : static enum GNUNET_DB_QueryStatus
13349 0 : postgres_insert_wire (void *cls,
13350 : const char *payto_uri,
13351 : struct GNUNET_TIME_Timestamp start_date,
13352 : const struct TALER_MasterSignatureP *master_sig)
13353 : {
13354 0 : struct PostgresClosure *pg = cls;
13355 0 : struct GNUNET_PQ_QueryParam params[] = {
13356 0 : GNUNET_PQ_query_param_string (payto_uri),
13357 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
13358 0 : GNUNET_PQ_query_param_timestamp (&start_date),
13359 : GNUNET_PQ_query_param_end
13360 : };
13361 :
13362 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13363 : "insert_wire",
13364 : params);
13365 : }
13366 :
13367 :
13368 : /**
13369 : * Update information about a wire account of the exchange.
13370 : *
13371 : * @param cls closure
13372 : * @param payto_uri account the update is about
13373 : * @param change_date date when the account status was last changed
13374 : * (only to be used for replay detection)
13375 : * @param enabled true to enable, false to disable (the actual change)
13376 : * @return transaction status code
13377 : */
13378 : static enum GNUNET_DB_QueryStatus
13379 0 : postgres_update_wire (void *cls,
13380 : const char *payto_uri,
13381 : struct GNUNET_TIME_Timestamp change_date,
13382 : bool enabled)
13383 : {
13384 0 : struct PostgresClosure *pg = cls;
13385 0 : struct GNUNET_PQ_QueryParam params[] = {
13386 0 : GNUNET_PQ_query_param_string (payto_uri),
13387 0 : GNUNET_PQ_query_param_bool (enabled),
13388 0 : GNUNET_PQ_query_param_timestamp (&change_date),
13389 : GNUNET_PQ_query_param_end
13390 : };
13391 :
13392 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13393 : "update_wire",
13394 : params);
13395 : }
13396 :
13397 :
13398 : /**
13399 : * Closure for #get_wire_accounts_cb().
13400 : */
13401 : struct GetWireAccountsContext
13402 : {
13403 : /**
13404 : * Function to call per result.
13405 : */
13406 : TALER_EXCHANGEDB_WireAccountCallback cb;
13407 :
13408 : /**
13409 : * Closure for @e cb.
13410 : */
13411 : void *cb_cls;
13412 :
13413 : /**
13414 : * Flag set to #GNUNET_OK as long as everything is fine.
13415 : */
13416 : enum GNUNET_GenericReturnValue status;
13417 :
13418 : };
13419 :
13420 :
13421 : /**
13422 : * Invoke the callback for each result.
13423 : *
13424 : * @param cls a `struct MissingWireContext *`
13425 : * @param result SQL result
13426 : * @param num_results number of rows in @a result
13427 : */
13428 : static void
13429 0 : get_wire_accounts_cb (void *cls,
13430 : PGresult *result,
13431 : unsigned int num_results)
13432 : {
13433 0 : struct GetWireAccountsContext *ctx = cls;
13434 :
13435 0 : for (unsigned int i = 0; i < num_results; i++)
13436 : {
13437 : char *payto_uri;
13438 : struct TALER_MasterSignatureP master_sig;
13439 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13440 0 : GNUNET_PQ_result_spec_string ("payto_uri",
13441 : &payto_uri),
13442 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
13443 : &master_sig),
13444 : GNUNET_PQ_result_spec_end
13445 : };
13446 :
13447 0 : if (GNUNET_OK !=
13448 0 : GNUNET_PQ_extract_result (result,
13449 : rs,
13450 : i))
13451 : {
13452 0 : GNUNET_break (0);
13453 0 : ctx->status = GNUNET_SYSERR;
13454 0 : return;
13455 : }
13456 0 : ctx->cb (ctx->cb_cls,
13457 : payto_uri,
13458 : &master_sig);
13459 0 : GNUNET_PQ_cleanup_result (rs);
13460 : }
13461 : }
13462 :
13463 :
13464 : /**
13465 : * Obtain information about the enabled wire accounts of the exchange.
13466 : *
13467 : * @param cls closure
13468 : * @param cb function to call on each account
13469 : * @param cb_cls closure for @a cb
13470 : * @return transaction status code
13471 : */
13472 : static enum GNUNET_DB_QueryStatus
13473 0 : postgres_get_wire_accounts (void *cls,
13474 : TALER_EXCHANGEDB_WireAccountCallback cb,
13475 : void *cb_cls)
13476 : {
13477 0 : struct PostgresClosure *pg = cls;
13478 0 : struct GetWireAccountsContext ctx = {
13479 : .cb = cb,
13480 : .cb_cls = cb_cls,
13481 : .status = GNUNET_OK
13482 : };
13483 0 : struct GNUNET_PQ_QueryParam params[] = {
13484 : GNUNET_PQ_query_param_end
13485 : };
13486 : enum GNUNET_DB_QueryStatus qs;
13487 :
13488 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
13489 : "get_wire_accounts",
13490 : params,
13491 : &get_wire_accounts_cb,
13492 : &ctx);
13493 0 : if (GNUNET_OK != ctx.status)
13494 0 : return GNUNET_DB_STATUS_HARD_ERROR;
13495 0 : return qs;
13496 :
13497 : }
13498 :
13499 :
13500 : /**
13501 : * Closure for #get_wire_fees_cb().
13502 : */
13503 : struct GetWireFeesContext
13504 : {
13505 : /**
13506 : * Function to call per result.
13507 : */
13508 : TALER_EXCHANGEDB_WireFeeCallback cb;
13509 :
13510 : /**
13511 : * Closure for @e cb.
13512 : */
13513 : void *cb_cls;
13514 :
13515 : /**
13516 : * Plugin context.
13517 : */
13518 : struct PostgresClosure *pg;
13519 :
13520 : /**
13521 : * Flag set to #GNUNET_OK as long as everything is fine.
13522 : */
13523 : enum GNUNET_GenericReturnValue status;
13524 :
13525 : };
13526 :
13527 :
13528 : /**
13529 : * Invoke the callback for each result.
13530 : *
13531 : * @param cls a `struct GetWireFeesContext *`
13532 : * @param result SQL result
13533 : * @param num_results number of rows in @a result
13534 : */
13535 : static void
13536 0 : get_wire_fees_cb (void *cls,
13537 : PGresult *result,
13538 : unsigned int num_results)
13539 : {
13540 0 : struct GetWireFeesContext *ctx = cls;
13541 0 : struct PostgresClosure *pg = ctx->pg;
13542 :
13543 0 : for (unsigned int i = 0; i < num_results; i++)
13544 : {
13545 : struct TALER_MasterSignatureP master_sig;
13546 : struct TALER_WireFeeSet fees;
13547 : struct GNUNET_TIME_Timestamp start_date;
13548 : struct GNUNET_TIME_Timestamp end_date;
13549 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13550 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
13551 : &fees.wire),
13552 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
13553 : &fees.closing),
13554 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("wad_fee",
13555 : &fees.wad),
13556 0 : GNUNET_PQ_result_spec_timestamp ("start_date",
13557 : &start_date),
13558 0 : GNUNET_PQ_result_spec_timestamp ("end_date",
13559 : &end_date),
13560 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
13561 : &master_sig),
13562 : GNUNET_PQ_result_spec_end
13563 : };
13564 :
13565 0 : if (GNUNET_OK !=
13566 0 : GNUNET_PQ_extract_result (result,
13567 : rs,
13568 : i))
13569 : {
13570 0 : GNUNET_break (0);
13571 0 : ctx->status = GNUNET_SYSERR;
13572 0 : return;
13573 : }
13574 0 : ctx->cb (ctx->cb_cls,
13575 : &fees,
13576 : start_date,
13577 : end_date,
13578 : &master_sig);
13579 0 : GNUNET_PQ_cleanup_result (rs);
13580 : }
13581 : }
13582 :
13583 :
13584 : /**
13585 : * Obtain information about the fee structure of the exchange for
13586 : * a given @a wire_method
13587 : *
13588 : * @param cls closure
13589 : * @param wire_method which wire method to obtain fees for
13590 : * @param cb function to call on each account
13591 : * @param cb_cls closure for @a cb
13592 : * @return transaction status code
13593 : */
13594 : static enum GNUNET_DB_QueryStatus
13595 0 : postgres_get_wire_fees (void *cls,
13596 : const char *wire_method,
13597 : TALER_EXCHANGEDB_WireFeeCallback cb,
13598 : void *cb_cls)
13599 : {
13600 0 : struct PostgresClosure *pg = cls;
13601 0 : struct GNUNET_PQ_QueryParam params[] = {
13602 0 : GNUNET_PQ_query_param_string (wire_method),
13603 : GNUNET_PQ_query_param_end
13604 : };
13605 0 : struct GetWireFeesContext ctx = {
13606 : .cb = cb,
13607 : .cb_cls = cb_cls,
13608 : .pg = pg,
13609 : .status = GNUNET_OK
13610 : };
13611 : enum GNUNET_DB_QueryStatus qs;
13612 :
13613 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
13614 : "get_wire_fees",
13615 : params,
13616 : &get_wire_fees_cb,
13617 : &ctx);
13618 0 : if (GNUNET_OK != ctx.status)
13619 0 : return GNUNET_DB_STATUS_HARD_ERROR;
13620 0 : return qs;
13621 : }
13622 :
13623 :
13624 : /**
13625 : * Store information about a revoked online signing key.
13626 : *
13627 : * @param cls closure
13628 : * @param exchange_pub exchange online signing key that was revoked
13629 : * @param master_sig signature affirming the revocation
13630 : * @return transaction status code
13631 : */
13632 : static enum GNUNET_DB_QueryStatus
13633 0 : postgres_insert_signkey_revocation (
13634 : void *cls,
13635 : const struct TALER_ExchangePublicKeyP *exchange_pub,
13636 : const struct TALER_MasterSignatureP *master_sig)
13637 : {
13638 0 : struct PostgresClosure *pg = cls;
13639 0 : struct GNUNET_PQ_QueryParam params[] = {
13640 0 : GNUNET_PQ_query_param_auto_from_type (exchange_pub),
13641 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
13642 : GNUNET_PQ_query_param_end
13643 : };
13644 :
13645 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13646 : "insert_signkey_revocation",
13647 : params);
13648 : }
13649 :
13650 :
13651 : /**
13652 : * Obtain information about a revoked online signing key.
13653 : *
13654 : * @param cls closure
13655 : * @param exchange_pub exchange online signing key
13656 : * @param[out] master_sig set to signature affirming the revocation (if revoked)
13657 : * @return transaction status code
13658 : */
13659 : static enum GNUNET_DB_QueryStatus
13660 0 : postgres_lookup_signkey_revocation (
13661 : void *cls,
13662 : const struct TALER_ExchangePublicKeyP *exchange_pub,
13663 : struct TALER_MasterSignatureP *master_sig)
13664 : {
13665 0 : struct PostgresClosure *pg = cls;
13666 0 : struct GNUNET_PQ_QueryParam params[] = {
13667 0 : GNUNET_PQ_query_param_auto_from_type (exchange_pub),
13668 : GNUNET_PQ_query_param_end
13669 : };
13670 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13671 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
13672 : master_sig),
13673 : GNUNET_PQ_result_spec_end
13674 : };
13675 :
13676 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13677 : "lookup_signkey_revocation",
13678 : params,
13679 : rs);
13680 : }
13681 :
13682 :
13683 : /**
13684 : * Lookup information about current denomination key.
13685 : *
13686 : * @param cls closure
13687 : * @param h_denom_pub hash of the denomination public key
13688 : * @param[out] meta set to various meta data about the key
13689 : * @return transaction status code
13690 : */
13691 : static enum GNUNET_DB_QueryStatus
13692 0 : postgres_lookup_denomination_key (
13693 : void *cls,
13694 : const struct TALER_DenominationHashP *h_denom_pub,
13695 : struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
13696 : {
13697 0 : struct PostgresClosure *pg = cls;
13698 0 : struct GNUNET_PQ_QueryParam params[] = {
13699 0 : GNUNET_PQ_query_param_auto_from_type (h_denom_pub),
13700 : GNUNET_PQ_query_param_end
13701 : };
13702 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13703 0 : GNUNET_PQ_result_spec_timestamp ("valid_from",
13704 : &meta->start),
13705 0 : GNUNET_PQ_result_spec_timestamp ("expire_withdraw",
13706 : &meta->expire_withdraw),
13707 0 : GNUNET_PQ_result_spec_timestamp ("expire_deposit",
13708 : &meta->expire_deposit),
13709 0 : GNUNET_PQ_result_spec_timestamp ("expire_legal",
13710 : &meta->expire_legal),
13711 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("coin",
13712 : &meta->value),
13713 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
13714 : &meta->fees.withdraw),
13715 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
13716 : &meta->fees.deposit),
13717 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
13718 : &meta->fees.refresh),
13719 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
13720 : &meta->fees.refund),
13721 0 : GNUNET_PQ_result_spec_uint32 ("age_mask",
13722 : &meta->age_mask.bits),
13723 : GNUNET_PQ_result_spec_end
13724 : };
13725 :
13726 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13727 : "lookup_denomination_key",
13728 : params,
13729 : rs);
13730 : }
13731 :
13732 :
13733 : /**
13734 : * Activate denomination key, turning it into a "current" or "valid"
13735 : * denomination key by adding the master signature.
13736 : *
13737 : * @param cls closure
13738 : * @param h_denom_pub hash of the denomination public key
13739 : * @param denom_pub the actual denomination key
13740 : * @param meta meta data about the denomination
13741 : * @param master_sig master signature to add
13742 : * @return transaction status code
13743 : */
13744 : static enum GNUNET_DB_QueryStatus
13745 0 : postgres_add_denomination_key (
13746 : void *cls,
13747 : const struct TALER_DenominationHashP *h_denom_pub,
13748 : const struct TALER_DenominationPublicKey *denom_pub,
13749 : const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
13750 : const struct TALER_MasterSignatureP *master_sig)
13751 : {
13752 0 : struct PostgresClosure *pg = cls;
13753 0 : struct GNUNET_PQ_QueryParam iparams[] = {
13754 0 : GNUNET_PQ_query_param_auto_from_type (h_denom_pub),
13755 0 : TALER_PQ_query_param_denom_pub (denom_pub),
13756 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
13757 0 : GNUNET_PQ_query_param_timestamp (&meta->start),
13758 0 : GNUNET_PQ_query_param_timestamp (&meta->expire_withdraw),
13759 0 : GNUNET_PQ_query_param_timestamp (&meta->expire_deposit),
13760 0 : GNUNET_PQ_query_param_timestamp (&meta->expire_legal),
13761 0 : TALER_PQ_query_param_amount (&meta->value),
13762 0 : TALER_PQ_query_param_amount (&meta->fees.withdraw),
13763 0 : TALER_PQ_query_param_amount (&meta->fees.deposit),
13764 0 : TALER_PQ_query_param_amount (&meta->fees.refresh),
13765 0 : TALER_PQ_query_param_amount (&meta->fees.refund),
13766 0 : GNUNET_PQ_query_param_uint32 (&meta->age_mask.bits),
13767 : GNUNET_PQ_query_param_end
13768 : };
13769 :
13770 : /* Sanity check: ensure fees match coin currency */
13771 0 : GNUNET_assert (GNUNET_YES ==
13772 : TALER_denom_fee_check_currency (meta->value.currency,
13773 : &meta->fees));
13774 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13775 : "denomination_insert",
13776 : iparams);
13777 : }
13778 :
13779 :
13780 : /**
13781 : * Add signing key.
13782 : *
13783 : * @param cls closure
13784 : * @param exchange_pub the exchange online signing public key
13785 : * @param meta meta data about @a exchange_pub
13786 : * @param master_sig master signature to add
13787 : * @return transaction status code
13788 : */
13789 : static enum GNUNET_DB_QueryStatus
13790 0 : postgres_activate_signing_key (
13791 : void *cls,
13792 : const struct TALER_ExchangePublicKeyP *exchange_pub,
13793 : const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
13794 : const struct TALER_MasterSignatureP *master_sig)
13795 : {
13796 0 : struct PostgresClosure *pg = cls;
13797 0 : struct GNUNET_PQ_QueryParam iparams[] = {
13798 0 : GNUNET_PQ_query_param_auto_from_type (exchange_pub),
13799 0 : GNUNET_PQ_query_param_timestamp (&meta->start),
13800 0 : GNUNET_PQ_query_param_timestamp (&meta->expire_sign),
13801 0 : GNUNET_PQ_query_param_timestamp (&meta->expire_legal),
13802 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
13803 : GNUNET_PQ_query_param_end
13804 : };
13805 :
13806 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13807 : "insert_signkey",
13808 : iparams);
13809 : }
13810 :
13811 :
13812 : /**
13813 : * Lookup signing key meta data.
13814 : *
13815 : * @param cls closure
13816 : * @param exchange_pub the exchange online signing public key
13817 : * @param[out] meta meta data about @a exchange_pub
13818 : * @return transaction status code
13819 : */
13820 : static enum GNUNET_DB_QueryStatus
13821 0 : postgres_lookup_signing_key (
13822 : void *cls,
13823 : const struct TALER_ExchangePublicKeyP *exchange_pub,
13824 : struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
13825 : {
13826 0 : struct PostgresClosure *pg = cls;
13827 0 : struct GNUNET_PQ_QueryParam params[] = {
13828 0 : GNUNET_PQ_query_param_auto_from_type (exchange_pub),
13829 : GNUNET_PQ_query_param_end
13830 : };
13831 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13832 0 : GNUNET_PQ_result_spec_timestamp ("valid_from",
13833 : &meta->start),
13834 0 : GNUNET_PQ_result_spec_timestamp ("expire_sign",
13835 : &meta->expire_sign),
13836 0 : GNUNET_PQ_result_spec_timestamp ("expire_legal",
13837 : &meta->expire_legal),
13838 : GNUNET_PQ_result_spec_end
13839 : };
13840 :
13841 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13842 : "lookup_signing_key",
13843 : params,
13844 : rs);
13845 : }
13846 :
13847 :
13848 : /**
13849 : * Insert information about an auditor auditing a denomination key.
13850 : *
13851 : * @param cls closure
13852 : * @param h_denom_pub the audited denomination
13853 : * @param auditor_pub the auditor's key
13854 : * @param auditor_sig signature affirming the auditor's audit activity
13855 : * @return transaction status code
13856 : */
13857 : static enum GNUNET_DB_QueryStatus
13858 0 : postgres_insert_auditor_denom_sig (
13859 : void *cls,
13860 : const struct TALER_DenominationHashP *h_denom_pub,
13861 : const struct TALER_AuditorPublicKeyP *auditor_pub,
13862 : const struct TALER_AuditorSignatureP *auditor_sig)
13863 : {
13864 0 : struct PostgresClosure *pg = cls;
13865 0 : struct GNUNET_PQ_QueryParam params[] = {
13866 0 : GNUNET_PQ_query_param_auto_from_type (auditor_pub),
13867 0 : GNUNET_PQ_query_param_auto_from_type (h_denom_pub),
13868 0 : GNUNET_PQ_query_param_auto_from_type (auditor_sig),
13869 : GNUNET_PQ_query_param_end
13870 : };
13871 :
13872 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
13873 : "insert_auditor_denom_sig",
13874 : params);
13875 : }
13876 :
13877 :
13878 : /**
13879 : * Select information about an auditor auditing a denomination key.
13880 : *
13881 : * @param cls closure
13882 : * @param h_denom_pub the audited denomination
13883 : * @param auditor_pub the auditor's key
13884 : * @param[out] auditor_sig set to signature affirming the auditor's audit activity
13885 : * @return transaction status code
13886 : */
13887 : static enum GNUNET_DB_QueryStatus
13888 0 : postgres_select_auditor_denom_sig (
13889 : void *cls,
13890 : const struct TALER_DenominationHashP *h_denom_pub,
13891 : const struct TALER_AuditorPublicKeyP *auditor_pub,
13892 : struct TALER_AuditorSignatureP *auditor_sig)
13893 : {
13894 0 : struct PostgresClosure *pg = cls;
13895 0 : struct GNUNET_PQ_QueryParam params[] = {
13896 0 : GNUNET_PQ_query_param_auto_from_type (auditor_pub),
13897 0 : GNUNET_PQ_query_param_auto_from_type (h_denom_pub),
13898 : GNUNET_PQ_query_param_end
13899 : };
13900 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13901 0 : GNUNET_PQ_result_spec_auto_from_type ("auditor_sig",
13902 : auditor_sig),
13903 : GNUNET_PQ_result_spec_end
13904 : };
13905 :
13906 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
13907 : "select_auditor_denom_sig",
13908 : params,
13909 : rs);
13910 : }
13911 :
13912 :
13913 : /**
13914 : * Closure for #wire_fee_by_time_helper()
13915 : */
13916 : struct WireFeeLookupContext
13917 : {
13918 :
13919 : /**
13920 : * Set to the wire fees. Set to invalid if fees conflict over
13921 : * the given time period.
13922 : */
13923 : struct TALER_WireFeeSet *fees;
13924 :
13925 : /**
13926 : * Plugin context.
13927 : */
13928 : struct PostgresClosure *pg;
13929 : };
13930 :
13931 :
13932 : /**
13933 : * Helper function for #postgres_lookup_wire_fee_by_time().
13934 : * Calls the callback with the wire fee structure.
13935 : *
13936 : * @param cls a `struct WireFeeLookupContext`
13937 : * @param result db results
13938 : * @param num_results number of results in @a result
13939 : */
13940 : static void
13941 0 : wire_fee_by_time_helper (void *cls,
13942 : PGresult *result,
13943 : unsigned int num_results)
13944 : {
13945 0 : struct WireFeeLookupContext *wlc = cls;
13946 0 : struct PostgresClosure *pg = wlc->pg;
13947 :
13948 0 : for (unsigned int i = 0; i<num_results; i++)
13949 : {
13950 : struct TALER_WireFeeSet fs;
13951 0 : struct GNUNET_PQ_ResultSpec rs[] = {
13952 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
13953 : &fs.wire),
13954 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
13955 : &fs.closing),
13956 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("wad_fee",
13957 : &fs.wad),
13958 : GNUNET_PQ_result_spec_end
13959 : };
13960 :
13961 0 : if (GNUNET_OK !=
13962 0 : GNUNET_PQ_extract_result (result,
13963 : rs,
13964 : i))
13965 : {
13966 0 : GNUNET_break (0);
13967 : /* invalidate */
13968 0 : memset (wlc->fees,
13969 : 0,
13970 : sizeof (struct TALER_WireFeeSet));
13971 0 : return;
13972 : }
13973 0 : if (0 == i)
13974 : {
13975 0 : *wlc->fees = fs;
13976 0 : continue;
13977 : }
13978 0 : if (0 !=
13979 0 : TALER_wire_fee_set_cmp (&fs,
13980 0 : wlc->fees))
13981 : {
13982 : /* invalidate */
13983 0 : memset (wlc->fees,
13984 : 0,
13985 : sizeof (struct TALER_WireFeeSet));
13986 0 : return;
13987 : }
13988 : }
13989 : }
13990 :
13991 :
13992 : /**
13993 : * Lookup information about known wire fees. Finds all applicable
13994 : * fees in the given range. If they are identical, returns the
13995 : * respective @a fees. If any of the fees
13996 : * differ between @a start_time and @a end_time, the transaction
13997 : * succeeds BUT returns an invalid amount for both fees.
13998 : *
13999 : * @param cls closure
14000 : * @param wire_method the wire method to lookup fees for
14001 : * @param start_time starting time of fee
14002 : * @param end_time end time of fee
14003 : * @param[out] fees wire fees for that time period; if
14004 : * different fees exists within this time
14005 : * period, an 'invalid' amount is returned.
14006 : * @return transaction status code
14007 : */
14008 : static enum GNUNET_DB_QueryStatus
14009 0 : postgres_lookup_wire_fee_by_time (
14010 : void *cls,
14011 : const char *wire_method,
14012 : struct GNUNET_TIME_Timestamp start_time,
14013 : struct GNUNET_TIME_Timestamp end_time,
14014 : struct TALER_WireFeeSet *fees)
14015 : {
14016 0 : struct PostgresClosure *pg = cls;
14017 0 : struct GNUNET_PQ_QueryParam params[] = {
14018 0 : GNUNET_PQ_query_param_string (wire_method),
14019 0 : GNUNET_PQ_query_param_timestamp (&start_time),
14020 0 : GNUNET_PQ_query_param_timestamp (&end_time),
14021 : GNUNET_PQ_query_param_end
14022 : };
14023 0 : struct WireFeeLookupContext wlc = {
14024 : .fees = fees,
14025 : .pg = pg
14026 : };
14027 :
14028 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
14029 : "lookup_wire_fee_by_time",
14030 : params,
14031 : &wire_fee_by_time_helper,
14032 : &wlc);
14033 : }
14034 :
14035 :
14036 : /**
14037 : * Closure for #global_fee_by_time_helper()
14038 : */
14039 : struct GlobalFeeLookupContext
14040 : {
14041 :
14042 : /**
14043 : * Set to the wire fees. Set to invalid if fees conflict over
14044 : * the given time period.
14045 : */
14046 : struct TALER_GlobalFeeSet *fees;
14047 :
14048 : /**
14049 : * Set to timeout of unmerged purses
14050 : */
14051 : struct GNUNET_TIME_Relative *purse_timeout;
14052 :
14053 : /**
14054 : * Set to timeout of accounts without kyc.
14055 : */
14056 : struct GNUNET_TIME_Relative *kyc_timeout;
14057 :
14058 : /**
14059 : * Set to history expiration for reserves.
14060 : */
14061 : struct GNUNET_TIME_Relative *history_expiration;
14062 :
14063 : /**
14064 : * Set to number of free purses per account.
14065 : */
14066 : uint32_t *purse_account_limit;
14067 :
14068 : /**
14069 : * Plugin context.
14070 : */
14071 : struct PostgresClosure *pg;
14072 : };
14073 :
14074 :
14075 : /**
14076 : * Helper function for #postgres_lookup_global_fee_by_time().
14077 : * Calls the callback with each denomination key.
14078 : *
14079 : * @param cls a `struct GlobalFeeLookupContext`
14080 : * @param result db results
14081 : * @param num_results number of results in @a result
14082 : */
14083 : static void
14084 0 : global_fee_by_time_helper (void *cls,
14085 : PGresult *result,
14086 : unsigned int num_results)
14087 : {
14088 0 : struct GlobalFeeLookupContext *wlc = cls;
14089 0 : struct PostgresClosure *pg = wlc->pg;
14090 :
14091 0 : for (unsigned int i = 0; i<num_results; i++)
14092 : {
14093 : struct TALER_GlobalFeeSet fs;
14094 : struct GNUNET_TIME_Relative purse_timeout;
14095 : struct GNUNET_TIME_Relative kyc_timeout;
14096 : struct GNUNET_TIME_Relative history_expiration;
14097 : uint32_t purse_account_limit;
14098 0 : struct GNUNET_PQ_ResultSpec rs[] = {
14099 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
14100 : &fs.history),
14101 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("kyc_fee",
14102 : &fs.kyc),
14103 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee",
14104 : &fs.account),
14105 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
14106 : &fs.purse),
14107 0 : GNUNET_PQ_result_spec_relative_time ("purse_timeout",
14108 : &purse_timeout),
14109 0 : GNUNET_PQ_result_spec_relative_time ("kyc_timeout",
14110 : &kyc_timeout),
14111 0 : GNUNET_PQ_result_spec_relative_time ("history_expiration",
14112 : &history_expiration),
14113 0 : GNUNET_PQ_result_spec_uint32 ("purse_account_limit",
14114 : &purse_account_limit),
14115 : GNUNET_PQ_result_spec_end
14116 : };
14117 :
14118 0 : if (GNUNET_OK !=
14119 0 : GNUNET_PQ_extract_result (result,
14120 : rs,
14121 : i))
14122 : {
14123 0 : GNUNET_break (0);
14124 : /* invalidate */
14125 0 : memset (wlc->fees,
14126 : 0,
14127 : sizeof (struct TALER_GlobalFeeSet));
14128 0 : return;
14129 : }
14130 0 : if (0 == i)
14131 : {
14132 0 : *wlc->fees = fs;
14133 0 : *wlc->purse_timeout = purse_timeout;
14134 0 : *wlc->kyc_timeout = kyc_timeout;
14135 0 : *wlc->history_expiration = history_expiration;
14136 0 : *wlc->purse_account_limit = purse_account_limit;
14137 0 : continue;
14138 : }
14139 0 : if ( (0 !=
14140 0 : TALER_global_fee_set_cmp (&fs,
14141 0 : wlc->fees)) ||
14142 0 : (purse_account_limit != *wlc->purse_account_limit) ||
14143 0 : (GNUNET_TIME_relative_cmp (purse_timeout,
14144 : !=,
14145 0 : *wlc->purse_timeout)) ||
14146 0 : (GNUNET_TIME_relative_cmp (kyc_timeout,
14147 : !=,
14148 0 : *wlc->kyc_timeout)) ||
14149 0 : (GNUNET_TIME_relative_cmp (history_expiration,
14150 : !=,
14151 : *wlc->history_expiration)) )
14152 : {
14153 : /* invalidate */
14154 0 : memset (wlc->fees,
14155 : 0,
14156 : sizeof (struct TALER_GlobalFeeSet));
14157 0 : return;
14158 : }
14159 : }
14160 : }
14161 :
14162 :
14163 : /**
14164 : * Lookup information about known global fees.
14165 : *
14166 : * @param cls closure
14167 : * @param start_time starting time of fee
14168 : * @param end_time end time of fee
14169 : * @param[out] fees set to wire fees for that time period; if
14170 : * different global fee exists within this time
14171 : * period, an 'invalid' amount is returned.
14172 : * @param[out] purse_timeout set to when unmerged purses expire
14173 : * @param[out] kyc_timeout set to when reserves without kyc expire
14174 : * @param[out] history_expiration set to when we expire reserve histories
14175 : * @param[out] purse_account_limit set to number of free purses
14176 : * @return transaction status code
14177 : */
14178 : static enum GNUNET_DB_QueryStatus
14179 0 : postgres_lookup_global_fee_by_time (
14180 : void *cls,
14181 : struct GNUNET_TIME_Timestamp start_time,
14182 : struct GNUNET_TIME_Timestamp end_time,
14183 : struct TALER_GlobalFeeSet *fees,
14184 : struct GNUNET_TIME_Relative *purse_timeout,
14185 : struct GNUNET_TIME_Relative *kyc_timeout,
14186 : struct GNUNET_TIME_Relative *history_expiration,
14187 : uint32_t *purse_account_limit)
14188 : {
14189 0 : struct PostgresClosure *pg = cls;
14190 0 : struct GNUNET_PQ_QueryParam params[] = {
14191 0 : GNUNET_PQ_query_param_timestamp (&start_time),
14192 0 : GNUNET_PQ_query_param_timestamp (&end_time),
14193 : GNUNET_PQ_query_param_end
14194 : };
14195 0 : struct GlobalFeeLookupContext wlc = {
14196 : .fees = fees,
14197 : .purse_timeout = purse_timeout,
14198 : .kyc_timeout = kyc_timeout,
14199 : .history_expiration = history_expiration,
14200 : .purse_account_limit = purse_account_limit,
14201 : .pg = pg
14202 : };
14203 :
14204 0 : return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
14205 : "lookup_global_fee_by_time",
14206 : params,
14207 : &global_fee_by_time_helper,
14208 : &wlc);
14209 : }
14210 :
14211 :
14212 : /**
14213 : * Lookup the latest serial number of @a table. Used in
14214 : * exchange-auditor database replication.
14215 : *
14216 : * @param cls closure
14217 : * @param table table for which we should return the serial
14218 : * @param[out] serial latest serial number in use
14219 : * @return transaction status code, GNUNET_DB_STATUS_HARD_ERROR if
14220 : * @a table does not have a serial number
14221 : */
14222 : static enum GNUNET_DB_QueryStatus
14223 0 : postgres_lookup_serial_by_table (void *cls,
14224 : enum TALER_EXCHANGEDB_ReplicatedTable table,
14225 : uint64_t *serial)
14226 : {
14227 0 : struct PostgresClosure *pg = cls;
14228 0 : struct GNUNET_PQ_QueryParam params[] = {
14229 : GNUNET_PQ_query_param_end
14230 : };
14231 0 : struct GNUNET_PQ_ResultSpec rs[] = {
14232 0 : GNUNET_PQ_result_spec_uint64 ("serial",
14233 : serial),
14234 : GNUNET_PQ_result_spec_end
14235 : };
14236 : const char *statement;
14237 :
14238 0 : switch (table)
14239 : {
14240 0 : case TALER_EXCHANGEDB_RT_DENOMINATIONS:
14241 0 : statement = "select_serial_by_table_denominations";
14242 0 : break;
14243 0 : case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS:
14244 0 : statement = "select_serial_by_table_denomination_revocations";
14245 0 : break;
14246 0 : case TALER_EXCHANGEDB_RT_WIRE_TARGETS:
14247 0 : statement = "select_serial_by_table_wire_targets";
14248 0 : break;
14249 0 : case TALER_EXCHANGEDB_RT_RESERVES:
14250 0 : statement = "select_serial_by_table_reserves";
14251 0 : break;
14252 0 : case TALER_EXCHANGEDB_RT_RESERVES_IN:
14253 0 : statement = "select_serial_by_table_reserves_in";
14254 0 : break;
14255 0 : case TALER_EXCHANGEDB_RT_RESERVES_CLOSE:
14256 0 : statement = "select_serial_by_table_reserves_close";
14257 0 : break;
14258 0 : case TALER_EXCHANGEDB_RT_RESERVES_OUT:
14259 0 : statement = "select_serial_by_table_reserves_out";
14260 0 : break;
14261 0 : case TALER_EXCHANGEDB_RT_AUDITORS:
14262 0 : statement = "select_serial_by_table_auditors";
14263 0 : break;
14264 0 : case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS:
14265 0 : statement = "select_serial_by_table_auditor_denom_sigs";
14266 0 : break;
14267 0 : case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS:
14268 0 : statement = "select_serial_by_table_exchange_sign_keys";
14269 0 : break;
14270 0 : case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS:
14271 0 : statement = "select_serial_by_table_signkey_revocations";
14272 0 : break;
14273 0 : case TALER_EXCHANGEDB_RT_KNOWN_COINS:
14274 0 : statement = "select_serial_by_table_known_coins";
14275 0 : break;
14276 0 : case TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS:
14277 0 : statement = "select_serial_by_table_refresh_commitments";
14278 0 : break;
14279 0 : case TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS:
14280 0 : statement = "select_serial_by_table_refresh_revealed_coins";
14281 0 : break;
14282 0 : case TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS:
14283 0 : statement = "select_serial_by_table_refresh_transfer_keys";
14284 0 : break;
14285 0 : case TALER_EXCHANGEDB_RT_DEPOSITS:
14286 0 : statement = "select_serial_by_table_deposits";
14287 0 : break;
14288 0 : case TALER_EXCHANGEDB_RT_REFUNDS:
14289 0 : statement = "select_serial_by_table_refunds";
14290 0 : break;
14291 0 : case TALER_EXCHANGEDB_RT_WIRE_OUT:
14292 0 : statement = "select_serial_by_table_wire_out";
14293 0 : break;
14294 0 : case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING:
14295 0 : statement = "select_serial_by_table_aggregation_tracking";
14296 0 : break;
14297 0 : case TALER_EXCHANGEDB_RT_WIRE_FEE:
14298 0 : statement = "select_serial_by_table_wire_fee";
14299 0 : break;
14300 0 : case TALER_EXCHANGEDB_RT_GLOBAL_FEE:
14301 0 : statement = "select_serial_by_table_global_fee";
14302 0 : break;
14303 0 : case TALER_EXCHANGEDB_RT_RECOUP:
14304 0 : statement = "select_serial_by_table_recoup";
14305 0 : break;
14306 0 : case TALER_EXCHANGEDB_RT_RECOUP_REFRESH:
14307 0 : statement = "select_serial_by_table_recoup_refresh";
14308 0 : break;
14309 0 : case TALER_EXCHANGEDB_RT_EXTENSIONS:
14310 0 : statement = "select_serial_by_table_extensions";
14311 0 : break;
14312 0 : case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
14313 0 : statement = "select_serial_by_table_extension_details";
14314 0 : break;
14315 0 : case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
14316 0 : statement = "select_serial_by_table_purse_requests";
14317 0 : break;
14318 0 : case TALER_EXCHANGEDB_RT_PURSE_REFUNDS:
14319 0 : statement = "select_serial_by_table_purse_refunds";
14320 0 : break;
14321 0 : case TALER_EXCHANGEDB_RT_PURSE_MERGES:
14322 0 : statement = "select_serial_by_table_purse_merges";
14323 0 : break;
14324 0 : case TALER_EXCHANGEDB_RT_PURSE_DEPOSITS:
14325 0 : statement = "select_serial_by_table_purse_deposits";
14326 0 : break;
14327 0 : case TALER_EXCHANGEDB_RT_ACCOUNT_MERGES:
14328 0 : statement = "select_serial_by_table_account_merges";
14329 0 : break;
14330 0 : case TALER_EXCHANGEDB_RT_HISTORY_REQUESTS:
14331 0 : statement = "select_serial_by_table_history_requests";
14332 0 : break;
14333 0 : case TALER_EXCHANGEDB_RT_CLOSE_REQUESTS:
14334 0 : statement = "select_serial_by_table_close_requests";
14335 0 : break;
14336 0 : case TALER_EXCHANGEDB_RT_WADS_OUT:
14337 0 : statement = "select_serial_by_table_wads_out";
14338 0 : break;
14339 0 : case TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES:
14340 0 : statement = "select_serial_by_table_wads_out_entries";
14341 0 : break;
14342 0 : case TALER_EXCHANGEDB_RT_WADS_IN:
14343 0 : statement = "select_serial_by_table_wads_in";
14344 0 : break;
14345 0 : case TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES:
14346 0 : statement = "select_serial_by_table_wads_in_entries";
14347 0 : break;
14348 0 : case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
14349 0 : statement = "select_serial_by_table_profit_drains";
14350 0 : break;
14351 0 : default:
14352 0 : GNUNET_break (0);
14353 0 : return GNUNET_DB_STATUS_HARD_ERROR;
14354 : }
14355 :
14356 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
14357 : statement,
14358 : params,
14359 : rs);
14360 : }
14361 :
14362 :
14363 : /**
14364 : * Closure for callbacks used by #postgres_lookup_records_by_table.
14365 : */
14366 : struct LookupRecordsByTableContext
14367 : {
14368 : /**
14369 : * Plugin context.
14370 : */
14371 : struct PostgresClosure *pg;
14372 :
14373 : /**
14374 : * Function to call with the results.
14375 : */
14376 : TALER_EXCHANGEDB_ReplicationCallback cb;
14377 :
14378 : /**
14379 : * Closure for @a cb.
14380 : */
14381 : void *cb_cls;
14382 :
14383 : /**
14384 : * Set to true on errors.
14385 : */
14386 : bool error;
14387 : };
14388 :
14389 :
14390 : #include "lrbt_callbacks.c"
14391 :
14392 :
14393 : /**
14394 : * Lookup records above @a serial number in @a table. Used in
14395 : * exchange-auditor database replication.
14396 : *
14397 : * @param cls closure
14398 : * @param table table for which we should return the serial
14399 : * @param serial largest serial number to exclude
14400 : * @param cb function to call on the records
14401 : * @param cb_cls closure for @a cb
14402 : * @return transaction status code, GNUNET_DB_STATUS_HARD_ERROR if
14403 : * @a table does not have a serial number
14404 : */
14405 : static enum GNUNET_DB_QueryStatus
14406 0 : postgres_lookup_records_by_table (void *cls,
14407 : enum TALER_EXCHANGEDB_ReplicatedTable table,
14408 : uint64_t serial,
14409 : TALER_EXCHANGEDB_ReplicationCallback cb,
14410 : void *cb_cls)
14411 : {
14412 0 : struct PostgresClosure *pg = cls;
14413 0 : struct GNUNET_PQ_QueryParam params[] = {
14414 0 : GNUNET_PQ_query_param_uint64 (&serial),
14415 : GNUNET_PQ_query_param_end
14416 : };
14417 0 : struct LookupRecordsByTableContext ctx = {
14418 : .pg = pg,
14419 : .cb = cb,
14420 : .cb_cls = cb_cls
14421 : };
14422 : GNUNET_PQ_PostgresResultHandler rh;
14423 : const char *statement;
14424 : enum GNUNET_DB_QueryStatus qs;
14425 :
14426 0 : switch (table)
14427 : {
14428 0 : case TALER_EXCHANGEDB_RT_DENOMINATIONS:
14429 0 : statement = "select_above_serial_by_table_denominations";
14430 0 : rh = &lrbt_cb_table_denominations;
14431 0 : break;
14432 0 : case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS:
14433 0 : statement = "select_above_serial_by_table_denomination_revocations";
14434 0 : rh = &lrbt_cb_table_denomination_revocations;
14435 0 : break;
14436 0 : case TALER_EXCHANGEDB_RT_WIRE_TARGETS:
14437 0 : statement = "select_above_serial_by_table_wire_targets";
14438 0 : rh = &lrbt_cb_table_wire_targets;
14439 0 : break;
14440 0 : case TALER_EXCHANGEDB_RT_RESERVES:
14441 0 : statement = "select_above_serial_by_table_reserves";
14442 0 : rh = &lrbt_cb_table_reserves;
14443 0 : break;
14444 0 : case TALER_EXCHANGEDB_RT_RESERVES_IN:
14445 0 : statement = "select_above_serial_by_table_reserves_in";
14446 0 : rh = &lrbt_cb_table_reserves_in;
14447 0 : break;
14448 0 : case TALER_EXCHANGEDB_RT_RESERVES_CLOSE:
14449 0 : statement = "select_above_serial_by_table_reserves_close";
14450 0 : rh = &lrbt_cb_table_reserves_close;
14451 0 : break;
14452 0 : case TALER_EXCHANGEDB_RT_RESERVES_OUT:
14453 0 : statement = "select_above_serial_by_table_reserves_out";
14454 0 : rh = &lrbt_cb_table_reserves_out;
14455 0 : break;
14456 0 : case TALER_EXCHANGEDB_RT_AUDITORS:
14457 0 : statement = "select_above_serial_by_table_auditors";
14458 0 : rh = &lrbt_cb_table_auditors;
14459 0 : break;
14460 0 : case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS:
14461 0 : statement = "select_above_serial_by_table_auditor_denom_sigs";
14462 0 : rh = &lrbt_cb_table_auditor_denom_sigs;
14463 0 : break;
14464 0 : case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS:
14465 0 : statement = "select_above_serial_by_table_exchange_sign_keys";
14466 0 : rh = &lrbt_cb_table_exchange_sign_keys;
14467 0 : break;
14468 0 : case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS:
14469 0 : statement = "select_above_serial_by_table_signkey_revocations";
14470 0 : rh = &lrbt_cb_table_signkey_revocations;
14471 0 : break;
14472 0 : case TALER_EXCHANGEDB_RT_KNOWN_COINS:
14473 0 : statement = "select_above_serial_by_table_known_coins";
14474 0 : rh = &lrbt_cb_table_known_coins;
14475 0 : break;
14476 0 : case TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS:
14477 0 : statement = "select_above_serial_by_table_refresh_commitments";
14478 0 : rh = &lrbt_cb_table_refresh_commitments;
14479 0 : break;
14480 0 : case TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS:
14481 0 : statement = "select_above_serial_by_table_refresh_revealed_coins";
14482 0 : rh = &lrbt_cb_table_refresh_revealed_coins;
14483 0 : break;
14484 0 : case TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS:
14485 0 : statement = "select_above_serial_by_table_refresh_transfer_keys";
14486 0 : rh = &lrbt_cb_table_refresh_transfer_keys;
14487 0 : break;
14488 0 : case TALER_EXCHANGEDB_RT_DEPOSITS:
14489 0 : statement = "select_above_serial_by_table_deposits";
14490 0 : rh = &lrbt_cb_table_deposits;
14491 0 : break;
14492 0 : case TALER_EXCHANGEDB_RT_REFUNDS:
14493 0 : statement = "select_above_serial_by_table_refunds";
14494 0 : rh = &lrbt_cb_table_refunds;
14495 0 : break;
14496 0 : case TALER_EXCHANGEDB_RT_WIRE_OUT:
14497 0 : statement = "select_above_serial_by_table_wire_out";
14498 0 : rh = &lrbt_cb_table_wire_out;
14499 0 : break;
14500 0 : case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING:
14501 0 : statement = "select_above_serial_by_table_aggregation_tracking";
14502 0 : rh = &lrbt_cb_table_aggregation_tracking;
14503 0 : break;
14504 0 : case TALER_EXCHANGEDB_RT_WIRE_FEE:
14505 0 : statement = "select_above_serial_by_table_wire_fee";
14506 0 : rh = &lrbt_cb_table_wire_fee;
14507 0 : break;
14508 0 : case TALER_EXCHANGEDB_RT_GLOBAL_FEE:
14509 0 : statement = "select_above_serial_by_table_global_fee";
14510 0 : rh = &lrbt_cb_table_global_fee;
14511 0 : break;
14512 0 : case TALER_EXCHANGEDB_RT_RECOUP:
14513 0 : statement = "select_above_serial_by_table_recoup";
14514 0 : rh = &lrbt_cb_table_recoup;
14515 0 : break;
14516 0 : case TALER_EXCHANGEDB_RT_RECOUP_REFRESH:
14517 0 : statement = "select_above_serial_by_table_recoup_refresh";
14518 0 : rh = &lrbt_cb_table_recoup_refresh;
14519 0 : break;
14520 0 : case TALER_EXCHANGEDB_RT_EXTENSIONS:
14521 0 : statement = "select_above_serial_by_table_extensions";
14522 0 : rh = &lrbt_cb_table_extensions;
14523 0 : break;
14524 0 : case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
14525 0 : statement = "select_above_serial_by_table_extension_details";
14526 0 : rh = &lrbt_cb_table_extension_details;
14527 0 : break;
14528 0 : case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
14529 0 : statement = "select_above_serial_by_table_purse_requests";
14530 0 : rh = &lrbt_cb_table_purse_requests;
14531 0 : break;
14532 0 : case TALER_EXCHANGEDB_RT_PURSE_REFUNDS:
14533 0 : statement = "select_above_serial_by_table_purse_refunds";
14534 0 : rh = &lrbt_cb_table_purse_refunds;
14535 0 : break;
14536 0 : case TALER_EXCHANGEDB_RT_PURSE_MERGES:
14537 0 : statement = "select_above_serial_by_table_purse_merges";
14538 0 : rh = &lrbt_cb_table_purse_merges;
14539 0 : break;
14540 0 : case TALER_EXCHANGEDB_RT_PURSE_DEPOSITS:
14541 0 : statement = "select_above_serial_by_table_purse_deposits";
14542 0 : rh = &lrbt_cb_table_purse_deposits;
14543 0 : break;
14544 0 : case TALER_EXCHANGEDB_RT_ACCOUNT_MERGES:
14545 0 : statement = "select_above_serial_by_table_account_merges";
14546 0 : rh = &lrbt_cb_table_account_merges;
14547 0 : break;
14548 0 : case TALER_EXCHANGEDB_RT_HISTORY_REQUESTS:
14549 0 : statement = "select_above_serial_by_table_history_requests";
14550 0 : rh = &lrbt_cb_table_history_requests;
14551 0 : break;
14552 0 : case TALER_EXCHANGEDB_RT_CLOSE_REQUESTS:
14553 0 : statement = "select_above_serial_by_table_close_requests";
14554 0 : rh = &lrbt_cb_table_close_requests;
14555 0 : break;
14556 0 : case TALER_EXCHANGEDB_RT_WADS_OUT:
14557 0 : statement = "select_above_serial_by_table_wads_out";
14558 0 : rh = &lrbt_cb_table_wads_out;
14559 0 : break;
14560 0 : case TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES:
14561 0 : statement = "select_above_serial_by_table_wads_out_entries";
14562 0 : rh = &lrbt_cb_table_wads_out_entries;
14563 0 : break;
14564 0 : case TALER_EXCHANGEDB_RT_WADS_IN:
14565 0 : statement = "select_above_serial_by_table_wads_in";
14566 0 : rh = &lrbt_cb_table_wads_in;
14567 0 : break;
14568 0 : case TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES:
14569 0 : statement = "select_above_serial_by_table_wads_in_entries";
14570 0 : rh = &lrbt_cb_table_wads_in_entries;
14571 0 : break;
14572 0 : case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
14573 0 : statement = "select_above_serial_by_table_profit_drains";
14574 0 : rh = &lrbt_cb_table_profit_drains;
14575 0 : break;
14576 0 : default:
14577 0 : GNUNET_break (0);
14578 0 : return GNUNET_DB_STATUS_HARD_ERROR;
14579 : }
14580 :
14581 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
14582 : statement,
14583 : params,
14584 : rh,
14585 : &ctx);
14586 0 : if (qs < 0)
14587 : {
14588 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
14589 : "Failed to run `%s'\n",
14590 : statement);
14591 0 : return qs;
14592 : }
14593 0 : if (ctx.error)
14594 : {
14595 0 : GNUNET_break (0);
14596 0 : return GNUNET_DB_STATUS_HARD_ERROR;
14597 : }
14598 0 : return qs;
14599 : }
14600 :
14601 :
14602 : /**
14603 : * Signature of helper functions of #postgres_insert_records_by_table.
14604 : *
14605 : * @param pg plugin context
14606 : * @param td record to insert
14607 : * @return transaction status code
14608 : */
14609 : typedef enum GNUNET_DB_QueryStatus
14610 : (*InsertRecordCallback)(struct PostgresClosure *pg,
14611 : const struct TALER_EXCHANGEDB_TableData *td);
14612 :
14613 :
14614 : #include "irbt_callbacks.c"
14615 :
14616 :
14617 : /**
14618 : * Insert record set into @a table. Used in exchange-auditor database
14619 : * replication.
14620 : *
14621 : * @param cls closure
14622 : * @param td table data to insert
14623 : * @return transaction status code, #GNUNET_DB_STATUS_HARD_ERROR if
14624 : * @e table in @a tr is not supported
14625 : */
14626 : static enum GNUNET_DB_QueryStatus
14627 0 : postgres_insert_records_by_table (void *cls,
14628 : const struct TALER_EXCHANGEDB_TableData *td)
14629 : {
14630 0 : struct PostgresClosure *pg = cls;
14631 : InsertRecordCallback rh;
14632 :
14633 0 : switch (td->table)
14634 : {
14635 0 : case TALER_EXCHANGEDB_RT_DENOMINATIONS:
14636 0 : rh = &irbt_cb_table_denominations;
14637 0 : break;
14638 0 : case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS:
14639 0 : rh = &irbt_cb_table_denomination_revocations;
14640 0 : break;
14641 0 : case TALER_EXCHANGEDB_RT_WIRE_TARGETS:
14642 0 : rh = &irbt_cb_table_wire_targets;
14643 0 : break;
14644 0 : case TALER_EXCHANGEDB_RT_RESERVES:
14645 0 : rh = &irbt_cb_table_reserves;
14646 0 : break;
14647 0 : case TALER_EXCHANGEDB_RT_RESERVES_IN:
14648 0 : rh = &irbt_cb_table_reserves_in;
14649 0 : break;
14650 0 : case TALER_EXCHANGEDB_RT_RESERVES_CLOSE:
14651 0 : rh = &irbt_cb_table_reserves_close;
14652 0 : break;
14653 0 : case TALER_EXCHANGEDB_RT_RESERVES_OUT:
14654 0 : rh = &irbt_cb_table_reserves_out;
14655 0 : break;
14656 0 : case TALER_EXCHANGEDB_RT_AUDITORS:
14657 0 : rh = &irbt_cb_table_auditors;
14658 0 : break;
14659 0 : case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS:
14660 0 : rh = &irbt_cb_table_auditor_denom_sigs;
14661 0 : break;
14662 0 : case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS:
14663 0 : rh = &irbt_cb_table_exchange_sign_keys;
14664 0 : break;
14665 0 : case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS:
14666 0 : rh = &irbt_cb_table_signkey_revocations;
14667 0 : break;
14668 0 : case TALER_EXCHANGEDB_RT_KNOWN_COINS:
14669 0 : rh = &irbt_cb_table_known_coins;
14670 0 : break;
14671 0 : case TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS:
14672 0 : rh = &irbt_cb_table_refresh_commitments;
14673 0 : break;
14674 0 : case TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS:
14675 0 : rh = &irbt_cb_table_refresh_revealed_coins;
14676 0 : break;
14677 0 : case TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS:
14678 0 : rh = &irbt_cb_table_refresh_transfer_keys;
14679 0 : break;
14680 0 : case TALER_EXCHANGEDB_RT_DEPOSITS:
14681 0 : rh = &irbt_cb_table_deposits;
14682 0 : break;
14683 0 : case TALER_EXCHANGEDB_RT_REFUNDS:
14684 0 : rh = &irbt_cb_table_refunds;
14685 0 : break;
14686 0 : case TALER_EXCHANGEDB_RT_WIRE_OUT:
14687 0 : rh = &irbt_cb_table_wire_out;
14688 0 : break;
14689 0 : case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING:
14690 0 : rh = &irbt_cb_table_aggregation_tracking;
14691 0 : break;
14692 0 : case TALER_EXCHANGEDB_RT_WIRE_FEE:
14693 0 : rh = &irbt_cb_table_wire_fee;
14694 0 : break;
14695 0 : case TALER_EXCHANGEDB_RT_GLOBAL_FEE:
14696 0 : rh = &irbt_cb_table_global_fee;
14697 0 : break;
14698 0 : case TALER_EXCHANGEDB_RT_RECOUP:
14699 0 : rh = &irbt_cb_table_recoup;
14700 0 : break;
14701 0 : case TALER_EXCHANGEDB_RT_RECOUP_REFRESH:
14702 0 : rh = &irbt_cb_table_recoup_refresh;
14703 0 : break;
14704 0 : case TALER_EXCHANGEDB_RT_EXTENSIONS:
14705 0 : rh = &irbt_cb_table_extensions;
14706 0 : break;
14707 0 : case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
14708 0 : rh = &irbt_cb_table_extension_details;
14709 0 : break;
14710 0 : case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
14711 0 : rh = &irbt_cb_table_purse_requests;
14712 0 : break;
14713 0 : case TALER_EXCHANGEDB_RT_PURSE_REFUNDS:
14714 0 : rh = &irbt_cb_table_purse_refunds;
14715 0 : break;
14716 0 : case TALER_EXCHANGEDB_RT_PURSE_MERGES:
14717 0 : rh = &irbt_cb_table_purse_merges;
14718 0 : break;
14719 0 : case TALER_EXCHANGEDB_RT_PURSE_DEPOSITS:
14720 0 : rh = &irbt_cb_table_purse_deposits;
14721 0 : break;
14722 0 : case TALER_EXCHANGEDB_RT_ACCOUNT_MERGES:
14723 0 : rh = &irbt_cb_table_account_mergers;
14724 0 : break;
14725 0 : case TALER_EXCHANGEDB_RT_HISTORY_REQUESTS:
14726 0 : rh = &irbt_cb_table_history_requests;
14727 0 : break;
14728 0 : case TALER_EXCHANGEDB_RT_CLOSE_REQUESTS:
14729 0 : rh = &irbt_cb_table_close_requests;
14730 0 : break;
14731 0 : case TALER_EXCHANGEDB_RT_WADS_OUT:
14732 0 : rh = &irbt_cb_table_wads_out;
14733 0 : break;
14734 0 : case TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES:
14735 0 : rh = &irbt_cb_table_wads_out_entries;
14736 0 : break;
14737 0 : case TALER_EXCHANGEDB_RT_WADS_IN:
14738 0 : rh = &irbt_cb_table_wads_in;
14739 0 : break;
14740 0 : case TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES:
14741 0 : rh = &irbt_cb_table_wads_in_entries;
14742 0 : break;
14743 0 : case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
14744 0 : rh = &irbt_cb_table_profit_drains;
14745 0 : break;
14746 0 : default:
14747 0 : GNUNET_break (0);
14748 0 : return GNUNET_DB_STATUS_HARD_ERROR;
14749 : }
14750 0 : return rh (pg,
14751 : td);
14752 : }
14753 :
14754 :
14755 : /**
14756 : * Function called to grab a work shard on an operation @a op. Runs in its
14757 : * own transaction.
14758 : *
14759 : * @param cls the @e cls of this struct with the plugin-specific state
14760 : * @param job_name name of the operation to grab a word shard for
14761 : * @param delay minimum age of a shard to grab
14762 : * @param shard_size desired shard size
14763 : * @param[out] start_row inclusive start row of the shard (returned)
14764 : * @param[out] end_row exclusive end row of the shard (returned)
14765 : * @return transaction status code
14766 : */
14767 : static enum GNUNET_DB_QueryStatus
14768 0 : postgres_begin_shard (void *cls,
14769 : const char *job_name,
14770 : struct GNUNET_TIME_Relative delay,
14771 : uint64_t shard_size,
14772 : uint64_t *start_row,
14773 : uint64_t *end_row)
14774 : {
14775 0 : struct PostgresClosure *pg = cls;
14776 :
14777 0 : for (unsigned int retries = 0; retries<10; retries++)
14778 : {
14779 0 : if (GNUNET_OK !=
14780 0 : postgres_start (pg,
14781 : "begin_shard"))
14782 : {
14783 0 : GNUNET_break (0);
14784 0 : return GNUNET_DB_STATUS_HARD_ERROR;
14785 : }
14786 :
14787 : {
14788 : struct GNUNET_TIME_Absolute past;
14789 : enum GNUNET_DB_QueryStatus qs;
14790 0 : struct GNUNET_PQ_QueryParam params[] = {
14791 0 : GNUNET_PQ_query_param_string (job_name),
14792 0 : GNUNET_PQ_query_param_absolute_time (&past),
14793 : GNUNET_PQ_query_param_end
14794 : };
14795 0 : struct GNUNET_PQ_ResultSpec rs[] = {
14796 0 : GNUNET_PQ_result_spec_uint64 ("start_row",
14797 : start_row),
14798 0 : GNUNET_PQ_result_spec_uint64 ("end_row",
14799 : end_row),
14800 : GNUNET_PQ_result_spec_end
14801 : };
14802 :
14803 0 : past = GNUNET_TIME_absolute_get ();
14804 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
14805 : "get_open_shard",
14806 : params,
14807 : rs);
14808 0 : switch (qs)
14809 : {
14810 0 : case GNUNET_DB_STATUS_HARD_ERROR:
14811 0 : GNUNET_break (0);
14812 0 : postgres_rollback (pg);
14813 0 : return qs;
14814 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
14815 0 : postgres_rollback (pg);
14816 0 : continue;
14817 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
14818 : {
14819 : enum GNUNET_DB_QueryStatus qs;
14820 : struct GNUNET_TIME_Absolute now;
14821 0 : struct GNUNET_PQ_QueryParam params[] = {
14822 0 : GNUNET_PQ_query_param_string (job_name),
14823 0 : GNUNET_PQ_query_param_absolute_time (&now),
14824 0 : GNUNET_PQ_query_param_uint64 (start_row),
14825 0 : GNUNET_PQ_query_param_uint64 (end_row),
14826 : GNUNET_PQ_query_param_end
14827 : };
14828 :
14829 0 : now = GNUNET_TIME_relative_to_absolute (delay);
14830 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
14831 : "reclaim_shard",
14832 : params);
14833 : switch (qs)
14834 : {
14835 0 : case GNUNET_DB_STATUS_HARD_ERROR:
14836 0 : GNUNET_break (0);
14837 0 : postgres_rollback (pg);
14838 0 : return qs;
14839 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
14840 0 : postgres_rollback (pg);
14841 0 : continue;
14842 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
14843 0 : goto commit;
14844 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
14845 0 : GNUNET_break (0); /* logic error, should be impossible */
14846 0 : postgres_rollback (pg);
14847 0 : return GNUNET_DB_STATUS_HARD_ERROR;
14848 : }
14849 : }
14850 0 : break; /* actually unreachable */
14851 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
14852 0 : break; /* continued below */
14853 : }
14854 0 : } /* get_open_shard */
14855 :
14856 : /* No open shard, find last 'end_row' */
14857 : {
14858 : enum GNUNET_DB_QueryStatus qs;
14859 0 : struct GNUNET_PQ_QueryParam params[] = {
14860 0 : GNUNET_PQ_query_param_string (job_name),
14861 : GNUNET_PQ_query_param_end
14862 : };
14863 0 : struct GNUNET_PQ_ResultSpec rs[] = {
14864 0 : GNUNET_PQ_result_spec_uint64 ("end_row",
14865 : start_row),
14866 : GNUNET_PQ_result_spec_end
14867 : };
14868 :
14869 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
14870 : "get_last_shard",
14871 : params,
14872 : rs);
14873 0 : switch (qs)
14874 : {
14875 0 : case GNUNET_DB_STATUS_HARD_ERROR:
14876 0 : GNUNET_break (0);
14877 0 : postgres_rollback (pg);
14878 0 : return qs;
14879 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
14880 0 : postgres_rollback (pg);
14881 0 : continue;
14882 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
14883 0 : break;
14884 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
14885 0 : *start_row = 0; /* base-case: no shards yet */
14886 0 : break; /* continued below */
14887 : }
14888 0 : *end_row = *start_row + shard_size;
14889 : } /* get_last_shard */
14890 :
14891 : /* Claim fresh shard */
14892 : {
14893 : enum GNUNET_DB_QueryStatus qs;
14894 : struct GNUNET_TIME_Absolute now;
14895 0 : struct GNUNET_PQ_QueryParam params[] = {
14896 0 : GNUNET_PQ_query_param_string (job_name),
14897 0 : GNUNET_PQ_query_param_absolute_time (&now),
14898 0 : GNUNET_PQ_query_param_uint64 (start_row),
14899 0 : GNUNET_PQ_query_param_uint64 (end_row),
14900 : GNUNET_PQ_query_param_end
14901 : };
14902 :
14903 0 : now = GNUNET_TIME_relative_to_absolute (delay);
14904 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
14905 : "Trying to claim shard (%llu-%llu]\n",
14906 : (unsigned long long) *start_row,
14907 : (unsigned long long) *end_row);
14908 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
14909 : "claim_next_shard",
14910 : params);
14911 0 : switch (qs)
14912 : {
14913 0 : case GNUNET_DB_STATUS_HARD_ERROR:
14914 0 : GNUNET_break (0);
14915 0 : postgres_rollback (pg);
14916 0 : return qs;
14917 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
14918 0 : postgres_rollback (pg);
14919 0 : continue;
14920 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
14921 : /* continued below */
14922 0 : break;
14923 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
14924 : /* someone else got this shard already,
14925 : try again */
14926 0 : postgres_rollback (pg);
14927 0 : continue;
14928 : }
14929 0 : } /* claim_next_shard */
14930 :
14931 : /* commit */
14932 0 : commit:
14933 : {
14934 : enum GNUNET_DB_QueryStatus qs;
14935 :
14936 0 : qs = postgres_commit (pg);
14937 0 : switch (qs)
14938 : {
14939 0 : case GNUNET_DB_STATUS_HARD_ERROR:
14940 0 : GNUNET_break (0);
14941 0 : postgres_rollback (pg);
14942 0 : return qs;
14943 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
14944 0 : postgres_rollback (pg);
14945 0 : continue;
14946 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
14947 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
14948 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
14949 : }
14950 : }
14951 : } /* retry 'for' loop */
14952 0 : return GNUNET_DB_STATUS_SOFT_ERROR;
14953 : }
14954 :
14955 :
14956 : /**
14957 : * Function called to abort work on a shard.
14958 : *
14959 : * @param cls the @e cls of this struct with the plugin-specific state
14960 : * @param job_name name of the operation to abort a word shard for
14961 : * @param start_row inclusive start row of the shard
14962 : * @param end_row exclusive end row of the shard
14963 : * @return transaction status code
14964 : */
14965 : static enum GNUNET_DB_QueryStatus
14966 0 : postgres_abort_shard (void *cls,
14967 : const char *job_name,
14968 : uint64_t start_row,
14969 : uint64_t end_row)
14970 : {
14971 0 : struct PostgresClosure *pg = cls;
14972 0 : struct GNUNET_PQ_QueryParam params[] = {
14973 0 : GNUNET_PQ_query_param_string (job_name),
14974 0 : GNUNET_PQ_query_param_uint64 (&start_row),
14975 0 : GNUNET_PQ_query_param_uint64 (&end_row),
14976 : GNUNET_PQ_query_param_end
14977 : };
14978 :
14979 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
14980 : "abort_shard",
14981 : params);
14982 : }
14983 :
14984 :
14985 : /**
14986 : * Function called to persist that work on a shard was completed.
14987 : *
14988 : * @param cls the @e cls of this struct with the plugin-specific state
14989 : * @param job_name name of the operation to grab a word shard for
14990 : * @param start_row inclusive start row of the shard
14991 : * @param end_row exclusive end row of the shard
14992 : * @return transaction status code
14993 : */
14994 : enum GNUNET_DB_QueryStatus
14995 0 : postgres_complete_shard (void *cls,
14996 : const char *job_name,
14997 : uint64_t start_row,
14998 : uint64_t end_row)
14999 : {
15000 0 : struct PostgresClosure *pg = cls;
15001 :
15002 0 : struct GNUNET_PQ_QueryParam params[] = {
15003 0 : GNUNET_PQ_query_param_string (job_name),
15004 0 : GNUNET_PQ_query_param_uint64 (&start_row),
15005 0 : GNUNET_PQ_query_param_uint64 (&end_row),
15006 : GNUNET_PQ_query_param_end
15007 : };
15008 :
15009 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
15010 : "Completing shard %llu-%llu\n",
15011 : (unsigned long long) start_row,
15012 : (unsigned long long) end_row);
15013 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
15014 : "complete_shard",
15015 : params);
15016 : }
15017 :
15018 :
15019 : /**
15020 : * Function called to grab a revolving work shard on an operation @a op. Runs
15021 : * in its own transaction. Returns the oldest inactive shard.
15022 : *
15023 : * @param cls the @e cls of this struct with the plugin-specific state
15024 : * @param job_name name of the operation to grab a revolving shard for
15025 : * @param shard_size desired shard size
15026 : * @param shard_limit exclusive end of the shard range
15027 : * @param[out] start_row inclusive start row of the shard (returned)
15028 : * @param[out] end_row inclusive end row of the shard (returned)
15029 : * @return transaction status code
15030 : */
15031 : static enum GNUNET_DB_QueryStatus
15032 0 : postgres_begin_revolving_shard (void *cls,
15033 : const char *job_name,
15034 : uint32_t shard_size,
15035 : uint32_t shard_limit,
15036 : uint32_t *start_row,
15037 : uint32_t *end_row)
15038 : {
15039 0 : struct PostgresClosure *pg = cls;
15040 :
15041 0 : GNUNET_assert (shard_limit <= 1U + (uint32_t) INT_MAX);
15042 0 : GNUNET_assert (shard_limit > 0);
15043 0 : GNUNET_assert (shard_size > 0);
15044 0 : for (unsigned int retries = 0; retries<3; retries++)
15045 : {
15046 0 : if (GNUNET_OK !=
15047 0 : postgres_start (pg,
15048 : "begin_revolving_shard"))
15049 : {
15050 0 : GNUNET_break (0);
15051 0 : return GNUNET_DB_STATUS_HARD_ERROR;
15052 : }
15053 :
15054 : /* First, find last 'end_row' */
15055 : {
15056 : enum GNUNET_DB_QueryStatus qs;
15057 : uint32_t last_end;
15058 0 : struct GNUNET_PQ_QueryParam params[] = {
15059 0 : GNUNET_PQ_query_param_string (job_name),
15060 : GNUNET_PQ_query_param_end
15061 : };
15062 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15063 0 : GNUNET_PQ_result_spec_uint32 ("end_row",
15064 : &last_end),
15065 : GNUNET_PQ_result_spec_end
15066 : };
15067 :
15068 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15069 : "get_last_revolving_shard",
15070 : params,
15071 : rs);
15072 0 : switch (qs)
15073 : {
15074 0 : case GNUNET_DB_STATUS_HARD_ERROR:
15075 0 : GNUNET_break (0);
15076 0 : postgres_rollback (pg);
15077 0 : return qs;
15078 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
15079 0 : postgres_rollback (pg);
15080 0 : continue;
15081 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
15082 0 : *start_row = 1U + last_end;
15083 0 : break;
15084 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
15085 0 : *start_row = 0; /* base-case: no shards yet */
15086 0 : break; /* continued below */
15087 : }
15088 0 : } /* get_last_shard */
15089 :
15090 0 : if (*start_row < shard_limit)
15091 : {
15092 : /* Claim fresh shard */
15093 : enum GNUNET_DB_QueryStatus qs;
15094 : struct GNUNET_TIME_Absolute now;
15095 0 : struct GNUNET_PQ_QueryParam params[] = {
15096 0 : GNUNET_PQ_query_param_string (job_name),
15097 0 : GNUNET_PQ_query_param_absolute_time (&now),
15098 0 : GNUNET_PQ_query_param_uint32 (start_row),
15099 0 : GNUNET_PQ_query_param_uint32 (end_row),
15100 : GNUNET_PQ_query_param_end
15101 : };
15102 :
15103 0 : *end_row = GNUNET_MIN (shard_limit,
15104 : *start_row + shard_size - 1);
15105 0 : now = GNUNET_TIME_absolute_get ();
15106 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
15107 : "Trying to claim shard %llu-%llu\n",
15108 : (unsigned long long) *start_row,
15109 : (unsigned long long) *end_row);
15110 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
15111 : "create_revolving_shard",
15112 : params);
15113 0 : switch (qs)
15114 : {
15115 0 : case GNUNET_DB_STATUS_HARD_ERROR:
15116 0 : GNUNET_break (0);
15117 0 : postgres_rollback (pg);
15118 0 : return qs;
15119 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
15120 0 : postgres_rollback (pg);
15121 0 : continue;
15122 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
15123 : /* continued below (with commit) */
15124 0 : break;
15125 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
15126 : /* someone else got this shard already,
15127 : try again */
15128 0 : postgres_rollback (pg);
15129 0 : continue;
15130 : }
15131 0 : } /* end create fresh reovlving shard */
15132 : else
15133 : {
15134 : /* claim oldest existing shard */
15135 : enum GNUNET_DB_QueryStatus qs;
15136 0 : struct GNUNET_PQ_QueryParam params[] = {
15137 0 : GNUNET_PQ_query_param_string (job_name),
15138 : GNUNET_PQ_query_param_end
15139 : };
15140 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15141 0 : GNUNET_PQ_result_spec_uint32 ("start_row",
15142 : start_row),
15143 0 : GNUNET_PQ_result_spec_uint32 ("end_row",
15144 : end_row),
15145 : GNUNET_PQ_result_spec_end
15146 : };
15147 :
15148 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15149 : "get_open_revolving_shard",
15150 : params,
15151 : rs);
15152 0 : switch (qs)
15153 : {
15154 0 : case GNUNET_DB_STATUS_HARD_ERROR:
15155 0 : GNUNET_break (0);
15156 0 : postgres_rollback (pg);
15157 0 : return qs;
15158 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
15159 0 : postgres_rollback (pg);
15160 0 : continue;
15161 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
15162 : /* no open shards available */
15163 0 : postgres_rollback (pg);
15164 0 : return qs;
15165 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
15166 : {
15167 : enum GNUNET_DB_QueryStatus qs;
15168 : struct GNUNET_TIME_Timestamp now;
15169 0 : struct GNUNET_PQ_QueryParam params[] = {
15170 0 : GNUNET_PQ_query_param_string (job_name),
15171 0 : GNUNET_PQ_query_param_timestamp (&now),
15172 0 : GNUNET_PQ_query_param_uint32 (start_row),
15173 0 : GNUNET_PQ_query_param_uint32 (end_row),
15174 : GNUNET_PQ_query_param_end
15175 : };
15176 :
15177 0 : now = GNUNET_TIME_timestamp_get ();
15178 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
15179 : "reclaim_revolving_shard",
15180 : params);
15181 : switch (qs)
15182 : {
15183 0 : case GNUNET_DB_STATUS_HARD_ERROR:
15184 0 : GNUNET_break (0);
15185 0 : postgres_rollback (pg);
15186 0 : return qs;
15187 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
15188 0 : postgres_rollback (pg);
15189 0 : continue;
15190 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
15191 0 : break; /* continue with commit */
15192 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
15193 0 : GNUNET_break (0); /* logic error, should be impossible */
15194 0 : postgres_rollback (pg);
15195 0 : return GNUNET_DB_STATUS_HARD_ERROR;
15196 : }
15197 0 : }
15198 0 : break; /* continue with commit */
15199 : }
15200 0 : } /* end claim oldest existing shard */
15201 :
15202 : /* commit */
15203 : {
15204 : enum GNUNET_DB_QueryStatus qs;
15205 :
15206 0 : qs = postgres_commit (pg);
15207 0 : switch (qs)
15208 : {
15209 0 : case GNUNET_DB_STATUS_HARD_ERROR:
15210 0 : GNUNET_break (0);
15211 0 : postgres_rollback (pg);
15212 0 : return qs;
15213 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
15214 0 : postgres_rollback (pg);
15215 0 : continue;
15216 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
15217 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
15218 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
15219 : }
15220 : }
15221 : } /* retry 'for' loop */
15222 0 : return GNUNET_DB_STATUS_SOFT_ERROR;
15223 : }
15224 :
15225 :
15226 : /**
15227 : * Function called to release a revolving shard
15228 : * back into the work pool. Clears the
15229 : * "completed" flag.
15230 : *
15231 : * @param cls the @e cls of this struct with the plugin-specific state
15232 : * @param job_name name of the operation to grab a word shard for
15233 : * @param start_row inclusive start row of the shard
15234 : * @param end_row exclusive end row of the shard
15235 : * @return transaction status code
15236 : */
15237 : enum GNUNET_DB_QueryStatus
15238 0 : postgres_release_revolving_shard (void *cls,
15239 : const char *job_name,
15240 : uint32_t start_row,
15241 : uint32_t end_row)
15242 : {
15243 0 : struct PostgresClosure *pg = cls;
15244 0 : struct GNUNET_PQ_QueryParam params[] = {
15245 0 : GNUNET_PQ_query_param_string (job_name),
15246 0 : GNUNET_PQ_query_param_uint32 (&start_row),
15247 0 : GNUNET_PQ_query_param_uint32 (&end_row),
15248 : GNUNET_PQ_query_param_end
15249 : };
15250 :
15251 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
15252 : "Releasing revolving shard %s %u-%u\n",
15253 : job_name,
15254 : (unsigned int) start_row,
15255 : (unsigned int) end_row);
15256 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
15257 : "release_revolving_shard",
15258 : params);
15259 : }
15260 :
15261 :
15262 : /**
15263 : * Function called to delete all revolving shards.
15264 : * To be used after a crash or when the shard size is
15265 : * changed.
15266 : *
15267 : * @param cls the @e cls of this struct with the plugin-specific state
15268 : * @return transaction status code
15269 : */
15270 : enum GNUNET_GenericReturnValue
15271 0 : postgres_delete_shard_locks (void *cls)
15272 : {
15273 0 : struct PostgresClosure *pg = cls;
15274 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
15275 0 : GNUNET_PQ_make_execute ("DELETE FROM work_shards;"),
15276 0 : GNUNET_PQ_make_execute ("DELETE FROM revolving_work_shards;"),
15277 : GNUNET_PQ_EXECUTE_STATEMENT_END
15278 : };
15279 :
15280 0 : return GNUNET_PQ_exec_statements (pg->conn,
15281 : es);
15282 : }
15283 :
15284 :
15285 : /**
15286 : * Function called to save the configuration of an extension
15287 : * (age-restriction, peer2peer, ...). After successful storage of the
15288 : * configuration it triggers the corresponding event.
15289 : *
15290 : * @param cls the @e cls of this struct with the plugin-specific state
15291 : * @param extension_name the name of the extension
15292 : * @param config JSON object of the configuration as string
15293 : * @return transaction status code
15294 : */
15295 : enum GNUNET_DB_QueryStatus
15296 0 : postgres_set_extension_config (void *cls,
15297 : const char *extension_name,
15298 : const char *config)
15299 : {
15300 0 : struct PostgresClosure *pg = cls;
15301 0 : struct GNUNET_PQ_QueryParam pcfg =
15302 0 : (NULL == config || 0 == *config)
15303 0 : ? GNUNET_PQ_query_param_null ()
15304 0 : : GNUNET_PQ_query_param_string (config);
15305 0 : struct GNUNET_PQ_QueryParam params[] = {
15306 0 : GNUNET_PQ_query_param_string (extension_name),
15307 : pcfg,
15308 : GNUNET_PQ_query_param_end
15309 : };
15310 :
15311 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
15312 : "set_extension_config",
15313 : params);
15314 : }
15315 :
15316 :
15317 : /**
15318 : * Function called to get the configuration of an extension
15319 : * (age-restriction, peer2peer, ...)
15320 : *
15321 : * @param cls the @e cls of this struct with the plugin-specific state
15322 : * @param extension_name the name of the extension
15323 : * @param[out] config JSON object of the configuration as string
15324 : * @return transaction status code
15325 : */
15326 : enum GNUNET_DB_QueryStatus
15327 0 : postgres_get_extension_config (void *cls,
15328 : const char *extension_name,
15329 : char **config)
15330 : {
15331 0 : struct PostgresClosure *pg = cls;
15332 0 : struct GNUNET_PQ_QueryParam params[] = {
15333 0 : GNUNET_PQ_query_param_string (extension_name),
15334 : GNUNET_PQ_query_param_end
15335 : };
15336 : bool is_null;
15337 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15338 0 : GNUNET_PQ_result_spec_allow_null (
15339 : GNUNET_PQ_result_spec_string ("config",
15340 : config),
15341 : &is_null),
15342 : GNUNET_PQ_result_spec_end
15343 : };
15344 :
15345 0 : *config = NULL;
15346 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15347 : "get_extension_config",
15348 : params,
15349 : rs);
15350 : }
15351 :
15352 :
15353 : /**
15354 : * Function called to store configuration data about a partner
15355 : * exchange that we are federated with.
15356 : *
15357 : * @param cls the @e cls of this struct with the plugin-specific state
15358 : * @param master_pub public offline signing key of the partner exchange
15359 : * @param start_date when does the following data start to be valid
15360 : * @param end_date when does the validity end (exclusive)
15361 : * @param wad_frequency how often do we do exchange-to-exchange settlements?
15362 : * @param wad_fee how much do we charge for transfers to the partner
15363 : * @param partner_base_url base URL of the partner exchange
15364 : * @param master_sig signature with our offline signing key affirming the above
15365 : * @return transaction status code
15366 : */
15367 : static enum GNUNET_DB_QueryStatus
15368 0 : postgres_insert_partner (void *cls,
15369 : const struct TALER_MasterPublicKeyP *master_pub,
15370 : struct GNUNET_TIME_Timestamp start_date,
15371 : struct GNUNET_TIME_Timestamp end_date,
15372 : struct GNUNET_TIME_Relative wad_frequency,
15373 : const struct TALER_Amount *wad_fee,
15374 : const char *partner_base_url,
15375 : const struct TALER_MasterSignatureP *master_sig)
15376 : {
15377 0 : struct PostgresClosure *pg = cls;
15378 0 : struct GNUNET_PQ_QueryParam params[] = {
15379 0 : GNUNET_PQ_query_param_auto_from_type (master_pub),
15380 0 : GNUNET_PQ_query_param_timestamp (&start_date),
15381 0 : GNUNET_PQ_query_param_timestamp (&end_date),
15382 0 : GNUNET_PQ_query_param_relative_time (&wad_frequency),
15383 0 : TALER_PQ_query_param_amount (wad_fee),
15384 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
15385 0 : GNUNET_PQ_query_param_string (partner_base_url),
15386 : GNUNET_PQ_query_param_end
15387 : };
15388 :
15389 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
15390 : "insert_partner",
15391 : params);
15392 : }
15393 :
15394 :
15395 : /**
15396 : * Function called to retrieve an encrypted contract.
15397 : *
15398 : * @param cls the @e cls of this struct with the plugin-specific state
15399 : * @param purse_pub key to lookup the contract by
15400 : * @param[out] pub_ckey set to the ephemeral DH used to encrypt the contract
15401 : * @param[out] econtract_sig set to the signature over the encrypted contract
15402 : * @param[out] econtract_size set to the number of bytes in @a econtract
15403 : * @param[out] econtract set to the encrypted contract on success, to be freed by the caller
15404 : * @return transaction status code
15405 : */
15406 : static enum GNUNET_DB_QueryStatus
15407 0 : postgres_select_contract (void *cls,
15408 : const struct TALER_ContractDiffiePublicP *pub_ckey,
15409 : struct TALER_PurseContractPublicKeyP *purse_pub,
15410 : struct TALER_PurseContractSignatureP *econtract_sig,
15411 : size_t *econtract_size,
15412 : void **econtract)
15413 : {
15414 0 : struct PostgresClosure *pg = cls;
15415 0 : struct GNUNET_PQ_QueryParam params[] = {
15416 0 : GNUNET_PQ_query_param_auto_from_type (pub_ckey),
15417 : GNUNET_PQ_query_param_end
15418 : };
15419 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15420 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
15421 : purse_pub),
15422 0 : GNUNET_PQ_result_spec_auto_from_type ("contract_sig",
15423 : econtract_sig),
15424 0 : GNUNET_PQ_result_spec_variable_size ("e_contract",
15425 : econtract,
15426 : econtract_size),
15427 : GNUNET_PQ_result_spec_end
15428 : };
15429 :
15430 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15431 : "select_contract",
15432 : params,
15433 : rs);
15434 :
15435 : }
15436 :
15437 :
15438 : /**
15439 : * Function called to retrieve an encrypted contract.
15440 : *
15441 : * @param cls the @e cls of this struct with the plugin-specific state
15442 : * @param purse_pub key to lookup the contract by
15443 : * @param[out] econtract set to the encrypted contract on success, to be freed by the caller
15444 : * @return transaction status code
15445 : */
15446 : static enum GNUNET_DB_QueryStatus
15447 0 : postgres_select_contract_by_purse (
15448 : void *cls,
15449 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15450 : struct TALER_EncryptedContract *econtract)
15451 : {
15452 0 : struct PostgresClosure *pg = cls;
15453 0 : struct GNUNET_PQ_QueryParam params[] = {
15454 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15455 : GNUNET_PQ_query_param_end
15456 : };
15457 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15458 0 : GNUNET_PQ_result_spec_auto_from_type ("pub_ckey",
15459 : &econtract->contract_pub),
15460 0 : GNUNET_PQ_result_spec_auto_from_type ("contract_sig",
15461 : &econtract->econtract_sig),
15462 0 : GNUNET_PQ_result_spec_variable_size ("e_contract",
15463 : &econtract->econtract,
15464 : &econtract->econtract_size),
15465 : GNUNET_PQ_result_spec_end
15466 : };
15467 :
15468 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15469 : "select_contract_by_purse",
15470 : params,
15471 : rs);
15472 :
15473 : }
15474 :
15475 :
15476 : /**
15477 : * Function called to persist an encrypted contract associated with a reserve.
15478 : *
15479 : * @param cls the @e cls of this struct with the plugin-specific state
15480 : * @param purse_pub the purse the contract is associated with (must exist)
15481 : * @param econtract the encrypted contract
15482 : * @param[out] in_conflict set to true if @a econtract
15483 : * conflicts with an existing contract;
15484 : * in this case, the return value will be
15485 : * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
15486 : * @return transaction status code
15487 : */
15488 : static enum GNUNET_DB_QueryStatus
15489 0 : postgres_insert_contract (
15490 : void *cls,
15491 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15492 : const struct TALER_EncryptedContract *econtract,
15493 : bool *in_conflict)
15494 : {
15495 0 : struct PostgresClosure *pg = cls;
15496 : enum GNUNET_DB_QueryStatus qs;
15497 0 : struct GNUNET_PQ_QueryParam params[] = {
15498 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15499 0 : GNUNET_PQ_query_param_auto_from_type (&econtract->contract_pub),
15500 0 : GNUNET_PQ_query_param_fixed_size (econtract->econtract,
15501 : econtract->econtract_size),
15502 0 : GNUNET_PQ_query_param_auto_from_type (&econtract->econtract_sig),
15503 : GNUNET_PQ_query_param_end
15504 : };
15505 :
15506 0 : *in_conflict = false;
15507 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
15508 : "insert_contract",
15509 : params);
15510 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
15511 0 : return qs;
15512 : {
15513 : struct TALER_EncryptedContract econtract2;
15514 :
15515 0 : qs = postgres_select_contract_by_purse (pg,
15516 : purse_pub,
15517 : &econtract2);
15518 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
15519 : {
15520 0 : GNUNET_break (0);
15521 0 : return GNUNET_DB_STATUS_HARD_ERROR;
15522 : }
15523 0 : if ( (0 == GNUNET_memcmp (&econtract->contract_pub,
15524 0 : &econtract2.contract_pub)) &&
15525 0 : (econtract2.econtract_size ==
15526 0 : econtract->econtract_size) &&
15527 0 : (0 == memcmp (econtract2.econtract,
15528 0 : econtract->econtract,
15529 : econtract->econtract_size)) )
15530 : {
15531 0 : GNUNET_free (econtract2.econtract);
15532 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
15533 : }
15534 0 : GNUNET_free (econtract2.econtract);
15535 0 : *in_conflict = true;
15536 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
15537 : }
15538 : }
15539 :
15540 :
15541 : /**
15542 : * Function called to return meta data about a purse by the
15543 : * purse public key.
15544 : *
15545 : * @param cls the @e cls of this struct with the plugin-specific state
15546 : * @param purse_pub public key of the purse
15547 : * @param[out] merge_pub public key representing the merge capability
15548 : * @param[out] purse_expiration when would an unmerged purse expire
15549 : * @param[out] h_contract_terms contract associated with the purse
15550 : * @param[out] age_limit the age limit for deposits into the purse
15551 : * @param[out] target_amount amount to be put into the purse
15552 : * @param[out] balance amount put so far into the purse
15553 : * @param[out] purse_sig signature of the purse over the initialization data
15554 : * @return transaction status code
15555 : */
15556 : static enum GNUNET_DB_QueryStatus
15557 0 : postgres_select_purse_request (
15558 : void *cls,
15559 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15560 : struct TALER_PurseMergePublicKeyP *merge_pub,
15561 : struct GNUNET_TIME_Timestamp *purse_expiration,
15562 : struct TALER_PrivateContractHashP *h_contract_terms,
15563 : uint32_t *age_limit,
15564 : struct TALER_Amount *target_amount,
15565 : struct TALER_Amount *balance,
15566 : struct TALER_PurseContractSignatureP *purse_sig)
15567 : {
15568 0 : struct PostgresClosure *pg = cls;
15569 0 : struct GNUNET_PQ_QueryParam params[] = {
15570 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15571 : GNUNET_PQ_query_param_end
15572 : };
15573 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15574 0 : GNUNET_PQ_result_spec_auto_from_type ("merge_pub",
15575 : merge_pub),
15576 0 : GNUNET_PQ_result_spec_timestamp ("purse_expiration",
15577 : purse_expiration),
15578 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
15579 : h_contract_terms),
15580 0 : GNUNET_PQ_result_spec_uint32 ("age_limit",
15581 : age_limit),
15582 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
15583 : target_amount),
15584 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
15585 : balance),
15586 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_sig",
15587 : purse_sig),
15588 : GNUNET_PQ_result_spec_end
15589 : };
15590 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15591 : "select_purse_request",
15592 : params,
15593 : rs);
15594 : }
15595 :
15596 :
15597 : /**
15598 : * Function called to create a new purse with certain meta data.
15599 : *
15600 : * @param cls the @e cls of this struct with the plugin-specific state
15601 : * @param purse_pub public key of the new purse
15602 : * @param merge_pub public key providing the merge capability
15603 : * @param purse_expiration time when the purse will expire
15604 : * @param h_contract_terms hash of the contract for the purse
15605 : * @param age_limit age limit to enforce for payments into the purse
15606 : * @param flags flags for the operation
15607 : * @param purse_fee fee we are allowed to charge to the reserve (depending on @a flags)
15608 : * @param amount target amount (with fees) to be put into the purse
15609 : * @param purse_sig signature with @a purse_pub's private key affirming the above
15610 : * @param[out] in_conflict set to true if the meta data
15611 : * conflicts with an existing purse;
15612 : * in this case, the return value will be
15613 : * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
15614 : * @return transaction status code
15615 : */
15616 : static enum GNUNET_DB_QueryStatus
15617 0 : postgres_insert_purse_request (
15618 : void *cls,
15619 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15620 : const struct TALER_PurseMergePublicKeyP *merge_pub,
15621 : struct GNUNET_TIME_Timestamp purse_expiration,
15622 : const struct TALER_PrivateContractHashP *h_contract_terms,
15623 : uint32_t age_limit,
15624 : enum TALER_WalletAccountMergeFlags flags,
15625 : const struct TALER_Amount *purse_fee,
15626 : const struct TALER_Amount *amount,
15627 : const struct TALER_PurseContractSignatureP *purse_sig,
15628 : bool *in_conflict)
15629 : {
15630 0 : struct PostgresClosure *pg = cls;
15631 : enum GNUNET_DB_QueryStatus qs;
15632 0 : struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
15633 0 : uint32_t flags32 = (uint32_t) flags;
15634 0 : bool in_reserve_quota = (TALER_WAMF_MODE_CREATE_FROM_PURSE_QUOTA
15635 0 : == (flags & TALER_WAMF_MERGE_MODE_MASK));
15636 0 : struct GNUNET_PQ_QueryParam params[] = {
15637 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15638 0 : GNUNET_PQ_query_param_auto_from_type (merge_pub),
15639 0 : GNUNET_PQ_query_param_timestamp (&now),
15640 0 : GNUNET_PQ_query_param_timestamp (&purse_expiration),
15641 0 : GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
15642 0 : GNUNET_PQ_query_param_uint32 (&age_limit),
15643 0 : GNUNET_PQ_query_param_uint32 (&flags32),
15644 0 : GNUNET_PQ_query_param_bool (in_reserve_quota),
15645 0 : TALER_PQ_query_param_amount (amount),
15646 0 : TALER_PQ_query_param_amount (purse_fee),
15647 0 : GNUNET_PQ_query_param_auto_from_type (purse_sig),
15648 : GNUNET_PQ_query_param_end
15649 : };
15650 :
15651 0 : *in_conflict = false;
15652 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
15653 : "insert_purse_request",
15654 : params);
15655 0 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
15656 0 : return qs;
15657 : {
15658 : struct TALER_PurseMergePublicKeyP merge_pub2;
15659 : struct GNUNET_TIME_Timestamp purse_expiration2;
15660 : struct TALER_PrivateContractHashP h_contract_terms2;
15661 : uint32_t age_limit2;
15662 : struct TALER_Amount amount2;
15663 : struct TALER_Amount balance;
15664 : struct TALER_PurseContractSignatureP purse_sig2;
15665 :
15666 0 : qs = postgres_select_purse_request (pg,
15667 : purse_pub,
15668 : &merge_pub2,
15669 : &purse_expiration2,
15670 : &h_contract_terms2,
15671 : &age_limit2,
15672 : &amount2,
15673 : &balance,
15674 : &purse_sig2);
15675 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
15676 : {
15677 0 : GNUNET_break (0);
15678 0 : return GNUNET_DB_STATUS_HARD_ERROR;
15679 : }
15680 0 : if ( (age_limit2 == age_limit) &&
15681 0 : (0 == TALER_amount_cmp (amount,
15682 0 : &amount2)) &&
15683 0 : (0 == GNUNET_memcmp (&h_contract_terms2,
15684 0 : h_contract_terms)) &&
15685 0 : (0 == GNUNET_memcmp (&merge_pub2,
15686 : merge_pub)) )
15687 : {
15688 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
15689 : }
15690 0 : *in_conflict = true;
15691 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
15692 : }
15693 : }
15694 :
15695 :
15696 : /**
15697 : * Function called to clean up one expired purse.
15698 : *
15699 : * @param cls the @e cls of this struct with the plugin-specific state
15700 : * @param start_time select purse expired after this time
15701 : * @param end_time select purse expired before this time
15702 : * @return transaction status code (#GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no purse expired in the given time interval).
15703 : */
15704 : static enum GNUNET_DB_QueryStatus
15705 0 : postgres_expire_purse (
15706 : void *cls,
15707 : struct GNUNET_TIME_Absolute start_time,
15708 : struct GNUNET_TIME_Absolute end_time)
15709 : {
15710 0 : struct PostgresClosure *pg = cls;
15711 0 : struct GNUNET_PQ_QueryParam params[] = {
15712 0 : GNUNET_PQ_query_param_absolute_time (&start_time),
15713 0 : GNUNET_PQ_query_param_absolute_time (&end_time),
15714 : GNUNET_PQ_query_param_end
15715 : };
15716 0 : bool found = false;
15717 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15718 0 : GNUNET_PQ_result_spec_bool ("found",
15719 : &found),
15720 : GNUNET_PQ_result_spec_end
15721 : };
15722 : enum GNUNET_DB_QueryStatus qs;
15723 :
15724 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15725 : "call_expire_purse",
15726 : params,
15727 : rs);
15728 0 : if (qs < 0)
15729 0 : return qs;
15730 0 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
15731 : return found
15732 : ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
15733 0 : : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
15734 : }
15735 :
15736 :
15737 : /**
15738 : * Function called to obtain information about a purse.
15739 : *
15740 : * @param cls the @e cls of this struct with the plugin-specific state
15741 : * @param purse_pub public key of the new purse
15742 : * @param[out] purse_expiration set to time when the purse will expire
15743 : * @param[out] amount set to target amount (with fees) to be put into the purse
15744 : * @param[out] deposited set to actual amount put into the purse so far
15745 : * @param[out] h_contract_terms set to hash of the contract for the purse
15746 : * @param[out] merge_timestamp set to time when the purse was merged, or NEVER if not
15747 : * @return transaction status code
15748 : */
15749 : static enum GNUNET_DB_QueryStatus
15750 0 : postgres_select_purse (
15751 : void *cls,
15752 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15753 : struct GNUNET_TIME_Timestamp *purse_expiration,
15754 : struct TALER_Amount *amount,
15755 : struct TALER_Amount *deposited,
15756 : struct TALER_PrivateContractHashP *h_contract_terms,
15757 : struct GNUNET_TIME_Timestamp *merge_timestamp)
15758 : {
15759 0 : struct PostgresClosure *pg = cls;
15760 0 : struct GNUNET_PQ_QueryParam params[] = {
15761 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15762 : GNUNET_PQ_query_param_end
15763 : };
15764 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15765 0 : GNUNET_PQ_result_spec_timestamp ("purse_expiration",
15766 : purse_expiration),
15767 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
15768 : amount),
15769 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
15770 : deposited),
15771 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
15772 : h_contract_terms),
15773 0 : GNUNET_PQ_result_spec_allow_null (
15774 : GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
15775 : merge_timestamp),
15776 : NULL),
15777 : GNUNET_PQ_result_spec_end
15778 : };
15779 :
15780 0 : *merge_timestamp = GNUNET_TIME_UNIT_FOREVER_TS;
15781 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15782 : "select_purse",
15783 : params,
15784 : rs);
15785 : }
15786 :
15787 :
15788 : /**
15789 : * Function called to return meta data about a purse by the
15790 : * merge capability key.
15791 : *
15792 : * @param cls the @e cls of this struct with the plugin-specific state
15793 : * @param merge_pub public key representing the merge capability
15794 : * @param[out] purse_pub public key of the purse
15795 : * @param[out] purse_expiration when would an unmerged purse expire
15796 : * @param[out] h_contract_terms contract associated with the purse
15797 : * @param[out] age_limit the age limit for deposits into the purse
15798 : * @param[out] target_amount amount to be put into the purse
15799 : * @param[out] balance amount put so far into the purse
15800 : * @param[out] purse_sig signature of the purse over the initialization data
15801 : * @return transaction status code
15802 : */
15803 : static enum GNUNET_DB_QueryStatus
15804 0 : postgres_select_purse_by_merge_pub (
15805 : void *cls,
15806 : const struct TALER_PurseMergePublicKeyP *merge_pub,
15807 : struct TALER_PurseContractPublicKeyP *purse_pub,
15808 : struct GNUNET_TIME_Timestamp *purse_expiration,
15809 : struct TALER_PrivateContractHashP *h_contract_terms,
15810 : uint32_t *age_limit,
15811 : struct TALER_Amount *target_amount,
15812 : struct TALER_Amount *balance,
15813 : struct TALER_PurseContractSignatureP *purse_sig)
15814 : {
15815 0 : struct PostgresClosure *pg = cls;
15816 0 : struct GNUNET_PQ_QueryParam params[] = {
15817 0 : GNUNET_PQ_query_param_auto_from_type (merge_pub),
15818 : GNUNET_PQ_query_param_end
15819 : };
15820 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15821 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
15822 : purse_pub),
15823 0 : GNUNET_PQ_result_spec_timestamp ("purse_expiration",
15824 : purse_expiration),
15825 0 : GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
15826 : h_contract_terms),
15827 0 : GNUNET_PQ_result_spec_uint32 ("age_limit",
15828 : age_limit),
15829 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
15830 : target_amount),
15831 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
15832 : balance),
15833 0 : GNUNET_PQ_result_spec_auto_from_type ("purse_sig",
15834 : purse_sig),
15835 : GNUNET_PQ_result_spec_end
15836 : };
15837 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15838 : "select_purse_by_merge_pub",
15839 : params,
15840 : rs);
15841 : }
15842 :
15843 :
15844 : /**
15845 : * Function called to execute a transaction crediting
15846 : * a purse with @a amount from @a coin_pub. Reduces the
15847 : * value of @a coin_pub and increase the balance of
15848 : * the @a purse_pub purse. If the balance reaches the
15849 : * target amount and the purse has been merged, triggers
15850 : * the updates of the reserve/account balance.
15851 : *
15852 : * @param cls the @e cls of this struct with the plugin-specific state
15853 : * @param purse_pub purse to credit
15854 : * @param coin_pub coin to deposit (debit)
15855 : * @param amount fraction of the coin's value to deposit
15856 : * @param coin_sig signature affirming the operation
15857 : * @param amount_minus_fee amount to add to the purse
15858 : * @param[out] balance_ok set to false if the coin's
15859 : * remaining balance is below @a amount;
15860 : * in this case, the return value will be
15861 : * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
15862 : * @param[out] conflict set to true if the deposit failed due to a conflict (coin already spent,
15863 : * or deposited into this purse with a different amount)
15864 : * @return transaction status code
15865 : */
15866 : static enum GNUNET_DB_QueryStatus
15867 0 : postgres_do_purse_deposit (
15868 : void *cls,
15869 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15870 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
15871 : const struct TALER_Amount *amount,
15872 : const struct TALER_CoinSpendSignatureP *coin_sig,
15873 : const struct TALER_Amount *amount_minus_fee,
15874 : bool *balance_ok,
15875 : bool *conflict)
15876 : {
15877 0 : struct PostgresClosure *pg = cls;
15878 : struct GNUNET_TIME_Timestamp reserve_expiration;
15879 0 : uint64_t partner_id = 0; /* FIXME #7271: WAD support... */
15880 0 : struct GNUNET_PQ_QueryParam params[] = {
15881 0 : GNUNET_PQ_query_param_uint64 (&partner_id),
15882 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15883 0 : TALER_PQ_query_param_amount (amount),
15884 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
15885 0 : GNUNET_PQ_query_param_auto_from_type (coin_sig),
15886 0 : TALER_PQ_query_param_amount (amount_minus_fee),
15887 0 : GNUNET_PQ_query_param_timestamp (&reserve_expiration),
15888 : GNUNET_PQ_query_param_end
15889 : };
15890 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15891 0 : GNUNET_PQ_result_spec_bool ("balance_ok",
15892 : balance_ok),
15893 0 : GNUNET_PQ_result_spec_bool ("conflict",
15894 : conflict),
15895 : GNUNET_PQ_result_spec_end
15896 : };
15897 :
15898 : reserve_expiration
15899 0 : = GNUNET_TIME_absolute_to_timestamp (
15900 : GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
15901 : pg->legal_reserve_expiration_time));
15902 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15903 : "call_purse_deposit",
15904 : params,
15905 : rs);
15906 : }
15907 :
15908 :
15909 : /**
15910 : * Set the current @a balance in the purse
15911 : * identified by @a purse_pub. Used by the auditor
15912 : * to update the balance as calculated by the auditor.
15913 : *
15914 : * @param cls closure
15915 : * @param purse_pub public key of a purse
15916 : * @param balance new balance to store under the purse
15917 : * @return transaction status
15918 : */
15919 : static enum GNUNET_DB_QueryStatus
15920 0 : postgres_set_purse_balance (
15921 : void *cls,
15922 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15923 : const struct TALER_Amount *balance)
15924 : {
15925 0 : struct PostgresClosure *pg = cls;
15926 0 : struct GNUNET_PQ_QueryParam params[] = {
15927 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15928 0 : TALER_PQ_query_param_amount (balance),
15929 : GNUNET_PQ_query_param_end
15930 : };
15931 :
15932 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
15933 : "set_purse_balance",
15934 : params);
15935 : }
15936 :
15937 :
15938 : /**
15939 : * Function called to obtain a coin deposit data from
15940 : * depositing the coin into a purse.
15941 : *
15942 : * @param cls the @e cls of this struct with the plugin-specific state
15943 : * @param purse_pub purse to credit
15944 : * @param coin_pub coin to deposit (debit)
15945 : * @param[out] amount set fraction of the coin's value that was deposited (with fee)
15946 : * @param[out] h_denom_pub set to hash of denomination of the coin
15947 : * @param[out] phac set to hash of age restriction on the coin
15948 : * @param[out] coin_sig set to signature affirming the operation
15949 : * @param[out] partner_url set to the URL of the partner exchange, or NULL for ourselves, must be freed by caller
15950 : * @return transaction status code
15951 : */
15952 : static enum GNUNET_DB_QueryStatus
15953 0 : postgres_get_purse_deposit (
15954 : void *cls,
15955 : const struct TALER_PurseContractPublicKeyP *purse_pub,
15956 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
15957 : struct TALER_Amount *amount,
15958 : struct TALER_DenominationHashP *h_denom_pub,
15959 : struct TALER_AgeCommitmentHash *phac,
15960 : struct TALER_CoinSpendSignatureP *coin_sig,
15961 : char **partner_url)
15962 : {
15963 0 : struct PostgresClosure *pg = cls;
15964 0 : struct GNUNET_PQ_QueryParam params[] = {
15965 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
15966 0 : GNUNET_PQ_query_param_auto_from_type (coin_pub),
15967 : GNUNET_PQ_query_param_end
15968 : };
15969 : bool is_null;
15970 0 : struct GNUNET_PQ_ResultSpec rs[] = {
15971 0 : GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
15972 : h_denom_pub),
15973 0 : GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
15974 : phac),
15975 0 : GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
15976 : coin_sig),
15977 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
15978 : amount),
15979 0 : GNUNET_PQ_result_spec_allow_null (
15980 : GNUNET_PQ_result_spec_string ("partner_base_url",
15981 : partner_url),
15982 : &is_null),
15983 : GNUNET_PQ_result_spec_end
15984 : };
15985 :
15986 0 : *partner_url = NULL;
15987 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
15988 : "select_purse_deposit_by_coin_pub",
15989 : params,
15990 : rs);
15991 : }
15992 :
15993 :
15994 : /**
15995 : * Function called to approve merging a purse into a
15996 : * reserve by the respective purse merge key.
15997 : *
15998 : * @param cls the @e cls of this struct with the plugin-specific state
15999 : * @param purse_pub purse to merge
16000 : * @param merge_sig signature affirming the merge
16001 : * @param merge_timestamp time of the merge
16002 : * @param reserve_sig signature of the reserve affirming the merge
16003 : * @param partner_url URL of the partner exchange, can be NULL if the reserves lives with us
16004 : * @param reserve_pub public key of the reserve to credit
16005 : * @param[out] no_partner set to true if @a partner_url is unknown
16006 : * @param[out] no_balance set to true if the @a purse_pub is not paid up yet
16007 : * @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already
16008 : * @return transaction status code
16009 : */
16010 : static enum GNUNET_DB_QueryStatus
16011 0 : postgres_do_purse_merge (
16012 : void *cls,
16013 : const struct TALER_PurseContractPublicKeyP *purse_pub,
16014 : const struct TALER_PurseMergeSignatureP *merge_sig,
16015 : const struct GNUNET_TIME_Timestamp merge_timestamp,
16016 : const struct TALER_ReserveSignatureP *reserve_sig,
16017 : const char *partner_url,
16018 : const struct TALER_ReservePublicKeyP *reserve_pub,
16019 : bool *no_partner,
16020 : bool *no_balance,
16021 : bool *in_conflict)
16022 : {
16023 0 : struct PostgresClosure *pg = cls;
16024 : struct TALER_PaytoHashP h_payto;
16025 : struct GNUNET_TIME_Timestamp expiration
16026 0 : = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS); /* FIXME: make this configurable? */
16027 0 : struct GNUNET_PQ_QueryParam params[] = {
16028 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
16029 0 : GNUNET_PQ_query_param_auto_from_type (merge_sig),
16030 0 : GNUNET_PQ_query_param_timestamp (&merge_timestamp),
16031 0 : GNUNET_PQ_query_param_auto_from_type (reserve_sig),
16032 : (NULL == partner_url)
16033 0 : ? GNUNET_PQ_query_param_null ()
16034 0 : : GNUNET_PQ_query_param_string (partner_url),
16035 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
16036 0 : GNUNET_PQ_query_param_auto_from_type (&h_payto),
16037 0 : GNUNET_PQ_query_param_timestamp (&expiration),
16038 : GNUNET_PQ_query_param_end
16039 : };
16040 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16041 0 : GNUNET_PQ_result_spec_bool ("no_partner",
16042 : no_partner),
16043 0 : GNUNET_PQ_result_spec_bool ("no_balance",
16044 : no_balance),
16045 0 : GNUNET_PQ_result_spec_bool ("conflict",
16046 : in_conflict),
16047 : GNUNET_PQ_result_spec_end
16048 : };
16049 :
16050 : {
16051 : char *payto_uri;
16052 :
16053 0 : payto_uri = TALER_reserve_make_payto (pg->exchange_url,
16054 : reserve_pub);
16055 0 : TALER_payto_hash (payto_uri,
16056 : &h_payto);
16057 0 : GNUNET_free (payto_uri);
16058 : }
16059 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16060 : "call_purse_merge",
16061 : params,
16062 : rs);
16063 : }
16064 :
16065 :
16066 : /**
16067 : * Function called insert request to merge a purse into a reserve by the
16068 : * respective purse merge key. The purse must not have been merged into a
16069 : * different reserve.
16070 : *
16071 : * @param cls the @e cls of this struct with the plugin-specific state
16072 : * @param purse_pub purse to merge
16073 : * @param merge_sig signature affirming the merge
16074 : * @param merge_timestamp time of the merge
16075 : * @param reserve_sig signature of the reserve affirming the merge
16076 : * @param purse_fee amount to charge the reserve for the purse creation, NULL to use the quota
16077 : * @param reserve_pub public key of the reserve to credit
16078 : * @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already
16079 : * @param[out] no_reserve set to true if @a reserve_pub is not a known reserve
16080 : * @param[out] insufficient_funds set to true if @a reserve_pub has insufficient capacity to create another purse
16081 : * @return transaction status code
16082 : */
16083 : static enum GNUNET_DB_QueryStatus
16084 0 : postgres_do_reserve_purse (
16085 : void *cls,
16086 : const struct TALER_PurseContractPublicKeyP *purse_pub,
16087 : const struct TALER_PurseMergeSignatureP *merge_sig,
16088 : const struct GNUNET_TIME_Timestamp merge_timestamp,
16089 : const struct TALER_ReserveSignatureP *reserve_sig,
16090 : const struct TALER_Amount *purse_fee,
16091 : const struct TALER_ReservePublicKeyP *reserve_pub,
16092 : bool *in_conflict,
16093 : bool *no_reserve,
16094 : bool *insufficient_funds)
16095 : {
16096 0 : struct PostgresClosure *pg = cls;
16097 : struct TALER_Amount zero_fee;
16098 : struct TALER_PaytoHashP h_payto;
16099 0 : struct GNUNET_PQ_QueryParam params[] = {
16100 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
16101 0 : GNUNET_PQ_query_param_auto_from_type (merge_sig),
16102 0 : GNUNET_PQ_query_param_timestamp (&merge_timestamp),
16103 0 : GNUNET_PQ_query_param_auto_from_type (reserve_sig),
16104 0 : GNUNET_PQ_query_param_bool (NULL == purse_fee),
16105 0 : TALER_PQ_query_param_amount (NULL == purse_fee
16106 : ? &zero_fee
16107 : : purse_fee),
16108 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
16109 0 : GNUNET_PQ_query_param_auto_from_type (&h_payto),
16110 : GNUNET_PQ_query_param_end
16111 : };
16112 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16113 0 : GNUNET_PQ_result_spec_bool ("insufficient_funds",
16114 : insufficient_funds),
16115 0 : GNUNET_PQ_result_spec_bool ("conflict",
16116 : in_conflict),
16117 0 : GNUNET_PQ_result_spec_bool ("no_reserve",
16118 : no_reserve),
16119 : GNUNET_PQ_result_spec_end
16120 : };
16121 :
16122 : {
16123 : char *payto_uri;
16124 :
16125 0 : payto_uri = TALER_reserve_make_payto (pg->exchange_url,
16126 : reserve_pub);
16127 0 : TALER_payto_hash (payto_uri,
16128 : &h_payto);
16129 0 : GNUNET_free (payto_uri);
16130 : }
16131 0 : GNUNET_assert (GNUNET_OK ==
16132 : TALER_amount_set_zero (pg->currency,
16133 : &zero_fee));
16134 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16135 : "call_reserve_purse",
16136 : params,
16137 : rs);
16138 : }
16139 :
16140 :
16141 : /**
16142 : * Function called to approve merging of a purse with
16143 : * an account, made by the receiving account.
16144 : *
16145 : * @param cls the @e cls of this struct with the plugin-specific state
16146 : * @param purse_pub public key of the purse
16147 : * @param[out] merge_sig set to the signature confirming the merge
16148 : * @param[out] merge_timestamp set to the time of the merge
16149 : * @param[out] partner_url set to the URL of the target exchange, or NULL if the target exchange is us. To be freed by the caller.
16150 : * @param[out] reserve_pub set to the public key of the reserve/account being credited
16151 : * @return transaction status code
16152 : */
16153 : static enum GNUNET_DB_QueryStatus
16154 0 : postgres_select_purse_merge (
16155 : void *cls,
16156 : const struct TALER_PurseContractPublicKeyP *purse_pub,
16157 : struct TALER_PurseMergeSignatureP *merge_sig,
16158 : struct GNUNET_TIME_Timestamp *merge_timestamp,
16159 : char **partner_url,
16160 : struct TALER_ReservePublicKeyP *reserve_pub)
16161 : {
16162 0 : struct PostgresClosure *pg = cls;
16163 0 : struct GNUNET_PQ_QueryParam params[] = {
16164 0 : GNUNET_PQ_query_param_auto_from_type (purse_pub),
16165 : GNUNET_PQ_query_param_end
16166 : };
16167 : bool is_null;
16168 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16169 0 : GNUNET_PQ_result_spec_auto_from_type ("merge_sig",
16170 : merge_sig),
16171 0 : GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
16172 : reserve_pub),
16173 0 : GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
16174 : merge_timestamp),
16175 0 : GNUNET_PQ_result_spec_allow_null (
16176 : GNUNET_PQ_result_spec_string ("partner_base_url",
16177 : partner_url),
16178 : &is_null),
16179 : GNUNET_PQ_result_spec_end
16180 : };
16181 :
16182 0 : *partner_url = NULL;
16183 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16184 : "select_purse_merge",
16185 : params,
16186 : rs);
16187 : }
16188 :
16189 :
16190 : /**
16191 : * Function called to persist a signature that
16192 : * prove that the client requested an
16193 : * account history. Debits the @a history_fee from
16194 : * the reserve (if possible).
16195 : *
16196 : * @param cls the @e cls of this struct with the plugin-specific state
16197 : * @param reserve_pub account that the history was requested for
16198 : * @param reserve_sig signature affirming the request
16199 : * @param request_timestamp when was the request made
16200 : * @param history_fee how much should the @a reserve_pub be charged for the request
16201 : * @param[out] balance_ok set to TRUE if the reserve balance
16202 : * was sufficient
16203 : * @param[out] idempotent set to TRUE if the request is already in the DB
16204 : * @return transaction status code
16205 : */
16206 : static enum GNUNET_DB_QueryStatus
16207 0 : postgres_insert_history_request (
16208 : void *cls,
16209 : const struct TALER_ReservePublicKeyP *reserve_pub,
16210 : const struct TALER_ReserveSignatureP *reserve_sig,
16211 : struct GNUNET_TIME_Timestamp request_timestamp,
16212 : const struct TALER_Amount *history_fee,
16213 : bool *balance_ok,
16214 : bool *idempotent)
16215 : {
16216 0 : struct PostgresClosure *pg = cls;
16217 0 : struct GNUNET_PQ_QueryParam params[] = {
16218 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
16219 0 : GNUNET_PQ_query_param_auto_from_type (reserve_sig),
16220 0 : GNUNET_PQ_query_param_timestamp (&request_timestamp),
16221 0 : TALER_PQ_query_param_amount (history_fee),
16222 : GNUNET_PQ_query_param_end
16223 : };
16224 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16225 0 : GNUNET_PQ_result_spec_bool ("balance_ok",
16226 : balance_ok),
16227 0 : GNUNET_PQ_result_spec_bool ("idempotent",
16228 : idempotent),
16229 : GNUNET_PQ_result_spec_end
16230 : };
16231 :
16232 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16233 : "call_history_request",
16234 : params,
16235 : rs);
16236 : }
16237 :
16238 :
16239 : /**
16240 : * Function called to initiate closure of an account.
16241 : *
16242 : * @param cls the @e cls of this struct with the plugin-specific state
16243 : * @param reserve_pub public key of the account to close
16244 : * @param reserve_sig signature affiming that the account is to be closed
16245 : * @param request_timestamp time of the close request (client-side?)
16246 : * @param[out] final_balance set to the final balance in the account that will be wired back to the origin account
16247 : * @return transaction status code
16248 : */
16249 : static enum GNUNET_DB_QueryStatus
16250 0 : postgres_insert_close_request (
16251 : void *cls,
16252 : const struct TALER_ReservePublicKeyP *reserve_pub,
16253 : const struct TALER_ReserveSignatureP *reserve_sig,
16254 : struct GNUNET_TIME_Timestamp request_timestamp,
16255 : struct TALER_Amount *final_balance)
16256 : {
16257 0 : struct PostgresClosure *pg = cls;
16258 0 : struct GNUNET_PQ_QueryParam params[] = {
16259 0 : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
16260 0 : GNUNET_PQ_query_param_timestamp (&request_timestamp),
16261 0 : GNUNET_PQ_query_param_auto_from_type (reserve_sig),
16262 : GNUNET_PQ_query_param_end
16263 : };
16264 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16265 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("out_final_balance",
16266 : final_balance),
16267 : GNUNET_PQ_result_spec_end
16268 : };
16269 :
16270 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16271 : "call_account_close",
16272 : params,
16273 : rs);
16274 : }
16275 :
16276 :
16277 : /**
16278 : * Function called to persist a request to drain profits.
16279 : *
16280 : * @param cls the @e cls of this struct with the plugin-specific state
16281 : * @param wtid wire transfer ID to use
16282 : * @param account_section account to drain
16283 : * @param payto_uri account to wire funds to
16284 : * @param request_timestamp when was the request made
16285 : * @param amount amount to wire
16286 : * @param master_sig signature affirming the operation
16287 : * @return transaction status code
16288 : */
16289 : static enum GNUNET_DB_QueryStatus
16290 0 : postgres_insert_drain_profit (
16291 : void *cls,
16292 : const struct TALER_WireTransferIdentifierRawP *wtid,
16293 : const char *account_section,
16294 : const char *payto_uri,
16295 : struct GNUNET_TIME_Timestamp request_timestamp,
16296 : const struct TALER_Amount *amount,
16297 : const struct TALER_MasterSignatureP *master_sig)
16298 : {
16299 0 : struct PostgresClosure *pg = cls;
16300 0 : struct GNUNET_PQ_QueryParam params[] = {
16301 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
16302 0 : GNUNET_PQ_query_param_string (account_section),
16303 0 : GNUNET_PQ_query_param_string (payto_uri),
16304 0 : GNUNET_PQ_query_param_timestamp (&request_timestamp),
16305 0 : TALER_PQ_query_param_amount (amount),
16306 0 : GNUNET_PQ_query_param_auto_from_type (master_sig),
16307 : GNUNET_PQ_query_param_end
16308 : };
16309 :
16310 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
16311 : "drain_profit_insert",
16312 : params);
16313 : }
16314 :
16315 :
16316 : /**
16317 : * Get profit drain operation ready to execute.
16318 : *
16319 : * @param cls the @e cls of this struct with the plugin-specific state
16320 : * @param[out] serial set to serial ID of the entry
16321 : * @param[out] wtid set set to wire transfer ID to use
16322 : * @param[out] account_section set to account to drain
16323 : * @param[out] payto_uri set to account to wire funds to
16324 : * @param[out] request_timestamp set to time of the signature
16325 : * @param[out] amount set to amount to wire
16326 : * @param[out] master_sig set to signature affirming the operation
16327 : * @return transaction status code
16328 : */
16329 : static enum GNUNET_DB_QueryStatus
16330 0 : postgres_profit_drains_get_pending (
16331 : void *cls,
16332 : uint64_t *serial,
16333 : struct TALER_WireTransferIdentifierRawP *wtid,
16334 : char **account_section,
16335 : char **payto_uri,
16336 : struct GNUNET_TIME_Timestamp *request_timestamp,
16337 : struct TALER_Amount *amount,
16338 : struct TALER_MasterSignatureP *master_sig)
16339 : {
16340 0 : struct PostgresClosure *pg = cls;
16341 0 : struct GNUNET_PQ_QueryParam params[] = {
16342 : GNUNET_PQ_query_param_end
16343 : };
16344 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16345 0 : GNUNET_PQ_result_spec_uint64 ("profit_drain_serial_id",
16346 : serial),
16347 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid",
16348 : wtid),
16349 0 : GNUNET_PQ_result_spec_string ("account_section",
16350 : account_section),
16351 0 : GNUNET_PQ_result_spec_string ("payto_uri",
16352 : payto_uri),
16353 0 : GNUNET_PQ_result_spec_timestamp ("trigger_date",
16354 : request_timestamp),
16355 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
16356 : amount),
16357 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
16358 : master_sig),
16359 : GNUNET_PQ_result_spec_end
16360 : };
16361 :
16362 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16363 : "get_ready_profit_drain",
16364 : params,
16365 : rs);
16366 : }
16367 :
16368 :
16369 : /**
16370 : * Function called to get information about a profit drain event.
16371 : *
16372 : * @param cls the @e cls of this struct with the plugin-specific state
16373 : * @param wtid wire transfer ID to look up drain event for
16374 : * @param[out] serial set to serial ID of the entry
16375 : * @param[out] account_section set to account to drain
16376 : * @param[out] payto_uri set to account to wire funds to
16377 : * @param[out] request_timestamp set to time of the signature
16378 : * @param[out] amount set to amount to wire
16379 : * @param[out] master_sig set to signature affirming the operation
16380 : * @return transaction status code
16381 : */
16382 : static enum GNUNET_DB_QueryStatus
16383 0 : postgres_get_drain_profit (
16384 : void *cls,
16385 : const struct TALER_WireTransferIdentifierRawP *wtid,
16386 : uint64_t *serial,
16387 : char **account_section,
16388 : char **payto_uri,
16389 : struct GNUNET_TIME_Timestamp *request_timestamp,
16390 : struct TALER_Amount *amount,
16391 : struct TALER_MasterSignatureP *master_sig)
16392 : {
16393 0 : struct PostgresClosure *pg = cls;
16394 0 : struct GNUNET_PQ_QueryParam params[] = {
16395 0 : GNUNET_PQ_query_param_auto_from_type (wtid),
16396 : GNUNET_PQ_query_param_end
16397 : };
16398 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16399 0 : GNUNET_PQ_result_spec_uint64 ("profit_drain_serial_id",
16400 : serial),
16401 0 : GNUNET_PQ_result_spec_string ("account_section",
16402 : account_section),
16403 0 : GNUNET_PQ_result_spec_string ("payto_uri",
16404 : payto_uri),
16405 0 : GNUNET_PQ_result_spec_timestamp ("trigger_date",
16406 : request_timestamp),
16407 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
16408 : amount),
16409 0 : GNUNET_PQ_result_spec_auto_from_type ("master_sig",
16410 : master_sig),
16411 : GNUNET_PQ_result_spec_end
16412 : };
16413 :
16414 0 : return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
16415 : "get_profit_drain",
16416 : params,
16417 : rs);
16418 : }
16419 :
16420 :
16421 : /**
16422 : * Set profit drain operation to finished.
16423 : *
16424 : * @param cls the @e cls of this struct with the plugin-specific state
16425 : * @param serial serial ID of the entry to mark finished
16426 : * @return transaction status code
16427 : */
16428 : static enum GNUNET_DB_QueryStatus
16429 0 : postgres_profit_drains_set_finished (
16430 : void *cls,
16431 : uint64_t serial)
16432 : {
16433 0 : struct PostgresClosure *pg = cls;
16434 0 : struct GNUNET_PQ_QueryParam params[] = {
16435 0 : GNUNET_PQ_query_param_uint64 (&serial),
16436 : GNUNET_PQ_query_param_end
16437 : };
16438 :
16439 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
16440 : "drain_profit_set_finished",
16441 : params);
16442 : }
16443 :
16444 :
16445 : /**
16446 : * Insert KYC requirement for @a h_payto account into table.
16447 : *
16448 : * @param cls closure
16449 : * @param provider_section provider that must be checked
16450 : * @param h_payto account that must be KYC'ed
16451 : * @param[out] requirement_row set to legitimization requirement row for this check
16452 : * @return database transaction status
16453 : */
16454 : static enum GNUNET_DB_QueryStatus
16455 0 : postgres_insert_kyc_requirement_for_account (
16456 : void *cls,
16457 : const char *provider_section,
16458 : const struct TALER_PaytoHashP *h_payto,
16459 : uint64_t *requirement_row)
16460 : {
16461 0 : struct PostgresClosure *pg = cls;
16462 0 : struct GNUNET_PQ_QueryParam params[] = {
16463 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16464 0 : GNUNET_PQ_query_param_string (provider_section),
16465 : GNUNET_PQ_query_param_end
16466 : };
16467 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16468 0 : GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
16469 : requirement_row),
16470 : GNUNET_PQ_result_spec_end
16471 : };
16472 :
16473 0 : return GNUNET_PQ_eval_prepared_singleton_select (
16474 : pg->conn,
16475 : "insert_legitimization_requirement",
16476 : params,
16477 : rs);
16478 : }
16479 :
16480 :
16481 : /**
16482 : * Begin KYC requirement process.
16483 : *
16484 : * @param cls closure
16485 : * @param h_payto account that must be KYC'ed
16486 : * @param provider_section provider that must be checked
16487 : * @param provider_account_id provider account ID
16488 : * @param provider_legitimization_id provider legitimization ID
16489 : * @param[out] process_row row the process is stored under
16490 : * @return database transaction status
16491 : */
16492 : static enum GNUNET_DB_QueryStatus
16493 0 : postgres_insert_kyc_requirement_process (
16494 : void *cls,
16495 : const struct TALER_PaytoHashP *h_payto,
16496 : const char *provider_section,
16497 : const char *provider_account_id,
16498 : const char *provider_legitimization_id,
16499 : uint64_t *process_row)
16500 : {
16501 0 : struct PostgresClosure *pg = cls;
16502 0 : struct GNUNET_PQ_QueryParam params[] = {
16503 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16504 0 : GNUNET_PQ_query_param_string (provider_section),
16505 : (NULL != provider_account_id)
16506 0 : ? GNUNET_PQ_query_param_string (provider_account_id)
16507 0 : : GNUNET_PQ_query_param_null (),
16508 : (NULL != provider_legitimization_id)
16509 0 : ? GNUNET_PQ_query_param_string (provider_legitimization_id)
16510 0 : : GNUNET_PQ_query_param_null (),
16511 : GNUNET_PQ_query_param_end
16512 : };
16513 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16514 0 : GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
16515 : process_row),
16516 : GNUNET_PQ_result_spec_end
16517 : };
16518 :
16519 0 : return GNUNET_PQ_eval_prepared_singleton_select (
16520 : pg->conn,
16521 : "insert_legitimization_process",
16522 : params,
16523 : rs);
16524 : }
16525 :
16526 :
16527 : /**
16528 : * Update KYC requirement check with provider-linkage and/or
16529 : * expiration data.
16530 : *
16531 : * @param cls closure
16532 : * @param process_row row to select by
16533 : * @param provider_section provider that must be checked (technically redundant)
16534 : * @param h_payto account that must be KYC'ed (helps access by shard, otherwise also redundant)
16535 : * @param provider_account_id provider account ID
16536 : * @param provider_legitimization_id provider legitimization ID
16537 : * @param expiration how long is this KYC check set to be valid (in the past if invalid)
16538 : * @return database transaction status
16539 : */
16540 : static enum GNUNET_DB_QueryStatus
16541 0 : postgres_update_kyc_process_by_row (
16542 : void *cls,
16543 : uint64_t process_row,
16544 : const char *provider_section,
16545 : const struct TALER_PaytoHashP *h_payto,
16546 : const char *provider_account_id,
16547 : const char *provider_legitimization_id,
16548 : struct GNUNET_TIME_Absolute expiration)
16549 : {
16550 0 : struct PostgresClosure *pg = cls;
16551 0 : struct GNUNET_PQ_QueryParam params[] = {
16552 0 : GNUNET_PQ_query_param_uint64 (&process_row),
16553 0 : GNUNET_PQ_query_param_string (provider_section),
16554 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16555 : (NULL != provider_account_id)
16556 0 : ? GNUNET_PQ_query_param_string (provider_account_id)
16557 0 : : GNUNET_PQ_query_param_null (),
16558 : (NULL != provider_legitimization_id)
16559 0 : ? GNUNET_PQ_query_param_string (provider_legitimization_id)
16560 0 : : GNUNET_PQ_query_param_null (),
16561 0 : GNUNET_PQ_query_param_absolute_time (&expiration),
16562 : GNUNET_PQ_query_param_end
16563 : };
16564 : enum GNUNET_DB_QueryStatus qs;
16565 :
16566 0 : qs = GNUNET_PQ_eval_prepared_non_select (
16567 : pg->conn,
16568 : "update_legitimization_process",
16569 : params);
16570 0 : if (qs <= 0)
16571 : {
16572 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
16573 : "Failed to update legitimization process: %d\n",
16574 : qs);
16575 0 : return qs;
16576 : }
16577 0 : if (GNUNET_TIME_absolute_is_future (expiration))
16578 : {
16579 : enum GNUNET_DB_QueryStatus qs2;
16580 0 : struct TALER_KycCompletedEventP rep = {
16581 0 : .header.size = htons (sizeof (rep)),
16582 0 : .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
16583 : .h_payto = *h_payto
16584 : };
16585 0 : uint32_t trigger_type = 1;
16586 0 : struct GNUNET_PQ_QueryParam params2[] = {
16587 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16588 0 : GNUNET_PQ_query_param_uint32 (&trigger_type),
16589 : GNUNET_PQ_query_param_end
16590 : };
16591 :
16592 0 : postgres_event_notify (pg,
16593 : &rep.header,
16594 : NULL,
16595 : 0);
16596 0 : qs2 = GNUNET_PQ_eval_prepared_non_select (
16597 : pg->conn,
16598 : "alert_kyc_status_change",
16599 : params2);
16600 0 : if (qs2 < 0)
16601 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
16602 : "Failed to store KYC alert: %d\n",
16603 : qs2);
16604 : }
16605 0 : return qs;
16606 : }
16607 :
16608 :
16609 : /**
16610 : * Lookup KYC requirement.
16611 : *
16612 : * @param cls closure
16613 : * @param requirement_row identifies requirement to look up
16614 : * @param[out] requirements provider that must be checked
16615 : * @param[out] h_payto account that must be KYC'ed
16616 : * @return database transaction status
16617 : */
16618 : static enum GNUNET_DB_QueryStatus
16619 0 : postgres_lookup_kyc_requirement_by_row (
16620 : void *cls,
16621 : uint64_t requirement_row,
16622 : char **requirements,
16623 : struct TALER_PaytoHashP *h_payto)
16624 : {
16625 0 : struct PostgresClosure *pg = cls;
16626 0 : struct GNUNET_PQ_QueryParam params[] = {
16627 0 : GNUNET_PQ_query_param_uint64 (&requirement_row),
16628 : GNUNET_PQ_query_param_end
16629 : };
16630 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16631 0 : GNUNET_PQ_result_spec_string ("required_checks",
16632 : requirements),
16633 0 : GNUNET_PQ_result_spec_auto_from_type ("h_payto",
16634 : h_payto),
16635 : GNUNET_PQ_result_spec_end
16636 : };
16637 :
16638 0 : return GNUNET_PQ_eval_prepared_singleton_select (
16639 : pg->conn,
16640 : "lookup_legitimization_requirement_by_row",
16641 : params,
16642 : rs);
16643 : }
16644 :
16645 :
16646 : /**
16647 : * Lookup KYC provider meta data.
16648 : *
16649 : * @param cls closure
16650 : * @param provider_section provider that must be checked
16651 : * @param h_payto account that must be KYC'ed
16652 : * @param[out] process_row row with the legitimization data
16653 : * @param[out] expiration how long is this KYC check set to be valid (in the past if invalid)
16654 : * @param[out] provider_account_id provider account ID
16655 : * @param[out] provider_legitimization_id provider legitimization ID
16656 : * @return database transaction status
16657 : */
16658 : static enum GNUNET_DB_QueryStatus
16659 0 : postgres_lookup_kyc_process_by_account (
16660 : void *cls,
16661 : const char *provider_section,
16662 : const struct TALER_PaytoHashP *h_payto,
16663 : uint64_t *process_row,
16664 : struct GNUNET_TIME_Absolute *expiration,
16665 : char **provider_account_id,
16666 : char **provider_legitimization_id)
16667 : {
16668 0 : struct PostgresClosure *pg = cls;
16669 0 : struct GNUNET_PQ_QueryParam params[] = {
16670 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16671 0 : GNUNET_PQ_query_param_string (provider_section),
16672 : GNUNET_PQ_query_param_end
16673 : };
16674 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16675 0 : GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
16676 : process_row),
16677 0 : GNUNET_PQ_result_spec_absolute_time ("expiration_time",
16678 : expiration),
16679 0 : GNUNET_PQ_result_spec_allow_null (
16680 : GNUNET_PQ_result_spec_string ("provider_user_id",
16681 : provider_account_id),
16682 : NULL),
16683 0 : GNUNET_PQ_result_spec_allow_null (
16684 : GNUNET_PQ_result_spec_string ("provider_legitimization_id",
16685 : provider_legitimization_id),
16686 : NULL),
16687 : GNUNET_PQ_result_spec_end
16688 : };
16689 :
16690 0 : *provider_account_id = NULL;
16691 0 : *provider_legitimization_id = NULL;
16692 0 : return GNUNET_PQ_eval_prepared_singleton_select (
16693 : pg->conn,
16694 : "lookup_process_by_account",
16695 : params,
16696 : rs);
16697 : }
16698 :
16699 :
16700 : /**
16701 : * Lookup an
16702 : * @a h_payto by @a provider_legitimization_id.
16703 : *
16704 : * @param cls closure
16705 : * @param provider_section
16706 : * @param provider_legitimization_id legi to look up
16707 : * @param[out] h_payto where to write the result
16708 : * @param[out] process_row where to write the row of the entry
16709 : * @return database transaction status
16710 : */
16711 : static enum GNUNET_DB_QueryStatus
16712 0 : postgres_kyc_provider_account_lookup (
16713 : void *cls,
16714 : const char *provider_section,
16715 : const char *provider_legitimization_id,
16716 : struct TALER_PaytoHashP *h_payto,
16717 : uint64_t *process_row)
16718 : {
16719 0 : struct PostgresClosure *pg = cls;
16720 0 : struct GNUNET_PQ_QueryParam params[] = {
16721 0 : GNUNET_PQ_query_param_string (provider_section),
16722 0 : GNUNET_PQ_query_param_string (provider_legitimization_id),
16723 : GNUNET_PQ_query_param_end
16724 : };
16725 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16726 0 : GNUNET_PQ_result_spec_auto_from_type ("h_payto",
16727 : h_payto),
16728 0 : GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
16729 : process_row),
16730 : GNUNET_PQ_result_spec_end
16731 : };
16732 :
16733 0 : return GNUNET_PQ_eval_prepared_singleton_select (
16734 : pg->conn,
16735 : "get_wire_target_by_legitimization_id",
16736 : params,
16737 : rs);
16738 : }
16739 :
16740 :
16741 : /**
16742 : * Closure for #get_wire_fees_cb().
16743 : */
16744 : struct GetLegitimizationsContext
16745 : {
16746 : /**
16747 : * Function to call per result.
16748 : */
16749 : TALER_EXCHANGEDB_SatisfiedProviderCallback cb;
16750 :
16751 : /**
16752 : * Closure for @e cb.
16753 : */
16754 : void *cb_cls;
16755 :
16756 : /**
16757 : * Plugin context.
16758 : */
16759 : struct PostgresClosure *pg;
16760 :
16761 : /**
16762 : * Flag set to #GNUNET_OK as long as everything is fine.
16763 : */
16764 : enum GNUNET_GenericReturnValue status;
16765 :
16766 : };
16767 :
16768 :
16769 : /**
16770 : * Invoke the callback for each result.
16771 : *
16772 : * @param cls a `struct GetLegitimizationsContext *`
16773 : * @param result SQL result
16774 : * @param num_results number of rows in @a result
16775 : */
16776 : static void
16777 0 : get_legitimizations_cb (void *cls,
16778 : PGresult *result,
16779 : unsigned int num_results)
16780 : {
16781 0 : struct GetLegitimizationsContext *ctx = cls;
16782 :
16783 0 : for (unsigned int i = 0; i < num_results; i++)
16784 : {
16785 : char *provider_section;
16786 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16787 0 : GNUNET_PQ_result_spec_string ("provider_section",
16788 : &provider_section),
16789 : GNUNET_PQ_result_spec_end
16790 : };
16791 :
16792 0 : if (GNUNET_OK !=
16793 0 : GNUNET_PQ_extract_result (result,
16794 : rs,
16795 : i))
16796 : {
16797 0 : GNUNET_break (0);
16798 0 : ctx->status = GNUNET_SYSERR;
16799 0 : return;
16800 : }
16801 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
16802 : "Found satisfied LEGI: %s\n",
16803 : provider_section);
16804 0 : ctx->cb (ctx->cb_cls,
16805 : provider_section);
16806 0 : GNUNET_PQ_cleanup_result (rs);
16807 : }
16808 : }
16809 :
16810 :
16811 : /**
16812 : * Call us on KYC processes satisfied for the given
16813 : * account.
16814 : *
16815 : * @param cls the @e cls of this struct with the plugin-specific state
16816 : * @param h_payto account identifier
16817 : * @param spc function to call for each satisfied KYC process
16818 : * @param spc_cls closure for @a spc
16819 : * @return transaction status code
16820 : */
16821 : static enum GNUNET_DB_QueryStatus
16822 0 : postgres_select_satisfied_kyc_processes (
16823 : void *cls,
16824 : const struct TALER_PaytoHashP *h_payto,
16825 : TALER_EXCHANGEDB_SatisfiedProviderCallback spc,
16826 : void *spc_cls)
16827 : {
16828 0 : struct PostgresClosure *pg = cls;
16829 : struct GNUNET_TIME_Absolute now
16830 0 : = GNUNET_TIME_absolute_get ();
16831 0 : struct GNUNET_PQ_QueryParam params[] = {
16832 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16833 0 : GNUNET_PQ_query_param_absolute_time (&now),
16834 : GNUNET_PQ_query_param_end
16835 : };
16836 0 : struct GetLegitimizationsContext ctx = {
16837 : .cb = spc,
16838 : .cb_cls = spc_cls,
16839 : .pg = pg,
16840 : .status = GNUNET_OK
16841 : };
16842 : enum GNUNET_DB_QueryStatus qs;
16843 :
16844 0 : qs = GNUNET_PQ_eval_prepared_multi_select (
16845 : pg->conn,
16846 : "get_satisfied_legitimizations",
16847 : params,
16848 : &get_legitimizations_cb,
16849 : &ctx);
16850 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
16851 : "Satisfied LEGI check returned %d\n",
16852 : qs);
16853 0 : if (GNUNET_OK != ctx.status)
16854 0 : return GNUNET_DB_STATUS_HARD_ERROR;
16855 0 : return qs;
16856 : }
16857 :
16858 :
16859 : /**
16860 : * Closure for #get_kyc_amounts_cb().
16861 : */
16862 : struct KycAmountCheckContext
16863 : {
16864 : /**
16865 : * Function to call per result.
16866 : */
16867 : TALER_EXCHANGEDB_KycAmountCallback cb;
16868 :
16869 : /**
16870 : * Closure for @e cb.
16871 : */
16872 : void *cb_cls;
16873 :
16874 : /**
16875 : * Plugin context.
16876 : */
16877 : struct PostgresClosure *pg;
16878 :
16879 : /**
16880 : * Flag set to #GNUNET_OK as long as everything is fine.
16881 : */
16882 : enum GNUNET_GenericReturnValue status;
16883 :
16884 : };
16885 :
16886 :
16887 : /**
16888 : * Invoke the callback for each result.
16889 : *
16890 : * @param cls a `struct KycAmountCheckContext *`
16891 : * @param result SQL result
16892 : * @param num_results number of rows in @a result
16893 : */
16894 : static void
16895 0 : get_kyc_amounts_cb (void *cls,
16896 : PGresult *result,
16897 : unsigned int num_results)
16898 : {
16899 0 : struct KycAmountCheckContext *ctx = cls;
16900 0 : struct PostgresClosure *pg = ctx->pg;
16901 :
16902 0 : for (unsigned int i = 0; i < num_results; i++)
16903 : {
16904 : struct GNUNET_TIME_Absolute date;
16905 : struct TALER_Amount amount;
16906 0 : struct GNUNET_PQ_ResultSpec rs[] = {
16907 0 : TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
16908 : &amount),
16909 0 : GNUNET_PQ_result_spec_absolute_time ("date",
16910 : &date),
16911 : GNUNET_PQ_result_spec_end
16912 : };
16913 : enum GNUNET_GenericReturnValue ret;
16914 :
16915 0 : if (GNUNET_OK !=
16916 0 : GNUNET_PQ_extract_result (result,
16917 : rs,
16918 : i))
16919 : {
16920 0 : GNUNET_break (0);
16921 0 : ctx->status = GNUNET_SYSERR;
16922 0 : return;
16923 : }
16924 0 : ret = ctx->cb (ctx->cb_cls,
16925 : &amount,
16926 : date);
16927 0 : GNUNET_PQ_cleanup_result (rs);
16928 0 : switch (ret)
16929 : {
16930 0 : case GNUNET_OK:
16931 0 : continue;
16932 0 : case GNUNET_NO:
16933 0 : break;
16934 0 : case GNUNET_SYSERR:
16935 0 : ctx->status = GNUNET_SYSERR;
16936 0 : break;
16937 : }
16938 0 : break;
16939 : }
16940 : }
16941 :
16942 :
16943 : /**
16944 : * Call @a kac on withdrawn amounts after @a time_limit which are relevant
16945 : * for a KYC trigger for a the (debited) account identified by @a h_payto.
16946 : *
16947 : * @param cls the @e cls of this struct with the plugin-specific state
16948 : * @param h_payto account identifier
16949 : * @param time_limit oldest transaction that could be relevant
16950 : * @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK).
16951 : * @param kac_cls closure for @a kac
16952 : * @return transaction status code, @a kac aborting with #GNUNET_NO is not an error
16953 : */
16954 : static enum GNUNET_DB_QueryStatus
16955 0 : postgres_select_withdraw_amounts_for_kyc_check (
16956 : void *cls,
16957 : const struct TALER_PaytoHashP *h_payto,
16958 : struct GNUNET_TIME_Absolute time_limit,
16959 : TALER_EXCHANGEDB_KycAmountCallback kac,
16960 : void *kac_cls)
16961 : {
16962 0 : struct PostgresClosure *pg = cls;
16963 0 : struct GNUNET_PQ_QueryParam params[] = {
16964 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
16965 0 : GNUNET_PQ_query_param_absolute_time (&time_limit),
16966 : GNUNET_PQ_query_param_end
16967 : };
16968 0 : struct KycAmountCheckContext ctx = {
16969 : .cb = kac,
16970 : .cb_cls = kac_cls,
16971 : .pg = pg,
16972 : .status = GNUNET_OK
16973 : };
16974 : enum GNUNET_DB_QueryStatus qs;
16975 :
16976 0 : qs = GNUNET_PQ_eval_prepared_multi_select (
16977 : pg->conn,
16978 : "select_kyc_relevant_withdraw_events",
16979 : params,
16980 : &get_kyc_amounts_cb,
16981 : &ctx);
16982 0 : if (GNUNET_OK != ctx.status)
16983 0 : return GNUNET_DB_STATUS_HARD_ERROR;
16984 0 : return qs;
16985 : }
16986 :
16987 :
16988 : /**
16989 : * Call @a kac on deposited amounts after @a time_limit which are relevant for a
16990 : * KYC trigger for a the (credited) account identified by @a h_payto.
16991 : *
16992 : * @param cls the @e cls of this struct with the plugin-specific state
16993 : * @param h_payto account identifier
16994 : * @param time_limit oldest transaction that could be relevant
16995 : * @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK).
16996 : * @param kac_cls closure for @a kac
16997 : * @return transaction status code, @a kac aborting with #GNUNET_NO is not an error
16998 : */
16999 : static enum GNUNET_DB_QueryStatus
17000 0 : postgres_select_aggregation_amounts_for_kyc_check (
17001 : void *cls,
17002 : const struct TALER_PaytoHashP *h_payto,
17003 : struct GNUNET_TIME_Absolute time_limit,
17004 : TALER_EXCHANGEDB_KycAmountCallback kac,
17005 : void *kac_cls)
17006 : {
17007 0 : struct PostgresClosure *pg = cls;
17008 0 : struct GNUNET_PQ_QueryParam params[] = {
17009 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
17010 0 : GNUNET_PQ_query_param_absolute_time (&time_limit),
17011 : GNUNET_PQ_query_param_end
17012 : };
17013 0 : struct KycAmountCheckContext ctx = {
17014 : .cb = kac,
17015 : .cb_cls = kac_cls,
17016 : .pg = pg,
17017 : .status = GNUNET_OK
17018 : };
17019 : enum GNUNET_DB_QueryStatus qs;
17020 :
17021 0 : qs = GNUNET_PQ_eval_prepared_multi_select (
17022 : pg->conn,
17023 : "select_kyc_relevant_aggregation_events",
17024 : params,
17025 : &get_kyc_amounts_cb,
17026 : &ctx);
17027 0 : if (GNUNET_OK != ctx.status)
17028 0 : return GNUNET_DB_STATUS_HARD_ERROR;
17029 0 : return qs;
17030 : }
17031 :
17032 :
17033 : /**
17034 : * Call @a kac on merged reserve amounts after @a time_limit which are relevant for a
17035 : * KYC trigger for a the wallet identified by @a h_payto.
17036 : *
17037 : * @param cls the @e cls of this struct with the plugin-specific state
17038 : * @param h_payto account identifier
17039 : * @param time_limit oldest transaction that could be relevant
17040 : * @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK).
17041 : * @param kac_cls closure for @a kac
17042 : * @return transaction status code, @a kac aborting with #GNUNET_NO is not an error
17043 : */
17044 : static enum GNUNET_DB_QueryStatus
17045 0 : postgres_select_merge_amounts_for_kyc_check (
17046 : void *cls,
17047 : const struct TALER_PaytoHashP *h_payto,
17048 : struct GNUNET_TIME_Absolute time_limit,
17049 : TALER_EXCHANGEDB_KycAmountCallback kac,
17050 : void *kac_cls)
17051 : {
17052 0 : struct PostgresClosure *pg = cls;
17053 0 : struct GNUNET_PQ_QueryParam params[] = {
17054 0 : GNUNET_PQ_query_param_auto_from_type (h_payto),
17055 0 : GNUNET_PQ_query_param_absolute_time (&time_limit),
17056 : GNUNET_PQ_query_param_end
17057 : };
17058 0 : struct KycAmountCheckContext ctx = {
17059 : .cb = kac,
17060 : .cb_cls = kac_cls,
17061 : .pg = pg,
17062 : .status = GNUNET_OK
17063 : };
17064 : enum GNUNET_DB_QueryStatus qs;
17065 :
17066 0 : qs = GNUNET_PQ_eval_prepared_multi_select (
17067 : pg->conn,
17068 : "select_kyc_relevant_merge_events",
17069 : params,
17070 : &get_kyc_amounts_cb,
17071 : &ctx);
17072 0 : if (GNUNET_OK != ctx.status)
17073 0 : return GNUNET_DB_STATUS_HARD_ERROR;
17074 0 : return qs;
17075 : }
17076 :
17077 :
17078 : /**
17079 : * Initialize Postgres database subsystem.
17080 : *
17081 : * @param cls a configuration instance
17082 : * @return NULL on error, otherwise a `struct
17083 : * TALER_EXCHANGEDB_Plugin`
17084 : */
17085 : void *
17086 21 : libtaler_plugin_exchangedb_postgres_init (void *cls)
17087 : {
17088 21 : const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
17089 : struct PostgresClosure *pg;
17090 : struct TALER_EXCHANGEDB_Plugin *plugin;
17091 :
17092 21 : pg = GNUNET_new (struct PostgresClosure);
17093 21 : pg->cfg = cfg;
17094 21 : if (GNUNET_OK !=
17095 21 : GNUNET_CONFIGURATION_get_value_filename (cfg,
17096 : "exchangedb-postgres",
17097 : "SQL_DIR",
17098 : &pg->sql_dir))
17099 : {
17100 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
17101 : "exchangedb-postgres",
17102 : "CONFIG");
17103 0 : GNUNET_free (pg);
17104 0 : return NULL;
17105 : }
17106 21 : if (GNUNET_OK !=
17107 21 : GNUNET_CONFIGURATION_get_value_string (cfg,
17108 : "exchange",
17109 : "BASE_URL",
17110 : &pg->exchange_url))
17111 : {
17112 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
17113 : "exchange",
17114 : "BASE_URL");
17115 0 : GNUNET_free (pg->sql_dir);
17116 0 : GNUNET_free (pg);
17117 0 : return NULL;
17118 : }
17119 21 : if ( (GNUNET_OK !=
17120 21 : GNUNET_CONFIGURATION_get_value_time (cfg,
17121 : "exchangedb",
17122 : "IDLE_RESERVE_EXPIRATION_TIME",
17123 : &pg->idle_reserve_expiration_time))
17124 21 : ||
17125 : (GNUNET_OK !=
17126 21 : GNUNET_CONFIGURATION_get_value_time (cfg,
17127 : "exchangedb",
17128 : "LEGAL_RESERVE_EXPIRATION_TIME",
17129 : &pg->legal_reserve_expiration_time)) )
17130 : {
17131 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
17132 : "exchangedb",
17133 : "LEGAL/IDLE_RESERVE_EXPIRATION_TIME");
17134 0 : GNUNET_free (pg->exchange_url);
17135 0 : GNUNET_free (pg->sql_dir);
17136 0 : GNUNET_free (pg);
17137 0 : return NULL;
17138 : }
17139 21 : if (GNUNET_OK !=
17140 21 : GNUNET_CONFIGURATION_get_value_time (cfg,
17141 : "exchangedb",
17142 : "AGGREGATOR_SHIFT",
17143 : &pg->aggregator_shift))
17144 : {
17145 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
17146 : "exchangedb",
17147 : "AGGREGATOR_SHIFT");
17148 : }
17149 :
17150 21 : if (GNUNET_OK !=
17151 21 : TALER_config_get_currency (cfg,
17152 : &pg->currency))
17153 : {
17154 0 : GNUNET_free (pg->exchange_url);
17155 0 : GNUNET_free (pg->sql_dir);
17156 0 : GNUNET_free (pg);
17157 0 : return NULL;
17158 : }
17159 21 : if (GNUNET_OK !=
17160 21 : internal_setup (pg,
17161 : true))
17162 : {
17163 21 : GNUNET_free (pg->exchange_url);
17164 21 : GNUNET_free (pg->currency);
17165 21 : GNUNET_free (pg->sql_dir);
17166 21 : GNUNET_free (pg);
17167 21 : return NULL;
17168 : }
17169 :
17170 0 : plugin = GNUNET_new (struct TALER_EXCHANGEDB_Plugin);
17171 0 : plugin->cls = pg;
17172 0 : plugin->drop_tables = &postgres_drop_tables;
17173 0 : plugin->create_tables = &postgres_create_tables;
17174 0 : plugin->create_shard_tables = &postgres_create_shard_tables;
17175 0 : plugin->setup_partitions = &postgres_setup_partitions;
17176 0 : plugin->setup_foreign_servers = &postgres_setup_foreign_servers;
17177 0 : plugin->start = &postgres_start;
17178 0 : plugin->start_read_committed = &postgres_start_read_committed;
17179 0 : plugin->start_read_only = &postgres_start_read_only;
17180 0 : plugin->commit = &postgres_commit;
17181 0 : plugin->preflight = &postgres_preflight;
17182 0 : plugin->rollback = &postgres_rollback;
17183 0 : plugin->event_listen = &postgres_event_listen;
17184 0 : plugin->event_listen_cancel = &postgres_event_listen_cancel;
17185 0 : plugin->event_notify = &postgres_event_notify;
17186 0 : plugin->insert_denomination_info = &postgres_insert_denomination_info;
17187 0 : plugin->get_denomination_info = &postgres_get_denomination_info;
17188 0 : plugin->iterate_denomination_info = &postgres_iterate_denomination_info;
17189 0 : plugin->iterate_denominations = &postgres_iterate_denominations;
17190 0 : plugin->iterate_active_signkeys = &postgres_iterate_active_signkeys;
17191 0 : plugin->iterate_active_auditors = &postgres_iterate_active_auditors;
17192 0 : plugin->iterate_auditor_denominations =
17193 : &postgres_iterate_auditor_denominations;
17194 0 : plugin->reserves_get = &postgres_reserves_get;
17195 0 : plugin->reserves_get_origin = &postgres_reserves_get_origin;
17196 0 : plugin->drain_kyc_alert = &postgres_drain_kyc_alert;
17197 0 : plugin->reserves_in_insert = &postgres_reserves_in_insert;
17198 0 : plugin->get_withdraw_info = &postgres_get_withdraw_info;
17199 0 : plugin->do_withdraw = &postgres_do_withdraw;
17200 0 : plugin->do_batch_withdraw = &postgres_do_batch_withdraw;
17201 0 : plugin->do_batch_withdraw_insert = &postgres_do_batch_withdraw_insert;
17202 0 : plugin->do_deposit = &postgres_do_deposit;
17203 0 : plugin->do_melt = &postgres_do_melt;
17204 0 : plugin->do_refund = &postgres_do_refund;
17205 0 : plugin->do_recoup = &postgres_do_recoup;
17206 0 : plugin->do_recoup_refresh = &postgres_do_recoup_refresh;
17207 0 : plugin->get_reserve_balance = &postgres_get_reserve_balance;
17208 0 : plugin->get_reserve_history = &postgres_get_reserve_history;
17209 0 : plugin->get_reserve_status = &postgres_get_reserve_status;
17210 0 : plugin->free_reserve_history = &common_free_reserve_history;
17211 0 : plugin->count_known_coins = &postgres_count_known_coins;
17212 0 : plugin->ensure_coin_known = &postgres_ensure_coin_known;
17213 0 : plugin->get_known_coin = &postgres_get_known_coin;
17214 0 : plugin->get_coin_denomination = &postgres_get_coin_denomination;
17215 0 : plugin->have_deposit2 = &postgres_have_deposit2;
17216 0 : plugin->aggregate = &postgres_aggregate;
17217 : plugin->create_aggregation_transient
17218 0 : = &postgres_create_aggregation_transient;
17219 : plugin->select_aggregation_transient
17220 0 : = &postgres_select_aggregation_transient;
17221 : plugin->find_aggregation_transient
17222 0 : = &postgres_find_aggregation_transient;
17223 : plugin->update_aggregation_transient
17224 0 : = &postgres_update_aggregation_transient;
17225 : plugin->delete_aggregation_transient
17226 0 : = &postgres_delete_aggregation_transient;
17227 0 : plugin->get_ready_deposit = &postgres_get_ready_deposit;
17228 0 : plugin->insert_deposit = &postgres_insert_deposit;
17229 0 : plugin->insert_refund = &postgres_insert_refund;
17230 0 : plugin->select_refunds_by_coin = &postgres_select_refunds_by_coin;
17231 0 : plugin->get_melt = &postgres_get_melt;
17232 0 : plugin->insert_refresh_reveal = &postgres_insert_refresh_reveal;
17233 0 : plugin->get_refresh_reveal = &postgres_get_refresh_reveal;
17234 0 : plugin->get_link_data = &postgres_get_link_data;
17235 0 : plugin->get_coin_transactions = &postgres_get_coin_transactions;
17236 0 : plugin->free_coin_transaction_list = &common_free_coin_transaction_list;
17237 0 : plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
17238 0 : plugin->lookup_transfer_by_deposit = &postgres_lookup_transfer_by_deposit;
17239 0 : plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
17240 0 : plugin->insert_wire_fee = &postgres_insert_wire_fee;
17241 0 : plugin->insert_global_fee = &postgres_insert_global_fee;
17242 0 : plugin->get_wire_fee = &postgres_get_wire_fee;
17243 0 : plugin->get_global_fee = &postgres_get_global_fee;
17244 0 : plugin->get_global_fees = &postgres_get_global_fees;
17245 0 : plugin->get_expired_reserves = &postgres_get_expired_reserves;
17246 0 : plugin->insert_reserve_closed = &postgres_insert_reserve_closed;
17247 0 : plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert;
17248 0 : plugin->wire_prepare_data_mark_finished =
17249 : &postgres_wire_prepare_data_mark_finished;
17250 0 : plugin->wire_prepare_data_mark_failed =
17251 : &postgres_wire_prepare_data_mark_failed;
17252 0 : plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get;
17253 0 : plugin->start_deferred_wire_out = &postgres_start_deferred_wire_out;
17254 0 : plugin->store_wire_transfer_out = &postgres_store_wire_transfer_out;
17255 0 : plugin->gc = &postgres_gc;
17256 : plugin->select_deposits_above_serial_id
17257 0 : = &postgres_select_deposits_above_serial_id;
17258 : plugin->select_purse_deposits_above_serial_id
17259 0 : = &postgres_select_purse_deposits_above_serial_id;
17260 : plugin->select_account_merges_above_serial_id
17261 0 : = &postgres_select_account_merges_above_serial_id;
17262 : plugin->select_purse_merges_above_serial_id
17263 0 : = &postgres_select_purse_merges_above_serial_id;
17264 : plugin->select_history_requests_above_serial_id
17265 0 : = &postgres_select_history_requests_above_serial_id;
17266 : plugin->select_purse_refunds_above_serial_id
17267 0 : = &postgres_select_purse_refunds_above_serial_id;
17268 : plugin->select_purse_deposits_by_purse
17269 0 : = &postgres_select_purse_deposits_by_purse;
17270 : plugin->select_refreshes_above_serial_id
17271 0 : = &postgres_select_refreshes_above_serial_id;
17272 : plugin->select_refunds_above_serial_id
17273 0 : = &postgres_select_refunds_above_serial_id;
17274 : plugin->select_reserves_in_above_serial_id
17275 0 : = &postgres_select_reserves_in_above_serial_id;
17276 : plugin->select_reserves_in_above_serial_id_by_account
17277 0 : = &postgres_select_reserves_in_above_serial_id_by_account;
17278 : plugin->select_withdrawals_above_serial_id
17279 0 : = &postgres_select_withdrawals_above_serial_id;
17280 : plugin->select_wire_out_above_serial_id
17281 0 : = &postgres_select_wire_out_above_serial_id;
17282 : plugin->select_wire_out_above_serial_id_by_account
17283 0 : = &postgres_select_wire_out_above_serial_id_by_account;
17284 : plugin->select_recoup_above_serial_id
17285 0 : = &postgres_select_recoup_above_serial_id;
17286 : plugin->select_recoup_refresh_above_serial_id
17287 0 : = &postgres_select_recoup_refresh_above_serial_id;
17288 : plugin->select_reserve_closed_above_serial_id
17289 0 : = &postgres_select_reserve_closed_above_serial_id;
17290 : plugin->get_reserve_by_h_blind
17291 0 : = &postgres_get_reserve_by_h_blind;
17292 : plugin->get_old_coin_by_h_blind
17293 0 : = &postgres_get_old_coin_by_h_blind;
17294 : plugin->insert_denomination_revocation
17295 0 : = &postgres_insert_denomination_revocation;
17296 : plugin->get_denomination_revocation
17297 0 : = &postgres_get_denomination_revocation;
17298 : plugin->select_deposits_missing_wire
17299 0 : = &postgres_select_deposits_missing_wire;
17300 : plugin->lookup_auditor_timestamp
17301 0 : = &postgres_lookup_auditor_timestamp;
17302 : plugin->lookup_auditor_status
17303 0 : = &postgres_lookup_auditor_status;
17304 : plugin->insert_auditor
17305 0 : = &postgres_insert_auditor;
17306 : plugin->update_auditor
17307 0 : = &postgres_update_auditor;
17308 : plugin->lookup_wire_timestamp
17309 0 : = &postgres_lookup_wire_timestamp;
17310 : plugin->insert_wire
17311 0 : = &postgres_insert_wire;
17312 : plugin->update_wire
17313 0 : = &postgres_update_wire;
17314 : plugin->get_wire_accounts
17315 0 : = &postgres_get_wire_accounts;
17316 : plugin->get_wire_fees
17317 0 : = &postgres_get_wire_fees;
17318 : plugin->insert_signkey_revocation
17319 0 : = &postgres_insert_signkey_revocation;
17320 : plugin->lookup_signkey_revocation
17321 0 : = &postgres_lookup_signkey_revocation;
17322 : plugin->lookup_denomination_key
17323 0 : = &postgres_lookup_denomination_key;
17324 : plugin->insert_auditor_denom_sig
17325 0 : = &postgres_insert_auditor_denom_sig;
17326 : plugin->select_auditor_denom_sig
17327 0 : = &postgres_select_auditor_denom_sig;
17328 : plugin->lookup_wire_fee_by_time
17329 0 : = &postgres_lookup_wire_fee_by_time;
17330 : plugin->lookup_global_fee_by_time
17331 0 : = &postgres_lookup_global_fee_by_time;
17332 : plugin->add_denomination_key
17333 0 : = &postgres_add_denomination_key;
17334 : plugin->activate_signing_key
17335 0 : = &postgres_activate_signing_key;
17336 : plugin->lookup_signing_key
17337 0 : = &postgres_lookup_signing_key;
17338 : plugin->lookup_serial_by_table
17339 0 : = &postgres_lookup_serial_by_table;
17340 : plugin->lookup_records_by_table
17341 0 : = &postgres_lookup_records_by_table;
17342 : plugin->insert_records_by_table
17343 0 : = &postgres_insert_records_by_table;
17344 : plugin->begin_shard
17345 0 : = &postgres_begin_shard;
17346 : plugin->abort_shard
17347 0 : = &postgres_abort_shard;
17348 : plugin->complete_shard
17349 0 : = &postgres_complete_shard;
17350 : plugin->begin_revolving_shard
17351 0 : = &postgres_begin_revolving_shard;
17352 : plugin->release_revolving_shard
17353 0 : = &postgres_release_revolving_shard;
17354 : plugin->delete_shard_locks
17355 0 : = &postgres_delete_shard_locks;
17356 : plugin->set_extension_config
17357 0 : = &postgres_set_extension_config;
17358 : plugin->get_extension_config
17359 0 : = &postgres_get_extension_config;
17360 : plugin->insert_partner
17361 0 : = &postgres_insert_partner;
17362 : plugin->insert_contract
17363 0 : = &postgres_insert_contract;
17364 : plugin->select_contract
17365 0 : = &postgres_select_contract;
17366 : plugin->select_contract_by_purse
17367 0 : = &postgres_select_contract_by_purse;
17368 : plugin->insert_purse_request
17369 0 : = &postgres_insert_purse_request;
17370 : plugin->select_purse_request
17371 0 : = &postgres_select_purse_request;
17372 : plugin->expire_purse
17373 0 : = &postgres_expire_purse;
17374 : plugin->select_purse
17375 0 : = &postgres_select_purse;
17376 : plugin->select_purse_by_merge_pub
17377 0 : = &postgres_select_purse_by_merge_pub;
17378 : plugin->do_purse_deposit
17379 0 : = &postgres_do_purse_deposit;
17380 : plugin->set_purse_balance
17381 0 : = &postgres_set_purse_balance;
17382 : plugin->get_purse_deposit
17383 0 : = &postgres_get_purse_deposit;
17384 : plugin->do_purse_merge
17385 0 : = &postgres_do_purse_merge;
17386 : plugin->do_reserve_purse
17387 0 : = &postgres_do_reserve_purse;
17388 : plugin->select_purse_merge
17389 0 : = &postgres_select_purse_merge;
17390 : plugin->insert_history_request
17391 0 : = &postgres_insert_history_request;
17392 : plugin->insert_close_request
17393 0 : = &postgres_insert_close_request;
17394 : plugin->insert_drain_profit
17395 0 : = &postgres_insert_drain_profit;
17396 : plugin->profit_drains_get_pending
17397 0 : = &postgres_profit_drains_get_pending;
17398 : plugin->get_drain_profit
17399 0 : = &postgres_get_drain_profit;
17400 : plugin->profit_drains_set_finished
17401 0 : = &postgres_profit_drains_set_finished;
17402 : plugin->insert_kyc_requirement_for_account
17403 0 : = &postgres_insert_kyc_requirement_for_account;
17404 : plugin->insert_kyc_requirement_process
17405 0 : = &postgres_insert_kyc_requirement_process;
17406 : plugin->update_kyc_process_by_row
17407 0 : = &postgres_update_kyc_process_by_row;
17408 : plugin->lookup_kyc_requirement_by_row
17409 0 : = &postgres_lookup_kyc_requirement_by_row;
17410 : plugin->lookup_kyc_process_by_account
17411 0 : = &postgres_lookup_kyc_process_by_account;
17412 : plugin->kyc_provider_account_lookup
17413 0 : = &postgres_kyc_provider_account_lookup;
17414 : plugin->select_satisfied_kyc_processes
17415 0 : = &postgres_select_satisfied_kyc_processes;
17416 : plugin->select_withdraw_amounts_for_kyc_check
17417 0 : = &postgres_select_withdraw_amounts_for_kyc_check;
17418 : plugin->select_aggregation_amounts_for_kyc_check
17419 0 : = &postgres_select_aggregation_amounts_for_kyc_check;
17420 : plugin->select_merge_amounts_for_kyc_check
17421 0 : = &postgres_select_merge_amounts_for_kyc_check;
17422 0 : return plugin;
17423 : }
17424 :
17425 :
17426 : /**
17427 : * Shutdown Postgres database subsystem.
17428 : *
17429 : * @param cls a `struct TALER_EXCHANGEDB_Plugin`
17430 : * @return NULL (always)
17431 : */
17432 : void *
17433 0 : libtaler_plugin_exchangedb_postgres_done (void *cls)
17434 : {
17435 0 : struct TALER_EXCHANGEDB_Plugin *plugin = cls;
17436 0 : struct PostgresClosure *pg = plugin->cls;
17437 :
17438 0 : if (NULL != pg->conn)
17439 : {
17440 0 : GNUNET_PQ_disconnect (pg->conn);
17441 0 : pg->conn = NULL;
17442 : }
17443 0 : GNUNET_free (pg->exchange_url);
17444 0 : GNUNET_free (pg->sql_dir);
17445 0 : GNUNET_free (pg->currency);
17446 0 : GNUNET_free (pg);
17447 0 : GNUNET_free (plugin);
17448 0 : return NULL;
17449 : }
17450 :
17451 :
17452 : /* end of plugin_exchangedb_postgres.c */
|