LCOV - code coverage report
Current view: top level - exchangedb - test_common.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.4 % 287 271
Test Date: 2026-10-10 21:00:14 Functions: 100.0 % 20 20

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file exchangedb/test_common.c
      18              :  * @brief shared scaffolding for the per-table exchangedb tests
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "test_common.h"
      22              : #include "exchange-database/create_tables.h"
      23              : #include "exchange-database/do_insert_known_coins.h"
      24              : #include "exchange-database/insert_denomination_info.h"
      25              : #include "exchange-database/get_denomination_info.h"
      26              : #include "exchange-database/do_deposit.h"
      27              : #include "exchange-database/insert_purse_request.h"
      28              : #include "exchange-database/do_withdraw.h"
      29              : 
      30              : 
      31              : /**
      32              :  * Name of the single check to run, NULL to run all of them.
      33              :  */
      34              : static char *only;
      35              : 
      36              : /**
      37              :  * Return value of the process.
      38              :  */
      39              : static int result;
      40              : 
      41              : /**
      42              :  * Checks the current binary wants to run.
      43              :  */
      44              : static const struct TDB_Test *tdb_tests;
      45              : 
      46              : 
      47              : enum GNUNET_GenericReturnValue
      48          113 : TDB_exec (struct TALER_EXCHANGEDB_PostgresContext *pg,
      49              :           const char *fmt,
      50              :           ...)
      51              : {
      52              :   enum GNUNET_GenericReturnValue ret;
      53              :   va_list ap;
      54              :   char *sql;
      55              :   int len;
      56              : 
      57          113 :   va_start (ap,
      58              :             fmt);
      59          113 :   len = vsnprintf (NULL,
      60              :                    0,
      61              :                    fmt,
      62              :                    ap);
      63          113 :   va_end (ap);
      64          113 :   GNUNET_assert (len >= 0);
      65          113 :   sql = GNUNET_malloc ((size_t) len + 1);
      66          113 :   va_start (ap,
      67              :             fmt);
      68          113 :   GNUNET_assert (len ==
      69              :                  vsnprintf (sql,
      70              :                             (size_t) len + 1,
      71              :                             fmt,
      72              :                             ap));
      73          113 :   va_end (ap);
      74              :   {
      75          113 :     struct GNUNET_PQ_ExecuteStatement es[] = {
      76          113 :       GNUNET_PQ_make_execute (sql),
      77              :       GNUNET_PQ_EXECUTE_STATEMENT_END
      78              :     };
      79              : 
      80          113 :     ret = GNUNET_PQ_exec_statements (pg->conn,
      81              :                                      es);
      82              :   }
      83          113 :   GNUNET_free (sql);
      84          113 :   return ret;
      85              : }
      86              : 
      87              : 
      88              : uint64_t
      89          240 : TDB_count (struct TALER_EXCHANGEDB_PostgresContext *pg,
      90              :            const char *fmt,
      91              :            ...)
      92              : {
      93          240 :   struct GNUNET_PQ_QueryParam params[] = {
      94              :     GNUNET_PQ_query_param_end
      95              :   };
      96              :   uint64_t n;
      97          240 :   struct GNUNET_PQ_ResultSpec rs[] = {
      98          240 :     GNUNET_PQ_result_spec_uint64 ("n",
      99              :                                   &n),
     100              :     GNUNET_PQ_result_spec_end
     101              :   };
     102              :   va_list ap;
     103              :   char *frag;
     104              :   char *sql;
     105              :   int len;
     106              : 
     107          240 :   va_start (ap,
     108              :             fmt);
     109          240 :   len = vsnprintf (NULL,
     110              :                    0,
     111              :                    fmt,
     112              :                    ap);
     113          240 :   va_end (ap);
     114          240 :   GNUNET_assert (len >= 0);
     115          240 :   frag = GNUNET_malloc ((size_t) len + 1);
     116          240 :   va_start (ap,
     117              :             fmt);
     118          240 :   GNUNET_assert (len ==
     119              :                  vsnprintf (frag,
     120              :                             (size_t) len + 1,
     121              :                             fmt,
     122              :                             ap));
     123          240 :   va_end (ap);
     124          240 :   GNUNET_asprintf (&sql,
     125              :                    "SELECT COUNT(*) AS n %s;",
     126              :                    frag);
     127          240 :   GNUNET_free (frag);
     128          240 :   GNUNET_assert (GNUNET_OK ==
     129              :                  GNUNET_PQ_prepare_anon (pg->conn,
     130              :                                          sql));
     131          240 :   GNUNET_free (sql);
     132          240 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     133              :                  GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     134              :                                                            "",
     135              :                                                            params,
     136              :                                                            rs));
     137          240 :   return n;
     138              : }
     139              : 
     140              : 
     141              : struct TALER_Amount
     142          411 : TDB_amount (const char *str)
     143              : {
     144              :   struct TALER_Amount amount;
     145              :   char *s;
     146              : 
     147          411 :   GNUNET_asprintf (&s,
     148              :                    CURRENCY ":%s",
     149              :                    str);
     150          411 :   GNUNET_assert (GNUNET_OK ==
     151              :                  TALER_string_to_amount (s,
     152              :                                          &amount));
     153          411 :   GNUNET_free (s);
     154          411 :   return amount;
     155              : }
     156              : 
     157              : 
     158              : void
     159          825 : TDB_fill (void *ptr,
     160              :           size_t size,
     161              :           uint32_t seed)
     162              : {
     163          825 :   unsigned char *buf = ptr;
     164          825 :   uint32_t state = seed * 2654435761U + 1;
     165              : 
     166        40957 :   for (size_t i = 0; i<size; i++)
     167              :   {
     168        40132 :     state = state * 1103515245U + 12345U;
     169        40132 :     buf[i] = (unsigned char) (state >> 16);
     170              :   }
     171          825 : }
     172              : 
     173              : 
     174              : char *
     175          174 : TDB_hex (const void *data,
     176              :          size_t size)
     177              : {
     178          174 :   const unsigned char *raw = data;
     179              :   char *hex;
     180              : 
     181          174 :   hex = GNUNET_malloc (size * 2 + 1);
     182         5742 :   for (size_t i = 0; i<size; i++)
     183         5568 :     GNUNET_snprintf (&hex[i * 2],
     184              :                      3,
     185              :                      "%02x",
     186         5568 :                      raw[i]);
     187          174 :   return hex;
     188              : }
     189              : 
     190              : 
     191              : void
     192           56 : TDB_denom_sig (uint32_t seed,
     193              :                struct TALER_DenominationSignature *sig)
     194              : {
     195              :   struct GNUNET_CRYPTO_UnblindedSignature *ubs;
     196              : 
     197           56 :   ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
     198           56 :   ubs->cipher = GNUNET_CRYPTO_BSA_CS;
     199           56 :   ubs->rc = 1;
     200           56 :   TDB_fill (&ubs->details.cs_signature,
     201              :             sizeof (ubs->details.cs_signature),
     202              :             seed);
     203           56 :   sig->unblinded_sig = ubs;
     204           56 : }
     205              : 
     206              : 
     207              : void
     208           29 : TDB_blinded_denom_sig (uint32_t seed,
     209              :                        struct TALER_BlindedDenominationSignature *sig)
     210              : {
     211              :   struct GNUNET_CRYPTO_BlindedSignature *bs;
     212              : 
     213           29 :   bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
     214           29 :   bs->cipher = GNUNET_CRYPTO_BSA_CS;
     215           29 :   bs->rc = 1;
     216           29 :   TDB_fill (&bs->details.blinded_cs_answer,
     217              :             sizeof (bs->details.blinded_cs_answer),
     218              :             seed);
     219           29 :   sig->blinded_sig = bs;
     220           29 : }
     221              : 
     222              : 
     223              : void
     224           36 : TDB_denom (struct TALER_EXCHANGEDB_PostgresContext *pg,
     225              :            uint32_t seed,
     226              :            const char *value,
     227              :            const char *fee,
     228              :            struct TDB_Denom *denom)
     229              : {
     230              :   struct GNUNET_TIME_Timestamp now;
     231              :   struct TALER_Amount f;
     232              : 
     233           36 :   memset (denom,
     234              :           0,
     235              :           sizeof (*denom));
     236              :   /* Build the Clause-Schnorr key pair from @a seed instead of at random, so
     237              :      that two calls with the same seed name the same denomination -- checks
     238              :      rely on that to refer to a row an earlier check created.  The top nibble
     239              :      of the scalar is cleared to keep it below the group order. */
     240              :   {
     241              :     struct GNUNET_CRYPTO_BlindSignPrivateKey *bpriv;
     242              :     struct GNUNET_CRYPTO_BlindSignPublicKey *bpub;
     243              :     unsigned char *d;
     244              : 
     245           36 :     bpriv = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPrivateKey);
     246           36 :     bpriv->cipher = GNUNET_CRYPTO_BSA_CS;
     247           36 :     bpriv->rc = 1;
     248           36 :     d = bpriv->details.cs_private_key.scalar.d;
     249           36 :     TDB_fill (d,
     250              :               sizeof (bpriv->details.cs_private_key.scalar.d),
     251              :               seed);
     252           36 :     d[sizeof (bpriv->details.cs_private_key.scalar.d) - 1] &= 0x0f;
     253           36 :     bpub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
     254           36 :     bpub->cipher = GNUNET_CRYPTO_BSA_CS;
     255           36 :     bpub->rc = 1;
     256           36 :     GNUNET_CRYPTO_cs_private_key_get_public (
     257           36 :       &bpriv->details.cs_private_key,
     258              :       &bpub->details.cs_public_key);
     259           36 :     GNUNET_CRYPTO_hash (&bpub->details.cs_public_key,
     260              :                         sizeof (bpub->details.cs_public_key),
     261              :                         &bpub->pub_key_hash);
     262           36 :     denom->priv.bsign_priv_key = bpriv;
     263           36 :     denom->pub.bsign_pub_key = bpub;
     264              :   }
     265           36 :   TALER_denom_pub_hash (&denom->pub,
     266              :                         &denom->h_denom_pub);
     267              :   /* The same seed may be used by more than one check to name the same
     268              :      denomination; the second call then only has to load it. */
     269           36 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     270           36 :       TALER_EXCHANGEDB_get_denomination_info (pg,
     271           36 :                                               &denom->h_denom_pub,
     272              :                                               &denom->serial,
     273              :                                               &denom->issue))
     274            9 :     return;
     275           27 :   now = GNUNET_TIME_timestamp_get ();
     276           27 :   f = TDB_amount (fee);
     277           27 :   denom->issue.start = now;
     278              :   denom->issue.expire_withdraw
     279           27 :     = GNUNET_TIME_absolute_to_timestamp (
     280              :         GNUNET_TIME_absolute_add (now.abs_time,
     281              :                                   GNUNET_TIME_UNIT_HOURS));
     282              :   denom->issue.expire_deposit
     283           27 :     = GNUNET_TIME_absolute_to_timestamp (
     284              :         GNUNET_TIME_absolute_add (now.abs_time,
     285              :                                   GNUNET_TIME_relative_multiply (
     286              :                                     GNUNET_TIME_UNIT_HOURS,
     287              :                                     2)));
     288              :   denom->issue.expire_legal
     289           27 :     = GNUNET_TIME_absolute_to_timestamp (
     290              :         GNUNET_TIME_absolute_add (now.abs_time,
     291              :                                   GNUNET_TIME_relative_multiply (
     292              :                                     GNUNET_TIME_UNIT_HOURS,
     293              :                                     3)));
     294           27 :   denom->issue.value = TDB_amount (value);
     295           27 :   denom->issue.fees.withdraw = f;
     296           27 :   denom->issue.fees.deposit = f;
     297           27 :   denom->issue.fees.refresh = f;
     298           27 :   denom->issue.fees.refund = f;
     299           27 :   denom->issue.denom_hash = denom->h_denom_pub;
     300           27 :   TDB_fill (&denom->issue.signature,
     301              :             sizeof (denom->issue.signature),
     302              :             seed);
     303           27 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     304              :                  TALER_EXCHANGEDB_insert_denomination_info (pg,
     305              :                                                             &denom->pub,
     306              :                                                             &denom->issue));
     307              :   {
     308           27 :     struct GNUNET_PQ_QueryParam params[] = {
     309           27 :       GNUNET_PQ_query_param_auto_from_type (&denom->h_denom_pub),
     310              :       GNUNET_PQ_query_param_end
     311              :     };
     312           27 :     struct GNUNET_PQ_ResultSpec rs[] = {
     313           27 :       GNUNET_PQ_result_spec_uint64 ("denominations_serial",
     314              :                                     &denom->serial),
     315              :       GNUNET_PQ_result_spec_end
     316              :     };
     317              : 
     318           27 :     GNUNET_assert (GNUNET_OK ==
     319              :                    GNUNET_PQ_prepare_anon (
     320              :                      pg->conn,
     321              :                      "SELECT denominations_serial"
     322              :                      " FROM denominations"
     323              :                      " WHERE denom_pub_hash=$1;"));
     324           27 :     GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     325              :                    GNUNET_PQ_eval_prepared_singleton_select (
     326              :                      pg->conn,
     327              :                      "",
     328              :                      params,
     329              :                      rs));
     330              :   }
     331              : }
     332              : 
     333              : 
     334              : void
     335           36 : TDB_denom_free (struct TDB_Denom *denom)
     336              : {
     337           36 :   TALER_denom_pub_free (&denom->pub);
     338           36 :   TALER_denom_priv_free (&denom->priv);
     339           36 : }
     340              : 
     341              : 
     342              : void
     343           46 : TDB_coin (struct TALER_EXCHANGEDB_PostgresContext *pg,
     344              :           const struct TDB_Denom *denom,
     345              :           uint32_t seed,
     346              :           struct TALER_CoinPublicInfo *coin,
     347              :           uint64_t *known_coin_id)
     348              : {
     349              :   struct TALER_EXCHANGEDB_CoinKnownResult res;
     350           46 :   const struct TALER_CoinPublicInfo *coins[1] = { coin };
     351              : 
     352           46 :   memset (coin,
     353              :           0,
     354              :           sizeof (*coin));
     355           46 :   TDB_FILL (coin->coin_pub,
     356              :             seed);
     357           46 :   coin->denom_pub_hash = denom->h_denom_pub;
     358           46 :   coin->no_age_commitment = true;
     359           46 :   TDB_denom_sig (seed,
     360              :                  &coin->denom_sig);
     361           46 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     362              :                  TALER_EXCHANGEDB_do_insert_known_coins (pg,
     363              :                                                          1,
     364              :                                                          coins,
     365              :                                                          &res));
     366              :   /* CKS_PRESENT is fine: the same seed may name a coin an earlier check
     367              :      already made known. */
     368           46 :   GNUNET_assert ( (TALER_EXCHANGEDB_CKS_ADDED == res.status) ||
     369              :                   (TALER_EXCHANGEDB_CKS_PRESENT == res.status) );
     370           46 :   if (NULL != known_coin_id)
     371           15 :     *known_coin_id = res.known_coin_id;
     372           46 : }
     373              : 
     374              : 
     375              : void
     376           46 : TDB_coin_free (struct TALER_CoinPublicInfo *coin)
     377              : {
     378           46 :   TALER_denom_sig_free (&coin->denom_sig);
     379           46 : }
     380              : 
     381              : 
     382              : void
     383           36 : TDB_account (struct TALER_EXCHANGEDB_PostgresContext *pg,
     384              :              uint32_t seed,
     385              :              struct TDB_Account *account)
     386              : {
     387              :   struct TALER_NormalizedPayto npayto;
     388              :   char *fhex;
     389              :   char *nhex;
     390              : 
     391           36 :   GNUNET_asprintf (&account->payto.full_payto,
     392              :                    "payto://x-taler-bank/localhost/tdb%u?receiver-name=tdb%u",
     393              :                    (unsigned int) seed,
     394              :                    (unsigned int) seed);
     395           36 :   TALER_full_payto_hash (account->payto,
     396              :                          &account->h_full);
     397           36 :   npayto = TALER_payto_normalize (account->payto);
     398           36 :   GNUNET_assert (NULL != npayto.normalized_payto);
     399           36 :   TALER_normalized_payto_hash (npayto,
     400              :                                &account->h_normalized);
     401           36 :   GNUNET_free (npayto.normalized_payto);
     402           36 :   fhex = TDB_hex (&account->h_full,
     403              :                   sizeof (account->h_full));
     404           36 :   nhex = TDB_hex (&account->h_normalized,
     405              :                   sizeof (account->h_normalized));
     406           36 :   GNUNET_assert (GNUNET_OK ==
     407              :                  TDB_exec (pg,
     408              :                            "INSERT INTO kyc_targets"
     409              :                            " (h_normalized_payto,is_wallet)"
     410              :                            " VALUES (decode('%s','hex'),FALSE)"
     411              :                            " ON CONFLICT DO NOTHING;"
     412              :                            "INSERT INTO wire_targets"
     413              :                            " (wire_target_h_payto,payto_uri"
     414              :                            " ,h_normalized_payto)"
     415              :                            " VALUES (decode('%s','hex'),'%s'"
     416              :                            "        ,decode('%s','hex'))"
     417              :                            " ON CONFLICT DO NOTHING;",
     418              :                            nhex,
     419              :                            fhex,
     420              :                            account->payto.full_payto,
     421              :                            nhex));
     422           36 :   GNUNET_free (fhex);
     423           36 :   GNUNET_free (nhex);
     424           36 : }
     425              : 
     426              : 
     427              : void
     428           37 : TDB_account_free (struct TDB_Account *account)
     429              : {
     430           37 :   GNUNET_free (account->payto.full_payto);
     431           37 : }
     432              : 
     433              : 
     434              : void
     435           35 : TDB_reserve (struct TALER_EXCHANGEDB_PostgresContext *pg,
     436              :              uint32_t seed,
     437              :              const char *balance,
     438              :              struct TALER_ReservePublicKeyP *reserve_pub)
     439              : {
     440           35 :   struct TALER_Amount b = TDB_amount (balance);
     441              :   char *hex;
     442              : 
     443           35 :   TDB_fill (reserve_pub,
     444              :             sizeof (*reserve_pub),
     445              :             seed);
     446           35 :   hex = TDB_hex (reserve_pub,
     447              :                  sizeof (*reserve_pub));
     448           35 :   GNUNET_assert (GNUNET_OK ==
     449              :                  TDB_exec (pg,
     450              :                            "INSERT INTO reserves"
     451              :                            " (reserve_pub,current_balance"
     452              :                            " ,expiration_date,gc_date)"
     453              :                            " VALUES (decode('%s','hex')"
     454              :                            "        ,ROW(%llu,%u)::taler_amount"
     455              :                            "        ,%llu,%llu)"
     456              :                            " ON CONFLICT DO NOTHING;",
     457              :                            hex,
     458              :                            (unsigned long long) b.value,
     459              :                            (unsigned int) b.fraction,
     460              :                            (unsigned long long) 4000000000000000LLU,
     461              :                            (unsigned long long) 5000000000000000LLU));
     462           35 :   GNUNET_free (hex);
     463           35 : }
     464              : 
     465              : 
     466              : void
     467           19 : TDB_purse (struct TALER_EXCHANGEDB_PostgresContext *pg,
     468              :            uint32_t seed,
     469              :            const char *amount,
     470              :            struct GNUNET_TIME_Timestamp purse_expiration,
     471              :            struct TDB_Purse *purse)
     472              : {
     473           19 :   struct TALER_Amount purse_fee = TDB_amount ("0");
     474              :   enum GNUNET_DB_QueryStatus qs;
     475           19 :   bool in_conflict = false;
     476              : 
     477           19 :   memset (purse,
     478              :           0,
     479              :           sizeof (*purse));
     480           19 :   TDB_fill (&purse->purse_pub,
     481              :             sizeof (purse->purse_pub),
     482              :             seed);
     483           19 :   TDB_fill (&purse->merge_pub,
     484              :             sizeof (purse->merge_pub),
     485              :             seed);
     486           19 :   TDB_fill (&purse->h_contract_terms,
     487              :             sizeof (purse->h_contract_terms),
     488              :             seed);
     489           19 :   TDB_fill (&purse->purse_sig,
     490              :             sizeof (purse->purse_sig),
     491              :             seed);
     492           19 :   purse->purse_expiration = purse_expiration;
     493           19 :   purse->amount = TDB_amount (amount);
     494           19 :   qs = TALER_EXCHANGEDB_insert_purse_request (
     495              :     pg,
     496           19 :     &purse->purse_pub,
     497           19 :     &purse->merge_pub,
     498              :     purse_expiration,
     499           19 :     &purse->h_contract_terms,
     500              :     0,
     501              :     TALER_WAMF_MODE_CREATE_FROM_PURSE_QUOTA,
     502              :     &purse_fee,
     503           19 :     &purse->amount,
     504           19 :     &purse->purse_sig,
     505              :     &in_conflict);
     506              :   /* SUCCESS_NO_RESULTS is the answer for an identical replay, which is
     507              :      what a second call with the same seed is. */
     508           19 :   GNUNET_assert (0 <= qs);
     509           19 :   GNUNET_assert (! in_conflict);
     510           19 : }
     511              : 
     512              : 
     513              : void
     514           12 : TDB_deposit (struct TALER_EXCHANGEDB_PostgresContext *pg,
     515              :              const struct TDB_Account *account,
     516              :              const struct TALER_CoinPublicInfo *coin,
     517              :              uint32_t seed,
     518              :              const char *amount,
     519              :              const char *fee,
     520              :              struct GNUNET_TIME_Timestamp wire_deadline,
     521              :              struct GNUNET_TIME_Timestamp refund_deadline,
     522              :              struct TDB_Deposit *dep)
     523              : {
     524              :   struct TALER_EXCHANGEDB_CoinDepositInformation cdi;
     525              :   struct TALER_EXCHANGEDB_BatchDeposit bd;
     526              :   struct TALER_Amount fees[1];
     527              :   struct TALER_Amount total;
     528              :   uint32_t bad_balance_index;
     529              :   bool balance_ok;
     530              :   bool in_conflict;
     531              : 
     532           12 :   memset (dep,
     533              :           0,
     534              :           sizeof (*dep));
     535           12 :   TDB_fill (&dep->merchant_pub,
     536              :             sizeof (dep->merchant_pub),
     537              :             seed);
     538           12 :   TDB_fill (&dep->merchant_sig,
     539              :             sizeof (dep->merchant_sig),
     540              :             seed);
     541           12 :   TDB_fill (&dep->h_contract_terms,
     542              :             sizeof (dep->h_contract_terms),
     543              :             seed);
     544           12 :   TDB_fill (&dep->wire_salt,
     545              :             sizeof (dep->wire_salt),
     546              :             seed);
     547           12 :   TALER_merchant_wire_signature_hash (account->payto,
     548           12 :                                       &dep->wire_salt,
     549              :                                       &dep->h_wire);
     550           12 :   dep->wire_deadline = wire_deadline;
     551           12 :   dep->refund_deadline = refund_deadline;
     552           12 :   memset (&cdi,
     553              :           0,
     554              :           sizeof (cdi));
     555           12 :   cdi.coin = *coin;
     556           12 :   TDB_fill (&cdi.csig,
     557              :             sizeof (cdi.csig),
     558              :             seed);
     559           12 :   cdi.amount_with_fee = TDB_amount (amount);
     560           12 :   fees[0] = TDB_amount (fee);
     561           12 :   memset (&bd,
     562              :           0,
     563              :           sizeof (bd));
     564           12 :   bd.merchant_pub = dep->merchant_pub;
     565           12 :   bd.merchant_sig = dep->merchant_sig;
     566           12 :   bd.h_contract_terms = dep->h_contract_terms;
     567           12 :   bd.no_wallet_data_hash = true;
     568           12 :   bd.wire_target_h_payto = account->h_full;
     569           12 :   bd.wire_salt = dep->wire_salt;
     570           12 :   bd.wallet_timestamp = wire_deadline;
     571           12 :   bd.refund_deadline = refund_deadline;
     572           12 :   bd.wire_deadline = wire_deadline;
     573           12 :   bd.receiver_wire_account = account->payto;
     574           12 :   bd.cdis = &cdi;
     575           12 :   bd.num_cdis = 1;
     576           12 :   dep->exchange_timestamp = GNUNET_TIME_timestamp_get ();
     577           12 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     578              :                  TALER_EXCHANGEDB_do_deposit (pg,
     579              :                                               &bd,
     580              :                                               fees,
     581              :                                               &dep->exchange_timestamp,
     582              :                                               &total,
     583              :                                               &balance_ok,
     584              :                                               &bad_balance_index,
     585              :                                               &in_conflict));
     586           12 :   GNUNET_assert (balance_ok);
     587           12 :   GNUNET_assert (! in_conflict);
     588              :   {
     589           12 :     struct GNUNET_PQ_QueryParam params[] = {
     590           12 :       GNUNET_PQ_query_param_auto_from_type (&dep->merchant_pub),
     591           12 :       GNUNET_PQ_query_param_auto_from_type (&dep->h_contract_terms),
     592              :       GNUNET_PQ_query_param_end
     593              :     };
     594           12 :     struct GNUNET_PQ_ResultSpec rs[] = {
     595           12 :       GNUNET_PQ_result_spec_uint64 ("batch_deposit_serial_id",
     596              :                                     &dep->serial),
     597              :       GNUNET_PQ_result_spec_end
     598              :     };
     599              : 
     600           12 :     GNUNET_assert (GNUNET_OK ==
     601              :                    GNUNET_PQ_prepare_anon (pg->conn,
     602              :                                            "SELECT batch_deposit_serial_id"
     603              :                                            " FROM batch_deposits"
     604              :                                            " WHERE merchant_pub=$1"
     605              :                                            "   AND h_contract_terms=$2;"));
     606           12 :     GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     607              :                    GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     608              :                                                              "",
     609              :                                                              params,
     610              :                                                              rs));
     611              :   }
     612           12 : }
     613              : 
     614              : 
     615              : uint64_t
     616            9 : TDB_withdraw (struct TALER_EXCHANGEDB_PostgresContext *pg,
     617              :               const struct TDB_Denom *denom,
     618              :               const struct TALER_ReservePublicKeyP *reserve_pub,
     619              :               uint32_t seed,
     620              :               const char *amount)
     621              : {
     622              :   struct TALER_EXCHANGEDB_Withdraw wd;
     623            9 :   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
     624              :   struct TALER_Amount reserve_balance;
     625              :   struct TALER_BlindedDenominationSignature denom_sig;
     626            9 :   uint64_t denom_serial = denom->serial;
     627              :   uint64_t withdraw_id;
     628              :   uint16_t allowed_maximum_age;
     629              :   uint16_t noreveal_index;
     630              :   uint32_t reserve_birthday;
     631              :   bool balance_ok;
     632              :   bool age_ok;
     633              :   bool idempotent;
     634              :   bool nonce_reuse;
     635              : 
     636            9 :   memset (&wd,
     637              :           0,
     638              :           sizeof (wd));
     639            9 :   wd.amount_with_fee = TDB_amount (amount);
     640            9 :   wd.reserve_pub = *reserve_pub;
     641            9 :   TDB_fill (&wd.planchets_h,
     642              :             sizeof (wd.planchets_h),
     643              :             seed);
     644            9 :   TDB_fill (&wd.reserve_sig,
     645              :             sizeof (wd.reserve_sig),
     646              :             seed);
     647            9 :   wd.num_coins = 1;
     648            9 :   wd.denom_serials = &denom_serial;
     649            9 :   TDB_blinded_denom_sig (seed,
     650              :                          &denom_sig);
     651            9 :   wd.denom_sigs = &denom_sig;
     652            9 :   wd.no_blinding_seed = true;
     653            9 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     654              :                  TALER_EXCHANGEDB_do_withdraw (pg,
     655              :                                                &wd,
     656              :                                                &now,
     657              :                                                &balance_ok,
     658              :                                                &reserve_balance,
     659              :                                                &age_ok,
     660              :                                                &allowed_maximum_age,
     661              :                                                &reserve_birthday,
     662              :                                                &idempotent,
     663              :                                                &noreveal_index,
     664              :                                                &nonce_reuse));
     665            9 :   GNUNET_assert (balance_ok);
     666            9 :   GNUNET_assert (age_ok);
     667            9 :   GNUNET_assert (! nonce_reuse);
     668            9 :   TALER_blinded_denom_sig_free (&denom_sig);
     669              :   {
     670            9 :     struct GNUNET_PQ_QueryParam params[] = {
     671            9 :       GNUNET_PQ_query_param_auto_from_type (&wd.planchets_h),
     672              :       GNUNET_PQ_query_param_end
     673              :     };
     674            9 :     struct GNUNET_PQ_ResultSpec rs[] = {
     675            9 :       GNUNET_PQ_result_spec_uint64 ("withdraw_id",
     676              :                                     &withdraw_id),
     677              :       GNUNET_PQ_result_spec_end
     678              :     };
     679              : 
     680            9 :     GNUNET_assert (GNUNET_OK ==
     681              :                    GNUNET_PQ_prepare_anon (pg->conn,
     682              :                                            "SELECT withdraw_id"
     683              :                                            " FROM withdraw"
     684              :                                            " WHERE planchets_h=$1;"));
     685            9 :     GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     686              :                    GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     687              :                                                              "",
     688              :                                                              params,
     689              :                                                              rs));
     690              :   }
     691            9 :   return withdraw_id;
     692              : }
     693              : 
     694              : 
     695              : uint64_t
     696           15 : TDB_reserve_in (struct TALER_EXCHANGEDB_PostgresContext *pg,
     697              :                 const struct TDB_Account *account,
     698              :                 uint32_t seed,
     699              :                 const char *amount,
     700              :                 struct TALER_ReservePublicKeyP *reserve_pub)
     701              : {
     702           15 :   struct TALER_Amount a = TDB_amount (amount);
     703              :   uint64_t serial;
     704              :   char *rhex;
     705              :   char *ahex;
     706              : 
     707           15 :   TDB_reserve (pg,
     708              :                seed,
     709              :                amount,
     710              :                reserve_pub);
     711           15 :   rhex = TDB_hex (reserve_pub,
     712              :                   sizeof (*reserve_pub));
     713           15 :   ahex = TDB_hex (&account->h_full,
     714              :                   sizeof (account->h_full));
     715           15 :   GNUNET_assert (GNUNET_OK ==
     716              :                  TDB_exec (pg,
     717              :                            "INSERT INTO reserves_in"
     718              :                            " (reserve_pub,wire_reference,credit"
     719              :                            " ,wire_source_h_payto"
     720              :                            " ,exchange_account_section,execution_date)"
     721              :                            " VALUES (decode('%s','hex'),%u"
     722              :                            "        ,ROW(%llu,%u)::taler_amount"
     723              :                            "        ,decode('%s','hex'),'exchange-account-1'"
     724              :                            "        ,%llu);",
     725              :                            rhex,
     726              :                            (unsigned int) seed,
     727              :                            (unsigned long long) a.value,
     728              :                            (unsigned int) a.fraction,
     729              :                            ahex,
     730              :                            (unsigned long long) 1600000000000000LLU));
     731              :   {
     732           15 :     struct GNUNET_PQ_QueryParam params[] = {
     733           15 :       GNUNET_PQ_query_param_auto_from_type (reserve_pub),
     734              :       GNUNET_PQ_query_param_end
     735              :     };
     736           15 :     struct GNUNET_PQ_ResultSpec rs[] = {
     737           15 :       GNUNET_PQ_result_spec_uint64 ("reserve_in_serial_id",
     738              :                                     &serial),
     739              :       GNUNET_PQ_result_spec_end
     740              :     };
     741              : 
     742           15 :     GNUNET_assert (GNUNET_OK ==
     743              :                    GNUNET_PQ_prepare_anon (
     744              :                      pg->conn,
     745              :                      "SELECT reserve_in_serial_id"
     746              :                      " FROM reserves_in"
     747              :                      " WHERE reserve_pub=$1;"));
     748           15 :     GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     749              :                    GNUNET_PQ_eval_prepared_singleton_select (
     750              :                      pg->conn,
     751              :                      "",
     752              :                      params,
     753              :                      rs));
     754              :   }
     755           15 :   GNUNET_free (rhex);
     756           15 :   GNUNET_free (ahex);
     757           15 :   return serial;
     758              : }
     759              : 
     760              : 
     761              : /**
     762              :  * Main function that runs the checks.
     763              :  *
     764              :  * @param cls closure
     765              :  * @param args remaining command-line arguments
     766              :  * @param cfgfile name of the configuration file used
     767              :  * @param cfg configuration
     768              :  */
     769              : static void
     770           53 : run (void *cls,
     771              :      char *const *args,
     772              :      const char *cfgfile,
     773              :      const struct GNUNET_CONFIGURATION_Handle *cfg)
     774              : {
     775              :   struct TALER_EXCHANGEDB_PostgresContext *pg;
     776           53 :   unsigned int ran = 0;
     777              : 
     778              :   (void) cls;
     779              :   (void) args;
     780              :   (void) cfgfile;
     781           53 :   pg = TALER_EXCHANGEDB_connect_admin (cfg);
     782           53 :   if (NULL == pg)
     783              :   {
     784            0 :     fprintf (stderr,
     785              :              "Failed to connect to the database\n");
     786            0 :     result = 77;
     787            0 :     return;
     788              :   }
     789           53 :   if (GNUNET_OK !=
     790           53 :       TALER_EXCHANGEDB_create_tables (pg,
     791              :                                       false,
     792              :                                       0))
     793              :   {
     794            0 :     fprintf (stderr,
     795              :              "Failed to create the database schema\n");
     796            0 :     result = 77;
     797            0 :     goto cleanup;
     798              :   }
     799          309 :   for (unsigned int i = 0; NULL != tdb_tests[i].name; i++)
     800              :   {
     801          256 :     if ( (NULL != only) &&
     802            0 :          (0 != strcmp (only,
     803            0 :                        tdb_tests[i].name)) )
     804            0 :       continue;
     805          256 :     fprintf (stderr,
     806              :              "Running check `%s'\n",
     807          256 :              tdb_tests[i].name);
     808          256 :     ran++;
     809          256 :     if (0 != tdb_tests[i].fn (pg))
     810              :     {
     811            0 :       fprintf (stderr,
     812              :                "Check `%s' FAILED\n",
     813            0 :                tdb_tests[i].name);
     814            0 :       result = 1;
     815              :     }
     816              :   }
     817           53 :   if (0 == ran)
     818              :   {
     819            0 :     fprintf (stderr,
     820              :              "No check matched `%s'\n",
     821              :              only);
     822            0 :     result = 1;
     823              :   }
     824           53 : cleanup:
     825           53 :   TALER_EXCHANGEDB_disconnect (pg);
     826              : }
     827              : 
     828              : 
     829              : int
     830           53 : TDB_main (int argc,
     831              :           char *const *argv,
     832              :           const char *binary,
     833              :           const char *description,
     834              :           const struct TDB_Test *tests)
     835              : {
     836           53 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
     837           53 :     GNUNET_GETOPT_option_string ('t',
     838              :                                  "test",
     839              :                                  "NAME",
     840              :                                  "only run the check called NAME",
     841              :                                  &only),
     842              :     GNUNET_GETOPT_OPTION_END
     843              :   };
     844              :   enum GNUNET_GenericReturnValue ret;
     845              : 
     846           53 :   result = 0;
     847           53 :   tdb_tests = tests;
     848           53 :   ret = GNUNET_PROGRAM_run (TALER_EXCHANGE_project_data (),
     849              :                             argc,
     850              :                             argv,
     851              :                             binary,
     852              :                             description,
     853              :                             options,
     854              :                             &run,
     855              :                             NULL);
     856           53 :   if (GNUNET_SYSERR == ret)
     857            0 :     return 3;
     858           53 :   if (GNUNET_NO == ret)
     859            0 :     return 0;
     860           53 :   return result;
     861              : }
     862              : 
     863              : 
     864              : /* end of test_common.c */
        

Generated by: LCOV version 2.0-1