Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 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 : * @file src/backenddb/insert_exchange_wire_fee.c
18 : * @brief Implementation of the insert_exchange_wire_fee function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <taler/taler_pq_lib.h>
23 : #include "merchant-database/insert_exchange_wire_fee.h"
24 : #include "helper.h"
25 :
26 :
27 : enum GNUNET_DB_QueryStatus
28 32 : TALER_MERCHANTDB_insert_exchange_wire_fee (
29 : struct TALER_MERCHANTDB_PostgresContext *pg,
30 : const struct TALER_MasterPublicKeyP *master_pub,
31 : const struct GNUNET_HashCode *h_wire_method,
32 : const struct TALER_WireFeeSet *fees,
33 : struct GNUNET_TIME_Timestamp start_date,
34 : struct GNUNET_TIME_Timestamp end_date,
35 : const struct TALER_MasterSignatureP *master_sig)
36 : {
37 32 : struct GNUNET_PQ_QueryParam params[] = {
38 32 : GNUNET_PQ_query_param_auto_from_type (master_pub),
39 32 : GNUNET_PQ_query_param_auto_from_type (h_wire_method),
40 32 : TALER_PQ_query_param_amount_with_currency (pg->conn,
41 : &fees->wire),
42 32 : TALER_PQ_query_param_amount_with_currency (pg->conn,
43 : &fees->closing),
44 32 : GNUNET_PQ_query_param_timestamp (&start_date),
45 32 : GNUNET_PQ_query_param_timestamp (&end_date),
46 32 : GNUNET_PQ_query_param_auto_from_type (master_sig),
47 : GNUNET_PQ_query_param_end
48 : };
49 : bool inserted;
50 : bool identical;
51 32 : struct GNUNET_PQ_ResultSpec rs[] = {
52 32 : GNUNET_PQ_result_spec_bool ("inserted",
53 : &inserted),
54 32 : GNUNET_PQ_result_spec_bool ("identical",
55 : &identical),
56 : GNUNET_PQ_result_spec_end
57 : };
58 : enum GNUNET_DB_QueryStatus qs;
59 :
60 : /* no preflight check here, run in its own transaction by the caller */
61 : /* Note: a bare 'ON CONFLICT DO NOTHING' would silently discard a
62 : *changed* fee for an existing (master_pub, h_wire_method,
63 : start_date), leaving us computing with the stale one. The CTE
64 : therefore also reports whether the row that is already there is the
65 : one we were asked to store; if it is not, the exchange contradicted
66 : a fee it signed earlier and the caller must not proceed. */
67 32 : PREPARE (pg,
68 : "insert_exchange_wire_fee",
69 : "WITH ins AS ("
70 : " INSERT INTO merchant.merchant_exchange_wire_fees"
71 : " (master_pub"
72 : " ,h_wire_method"
73 : " ,wire_fee"
74 : " ,closing_fee"
75 : " ,start_date"
76 : " ,end_date"
77 : " ,master_sig)"
78 : " VALUES "
79 : " ($1, $2, $3, $4, $5, $6, $7)"
80 : " ON CONFLICT (master_pub,h_wire_method,start_date)"
81 : " DO NOTHING"
82 : " RETURNING 1)"
83 : "SELECT"
84 : " EXISTS (SELECT 1 FROM ins) AS inserted"
85 : ",EXISTS (SELECT 1"
86 : " FROM merchant.merchant_exchange_wire_fees"
87 : " WHERE master_pub=$1"
88 : " AND h_wire_method=$2"
89 : " AND start_date=$5"
90 : " AND end_date=$6"
91 : " AND wire_fee=$3"
92 : " AND closing_fee=$4"
93 : " AND master_sig=$7) AS identical");
94 32 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
95 : "Storing wire fee for %s starting at %s of %s\n",
96 : TALER_B2S (master_pub),
97 : GNUNET_TIME_timestamp2s (start_date),
98 : TALER_amount2s (&fees->wire));
99 32 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
100 : "insert_exchange_wire_fee",
101 : params,
102 : rs);
103 32 : if (qs < 0)
104 0 : return qs;
105 32 : GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
106 32 : if (inserted)
107 30 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
108 2 : if (identical)
109 1 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
110 : /* FIXME: should properly distinguish this error from
111 : actual database failures; change signature of function eventually! */
112 1 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
113 : "Exchange %s signed a different wire fee for the same wire method and start date %s; keeping the fee we already have on file\n",
114 : TALER_B2S (master_pub),
115 : GNUNET_TIME_timestamp2s (start_date));
116 1 : GNUNET_break (0);
117 1 : return GNUNET_DB_STATUS_HARD_ERROR;
118 : }
|