exchange

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

fakebank_tbr_get_history.c (9513B)


      1 /*
      2   This file is part of TALER
      3   (C) 2016-2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or
      6   modify it under the terms of the GNU General Public License
      7   as published by the Free Software Foundation; either version 3,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful,
     11   but 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 bank-lib/fakebank_tbr_get_history.c
     21  * @brief library that fakes being a Taler bank for testcases
     22  * @author Christian Grothoff <christian@grothoff.org>
     23  */
     24 #include <pthread.h>
     25 #include "taler/taler_fakebank_lib.h"
     26 #include "taler/taler_bank_service.h"
     27 #include "taler/taler_mhd_lib.h"
     28 #include <gnunet/gnunet_mhd_compat.h>
     29 #include "fakebank.h"
     30 #include "fakebank_common_lookup.h"
     31 #include "fakebank_common_lp.h"
     32 #include "fakebank_common_parser.h"
     33 #include "fakebank_tbr_get_history.h"
     34 
     35 
     36 /**
     37  * Function called to clean up a history context.
     38  *
     39  * @param cls a `struct HistoryContext *`
     40  */
     41 static void
     42 history_cleanup (void *cls)
     43 {
     44   struct HistoryContext *hc = cls;
     45 
     46   json_decref (hc->history);
     47   GNUNET_free (hc);
     48 }
     49 
     50 
     51 MHD_RESULT
     52 TALER_FAKEBANK_tbr_get_history (
     53   struct TALER_FAKEBANK_Handle *h,
     54   struct MHD_Connection *connection,
     55   const char *account,
     56   void **con_cls)
     57 {
     58   struct ConnectionContext *cc = *con_cls;
     59   struct HistoryContext *hc;
     60   const struct Transaction *pos;
     61   enum GNUNET_GenericReturnValue ret;
     62   bool in_shutdown;
     63   const char *acc_payto_uri;
     64 
     65   if (NULL == cc)
     66   {
     67     cc = GNUNET_new (struct ConnectionContext);
     68     cc->ctx_cleaner = &history_cleanup;
     69     *con_cls = cc;
     70     hc = GNUNET_new (struct HistoryContext);
     71     cc->ctx = hc;
     72     hc->history = json_array ();
     73     if (NULL == hc->history)
     74     {
     75       GNUNET_break (0);
     76       return MHD_NO;
     77     }
     78     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     79                 "Handling /accounts/%s/taler-revenue/history request\n",
     80                 account);
     81     if (GNUNET_OK !=
     82         (ret = TALER_FAKEBANK_common_parse_history_args (h,
     83                                                          connection,
     84                                                          &hc->ha)))
     85     {
     86       GNUNET_break_op (0);
     87       return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
     88     }
     89     hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout);
     90     GNUNET_assert (0 ==
     91                    pthread_mutex_lock (&h->big_lock));
     92     if (UINT64_MAX == hc->ha.start_idx)
     93       hc->ha.start_idx = h->serial_counter;
     94     hc->acc = TALER_FAKEBANK_lookup_account_ (h,
     95                                               account,
     96                                               NULL);
     97     if (NULL == hc->acc)
     98     {
     99       GNUNET_assert (0 ==
    100                      pthread_mutex_unlock (&h->big_lock));
    101       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    102                   "Account %s is unknown\n",
    103                   account);
    104       return TALER_MHD_reply_with_error (connection,
    105                                          MHD_HTTP_NOT_FOUND,
    106                                          TALER_EC_BANK_UNKNOWN_ACCOUNT,
    107                                          account);
    108     }
    109   }
    110   else
    111   {
    112     hc = cc->ctx;
    113     GNUNET_assert (0 ==
    114                    pthread_mutex_lock (&h->big_lock));
    115   }
    116 
    117   if (! hc->ha.have_start)
    118   {
    119     pos = (0 > hc->ha.delta)
    120           ? hc->acc->in_tail
    121           : hc->acc->in_head;
    122   }
    123   else
    124   {
    125     struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit];
    126     bool overflow;
    127     uint64_t dir;
    128     bool skip = true;
    129 
    130     overflow = ( (NULL != t) && (t->row_id != hc->ha.start_idx) );
    131     dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1;
    132     /* If account does not match, linear scan for
    133        first matching account. */
    134     while ( (! overflow) &&
    135             (NULL != t) &&
    136             (t->credit_account != hc->acc) )
    137     {
    138       skip = false;
    139       t = h->transactions[(t->row_id + dir) % h->ram_limit];
    140       if ( (NULL != t) &&
    141            (t->row_id == hc->ha.start_idx) )
    142         overflow = true; /* full circle, give up! */
    143     }
    144     if ( (NULL == t) ||
    145          overflow)
    146     {
    147       in_shutdown = h->in_shutdown;
    148       /* FIXME: these conditions are unclear to me. */
    149       if (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout) &&
    150           (0 < hc->ha.delta))
    151       {
    152         acc_payto_uri = hc->acc->payto_uri;
    153         GNUNET_assert (0 ==
    154                        pthread_mutex_unlock (&h->big_lock));
    155         if (overflow)
    156         {
    157           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    158                       "Transactions lost due to RAM limits\n");
    159           return TALER_MHD_reply_with_ec (
    160             connection,
    161             TALER_EC_BANK_ANCIENT_TRANSACTION_GONE,
    162             NULL);
    163         }
    164         goto finish;
    165       }
    166       if (in_shutdown)
    167       {
    168         acc_payto_uri = hc->acc->payto_uri;
    169         GNUNET_assert (0 ==
    170                        pthread_mutex_unlock (&h->big_lock));
    171         goto finish;
    172       }
    173       TALER_FAKEBANK_start_lp_ (h,
    174                                 connection,
    175                                 hc->acc,
    176                                 GNUNET_TIME_absolute_get_remaining (
    177                                   hc->timeout),
    178                                 LP_CREDIT,
    179                                 NULL);
    180       GNUNET_assert (0 ==
    181                      pthread_mutex_unlock (&h->big_lock));
    182       return MHD_YES;
    183     }
    184     if (skip)
    185     {
    186       /* range from application is exclusive, skip the
    187   matching entry */
    188       if (0 > hc->ha.delta)
    189         pos = t->prev_in;
    190       else
    191         pos = t->next_in;
    192     }
    193     else
    194     {
    195       pos = t;
    196     }
    197   }
    198   if (NULL != pos)
    199     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    200                 "Returning %lld credit transactions starting (inclusive) from %llu\n",
    201                 (long long) hc->ha.delta,
    202                 (unsigned long long) pos->row_id);
    203   while ( (0 != hc->ha.delta) &&
    204           (NULL != pos) )
    205   {
    206     json_t *trans;
    207     char *subject;
    208 
    209     if (T_DEBIT != pos->type)
    210     {
    211       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    212                   "Unexpected CREDIT transaction #%llu for account `%s'\n",
    213                   (unsigned long long) pos->row_id,
    214                   account);
    215       if (0 > hc->ha.delta)
    216         pos = pos->prev_in;
    217       if (0 < hc->ha.delta)
    218         pos = pos->next_in;
    219       continue;
    220     }
    221 
    222     {
    223       char *wtids;
    224 
    225       wtids = GNUNET_STRINGS_data_to_string_alloc (
    226         &pos->subject.debit.wtid,
    227         sizeof (pos->subject.debit.wtid));
    228       GNUNET_asprintf (&subject,
    229                        "%s %s",
    230                        wtids,
    231                        pos->subject.debit.exchange_base_url);
    232       GNUNET_free (wtids);
    233     }
    234     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    235                 "Found transaction over %s with subject %s\n",
    236                 TALER_amount2s (&pos->amount),
    237                 subject);
    238     trans = GNUNET_JSON_PACK (
    239       GNUNET_JSON_pack_string ("type",
    240                                "RESERVE"),
    241       GNUNET_JSON_pack_uint64 ("row_id",
    242                                pos->row_id),
    243       GNUNET_JSON_pack_timestamp ("date",
    244                                   pos->date),
    245       TALER_JSON_pack_amount ("amount",
    246                               &pos->amount),
    247       GNUNET_JSON_pack_string ("debit_account",
    248                                pos->debit_account->payto_uri),
    249       GNUNET_JSON_pack_string ("subject",
    250                                subject));
    251     GNUNET_free (subject);
    252     GNUNET_assert (NULL != trans);
    253     GNUNET_assert (0 ==
    254                    json_array_append_new (hc->history,
    255                                           trans));
    256     if (hc->ha.delta > 0)
    257       hc->ha.delta--;
    258     else
    259       hc->ha.delta++;
    260     if (0 > hc->ha.delta)
    261       pos = pos->prev_in;
    262     if (0 < hc->ha.delta)
    263       pos = pos->next_in;
    264   }
    265   if ( (0 == json_array_size (hc->history)) &&
    266        (! h->in_shutdown) &&
    267        (GNUNET_TIME_absolute_is_future (hc->timeout)) &&
    268        (0 < hc->ha.delta))
    269   {
    270     TALER_FAKEBANK_start_lp_ (h,
    271                               connection,
    272                               hc->acc,
    273                               GNUNET_TIME_absolute_get_remaining (hc->timeout),
    274                               LP_CREDIT,
    275                               NULL);
    276     GNUNET_assert (0 ==
    277                    pthread_mutex_unlock (&h->big_lock));
    278     return MHD_YES;
    279   }
    280   in_shutdown = h->in_shutdown;
    281   acc_payto_uri = hc->acc->payto_uri;
    282   GNUNET_assert (0 ==
    283                  pthread_mutex_unlock (&h->big_lock));
    284 finish:
    285   if (0 == json_array_size (hc->history))
    286   {
    287     GNUNET_break (in_shutdown ||
    288                   (! GNUNET_TIME_absolute_is_future (hc->timeout)));
    289     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    290                 "Zero transactions found\n");
    291     return TALER_MHD_reply_static (connection,
    292                                    MHD_HTTP_NO_CONTENT,
    293                                    NULL,
    294                                    NULL,
    295                                    0);
    296   }
    297   {
    298     json_t *jh = hc->history;
    299 
    300     hc->history = NULL;
    301     return TALER_MHD_REPLY_JSON_PACK (
    302       connection,
    303       MHD_HTTP_OK,
    304       GNUNET_JSON_pack_string (
    305         "credit_account",
    306         acc_payto_uri),
    307       GNUNET_JSON_pack_array_steal (
    308         "incoming_transactions",
    309         jh));
    310   }
    311 }