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