LCOV - code coverage report
Current view: top level - exchangedb - ensure_coin_known.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.1 % 43 28
Test Date: 2026-04-14 15:39:31 Functions: 100.0 % 1 1

            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/ensure_coin_known.c
      18              :  * @brief Implementation of the ensure_coin_known function for Postgres
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "taler/taler_exchangedb_lib.h"
      22              : #include "taler/taler_pq_lib.h"
      23              : #include "exchange-database/ensure_coin_known.h"
      24              : #include "helper.h"
      25              : 
      26              : 
      27              : enum TALER_EXCHANGEDB_CoinKnownStatus
      28          169 : TALER_EXCHANGEDB_ensure_coin_known (
      29              :   struct TALER_EXCHANGEDB_PostgresContext *pg,
      30              :   const struct TALER_CoinPublicInfo *coin,
      31              :   uint64_t *known_coin_id,
      32              :   struct TALER_DenominationHashP *denom_hash,
      33              :   struct TALER_AgeCommitmentHashP *h_age_commitment)
      34              : {
      35              :   enum GNUNET_DB_QueryStatus qs;
      36              :   bool existed;
      37              :   bool no_denom_pub_hash;
      38              :   bool no_age_commitment_hash;
      39          169 :   struct GNUNET_PQ_QueryParam params[] = {
      40          169 :     GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
      41          169 :     GNUNET_PQ_query_param_auto_from_type (&coin->denom_pub_hash),
      42          169 :     coin->no_age_commitment
      43          105 :     ? GNUNET_PQ_query_param_null ()
      44          169 :     : GNUNET_PQ_query_param_auto_from_type (&coin->h_age_commitment),
      45          169 :     TALER_PQ_query_param_denom_sig (&coin->denom_sig),
      46              :     GNUNET_PQ_query_param_end
      47              :   };
      48          169 :   struct GNUNET_PQ_ResultSpec rs[] = {
      49          169 :     GNUNET_PQ_result_spec_bool ("existed",
      50              :                                 &existed),
      51          169 :     GNUNET_PQ_result_spec_uint64 ("known_coin_id",
      52              :                                   known_coin_id),
      53          169 :     GNUNET_PQ_result_spec_allow_null (
      54              :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
      55              :                                             denom_hash),
      56              :       &no_denom_pub_hash),
      57          169 :     GNUNET_PQ_result_spec_allow_null (
      58              :       GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
      59              :                                             h_age_commitment),
      60              :       &no_age_commitment_hash),
      61              :     GNUNET_PQ_result_spec_end
      62              :   };
      63              : 
      64              :   /*
      65              :      See also:
      66              :      https://stackoverflow.com/questions/34708509/how-to-use-returning-with-on-conflict-in-postgresql/37543015#37543015
      67              :   */
      68          169 :   PREPARE (pg,
      69              :            "insert_known_coin",
      70              :            "WITH dd"
      71              :            "  (denominations_serial"
      72              :            "  ,coin"
      73              :            "  ) AS ("
      74              :            "    SELECT "
      75              :            "       denominations_serial"
      76              :            "      ,coin"
      77              :            "        FROM denominations"
      78              :            "        WHERE denom_pub_hash=$2"
      79              :            "  ), input_rows"
      80              :            "    (coin_pub) AS ("
      81              :            "      VALUES ($1::BYTEA)"
      82              :            "  ), ins AS ("
      83              :            "  INSERT INTO known_coins "
      84              :            "  (coin_pub"
      85              :            "  ,denominations_serial"
      86              :            "  ,age_commitment_hash"
      87              :            "  ,denom_sig"
      88              :            "  ,remaining"
      89              :            "  ) SELECT "
      90              :            "     $1"
      91              :            "    ,denominations_serial"
      92              :            "    ,$3"
      93              :            "    ,$4"
      94              :            "    ,coin"
      95              :            "  FROM dd"
      96              :            "  ON CONFLICT DO NOTHING" /* CONFLICT on (coin_pub) */
      97              :            "  RETURNING "
      98              :            "     known_coin_id"
      99              :            "  ) "
     100              :            "SELECT "
     101              :            "   FALSE AS existed"
     102              :            "  ,known_coin_id"
     103              :            "  ,NULL AS denom_pub_hash"
     104              :            "  ,NULL AS age_commitment_hash"
     105              :            "  FROM ins "
     106              :            "UNION ALL "
     107              :            "SELECT "
     108              :            "   TRUE AS existed"
     109              :            "  ,known_coin_id"
     110              :            "  ,denom_pub_hash"
     111              :            "  ,kc.age_commitment_hash"
     112              :            "  FROM input_rows"
     113              :            "  JOIN known_coins kc USING (coin_pub)"
     114              :            "  JOIN denominations USING (denominations_serial)"
     115              :            "  LIMIT 1");
     116          169 :   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     117              :                                                  "insert_known_coin",
     118              :                                                  params,
     119              :                                                  rs);
     120          169 :   switch (qs)
     121              :   {
     122            0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     123            0 :     GNUNET_break (0);
     124            0 :     return TALER_EXCHANGEDB_CKS_HARD_FAIL;
     125            0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     126            0 :     return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
     127            0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     128            0 :     GNUNET_break (0); /* should be impossible */
     129            0 :     return TALER_EXCHANGEDB_CKS_HARD_FAIL;
     130          169 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     131          169 :     if (! existed)
     132           97 :       return TALER_EXCHANGEDB_CKS_ADDED;
     133           72 :     break; /* continued below */
     134              :   }
     135              : 
     136           72 :   if ( (! no_denom_pub_hash) &&
     137           72 :        (0 != GNUNET_memcmp (denom_hash,
     138              :                             &coin->denom_pub_hash)) )
     139              :   {
     140            2 :     GNUNET_break_op (0);
     141            2 :     return TALER_EXCHANGEDB_CKS_DENOM_CONFLICT;
     142              :   }
     143              : 
     144           70 :   if (no_age_commitment_hash != coin->no_age_commitment)
     145              :   {
     146            0 :     if (no_age_commitment_hash)
     147              :     {
     148            0 :       GNUNET_break_op (0);
     149            0 :       return TALER_EXCHANGEDB_CKS_AGE_CONFLICT_EXPECTED_NULL;
     150              :     }
     151              :     else
     152              :     {
     153            0 :       GNUNET_break_op (0);
     154            0 :       return TALER_EXCHANGEDB_CKS_AGE_CONFLICT_EXPECTED_NON_NULL;
     155              :     }
     156              :   }
     157           70 :   else if ( (! no_age_commitment_hash) &&
     158           24 :             (0 != GNUNET_memcmp (h_age_commitment,
     159              :                                  &coin->h_age_commitment)) )
     160              :   {
     161            0 :     GNUNET_break_op (0);
     162            0 :     return TALER_EXCHANGEDB_CKS_AGE_CONFLICT_VALUE_DIFFERS;
     163              :   }
     164              : 
     165           70 :   return TALER_EXCHANGEDB_CKS_PRESENT;
     166              : }
        

Generated by: LCOV version 2.0-1