exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_stefan.c (6852B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2023 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
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file lib/test_stefan.c
     19  * @brief test calculations on the STEFAN curve
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include "taler/taler_json_lib.h"
     24 #include <gnunet/gnunet_curl_lib.h>
     25 #include "exchange_api_handle.h"
     26 
     27 
     28 /**
     29  * Check if @a a and @a b are numerically close.
     30  *
     31  * @param a an amount
     32  * @param b an amount
     33  * @return true if both values are quite close
     34  */
     35 static bool
     36 amount_close (const struct TALER_Amount *a,
     37               const struct TALER_Amount *b)
     38 {
     39   struct TALER_Amount delta;
     40 
     41   switch (TALER_amount_cmp (a,
     42                             b))
     43   {
     44   case -1: /* a < b */
     45     GNUNET_assert (0 <
     46                    TALER_amount_subtract (&delta,
     47                                           b,
     48                                           a));
     49     break;
     50   case 0:
     51     /* perfect */
     52     return true;
     53   case 1: /* a > b */
     54     GNUNET_assert (0 <
     55                    TALER_amount_subtract (&delta,
     56                                           a,
     57                                           b));
     58     break;
     59   }
     60   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     61               "Rounding error is %s\n",
     62               TALER_amount2s (&delta));
     63   if (delta.value > 0)
     64   {
     65     GNUNET_break (0);
     66     return false;
     67   }
     68   if (delta.fraction > 5000)
     69   {
     70     GNUNET_break (0);
     71     return false;
     72   }
     73   return true; /* let's consider this a rounding error */
     74 }
     75 
     76 
     77 int
     78 main (int argc,
     79       char **argv)
     80 {
     81   struct TALER_EXCHANGE_DenomPublicKey dk;
     82   struct TALER_EXCHANGE_Keys keys = {
     83     .denom_keys = &dk,
     84     .num_denom_keys = 1
     85   };
     86   struct TALER_Amount brut;
     87   struct TALER_Amount net;
     88 
     89   (void) argc;
     90   (void) argv;
     91   GNUNET_log_setup ("test-stefan",
     92                     "INFO",
     93                     NULL);
     94   GNUNET_assert (GNUNET_OK ==
     95                  TALER_string_to_amount ("MAGIC:0.00001",
     96                                          &dk.value));
     97   GNUNET_assert (GNUNET_OK ==
     98                  TALER_string_to_amount ("MAGIC:1",
     99                                          &keys.stefan_abs));
    100   GNUNET_assert (GNUNET_OK ==
    101                  TALER_string_to_amount ("MAGIC:0.13",
    102                                          &keys.stefan_log));
    103   keys.stefan_lin = 1.15;
    104   GNUNET_assert (GNUNET_OK ==
    105                  TALER_string_to_amount ("MAGIC:4",
    106                                          &brut));
    107   GNUNET_log_skip (1,
    108                    GNUNET_NO);
    109   GNUNET_assert (GNUNET_SYSERR ==
    110                  TALER_EXCHANGE_keys_stefan_b2n (&keys,
    111                                                  &brut,
    112                                                  &net));
    113   GNUNET_assert (GNUNET_OK ==
    114                  TALER_string_to_amount ("MAGIC:4",
    115                                          &net));
    116   GNUNET_log_skip (1,
    117                    GNUNET_NO);
    118   GNUNET_assert (GNUNET_SYSERR ==
    119                  TALER_EXCHANGE_keys_stefan_n2b (&keys,
    120                                                  &net,
    121                                                  &brut));
    122   keys.stefan_lin = 1.0;
    123   GNUNET_assert (GNUNET_OK ==
    124                  TALER_string_to_amount ("MAGIC:4",
    125                                          &brut));
    126   GNUNET_log_skip (1,
    127                    GNUNET_NO);
    128   GNUNET_assert (GNUNET_SYSERR ==
    129                  TALER_EXCHANGE_keys_stefan_b2n (&keys,
    130                                                  &brut,
    131                                                  &net));
    132   GNUNET_assert (GNUNET_OK ==
    133                  TALER_string_to_amount ("MAGIC:4",
    134                                          &net));
    135   GNUNET_log_skip (1,
    136                    GNUNET_NO);
    137   GNUNET_assert (GNUNET_SYSERR ==
    138                  TALER_EXCHANGE_keys_stefan_n2b (&keys,
    139                                                  &net,
    140                                                  &brut));
    141   GNUNET_assert (0 == GNUNET_get_log_skip ());
    142   keys.stefan_lin = 0.1;
    143 
    144   /* try various values for lin and log STEFAN values */
    145   for (unsigned int li = 1; li < 13; li += 1)
    146   {
    147     keys.stefan_lin = 1.0 * li / 100.0;
    148 
    149     for (unsigned int lx = 1; lx < 100; lx += 1)
    150     {
    151       keys.stefan_log.fraction = lx * TALER_AMOUNT_FRAC_BASE / 100;
    152 
    153       /* Check brutto-to-netto is stable */
    154       for (unsigned int i = 0; i<10; i++)
    155       {
    156         struct TALER_Amount rval;
    157 
    158         brut.value = i;
    159         brut.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
    160         GNUNET_assert (GNUNET_SYSERR !=
    161                        TALER_EXCHANGE_keys_stefan_b2n (&keys,
    162                                                        &brut,
    163                                                        &net));
    164         GNUNET_assert (GNUNET_SYSERR !=
    165                        TALER_EXCHANGE_keys_stefan_n2b (&keys,
    166                                                        &net,
    167                                                        &rval));
    168         if (TALER_amount_is_zero (&net))
    169           GNUNET_assert (TALER_amount_is_zero (&rval));
    170         else
    171         {
    172           GNUNET_assert (amount_close (&brut,
    173                                        &rval));
    174           TALER_EXCHANGE_keys_stefan_round (&keys,
    175                                             &rval);
    176           GNUNET_assert (amount_close (&brut,
    177                                        &rval));
    178         }
    179       }
    180 
    181       /* Check netto-to-brutto is stable */
    182       for (unsigned int i = 0; i<10; i++)
    183       {
    184         struct TALER_Amount rval;
    185 
    186         net.value = i;
    187         net.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
    188         GNUNET_assert (GNUNET_SYSERR !=
    189                        TALER_EXCHANGE_keys_stefan_n2b (&keys,
    190                                                        &net,
    191                                                        &brut));
    192         GNUNET_assert (GNUNET_SYSERR !=
    193                        TALER_EXCHANGE_keys_stefan_b2n (&keys,
    194                                                        &brut,
    195                                                        &rval));
    196         GNUNET_assert (amount_close (&net,
    197                                      &rval));
    198         TALER_EXCHANGE_keys_stefan_round (&keys,
    199                                           &rval);
    200         GNUNET_assert (amount_close (&net,
    201                                      &rval));
    202       }
    203     }
    204   }
    205   return 0;
    206 }