exchange

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

test_auditor_denom_sigs.c (11807B)


      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_auditor_denom_sigs.c
     18  * @brief tests for the exchangedb functions whose primary table is
     19  *        `auditor_denom_sigs`
     20  * @author Christian Grothoff
     21  *
     22  * Covers #TALER_EXCHANGEDB_insert_auditor_denom_sig(),
     23  * #TALER_EXCHANGEDB_get_auditor_denom_sig() and
     24  * #TALER_EXCHANGEDB_iterate_auditor_denominations().
     25  *
     26  * The table references `auditors` and `denominations`, and the insert
     27  * resolves both by their natural keys inside the statement -- so an unknown
     28  * auditor or denomination has to come back as "nothing inserted".  Fixtures
     29  * come from #TALER_EXCHANGEDB_insert_auditor() and TDB_denom(), whose own
     30  * tables are covered by test_auditors.c and test_denominations.c.
     31  */
     32 #include "test_common.h"
     33 #include "exchange-database/insert_auditor.h"
     34 #include "exchange-database/update_auditor.h"
     35 #include "exchange-database/insert_auditor_denom_sig.h"
     36 #include "exchange-database/get_auditor_denom_sig.h"
     37 #include "exchange-database/iterate_auditor_denominations.h"
     38 
     39 
     40 /**
     41  * Closure for #count_cb().
     42  */
     43 struct CountContext
     44 {
     45   /**
     46    * Auditor we are looking for.
     47    */
     48   const struct TALER_AuditorPublicKeyP *auditor_pub;
     49 
     50   /**
     51    * Denomination we are looking for.
     52    */
     53   const struct TALER_DenominationHashP *h_denom_pub;
     54 
     55   /**
     56    * How many rows did the callback see in total?
     57    */
     58   unsigned int total;
     59 
     60   /**
     61    * How many times did we see the pair we are after?
     62    */
     63   unsigned int matched;
     64 
     65   /**
     66    * Signature reported for that pair.
     67    */
     68   struct TALER_AuditorSignatureP auditor_sig;
     69 };
     70 
     71 
     72 /**
     73  * Callback for #TALER_EXCHANGEDB_iterate_auditor_denominations().
     74  *
     75  * @param cls a `struct CountContext *`
     76  * @param auditor_pub public key of the auditor
     77  * @param h_denom_pub denomination audited by @a auditor_pub
     78  * @param auditor_sig the auditor's signature
     79  */
     80 static void
     81 count_cb (void *cls,
     82           const struct TALER_AuditorPublicKeyP *auditor_pub,
     83           const struct TALER_DenominationHashP *h_denom_pub,
     84           const struct TALER_AuditorSignatureP *auditor_sig)
     85 {
     86   struct CountContext *ctx = cls;
     87 
     88   ctx->total++;
     89   if ( (0 != GNUNET_memcmp (auditor_pub,
     90                             ctx->auditor_pub)) ||
     91        (0 != GNUNET_memcmp (h_denom_pub,
     92                             ctx->h_denom_pub)) )
     93     return;
     94   ctx->matched++;
     95   ctx->auditor_sig = *auditor_sig;
     96 }
     97 
     98 
     99 /**
    100  * Neither half of the pair existing means nothing is inserted and nothing
    101  * is found.
    102  *
    103  * @param pg the database context
    104  * @return 0 on success
    105  */
    106 static int
    107 check_unknown_references (struct TALER_EXCHANGEDB_PostgresContext *pg)
    108 {
    109   struct TALER_AuditorPublicKeyP auditor_pub;
    110   struct TALER_DenominationHashP h_denom_pub;
    111   struct TALER_AuditorSignatureP auditor_sig;
    112   struct TALER_AuditorSignatureP got;
    113   struct TDB_Denom denom;
    114 
    115   TDB_FILL (auditor_pub,
    116             1);
    117   TDB_FILL (h_denom_pub,
    118             1);
    119   TDB_FILL (auditor_sig,
    120             1);
    121   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    122           TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
    123                                                   &h_denom_pub,
    124                                                   &auditor_pub,
    125                                                   &got));
    126   /* neither the auditor nor the denomination exist */
    127   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    128           TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
    129                                                      &h_denom_pub,
    130                                                      &auditor_pub,
    131                                                      &auditor_sig));
    132   /* the denomination exists, the auditor does not */
    133   TDB_denom (pg,
    134              10,
    135              "5",
    136              "0.1",
    137              &denom);
    138   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    139             TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
    140                                                        &denom.h_denom_pub,
    141                                                        &auditor_pub,
    142                                                        &auditor_sig),
    143             TDB_denom_free (&denom));
    144   /* the auditor exists, the denomination does not */
    145   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    146             TALER_EXCHANGEDB_insert_auditor (pg,
    147                                              &auditor_pub,
    148                                              "https://auditor.example/",
    149                                              "The Auditor",
    150                                              GNUNET_TIME_timestamp_get ()),
    151             TDB_denom_free (&denom));
    152   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    153             TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
    154                                                        &h_denom_pub,
    155                                                        &auditor_pub,
    156                                                        &auditor_sig),
    157             TDB_denom_free (&denom));
    158   FAILIF_C (0 != TDB_count (pg,
    159                             "FROM auditor_denom_sigs"),
    160             TDB_denom_free (&denom));
    161   TDB_denom_free (&denom);
    162   return 0;
    163 }
    164 
    165 
    166 /**
    167  * With both halves present the signature is stored, found and iterated;
    168  * a repeated insert is a no-op.
    169  *
    170  * @param pg the database context
    171  * @return 0 on success
    172  */
    173 static int
    174 check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg)
    175 {
    176   struct TALER_AuditorPublicKeyP auditor_pub;
    177   struct TALER_AuditorSignatureP auditor_sig;
    178   struct TALER_AuditorSignatureP other_sig;
    179   struct TALER_AuditorSignatureP got;
    180   struct TDB_Denom denom;
    181   struct CountContext ctx;
    182 
    183   /* the auditor and denomination from the previous check */
    184   TDB_FILL (auditor_pub,
    185             1);
    186   TDB_FILL (auditor_sig,
    187             1);
    188   TDB_FILL (other_sig,
    189             77);
    190   TDB_denom (pg,
    191              10,
    192              "5",
    193              "0.1",
    194              &denom);
    195   /* TDB_denom() with the same seed builds the same key, so the row is the
    196      one the previous check created; that is exactly what we want here. */
    197   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    198             TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
    199                                                        &denom.h_denom_pub,
    200                                                        &auditor_pub,
    201                                                        &auditor_sig),
    202             TDB_denom_free (&denom));
    203   memset (&got,
    204           0,
    205           sizeof (got));
    206   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    207             TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
    208                                                     &denom.h_denom_pub,
    209                                                     &auditor_pub,
    210                                                     &got),
    211             TDB_denom_free (&denom));
    212   FAILIF_C (0 != GNUNET_memcmp (&got,
    213                                 &auditor_sig),
    214             TDB_denom_free (&denom));
    215 
    216   /* re-inserting with a different signature does nothing (ON CONFLICT DO
    217      NOTHING), and in particular does not overwrite the stored one */
    218   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    219             TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
    220                                                        &denom.h_denom_pub,
    221                                                        &auditor_pub,
    222                                                        &other_sig),
    223             TDB_denom_free (&denom));
    224   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    225             TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
    226                                                     &denom.h_denom_pub,
    227                                                     &auditor_pub,
    228                                                     &got),
    229             TDB_denom_free (&denom));
    230   FAILIF_C (0 != GNUNET_memcmp (&got,
    231                                 &auditor_sig),
    232             TDB_denom_free (&denom));
    233 
    234   memset (&ctx,
    235           0,
    236           sizeof (ctx));
    237   ctx.auditor_pub = &auditor_pub;
    238   ctx.h_denom_pub = &denom.h_denom_pub;
    239   FAILIF_C (0 >=
    240             TALER_EXCHANGEDB_iterate_auditor_denominations (pg,
    241                                                             &count_cb,
    242                                                             &ctx),
    243             TDB_denom_free (&denom));
    244   FAILIF_C (1 != ctx.matched,
    245             TDB_denom_free (&denom));
    246   FAILIF_C (0 != GNUNET_memcmp (&ctx.auditor_sig,
    247                                 &auditor_sig),
    248             TDB_denom_free (&denom));
    249   TDB_denom_free (&denom);
    250   return 0;
    251 }
    252 
    253 
    254 /**
    255  * A disabled auditor keeps its rows but drops out of the iterator.
    256  *
    257  * @param pg the database context
    258  * @return 0 on success
    259  */
    260 static int
    261 check_disabled_auditor (struct TALER_EXCHANGEDB_PostgresContext *pg)
    262 {
    263   struct TALER_AuditorPublicKeyP auditor_pub;
    264   struct TALER_AuditorSignatureP got;
    265   struct TDB_Denom denom;
    266   struct CountContext ctx;
    267 
    268   TDB_FILL (auditor_pub,
    269             1);
    270   TDB_denom (pg,
    271              10,
    272              "5",
    273              "0.1",
    274              &denom);
    275   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    276             TALER_EXCHANGEDB_update_auditor (pg,
    277                                              &auditor_pub,
    278                                              "https://auditor.example/",
    279                                              "The Auditor",
    280                                              GNUNET_TIME_timestamp_get (),
    281                                              false),
    282             TDB_denom_free (&denom));
    283   memset (&ctx,
    284           0,
    285           sizeof (ctx));
    286   ctx.auditor_pub = &auditor_pub;
    287   ctx.h_denom_pub = &denom.h_denom_pub;
    288   FAILIF_C (0 >
    289             TALER_EXCHANGEDB_iterate_auditor_denominations (pg,
    290                                                             &count_cb,
    291                                                             &ctx),
    292             TDB_denom_free (&denom));
    293   FAILIF_C (0 != ctx.matched,
    294             TDB_denom_free (&denom));
    295   FAILIF_C (0 != ctx.total,
    296             TDB_denom_free (&denom));
    297   /* the row itself is untouched, and the direct lookup ignores is_active */
    298   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    299             TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
    300                                                     &denom.h_denom_pub,
    301                                                     &auditor_pub,
    302                                                     &got),
    303             TDB_denom_free (&denom));
    304   FAILIF_C (1 != TDB_count (pg,
    305                             "FROM auditor_denom_sigs"),
    306             TDB_denom_free (&denom));
    307   TDB_denom_free (&denom);
    308   return 0;
    309 }
    310 
    311 
    312 /**
    313  * The checks to run, in order.
    314  */
    315 static const struct TDB_Test tests[] = {
    316   { "auditor-denom-sigs-unknown-references",
    317     &check_unknown_references },
    318   { "auditor-denom-sigs-insert-and-lookup",
    319     &check_insert_and_lookup },
    320   { "auditor-denom-sigs-disabled-auditor",
    321     &check_disabled_auditor },
    322   { NULL, NULL }
    323 };
    324 
    325 
    326 int
    327 main (int argc,
    328       char *const *argv)
    329 {
    330   return TDB_main (argc,
    331                    argv,
    332                    "test-auditor-denom-sigs",
    333                    "Tests for the exchangedb `auditor_denom_sigs' table",
    334                    tests);
    335 }
    336 
    337 
    338 /* end of test_auditor_denom_sigs.c */