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

Generated by: LCOV version 2.0-1