LCOV - code coverage report
Current view: top level - exchangedb - pg_batch_ensure_coin_known.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 216 0.0 %
Date: 2025-06-05 21:03:14 Functions: 0 4 0.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 "platform.h"
      25             : #include "taler_error_codes.h"
      26             : #include "taler_dbevents.h"
      27             : #include "taler_exchangedb_plugin.h"
      28             : #include "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_AgeCommitmentHash_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_AgeCommitmentHash_NullExpected;
     116             :     }
     117             :     else
     118             :     {
     119           0 :       GNUNET_break_op (0);
     120           0 :       result[0].age_conflict = TALER_AgeCommitmentHash_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_AgeCommitmentHash_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_AgeCommitmentHash_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_AgeCommitmentHash_NullExpected;
     233             :       }
     234             :       else
     235             :       {
     236           0 :         GNUNET_break_op (0);
     237           0 :         result[i].age_conflict = TALER_AgeCommitmentHash_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_AgeCommitmentHash_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_AgeCommitmentHash_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_AgeCommitmentHash_NullExpected;
     393             :       }
     394             :       else
     395             :       {
     396           0 :         GNUNET_break_op (0);
     397           0 :         result[i].age_conflict = TALER_AgeCommitmentHash_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_AgeCommitmentHash_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 1.16