Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2026 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/test_denomination_revocations.c
18 : * @brief tests for the exchangedb functions whose primary table is
19 : * `denomination_revocations`
20 : * @author Christian Grothoff
21 : *
22 : * Covers #TALER_EXCHANGEDB_insert_denomination_revocation() and
23 : * #TALER_EXCHANGEDB_get_denomination_revocation().
24 : *
25 : * `denomination_revocations` references `denominations`, so a denomination
26 : * has to exist first; that is what TDB_denom() is for. The check for the
27 : * `recoup_possible` flag of #TALER_EXCHANGEDB_iterate_denominations() lives
28 : * here too, since that flag is what the revocation row is *for*.
29 : */
30 : #include "test_common.h"
31 : #include "exchange-database/insert_denomination_revocation.h"
32 : #include "exchange-database/get_denomination_revocation.h"
33 : #include "exchange-database/iterate_denominations.h"
34 :
35 :
36 : /**
37 : * Closure for #recoup_cb().
38 : */
39 : struct RecoupContext
40 : {
41 : /**
42 : * Denomination we are looking for.
43 : */
44 : const struct TALER_DenominationHashP *h_denom_pub;
45 :
46 : /**
47 : * How many times did we see it?
48 : */
49 : unsigned int matched;
50 :
51 : /**
52 : * Recoup flag reported for it.
53 : */
54 : bool recoup_possible;
55 : };
56 :
57 :
58 : /**
59 : * Callback for #TALER_EXCHANGEDB_iterate_denominations().
60 : *
61 : * @param cls a `struct RecoupContext *`
62 : * @param denom_pub public key of the denomination
63 : * @param h_denom_pub hash of @a denom_pub
64 : * @param meta meta data of the denomination
65 : * @param master_sig master signature over the denomination
66 : * @param recoup_possible true if the denomination was revoked
67 : */
68 : static void
69 6 : recoup_cb (void *cls,
70 : const struct TALER_DenominationPublicKey *denom_pub,
71 : const struct TALER_DenominationHashP *h_denom_pub,
72 : const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
73 : const struct TALER_MasterSignatureP *master_sig,
74 : bool recoup_possible)
75 : {
76 6 : struct RecoupContext *ctx = cls;
77 :
78 : (void) denom_pub;
79 : (void) meta;
80 : (void) master_sig;
81 6 : if (0 != GNUNET_memcmp (h_denom_pub,
82 : ctx->h_denom_pub))
83 3 : return;
84 3 : ctx->matched++;
85 3 : ctx->recoup_possible = recoup_possible;
86 : }
87 :
88 :
89 : /**
90 : * A denomination that does not exist cannot be revoked, and is reported as
91 : * not revoked.
92 : *
93 : * @param pg the database context
94 : * @return 0 on success
95 : */
96 : static int
97 1 : check_unknown_denomination (struct TALER_EXCHANGEDB_PostgresContext *pg)
98 : {
99 : struct TALER_DenominationHashP h_denom_pub;
100 : struct TALER_MasterSignatureP master_sig;
101 : struct TALER_MasterSignatureP got;
102 : uint64_t rowid;
103 :
104 1 : TDB_FILL (h_denom_pub,
105 : 1);
106 1 : TDB_FILL (master_sig,
107 : 1);
108 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
109 : TALER_EXCHANGEDB_get_denomination_revocation (pg,
110 : &h_denom_pub,
111 : &got,
112 : &rowid));
113 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
114 : TALER_EXCHANGEDB_insert_denomination_revocation (pg,
115 : &h_denom_pub,
116 : &master_sig));
117 1 : FAILIF (0 != TDB_count (pg,
118 : "FROM denomination_revocations"));
119 1 : return 0;
120 : }
121 :
122 :
123 : /**
124 : * Revoking a denomination records the signature and flips
125 : * `recoup_possible`.
126 : *
127 : * @param pg the database context
128 : * @return 0 on success
129 : */
130 : static int
131 1 : check_revoke (struct TALER_EXCHANGEDB_PostgresContext *pg)
132 : {
133 : struct TDB_Denom revoked;
134 : struct TDB_Denom intact;
135 : struct TALER_MasterSignatureP master_sig;
136 : struct TALER_MasterSignatureP got;
137 : struct RecoupContext ctx;
138 1 : uint64_t rowid = 0;
139 :
140 1 : TDB_denom (pg,
141 : 10,
142 : "5",
143 : "0.1",
144 : &revoked);
145 1 : TDB_denom (pg,
146 : 11,
147 : "5",
148 : "0.1",
149 : &intact);
150 1 : TDB_FILL (master_sig,
151 : 42);
152 :
153 : /* before the revocation, recoup is not possible */
154 1 : memset (&ctx,
155 : 0,
156 : sizeof (ctx));
157 1 : ctx.h_denom_pub = &revoked.h_denom_pub;
158 1 : FAILIF_C (0 >=
159 : TALER_EXCHANGEDB_iterate_denominations (pg,
160 : &recoup_cb,
161 : &ctx),
162 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
163 1 : FAILIF_C (1 != ctx.matched,
164 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
165 1 : FAILIF_C (ctx.recoup_possible,
166 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
167 :
168 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
169 : TALER_EXCHANGEDB_insert_denomination_revocation (
170 : pg,
171 : &revoked.h_denom_pub,
172 : &master_sig),
173 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
174 1 : memset (&got,
175 : 0,
176 : sizeof (got));
177 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
178 : TALER_EXCHANGEDB_get_denomination_revocation (
179 : pg,
180 : &revoked.h_denom_pub,
181 : &got,
182 : &rowid),
183 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
184 1 : FAILIF_C (0 != GNUNET_memcmp (&got,
185 : &master_sig),
186 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
187 1 : FAILIF_C (0 == rowid,
188 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
189 :
190 : /* now recoup is possible for the revoked denomination... */
191 1 : memset (&ctx,
192 : 0,
193 : sizeof (ctx));
194 1 : ctx.h_denom_pub = &revoked.h_denom_pub;
195 1 : FAILIF_C (0 >=
196 : TALER_EXCHANGEDB_iterate_denominations (pg,
197 : &recoup_cb,
198 : &ctx),
199 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
200 1 : FAILIF_C (1 != ctx.matched,
201 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
202 1 : FAILIF_C (! ctx.recoup_possible,
203 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
204 :
205 : /* ...and only for that one */
206 1 : memset (&ctx,
207 : 0,
208 : sizeof (ctx));
209 1 : ctx.h_denom_pub = &intact.h_denom_pub;
210 1 : FAILIF_C (0 >=
211 : TALER_EXCHANGEDB_iterate_denominations (pg,
212 : &recoup_cb,
213 : &ctx),
214 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
215 1 : FAILIF_C (1 != ctx.matched,
216 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
217 1 : FAILIF_C (ctx.recoup_possible,
218 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
219 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
220 : TALER_EXCHANGEDB_get_denomination_revocation (
221 : pg,
222 : &intact.h_denom_pub,
223 : &got,
224 : &rowid),
225 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
226 1 : FAILIF_C (1 != TDB_count (pg,
227 : "FROM denomination_revocations"),
228 : TDB_denom_free (&revoked); TDB_denom_free (&intact));
229 1 : TDB_denom_free (&revoked);
230 1 : TDB_denom_free (&intact);
231 1 : return 0;
232 : }
233 :
234 :
235 : /**
236 : * The checks to run, in order.
237 : */
238 : static const struct TDB_Test tests[] = {
239 : { "denomination-revocations-unknown-denomination",
240 : &check_unknown_denomination },
241 : { "denomination-revocations-revoke",
242 : &check_revoke },
243 : { NULL, NULL }
244 : };
245 :
246 :
247 : int
248 1 : main (int argc,
249 : char *const *argv)
250 : {
251 1 : return TDB_main (argc,
252 : argv,
253 : "test-denomination-revocations",
254 : "Tests for the exchangedb `denomination_revocations' table",
255 : tests);
256 : }
257 :
258 :
259 : /* end of test_denomination_revocations.c */
|