LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_insert_deposit.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 80.9 % 110 89
Test Date: 2026-04-14 15:39:31 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2018, 2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it
       6              :   under the terms of the GNU General Public License as published
       7              :   by the Free Software Foundation; either version 3, or (at your
       8              :   option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not,
      17              :   see <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file testing/testing_api_cmd_insert_deposit.c
      21              :  * @brief deposit a coin directly into the database.
      22              :  * @author Marcello Stanisci
      23              :  * @author Christian Grothoff
      24              :  */
      25              : #include "taler/platform.h"  /* UNNECESSARY? */
      26              : #include "taler/taler_util.h"
      27              : #include "taler/taler_json_lib.h"
      28              : #include <gnunet/gnunet_curl_lib.h>
      29              : #include "taler/taler_signatures.h"
      30              : #include "taler/taler_testing_lib.h"
      31              : #include "taler/taler_exchangedb_lib.h"
      32              : #include "taler/taler_exchangedb_lib.h"
      33              : #include "exchange-database/rollback.h"
      34              : #include "exchange-database/start.h"  /* UNNECESSARY? */
      35              : #include "exchange-database/commit.h"
      36              : #include "exchange-database/preflight.h"
      37              : #include "exchange-database/do_deposit.h"
      38              : #include "exchange-database/insert_denomination_info.h"
      39              : #include "exchange-database/ensure_coin_known.h"
      40              : 
      41              : /**
      42              :  * State for a "insert-deposit" CMD.
      43              :  */
      44              : struct InsertDepositState
      45              : {
      46              :   /**
      47              :    * Database connection we use.
      48              :    */
      49              :   struct TALER_EXCHANGEDB_PostgresContext *plugin;
      50              : 
      51              :   /**
      52              :    * Human-readable name of the shop.
      53              :    */
      54              :   const char *merchant_name;
      55              : 
      56              :   /**
      57              :    * Merchant account name (NOT a payto-URI).
      58              :    */
      59              :   const char *merchant_account;
      60              : 
      61              :   /**
      62              :    * Deadline before which the aggregator should
      63              :    * send the payment to the merchant.
      64              :    */
      65              :   struct GNUNET_TIME_Relative wire_deadline;
      66              : 
      67              :   /**
      68              :    * When did the exchange receive the deposit?
      69              :    */
      70              :   struct GNUNET_TIME_Timestamp exchange_timestamp;
      71              : 
      72              :   /**
      73              :    * Amount to deposit, inclusive of deposit fee.
      74              :    */
      75              :   const char *amount_with_fee;
      76              : 
      77              :   /**
      78              :    * Deposit fee.
      79              :    */
      80              :   const char *deposit_fee;
      81              : 
      82              :   /**
      83              :    * Do we used a cached @e plugin?
      84              :    */
      85              :   bool cached;
      86              : };
      87              : 
      88              : /**
      89              :  * Setup (fake) information about a coin used in deposit.
      90              :  *
      91              :  * @param[out] issue information to initialize with "valid" data
      92              :  */
      93              : static void
      94           24 : fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
      95              : {
      96              :   struct GNUNET_TIME_Timestamp now;
      97              : 
      98           24 :   memset (issue,
      99              :           0,
     100              :           sizeof (*issue));
     101           24 :   now = GNUNET_TIME_timestamp_get ();
     102              :   issue->start
     103           24 :     = now;
     104              :   issue->expire_withdraw
     105           24 :     = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES);
     106              :   issue->expire_deposit
     107           24 :     = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS);
     108              :   issue->expire_legal
     109           24 :     = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_DAYS);
     110           24 :   GNUNET_assert (GNUNET_OK ==
     111              :                  TALER_string_to_amount ("EUR:1",
     112              :                                          &issue->value));
     113           24 :   GNUNET_assert (GNUNET_OK ==
     114              :                  TALER_string_to_amount ("EUR:0.1",
     115              :                                          &issue->fees.withdraw));
     116           24 :   GNUNET_assert (GNUNET_OK ==
     117              :                  TALER_string_to_amount ("EUR:0.1",
     118              :                                          &issue->fees.deposit));
     119           24 :   GNUNET_assert (GNUNET_OK ==
     120              :                  TALER_string_to_amount ("EUR:0.1",
     121              :                                          &issue->fees.refresh));
     122           24 :   GNUNET_assert (GNUNET_OK ==
     123              :                  TALER_string_to_amount ("EUR:0.1",
     124              :                                          &issue->fees.refund));
     125           24 : }
     126              : 
     127              : 
     128              : /**
     129              :  * Run the command.
     130              :  *
     131              :  * @param cls closure.
     132              :  * @param cmd the commaind being run.
     133              :  * @param is interpreter state.
     134              :  */
     135              : static void
     136           24 : insert_deposit_run (void *cls,
     137              :                     const struct TALER_TESTING_Command *cmd,
     138              :                     struct TALER_TESTING_Interpreter *is)
     139              : {
     140           24 :   struct InsertDepositState *ids = cls;
     141              :   struct TALER_EXCHANGEDB_CoinDepositInformation deposit;
     142              :   struct TALER_EXCHANGEDB_BatchDeposit bd;
     143              :   struct TALER_MerchantPrivateKeyP merchant_priv;
     144              :   struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
     145              :   struct TALER_DenominationPublicKey dpk;
     146              :   struct TALER_DenominationPrivateKey denom_priv;
     147              :   struct TALER_FullPayto receiver_wire_account;
     148              : 
     149              :   (void) cmd;
     150           24 :   if (NULL == ids->plugin)
     151              :   {
     152            0 :     GNUNET_break (0);
     153            0 :     TALER_TESTING_interpreter_fail (is);
     154            0 :     return;
     155              :   }
     156           24 :   if (GNUNET_OK !=
     157           24 :       TALER_EXCHANGEDB_preflight (ids->plugin))
     158              :   {
     159            0 :     GNUNET_break (0);
     160            0 :     TALER_TESTING_interpreter_fail (is);
     161            0 :     return;
     162              :   }
     163           24 :   fake_issue (&issue);
     164           24 :   GNUNET_assert (GNUNET_OK ==
     165              :                  TALER_denom_priv_create (&denom_priv,
     166              :                                           &dpk,
     167              :                                           GNUNET_CRYPTO_BSA_RSA,
     168              :                                           1024));
     169           24 :   TALER_denom_pub_hash (&dpk,
     170              :                         &issue.denom_hash);
     171              : 
     172           24 :   if ( (GNUNET_OK !=
     173           24 :         TALER_EXCHANGEDB_start (ids->plugin,
     174           24 :                                 "talertestinglib: denomination insertion")) ||
     175              :        (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     176           24 :         TALER_EXCHANGEDB_insert_denomination_info (ids->plugin,
     177              :                                                    &dpk,
     178           24 :                                                    &issue)) ||
     179              :        (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     180           24 :         TALER_EXCHANGEDB_commit (ids->plugin)) )
     181              :   {
     182            0 :     TALER_TESTING_interpreter_fail (is);
     183            0 :     TALER_denom_pub_free (&dpk);
     184            0 :     TALER_denom_priv_free (&denom_priv);
     185            0 :     return;
     186              :   }
     187              : 
     188              :   /* prepare and store deposit now. */
     189           24 :   memset (&deposit,
     190              :           0,
     191              :           sizeof (deposit));
     192           24 :   memset (&bd,
     193              :           0,
     194              :           sizeof (bd));
     195           24 :   bd.cdis = &deposit;
     196           24 :   bd.num_cdis = 1;
     197              : 
     198           24 :   GNUNET_assert (
     199              :     GNUNET_YES ==
     200              :     GNUNET_CRYPTO_hkdf_gnunet (
     201              :       &merchant_priv,
     202              :       sizeof (struct TALER_MerchantPrivateKeyP),
     203              :       "merchant-priv",
     204              :       strlen ("merchant-priv"),
     205              :       ids->merchant_name,
     206              :       strlen (ids->merchant_name)));
     207           24 :   GNUNET_assert (
     208              :     GNUNET_YES ==
     209              :     GNUNET_CRYPTO_hkdf_gnunet (
     210              :       &bd.merchant_sig,
     211              :       sizeof (struct TALER_MerchantSignatureP),
     212              :       "merchant-sig",
     213              :       strlen ("merchant-sig"),
     214              :       ids->merchant_name,
     215              :       strlen (ids->merchant_name)));
     216           24 :   GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
     217              :                                       &bd.merchant_pub.eddsa_pub);
     218           24 :   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
     219              :                                     &bd.h_contract_terms.hash);
     220           24 :   if (GNUNET_OK !=
     221           24 :       TALER_string_to_amount (ids->amount_with_fee,
     222              :                               &deposit.amount_with_fee))
     223              :   {
     224            0 :     TALER_TESTING_interpreter_fail (is);
     225            0 :     TALER_denom_pub_free (&dpk);
     226            0 :     TALER_denom_priv_free (&denom_priv);
     227            0 :     return;
     228              :   }
     229              : 
     230           24 :   TALER_denom_pub_hash (&dpk,
     231              :                         &deposit.coin.denom_pub_hash);
     232           24 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     233              :                               &deposit.coin.coin_pub,
     234              :                               sizeof (deposit.coin.coin_pub));
     235              :   {
     236              :     struct TALER_CoinPubHashP c_hash;
     237              :     struct TALER_PlanchetDetail pd;
     238              :     struct TALER_BlindedDenominationSignature bds;
     239              :     struct TALER_PlanchetMasterSecretP ps;
     240              :     union GNUNET_CRYPTO_BlindingSecretP bks;
     241              :     const struct TALER_ExchangeBlindingValues *alg_values;
     242              : 
     243           24 :     alg_values = TALER_denom_ewv_rsa_singleton ();
     244           24 :     TALER_planchet_blinding_secret_create (&ps,
     245              :                                            alg_values,
     246              :                                            &bks);
     247           24 :     GNUNET_assert (GNUNET_OK ==
     248              :                    TALER_denom_blind (&dpk,
     249              :                                       &bks,
     250              :                                       NULL, /* no age restriction active */
     251              :                                       NULL, /* no nonce needed */
     252              :                                       &deposit.coin.coin_pub,
     253              :                                       alg_values,
     254              :                                       &c_hash,
     255              :                                       &pd.blinded_planchet));
     256           24 :     GNUNET_assert (GNUNET_OK ==
     257              :                    TALER_denom_sign_blinded (&bds,
     258              :                                              &denom_priv,
     259              :                                              false,
     260              :                                              &pd.blinded_planchet));
     261           24 :     TALER_blinded_planchet_free (&pd.blinded_planchet);
     262           24 :     GNUNET_assert (GNUNET_OK ==
     263              :                    TALER_denom_sig_unblind (&deposit.coin.denom_sig,
     264              :                                             &bds,
     265              :                                             &bks,
     266              :                                             &c_hash,
     267              :                                             alg_values,
     268              :                                             &dpk));
     269           24 :     TALER_blinded_denom_sig_free (&bds);
     270              :   }
     271           24 :   GNUNET_asprintf (&receiver_wire_account.full_payto,
     272              :                    "payto://x-taler-bank/localhost/%s?receiver-name=%s",
     273              :                    ids->merchant_account,
     274              :                    ids->merchant_account);
     275           24 :   bd.receiver_wire_account = receiver_wire_account;
     276           24 :   TALER_full_payto_hash (bd.receiver_wire_account,
     277              :                          &bd.wire_target_h_payto);
     278           24 :   memset (&bd.wire_salt,
     279              :           46,
     280              :           sizeof (bd.wire_salt));
     281           24 :   bd.wallet_timestamp = GNUNET_TIME_timestamp_get ();
     282           24 :   bd.wire_deadline = GNUNET_TIME_relative_to_timestamp (
     283              :     ids->wire_deadline);
     284              :   /* finally, actually perform the DB operation */
     285              :   {
     286              :     uint64_t known_coin_id;
     287              :     struct TALER_Amount total;
     288              :     struct TALER_DenominationHashP dph;
     289              :     struct TALER_AgeCommitmentHashP agh;
     290              :     bool balance_ok;
     291              :     uint32_t bad_index;
     292              :     bool ctr_conflict;
     293              : 
     294           24 :     if ( (GNUNET_OK !=
     295           24 :           TALER_EXCHANGEDB_start (ids->plugin,
     296           24 :                                   "libtalertesting: insert deposit")) ||
     297              :          (0 >
     298           24 :           TALER_EXCHANGEDB_ensure_coin_known (ids->plugin,
     299              :                                               &deposit.coin,
     300              :                                               &known_coin_id,
     301              :                                               &dph,
     302           24 :                                               &agh)) ||
     303              :          (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     304           24 :           TALER_EXCHANGEDB_do_deposit (ids->plugin,
     305              :                                        &bd,
     306              :                                        &issue.fees.deposit,
     307              :                                        &ids->exchange_timestamp,
     308              :                                        &total,
     309              :                                        &balance_ok,
     310              :                                        &bad_index,
     311           24 :                                        &ctr_conflict)) ||
     312              :          (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     313           24 :           TALER_EXCHANGEDB_commit (ids->plugin)) )
     314              :     {
     315            0 :       GNUNET_break (0);
     316            0 :       TALER_EXCHANGEDB_rollback (ids->plugin);
     317            0 :       GNUNET_free (receiver_wire_account.full_payto);
     318            0 :       TALER_denom_pub_free (&dpk);
     319            0 :       TALER_denom_priv_free (&denom_priv);
     320            0 :       TALER_TESTING_interpreter_fail (is);
     321            0 :       return;
     322              :     }
     323              :   }
     324              : 
     325           24 :   TALER_denom_sig_free (&deposit.coin.denom_sig);
     326           24 :   TALER_denom_pub_free (&dpk);
     327           24 :   TALER_denom_priv_free (&denom_priv);
     328           24 :   GNUNET_free (receiver_wire_account.full_payto);
     329           24 :   TALER_TESTING_interpreter_next (is);
     330              : }
     331              : 
     332              : 
     333              : /**
     334              :  * Free the state of a "auditor-dbinit" CMD, and possibly kills its
     335              :  * process if it did not terminate correctly.
     336              :  *
     337              :  * @param cls closure.
     338              :  * @param cmd the command being freed.
     339              :  */
     340              : static void
     341           24 : insert_deposit_cleanup (void *cls,
     342              :                         const struct TALER_TESTING_Command *cmd)
     343              : {
     344           24 :   struct InsertDepositState *ids = cls;
     345              : 
     346              :   (void) cmd;
     347           24 :   if ( (NULL != ids->plugin) &&
     348           24 :        (! ids->cached) )
     349              :   {
     350              :     // FIXME: historically, we also did:
     351              :     // TALER_EXCHANGEDB_drop_tables (ids->plugin);
     352            1 :     TALER_EXCHANGEDB_disconnect (ids->plugin);
     353            1 :     ids->plugin = NULL;
     354              :   }
     355           24 :   GNUNET_free (ids);
     356           24 : }
     357              : 
     358              : 
     359              : struct TALER_TESTING_Command
     360           24 : TALER_TESTING_cmd_insert_deposit (
     361              :   const char *label,
     362              :   const struct GNUNET_CONFIGURATION_Handle *db_cfg,
     363              :   const char *merchant_name,
     364              :   const char *merchant_account,
     365              :   struct GNUNET_TIME_Timestamp exchange_timestamp,
     366              :   struct GNUNET_TIME_Relative wire_deadline,
     367              :   const char *amount_with_fee,
     368              :   const char *deposit_fee)
     369              : {
     370              :   static struct TALER_EXCHANGEDB_PostgresContext *pluginc;
     371              :   static const struct GNUNET_CONFIGURATION_Handle *db_cfgc;
     372              :   struct InsertDepositState *ids;
     373              : 
     374           24 :   ids = GNUNET_new (struct InsertDepositState);
     375           24 :   if (db_cfgc == db_cfg)
     376              :   {
     377           23 :     ids->plugin = pluginc;
     378           23 :     ids->cached = true;
     379              :   }
     380              :   else
     381              :   {
     382            1 :     ids->plugin = TALER_EXCHANGEDB_connect (db_cfg,
     383              :                                             false);
     384            1 :     pluginc = ids->plugin;
     385            1 :     db_cfgc = db_cfg;
     386              :   }
     387           24 :   ids->merchant_name = merchant_name;
     388           24 :   ids->merchant_account = merchant_account;
     389           24 :   ids->exchange_timestamp = exchange_timestamp;
     390           24 :   ids->wire_deadline = wire_deadline;
     391           24 :   ids->amount_with_fee = amount_with_fee;
     392           24 :   ids->deposit_fee = deposit_fee;
     393              : 
     394              :   {
     395           24 :     struct TALER_TESTING_Command cmd = {
     396              :       .cls = ids,
     397              :       .label = label,
     398              :       .run = &insert_deposit_run,
     399              :       .cleanup = &insert_deposit_cleanup
     400              :     };
     401              : 
     402           24 :     return cmd;
     403              :   }
     404              : }
     405              : 
     406              : 
     407              : /* end of testing_api_cmd_insert_deposit.c */
        

Generated by: LCOV version 2.0-1