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 exchangedb/add_policy_fulfillment_proof.c
18 : * @brief Implementation of the add_policy_fulfillment_proof function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "taler/platform.h" /* UNNECESSARY? */
22 : #include "taler/taler_error_codes.h" /* UNNECESSARY? */
23 : #include "taler/taler_dbevents.h" /* UNNECESSARY? */
24 : #include "taler/taler_pq_lib.h"
25 : #include "exchange-database/add_policy_fulfillment_proof.h"
26 : #include "helper.h"
27 :
28 :
29 : /**
30 : * Compares two indices into an array of hash codes according to
31 : * GNUNET_CRYPTO_hash_cmp of the content at those index positions.
32 : *
33 : * Used in a call qsort_t in order to generate sorted policy_hash_codes.
34 : */
35 : static int
36 0 : hash_code_cmp (
37 : const void *hc1,
38 : const void *hc2,
39 : void *arg)
40 : {
41 0 : size_t i1 = *(size_t *) hc1;
42 0 : size_t i2 = *(size_t *) hc2;
43 0 : const struct TALER_PolicyDetails *d = arg;
44 :
45 0 : return GNUNET_CRYPTO_hash_cmp (&d[i1].hash_code,
46 0 : &d[i2].hash_code);
47 : }
48 :
49 :
50 : enum GNUNET_DB_QueryStatus
51 0 : TALER_EXCHANGEDB_add_policy_fulfillment_proof (
52 : struct TALER_EXCHANGEDB_PostgresContext *pg,
53 : struct TALER_PolicyFulfillmentTransactionData *fulfillment)
54 0 : {
55 : enum GNUNET_DB_QueryStatus qs;
56 0 : size_t count = fulfillment->details_count;
57 : /* FIXME[Oec]: this seems to be prone to VLA attacks */
58 0 : struct GNUNET_HashCode hcs[GNUNET_NZL (count)];
59 :
60 : /* Create the sorted policy_hash_codes */
61 0 : {
62 0 : size_t idx[GNUNET_NZL (count)];
63 0 : for (size_t i = 0; i < count; i++)
64 0 : idx[i] = i;
65 :
66 : /* Sort the indices according to the hash codes of the corresponding
67 : * details. */
68 0 : qsort_r (idx,
69 : count,
70 : sizeof(size_t),
71 : hash_code_cmp,
72 0 : fulfillment->details);
73 :
74 : /* Finally, concatenate all hash_codes in sorted order */
75 0 : for (size_t i = 0; i < count; i++)
76 0 : hcs[i] = fulfillment->details[idx[i]].hash_code;
77 : }
78 :
79 :
80 : /* Now, add the proof to the policy_fulfillments table, retrieve the
81 : * record_id */
82 : {
83 0 : struct GNUNET_PQ_QueryParam params[] = {
84 0 : GNUNET_PQ_query_param_timestamp (&fulfillment->timestamp),
85 0 : TALER_PQ_query_param_json (fulfillment->proof),
86 0 : GNUNET_PQ_query_param_auto_from_type (&fulfillment->h_proof),
87 0 : TALER_PQ_query_param_array_hash_code (count, hcs, pg->conn),
88 : GNUNET_PQ_query_param_end
89 : };
90 0 : struct GNUNET_PQ_ResultSpec rs[] = {
91 0 : GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
92 : &fulfillment->fulfillment_id),
93 : GNUNET_PQ_result_spec_end
94 : };
95 :
96 0 : PREPARE (pg,
97 : "insert_proof_into_policy_fulfillments",
98 : "INSERT INTO policy_fulfillments"
99 : "(fulfillment_timestamp"
100 : ",fulfillment_proof"
101 : ",h_fulfillment_proof"
102 : ",policy_hash_codes"
103 : ") VALUES ($1, $2::TEXT::JSON, $3, $4)"
104 : " ON CONFLICT DO NOTHING;");
105 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
106 : "insert_proof_into_policy_fulfillments",
107 : params,
108 : rs);
109 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
110 0 : return qs;
111 : }
112 :
113 : /* Now, set the states of each entry corresponding to the hash_codes in
114 : * policy_details accordingly */
115 0 : for (size_t i = 0; i < count; i++)
116 : {
117 0 : struct TALER_PolicyDetails *pos = &fulfillment->details[i];
118 : {
119 0 : struct GNUNET_PQ_QueryParam params[] = {
120 0 : GNUNET_PQ_query_param_auto_from_type (&pos->hash_code),
121 0 : GNUNET_PQ_query_param_timestamp (&pos->deadline),
122 0 : TALER_PQ_query_param_amount (pg->conn,
123 0 : &pos->commitment),
124 0 : TALER_PQ_query_param_amount (pg->conn,
125 0 : &pos->accumulated_total),
126 0 : TALER_PQ_query_param_amount (pg->conn,
127 0 : &pos->policy_fee),
128 0 : TALER_PQ_query_param_amount (pg->conn,
129 0 : &pos->transferable_amount),
130 0 : GNUNET_PQ_query_param_auto_from_type (&pos->fulfillment_state),
131 : GNUNET_PQ_query_param_end
132 : };
133 :
134 0 : PREPARE (pg,
135 : "update_policy_details",
136 : "UPDATE policy_details SET"
137 : " deadline=$2"
138 : ",commitment=$3"
139 : ",accumulated_total=$4"
140 : ",fee=$5"
141 : ",transferable=$6"
142 : ",fulfillment_state=$7"
143 : " WHERE policy_hash_code=$1;");
144 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
145 : "update_policy_details",
146 : params);
147 0 : if (qs < 0)
148 0 : return qs;
149 : }
150 : }
151 :
152 : /*
153 : * FIXME[oec]-#7999: When all policies of a deposit are fulfilled,
154 : * unblock it and trigger a wire-transfer.
155 : */
156 :
157 0 : return qs;
158 : }
|