LCOV - code coverage report
Current view: top level - exchangedb - batch_ensure_coin_known.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 215 0
Test Date: 2026-04-14 15:39:31 Functions: 0.0 % 4 0

            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/batch_ensure_coin_known.c
      18              :  * @brief Implementation of the batch_ensure_coin_known function for Postgres
      19              :  * @author Christian Grothoff
      20              :  *
      21              :  * FIXME-#9373: use the array support for postgres to simplify this code!
      22              :  *
      23              :  */
      24              : #include "taler/taler_exchangedb_lib.h"
      25              : #include "taler/taler_pq_lib.h"
      26              : #include "exchange-database/batch_ensure_coin_known.h"
      27              : #include "helper.h"
      28              : 
      29              : 
      30              : static enum GNUNET_DB_QueryStatus
      31            0 : insert1 (struct TALER_EXCHANGEDB_PostgresContext *pg,
      32              :          const struct TALER_CoinPublicInfo coin[1],
      33              :          struct TALER_EXCHANGEDB_CoinInfo result[1])
      34              : {
      35              :   enum GNUNET_DB_QueryStatus qs;
      36            0 :   bool is_denom_pub_hash_null = false;
      37            0 :   bool is_age_hash_null = false;
      38            0 :   struct GNUNET_PQ_QueryParam params[] = {
      39            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
      40            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
      41            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
      42            0 :     TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
      43              :     GNUNET_PQ_query_param_end
      44              :   };
      45            0 :   struct GNUNET_PQ_ResultSpec rs[] = {
      46            0 :     GNUNET_PQ_result_spec_bool ("existed",
      47              :                                 &result[0].existed),
      48            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id",
      49              :                                   &result[0].known_coin_id),
      50            0 :     GNUNET_PQ_result_spec_allow_null (
      51            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
      52              :                                             &result[0].denom_hash),
      53              :       &is_denom_pub_hash_null),
      54            0 :     GNUNET_PQ_result_spec_allow_null (
      55            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
      56              :                                             &result[0].h_age_commitment),
      57              :       &is_age_hash_null),
      58              :     GNUNET_PQ_result_spec_end
      59              :   };
      60              : 
      61            0 :   PREPARE (pg,
      62              :            "batch1_known_coin",
      63              :            "SELECT"
      64              :            " existed1 AS existed"
      65              :            ",known_coin_id1 AS known_coin_id"
      66              :            ",denom_pub_hash1 AS denom_hash"
      67              :            ",age_commitment_hash1 AS h_age_commitment"
      68              :            " FROM exchange_do_batch1_known_coin"
      69              :            "  ($1, $2, $3, $4);"
      70              :            );
      71            0 :   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
      72              :                                                  "batch1_known_coin",
      73              :                                                  params,
      74              :                                                  rs);
      75            0 :   switch (qs)
      76              :   {
      77            0 :   case GNUNET_DB_STATUS_HARD_ERROR:
      78            0 :     GNUNET_break (0);
      79            0 :     return qs;
      80            0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
      81            0 :     return qs;
      82            0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
      83            0 :     GNUNET_break (0); /* should be impossible */
      84            0 :     return GNUNET_DB_STATUS_HARD_ERROR;
      85            0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
      86            0 :     break; /* continued below */
      87              :   }
      88              : 
      89            0 :   if ( (! is_denom_pub_hash_null) &&
      90            0 :        (0 != GNUNET_memcmp (&result[0].denom_hash,
      91              :                             &coin->denom_pub_hash)) )
      92              :   {
      93            0 :     GNUNET_break_op (0);
      94            0 :     result[0].denom_conflict = true;
      95              :   }
      96              : 
      97            0 :   if ( (! is_denom_pub_hash_null) &&
      98            0 :        (0 != GNUNET_memcmp (&result[0].denom_hash,
      99              :                             &coin[0].denom_pub_hash)) )
     100              :   {
     101            0 :     GNUNET_break_op (0);
     102            0 :     result[0].denom_conflict = true;
     103              :   }
     104              : 
     105            0 :   result[0].age_conflict = TALER_AgeCommitmentHashP_NoConflict;
     106              : 
     107            0 :   if (is_age_hash_null != coin[0].no_age_commitment)
     108              :   {
     109            0 :     if (is_age_hash_null)
     110              :     {
     111            0 :       GNUNET_break_op (0);
     112            0 :       result[0].age_conflict = TALER_AgeCommitmentHashP_NullExpected;
     113              :     }
     114              :     else
     115              :     {
     116            0 :       GNUNET_break_op (0);
     117            0 :       result[0].age_conflict = TALER_AgeCommitmentHashP_ValueExpected;
     118              :     }
     119              :   }
     120            0 :   else if ( (! is_age_hash_null) &&
     121            0 :             (0 != GNUNET_memcmp (&result[0].h_age_commitment,
     122              :                                  &coin[0].h_age_commitment)) )
     123              :   {
     124            0 :     GNUNET_break_op (0);
     125            0 :     result[0].age_conflict = TALER_AgeCommitmentHashP_ValueDiffers;
     126              :   }
     127              : 
     128            0 :   return qs;
     129              : }
     130              : 
     131              : 
     132              : static enum GNUNET_DB_QueryStatus
     133            0 : insert2 (struct TALER_EXCHANGEDB_PostgresContext *pg,
     134              :          const struct TALER_CoinPublicInfo coin[2],
     135              :          struct TALER_EXCHANGEDB_CoinInfo result[2])
     136              : {
     137              :   enum GNUNET_DB_QueryStatus qs;
     138            0 :   bool is_denom_pub_hash_null[2] = {false, false};
     139            0 :   bool is_age_hash_null[2] = {false, false};
     140            0 :   struct GNUNET_PQ_QueryParam params[] = {
     141            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
     142            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
     143            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
     144            0 :     TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
     145              : 
     146            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub),
     147            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash),
     148            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment),
     149            0 :     TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
     150              :     GNUNET_PQ_query_param_end
     151              :   };
     152            0 :   struct GNUNET_PQ_ResultSpec rs[] = {
     153            0 :     GNUNET_PQ_result_spec_bool ("existed",
     154              :                                 &result[0].existed),
     155            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id",
     156              :                                   &result[0].known_coin_id),
     157            0 :     GNUNET_PQ_result_spec_allow_null (
     158            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
     159              :                                             &result[0].denom_hash),
     160              :       &is_denom_pub_hash_null[0]),
     161            0 :     GNUNET_PQ_result_spec_allow_null (
     162            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
     163              :                                             &result[0].h_age_commitment),
     164              :       &is_age_hash_null[0]),
     165            0 :     GNUNET_PQ_result_spec_bool ("existed2",
     166            0 :                                 &result[1].existed),
     167            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id2",
     168            0 :                                   &result[1].known_coin_id),
     169            0 :     GNUNET_PQ_result_spec_allow_null (
     170            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2",
     171              :                                             &result[1].denom_hash),
     172              :       &is_denom_pub_hash_null[1]),
     173            0 :     GNUNET_PQ_result_spec_allow_null (
     174            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2",
     175              :                                             &result[1].h_age_commitment),
     176              :       &is_age_hash_null[1]),
     177              :     GNUNET_PQ_result_spec_end
     178              :   };
     179              : 
     180            0 :   PREPARE (pg,
     181              :            "batch2_known_coin",
     182              :            "SELECT"
     183              :            " existed1 AS existed"
     184              :            ",known_coin_id1 AS known_coin_id"
     185              :            ",denom_pub_hash1 AS denom_hash"
     186              :            ",age_commitment_hash1 AS h_age_commitment"
     187              :            ",existed2 AS existed2"
     188              :            ",known_coin_id2 AS known_coin_id2"
     189              :            ",denom_pub_hash2 AS denom_hash2"
     190              :            ",age_commitment_hash2 AS h_age_commitment2"
     191              :            " FROM exchange_do_batch2_known_coin"
     192              :            "  ($1, $2, $3, $4, $5, $6, $7, $8);"
     193              :            );
     194            0 :   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     195              :                                                  "batch2_known_coin",
     196              :                                                  params,
     197              :                                                  rs);
     198            0 :   switch (qs)
     199              :   {
     200            0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     201            0 :     GNUNET_break (0);
     202            0 :     return qs;
     203            0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     204            0 :     return qs;
     205            0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     206            0 :     GNUNET_break (0); /* should be impossible */
     207            0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     208            0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     209            0 :     break; /* continued below */
     210              :   }
     211              : 
     212            0 :   for (int i = 0; i < 2; i++)
     213              :   {
     214            0 :     if ( (! is_denom_pub_hash_null[i]) &&
     215            0 :          (0 != GNUNET_memcmp (&result[i].denom_hash,
     216              :                               &coin[i].denom_pub_hash)) )
     217              :     {
     218            0 :       GNUNET_break_op (0);
     219            0 :       result[i].denom_conflict = true;
     220              :     }
     221              : 
     222            0 :     result[i].age_conflict = TALER_AgeCommitmentHashP_NoConflict;
     223              : 
     224            0 :     if (is_age_hash_null[i] != coin[i].no_age_commitment)
     225              :     {
     226            0 :       if (is_age_hash_null[i])
     227              :       {
     228            0 :         GNUNET_break_op (0);
     229            0 :         result[i].age_conflict = TALER_AgeCommitmentHashP_NullExpected;
     230              :       }
     231              :       else
     232              :       {
     233            0 :         GNUNET_break_op (0);
     234            0 :         result[i].age_conflict = TALER_AgeCommitmentHashP_ValueExpected;
     235              :       }
     236              :     }
     237            0 :     else if ( (! is_age_hash_null[i]) &&
     238            0 :               (0 != GNUNET_memcmp (&result[i].h_age_commitment,
     239              :                                    &coin[i].h_age_commitment)) )
     240              :     {
     241            0 :       GNUNET_break_op (0);
     242            0 :       result[i].age_conflict = TALER_AgeCommitmentHashP_ValueDiffers;
     243              :     }
     244              :   }
     245              : 
     246            0 :   return qs;
     247              : }
     248              : 
     249              : 
     250              : static enum GNUNET_DB_QueryStatus
     251            0 : insert4 (struct TALER_EXCHANGEDB_PostgresContext *pg,
     252              :          const struct TALER_CoinPublicInfo coin[4],
     253              :          struct TALER_EXCHANGEDB_CoinInfo result[4])
     254              : {
     255              :   enum GNUNET_DB_QueryStatus qs;
     256            0 :   bool is_denom_pub_hash_null[4] = {false, false, false, false};
     257            0 :   bool is_age_hash_null[4] = {false, false, false, false};
     258            0 :   struct GNUNET_PQ_QueryParam params[] = {
     259            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
     260            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
     261            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
     262            0 :     TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
     263              : 
     264            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub),
     265            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash),
     266            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment),
     267            0 :     TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
     268              : 
     269            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[2].coin_pub),
     270            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[2].denom_pub_hash),
     271            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[2].h_age_commitment),
     272            0 :     TALER_PQ_query_param_denom_sig (&coin[2].denom_sig),
     273              : 
     274            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[3].coin_pub),
     275            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[3].denom_pub_hash),
     276            0 :     GNUNET_PQ_query_param_auto_from_type (&coin[3].h_age_commitment),
     277            0 :     TALER_PQ_query_param_denom_sig (&coin[3].denom_sig),
     278              :     GNUNET_PQ_query_param_end
     279              :   };
     280            0 :   struct GNUNET_PQ_ResultSpec rs[] = {
     281            0 :     GNUNET_PQ_result_spec_bool ("existed",
     282              :                                 &result[0].existed),
     283            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id",
     284              :                                   &result[0].known_coin_id),
     285            0 :     GNUNET_PQ_result_spec_allow_null (
     286            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
     287              :                                             &result[0].denom_hash),
     288              :       &is_denom_pub_hash_null[0]),
     289            0 :     GNUNET_PQ_result_spec_allow_null (
     290            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
     291              :                                             &result[0].h_age_commitment),
     292              :       &is_age_hash_null[0]),
     293            0 :     GNUNET_PQ_result_spec_bool ("existed2",
     294            0 :                                 &result[1].existed),
     295            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id2",
     296            0 :                                   &result[1].known_coin_id),
     297            0 :     GNUNET_PQ_result_spec_allow_null (
     298            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2",
     299              :                                             &result[1].denom_hash),
     300              :       &is_denom_pub_hash_null[1]),
     301            0 :     GNUNET_PQ_result_spec_allow_null (
     302            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2",
     303              :                                             &result[1].h_age_commitment),
     304              :       &is_age_hash_null[1]),
     305            0 :     GNUNET_PQ_result_spec_bool ("existed3",
     306            0 :                                 &result[2].existed),
     307            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id3",
     308            0 :                                   &result[2].known_coin_id),
     309            0 :     GNUNET_PQ_result_spec_allow_null (
     310            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash3",
     311              :                                             &result[2].denom_hash),
     312              :       &is_denom_pub_hash_null[2]),
     313            0 :     GNUNET_PQ_result_spec_allow_null (
     314            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash3",
     315              :                                             &result[2].h_age_commitment),
     316              :       &is_age_hash_null[2]),
     317            0 :     GNUNET_PQ_result_spec_bool ("existed4",
     318            0 :                                 &result[3].existed),
     319            0 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id4",
     320            0 :                                   &result[3].known_coin_id),
     321            0 :     GNUNET_PQ_result_spec_allow_null (
     322            0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash4",
     323              :                                             &result[3].denom_hash),
     324              :       &is_denom_pub_hash_null[3]),
     325            0 :     GNUNET_PQ_result_spec_allow_null (
     326            0 :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash4",
     327              :                                             &result[3].h_age_commitment),
     328              :       &is_age_hash_null[3]),
     329              :     GNUNET_PQ_result_spec_end
     330              :   };
     331              : 
     332            0 :   PREPARE (pg,
     333              :            "batch4_known_coin",
     334              :            "SELECT"
     335              :            " existed1 AS existed"
     336              :            ",known_coin_id1 AS known_coin_id"
     337              :            ",denom_pub_hash1 AS denom_hash"
     338              :            ",age_commitment_hash1 AS h_age_commitment"
     339              :            ",existed2 AS existed2"
     340              :            ",known_coin_id2 AS known_coin_id2"
     341              :            ",denom_pub_hash2 AS denom_hash2"
     342              :            ",age_commitment_hash2 AS h_age_commitment2"
     343              :            ",existed3 AS existed3"
     344              :            ",known_coin_id3 AS known_coin_id3"
     345              :            ",denom_pub_hash3 AS denom_hash3"
     346              :            ",age_commitment_hash3 AS h_age_commitment3"
     347              :            ",existed4 AS existed4"
     348              :            ",known_coin_id4 AS known_coin_id4"
     349              :            ",denom_pub_hash4 AS denom_hash4"
     350              :            ",age_commitment_hash4 AS h_age_commitment4"
     351              :            " FROM exchange_do_batch2_known_coin"
     352              :            "  ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);"
     353              :            );
     354            0 :   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     355              :                                                  "batch4_known_coin",
     356              :                                                  params,
     357              :                                                  rs);
     358            0 :   switch (qs)
     359              :   {
     360            0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     361            0 :     GNUNET_break (0);
     362            0 :     return qs;
     363            0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     364            0 :     return qs;
     365            0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     366            0 :     GNUNET_break (0); /* should be impossible */
     367            0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     368            0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     369            0 :     break; /* continued below */
     370              :   }
     371              : 
     372            0 :   for (int i = 0; i < 4; i++)
     373              :   {
     374            0 :     if ( (! is_denom_pub_hash_null[i]) &&
     375            0 :          (0 != GNUNET_memcmp (&result[i].denom_hash,
     376              :                               &coin[i].denom_pub_hash)) )
     377              :     {
     378            0 :       GNUNET_break_op (0);
     379            0 :       result[i].denom_conflict = true;
     380              :     }
     381              : 
     382            0 :     result[i].age_conflict = TALER_AgeCommitmentHashP_NoConflict;
     383              : 
     384            0 :     if (is_age_hash_null[i] != coin[i].no_age_commitment)
     385              :     {
     386            0 :       if (is_age_hash_null[i])
     387              :       {
     388            0 :         GNUNET_break_op (0);
     389            0 :         result[i].age_conflict = TALER_AgeCommitmentHashP_NullExpected;
     390              :       }
     391              :       else
     392              :       {
     393            0 :         GNUNET_break_op (0);
     394            0 :         result[i].age_conflict = TALER_AgeCommitmentHashP_ValueExpected;
     395              :       }
     396              :     }
     397            0 :     else if ( (! is_age_hash_null[i]) &&
     398            0 :               (0 != GNUNET_memcmp (&result[i].h_age_commitment,
     399              :                                    &coin[i].h_age_commitment)) )
     400              :     {
     401            0 :       GNUNET_break_op (0);
     402            0 :       result[i].age_conflict = TALER_AgeCommitmentHashP_ValueDiffers;
     403              :     }
     404              :   }
     405              : 
     406            0 :   return qs;
     407              : }
     408              : 
     409              : 
     410              : enum GNUNET_DB_QueryStatus
     411            0 : TALER_EXCHANGEDB_batch_ensure_coin_known (
     412              :   struct TALER_EXCHANGEDB_PostgresContext *pg,
     413              :   const struct TALER_CoinPublicInfo *coin,
     414              :   struct TALER_EXCHANGEDB_CoinInfo *result,
     415              :   unsigned int coin_length,
     416              :   unsigned int batch_size)
     417              : {
     418            0 :   enum GNUNET_DB_QueryStatus qs = 0;
     419            0 :   unsigned int i = 0;
     420              : 
     421            0 :   while ( (qs >= 0) &&
     422              :           (i < coin_length) )
     423              :   {
     424            0 :     unsigned int bs = GNUNET_MIN (batch_size,
     425              :                                   coin_length - i);
     426            0 :     if (bs >= 4)
     427              :     {
     428            0 :       qs = insert4 (pg,
     429            0 :                     &coin[i],
     430            0 :                     &result[i]);
     431            0 :       i += 4;
     432            0 :       continue;
     433              :     }
     434            0 :     switch (bs)
     435              :     {
     436            0 :     case 3:
     437              :     case 2:
     438            0 :       qs = insert2 (pg,
     439            0 :                     &coin[i],
     440            0 :                     &result[i]);
     441            0 :       i += 2;
     442            0 :       break;
     443            0 :     case 1:
     444            0 :       qs = insert1 (pg,
     445            0 :                     &coin[i],
     446            0 :                     &result[i]);
     447            0 :       i += 1;
     448            0 :       break;
     449            0 :     case 0:
     450            0 :       GNUNET_assert (0);
     451              :       break;
     452              :     }
     453              :   } /* end while */
     454            0 :   if (qs < 0)
     455            0 :     return qs;
     456            0 :   return i;
     457              : }
        

Generated by: LCOV version 2.0-1