From 48e58124fb61ded372f147d00d112f108c997f81 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 21 Sep 2023 00:01:45 +0200 Subject: major refactor of fakebank implementation --- src/bank-lib/fakebank.h | 696 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 696 insertions(+) create mode 100644 src/bank-lib/fakebank.h (limited to 'src/bank-lib/fakebank.h') diff --git a/src/bank-lib/fakebank.h b/src/bank-lib/fakebank.h new file mode 100644 index 000000000..a9285ec13 --- /dev/null +++ b/src/bank-lib/fakebank.h @@ -0,0 +1,696 @@ +/* + This file is part of TALER + (C) 2016-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file bank-lib/fakebank.h + * @brief general state of the fakebank + * @author Christian Grothoff + */ +#ifndef FAKEBANK_H +#define FAKEBANK_H + +#include "taler_fakebank_lib.h" +#include "taler_bank_service.h" +#include "taler_mhd_lib.h" +#include + + +/** + * How long are exchange base URLs allowed to be at most? + * Set to a relatively low number as this does contribute + * significantly to our RAM consumption. + */ +#define MAX_URL_LEN 64 + + +/** + * Maximum POST request size. + */ +#define REQUEST_BUFFER_MAX (4 * 1024) + + +/** + * Per account information. + */ +struct Account; + + +/** + * Types of long polling activities. + */ +enum LongPollType +{ + /** + * Transfer TO the exchange. + */ + LP_CREDIT, + + /** + * Transfer FROM the exchange. + */ + LP_DEBIT, + + /** + * Withdraw operation completion/abort. + */ + LP_WITHDRAW + +}; + +/** + * Client waiting for activity on this account. + */ +struct LongPoller +{ + + /** + * Kept in a DLL. + */ + struct LongPoller *next; + + /** + * Kept in a DLL. + */ + struct LongPoller *prev; + + /** + * Fakebank this long poller belongs with. + */ + struct TALER_FAKEBANK_Handle *h; + + /** + * Account this long poller is waiting on. + */ + struct Account *account; + + /** + * Withdraw operation we are waiting on, + * only if @e type is #LP_WITHDRAW, otherwise NULL. + */ + const struct WithdrawalOperation *wo; + + /** + * Entry in the heap for this long poller. + */ + struct GNUNET_CONTAINER_HeapNode *hn; + + /** + * Client that is waiting for transactions. + */ + struct MHD_Connection *conn; + + /** + * When will this long poller time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * What does the @e connection wait for? + */ + enum LongPollType type; + +}; + + +/** + * Details about a transcation we (as the simulated bank) received. + */ +struct Transaction; + + +/** + * Information we keep per withdraw operation. + */ +struct WithdrawalOperation +{ + /** + * Unique (random) operation ID. + */ + struct GNUNET_ShortHashCode wopid; + + /** + * Debited account. + */ + struct Account *debit_account; + + /** + * Target exchange account, or NULL if unknown. + */ + const struct Account *exchange_account; + + /** + * RowID of the resulting transaction, if any. Otherwise 0. + */ + uint64_t row_id; + + /** + * Amount transferred. + */ + struct TALER_Amount amount; + + /** + * Public key of the reserve, wire transfer subject. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * When was the transaction made? 0 if not yet. + */ + struct GNUNET_TIME_Timestamp timestamp; + + /** + * Was the withdrawal aborted? + */ + bool aborted; + + /** + * Did the bank confirm the withdrawal? + */ + bool confirmation_done; + + /** + * Is @e reserve_pub initialized? + */ + bool selection_done; + +}; + + +/** + * Per account information. + */ +struct Account +{ + + /** + * Inbound transactions for this account in a MDLL. + */ + struct Transaction *in_head; + + /** + * Inbound transactions for this account in a MDLL. + */ + struct Transaction *in_tail; + + /** + * Outbound transactions for this account in a MDLL. + */ + struct Transaction *out_head; + + /** + * Outbound transactions for this account in a MDLL. + */ + struct Transaction *out_tail; + + /** + * Kept in a DLL. + */ + struct LongPoller *lp_head; + + /** + * Kept in a DLL. + */ + struct LongPoller *lp_tail; + + /** + * Account name (string, not payto!) + */ + char *account_name; + + /** + * Receiver name for payto:// URIs. + */ + char *receiver_name; + + /** + * Payto URI for this account. + */ + char *payto_uri; + + /** + * Password set for the account (if any). + */ + char *password; + + /** + * Current account balance. + */ + struct TALER_Amount balance; + + /** + * true if the balance is negative. + */ + bool is_negative; + +}; + + +/** + * Details about a transcation we (as the simulated bank) received. + */ +struct Transaction +{ + /** + * We store inbound transactions in a MDLL. + */ + struct Transaction *next_in; + + /** + * We store inbound transactions in a MDLL. + */ + struct Transaction *prev_in; + + /** + * We store outbound transactions in a MDLL. + */ + struct Transaction *next_out; + + /** + * We store outbound transactions in a MDLL. + */ + struct Transaction *prev_out; + + /** + * Amount to be transferred. + */ + struct TALER_Amount amount; + + /** + * Account to debit. + */ + struct Account *debit_account; + + /** + * Account to credit. + */ + struct Account *credit_account; + + /** + * Random unique identifier for the request. + * Used to detect idempotent requests. + */ + struct GNUNET_HashCode request_uid; + + /** + * When did the transaction happen? + */ + struct GNUNET_TIME_Timestamp date; + + /** + * Number of this transaction. + */ + uint64_t row_id; + + /** + * What does the @e subject contain? + */ + enum + { + /** + * Transfer TO the exchange. + */ + T_CREDIT, + + /** + * Transfer FROM the exchange. + */ + T_DEBIT, + + /** + * Exchange-to-exchange WAD transfer. + */ + T_WAD, + } type; + + /** + * Wire transfer subject. + */ + union + { + + /** + * Used if @e type is T_DEBIT. + */ + struct + { + + /** + * Subject of the transfer. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Base URL of the exchange. + */ + char exchange_base_url[MAX_URL_LEN]; + + } debit; + + /** + * Used if @e type is T_CREDIT. + */ + struct + { + + /** + * Reserve public key of the credit operation. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + } credit; + + /** + * Used if @e type is T_WAD. + */ + struct + { + + /** + * Subject of the transfer. + */ + struct TALER_WadIdentifierP wad; + + /** + * Base URL of the originating exchange. + */ + char origin_base_url[MAX_URL_LEN]; + + } wad; + + } subject; + + /** + * Has this transaction not yet been subjected to + * #TALER_FAKEBANK_check_credit() or #TALER_FAKEBANK_check_debit() and + * should thus be counted in #TALER_FAKEBANK_check_empty()? + */ + bool unchecked; +}; + + +/** + * Function called to clean up context of a connection. + * + * @param ctx context to clean up + */ +typedef void +(*ConnectionCleaner)(void *ctx); + +/** + * Universal context we keep per connection. + */ +struct ConnectionContext +{ + /** + * Function we call upon completion to clean up. + */ + ConnectionCleaner ctx_cleaner; + + /** + * Request-handler specific context. + */ + void *ctx; +}; + + +/** + * This is the "base" structure for both the /history and the + * /history-range API calls. + */ +struct HistoryArgs +{ + + /** + * Bank account number of the requesting client. + */ + uint64_t account_number; + + /** + * Index of the starting transaction, exclusive (!). + */ + uint64_t start_idx; + + /** + * Requested number of results and order + * (positive: ascending, negative: descending) + */ + int64_t delta; + + /** + * Timeout for long polling. + */ + struct GNUNET_TIME_Relative lp_timeout; + + /** + * true if starting point was given. + */ + bool have_start; + +}; + + +/** + * Context we keep per history request. + */ +struct HistoryContext +{ + /** + * When does this request time out. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Client arguments for this request. + */ + struct HistoryArgs ha; + + /** + * Account the request is about. + */ + struct Account *acc; + + /** + * Payto URI of the account. + */ + char *payto_uri; + + /** + * JSON object we are building to return. + */ + json_t *history; + +}; + + +/** + * Context we keep per get withdrawal operation request. + */ +struct WithdrawContext +{ + /** + * When does this request time out. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * The withdrawal operation this is about. + */ + struct WithdrawalOperation *wo; + +}; + + +/** + * Handle for the fake bank. + */ +struct TALER_FAKEBANK_Handle +{ + /** + * We store transactions in a revolving array. + */ + struct Transaction **transactions; + + /** + * HTTP server we run to pretend to be the "test" bank. + */ + struct MHD_Daemon *mhd_bank; + + /** + * Task running HTTP server for the "test" bank, + * unless we are using a thread pool (then NULL). + */ + struct GNUNET_SCHEDULER_Task *mhd_task; + + /** + * Task for expiring long-polling connections, + * unless we are using a thread pool (then NULL). + */ + struct GNUNET_SCHEDULER_Task *lp_task; + + /** + * Task for expiring long-polling connections, unless we are using the + * GNUnet scheduler (then NULL). + */ + pthread_t lp_thread; + + /** + * MIN-heap of long pollers, sorted by timeout. + */ + struct GNUNET_CONTAINER_Heap *lp_heap; + + /** + * Hashmap of reserve public keys to + * `struct Transaction` with that reserve public + * key. Used to prevent public-key re-use. + */ + struct GNUNET_CONTAINER_MultiPeerMap *rpubs; + + /** + * Hashmap of short hashes (wopids) to + * `struct WithdrawalOperation`. + * Used to lookup withdrawal operations. + */ + struct GNUNET_CONTAINER_MultiShortmap *wops; + + /** + * (Base) URL to suggest for the exchange. Can + * be NULL if there is no suggestion to be made. + */ + char *exchange_url; + + /** + * Lock for accessing @a rpubs map. + */ + pthread_mutex_t rpubs_lock; + + /** + * Hashmap of hashes of account names to `struct Account`. + */ + struct GNUNET_CONTAINER_MultiHashMap *accounts; + + /** + * Lock for accessing @a accounts hash map. + */ + pthread_mutex_t accounts_lock; + + /** + * Hashmap of hashes of transaction request_uids to `struct Transaction`. + */ + struct GNUNET_CONTAINER_MultiHashMap *uuid_map; + + /** + * Lock for accessing @a uuid_map. + */ + pthread_mutex_t uuid_map_lock; + + /** + * Lock for accessing the internals of + * accounts and transaction array entries. + */ + pthread_mutex_t big_lock; + + /** + * How much money should be put into new accounts + * on /register. + */ + struct TALER_Amount signup_bonus; + + /** + * Current transaction counter. + */ + uint64_t serial_counter; + + /** + * Number of transactions we keep in memory (at most). + */ + uint64_t ram_limit; + + /** + * Currency used by the fakebank. + */ + char *currency; + + /** + * Hostname of the fakebank. + */ + char *hostname; + + /** + * BaseURL of the fakebank. + */ + char *my_baseurl; + + /** + * Our port number. + */ + uint16_t port; + +#ifdef __linux__ + /** + * Event FD to signal @a lp_thread a change in + * @a lp_heap. + */ + int lp_event; +#else + /** + * Pipe input to signal @a lp_thread a change in + * @a lp_heap. + */ + int lp_event_in; + + /** + * Pipe output to signal @a lp_thread a change in + * @a lp_heap. + */ + int lp_event_out; +#endif + + /** + * Set to true once we are shutting down. + */ + bool in_shutdown; + + /** + * Should we run MHD immediately again? + */ + bool mhd_again; + +#if EPOLL_SUPPORT + /** + * Boxed @e mhd_fd. + */ + struct GNUNET_NETWORK_Handle *mhd_rfd; + + /** + * File descriptor to use to wait for MHD. + */ + int mhd_fd; +#endif +}; + + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls the `struct TALER_FAKEBANK_Handle` + */ +void +TALER_FAKEBANK_run_mhd_ (void *cls); + + +#endif -- cgit v1.2.3