exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_denomination_revocations.c (8254B)


      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 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   struct RecoupContext *ctx = cls;
     77 
     78   (void) denom_pub;
     79   (void) meta;
     80   (void) master_sig;
     81   if (0 != GNUNET_memcmp (h_denom_pub,
     82                           ctx->h_denom_pub))
     83     return;
     84   ctx->matched++;
     85   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 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   TDB_FILL (h_denom_pub,
    105             1);
    106   TDB_FILL (master_sig,
    107             1);
    108   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    109           TALER_EXCHANGEDB_get_denomination_revocation (pg,
    110                                                         &h_denom_pub,
    111                                                         &got,
    112                                                         &rowid));
    113   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    114           TALER_EXCHANGEDB_insert_denomination_revocation (pg,
    115                                                            &h_denom_pub,
    116                                                            &master_sig));
    117   FAILIF (0 != TDB_count (pg,
    118                           "FROM denomination_revocations"));
    119   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 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   uint64_t rowid = 0;
    139 
    140   TDB_denom (pg,
    141              10,
    142              "5",
    143              "0.1",
    144              &revoked);
    145   TDB_denom (pg,
    146              11,
    147              "5",
    148              "0.1",
    149              &intact);
    150   TDB_FILL (master_sig,
    151             42);
    152 
    153   /* before the revocation, recoup is not possible */
    154   memset (&ctx,
    155           0,
    156           sizeof (ctx));
    157   ctx.h_denom_pub = &revoked.h_denom_pub;
    158   FAILIF_C (0 >=
    159             TALER_EXCHANGEDB_iterate_denominations (pg,
    160                                                     &recoup_cb,
    161                                                     &ctx),
    162             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    163   FAILIF_C (1 != ctx.matched,
    164             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    165   FAILIF_C (ctx.recoup_possible,
    166             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    167 
    168   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   memset (&got,
    175           0,
    176           sizeof (got));
    177   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   FAILIF_C (0 != GNUNET_memcmp (&got,
    185                                 &master_sig),
    186             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    187   FAILIF_C (0 == rowid,
    188             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    189 
    190   /* now recoup is possible for the revoked denomination... */
    191   memset (&ctx,
    192           0,
    193           sizeof (ctx));
    194   ctx.h_denom_pub = &revoked.h_denom_pub;
    195   FAILIF_C (0 >=
    196             TALER_EXCHANGEDB_iterate_denominations (pg,
    197                                                     &recoup_cb,
    198                                                     &ctx),
    199             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    200   FAILIF_C (1 != ctx.matched,
    201             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    202   FAILIF_C (! ctx.recoup_possible,
    203             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    204 
    205   /* ...and only for that one */
    206   memset (&ctx,
    207           0,
    208           sizeof (ctx));
    209   ctx.h_denom_pub = &intact.h_denom_pub;
    210   FAILIF_C (0 >=
    211             TALER_EXCHANGEDB_iterate_denominations (pg,
    212                                                     &recoup_cb,
    213                                                     &ctx),
    214             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    215   FAILIF_C (1 != ctx.matched,
    216             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    217   FAILIF_C (ctx.recoup_possible,
    218             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    219   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   FAILIF_C (1 != TDB_count (pg,
    227                             "FROM denomination_revocations"),
    228             TDB_denom_free (&revoked); TDB_denom_free (&intact));
    229   TDB_denom_free (&revoked);
    230   TDB_denom_free (&intact);
    231   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 main (int argc,
    249       char *const *argv)
    250 {
    251   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 */