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

Generated by: LCOV version 2.0-1