merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-httpd_post-private-orders.c (147512B)


      1 /*
      2   This file is part of TALER
      3   (C) 2014-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   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, 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 /**
     21  * @file src/backend/taler-merchant-httpd_post-private-orders.c
     22  * @brief the POST /orders handler
     23  * @author Christian Grothoff
     24  * @author Marcello Stanisci
     25  * @author Christian Blättler
     26  */
     27 #include "platform.h"
     28 #include <gnunet/gnunet_common.h>
     29 #include <gnunet/gnunet_db_lib.h>
     30 #include <gnunet/gnunet_json_lib.h>
     31 #include <gnunet/gnunet_time_lib.h>
     32 #include <jansson.h>
     33 #include <microhttpd.h>
     34 #include <string.h>
     35 #include <taler/taler_error_codes.h>
     36 #include <taler/taler_signatures.h>
     37 #include <taler/taler_json_lib.h>
     38 #include <taler/taler_dbevents.h>
     39 #include <taler/taler_util.h>
     40 #include <taler/taler_merchant_util.h>
     41 #include <time.h>
     42 #include "taler-merchant-httpd.h"
     43 #include "taler-merchant-httpd_exchanges.h"
     44 #include "taler-merchant-httpd_post-private-orders.h"
     45 #include "taler-merchant-httpd_get-exchanges.h"
     46 #include "taler-merchant-httpd_contract.h"
     47 #include "taler-merchant-httpd_helper.h"
     48 #include "taler-merchant-httpd_get-private-orders.h"
     49 #include "merchantdb_lib.h"
     50 #include "merchant-database/start.h"
     51 #include "merchant-database/event_listen.h"
     52 #include "merchant-database/event_notify.h"
     53 #include "merchant-database/preflight.h"
     54 #include "merchant-database/expire_locks.h"
     55 #include "merchant-database/check_money_pots.h"
     56 #include "merchant-database/insert_order.h"
     57 #include "merchant-database/insert_order_lock.h"
     58 #include "merchant-database/insert_token_family_key.h"
     59 #include "merchant-database/lookup_order.h"
     60 #include "merchant-database/lookup_order_summary.h"
     61 #include "merchant-database/lookup_product.h"
     62 #include "merchant-database/lookup_token_family_key.h"
     63 #include "merchant-database/lookup_token_family_keys.h"
     64 #include "merchant-database/select_donau_instances_filtered.h"
     65 #include "merchant-database/select_otp.h"
     66 #include "merchant-database/unlock_inventory.h"
     67 
     68 
     69 /**
     70  * How often do we retry the simple INSERT database transaction?
     71  */
     72 #define MAX_RETRIES 3
     73 
     74 /**
     75  * Maximum number of inventory products per order.
     76  */
     77 #define MAX_PRODUCTS 1024
     78 
     79 /**
     80  * What is the label under which we find/place the merchant's
     81  * jurisdiction in the locations list by default?
     82  */
     83 #define STANDARD_LABEL_MERCHANT_JURISDICTION "_mj"
     84 
     85 /**
     86  * What is the label under which we find/place the merchant's
     87  * address in the locations list by default?
     88  */
     89 #define STANDARD_LABEL_MERCHANT_ADDRESS "_ma"
     90 
     91 /**
     92  * How long do we wait at most for /keys from the exchange(s)?
     93  * Ensures that we do not block forever just because some exchange
     94  * fails to respond *or* because our taler-merchant-keyscheck
     95  * refuses a forced download.
     96  */
     97 #define MAX_KEYS_WAIT \
     98         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500)
     99 
    100 /**
    101  * Generate the base URL for the given merchant instance.
    102  *
    103  * @param connection the MHD connection
    104  * @param instance_id the merchant instance ID
    105  * @returns the merchant instance's base URL
    106  */
    107 static char *
    108 make_merchant_base_url (struct MHD_Connection *connection,
    109                         const char *instance_id)
    110 {
    111   struct GNUNET_Buffer buf;
    112 
    113   if (GNUNET_OK !=
    114       TMH_base_url_by_connection (connection,
    115                                   instance_id,
    116                                   &buf))
    117     return NULL;
    118   GNUNET_buffer_write_path (&buf,
    119                             "");
    120   return GNUNET_buffer_reap_str (&buf);
    121 }
    122 
    123 
    124 /**
    125  * Information about a product we are supposed to add to the order
    126  * based on what we know it from our inventory.
    127  */
    128 struct InventoryProduct
    129 {
    130   /**
    131    * Identifier of the product in the inventory.
    132    */
    133   const char *product_id;
    134 
    135   /**
    136    * Number of units of the product to add to the order (integer part).
    137    */
    138   uint64_t quantity;
    139 
    140   /**
    141    * Fractional part of the quantity in units of 1/1000000 of the base value.
    142    */
    143   uint32_t quantity_frac;
    144 
    145   /**
    146    * True if the integer quantity field was missing in the request.
    147    */
    148   bool quantity_missing;
    149 
    150   /**
    151    * String representation of the quantity, if supplied.
    152    */
    153   const char *unit_quantity;
    154 
    155   /**
    156    * True if the string quantity field was missing in the request.
    157    */
    158   bool unit_quantity_missing;
    159 
    160   /**
    161    * Money pot associated with the product. 0 for none.
    162    */
    163   uint64_t product_money_pot;
    164 
    165 };
    166 
    167 
    168 /**
    169  * Handle for a rekey operation where we (re)request
    170  * the /keys from the exchange.
    171  */
    172 struct RekeyExchange
    173 {
    174   /**
    175    * Kept in a DLL.
    176    */
    177   struct RekeyExchange *prev;
    178 
    179   /**
    180    * Kept in a DLL.
    181    */
    182   struct RekeyExchange *next;
    183 
    184   /**
    185    * order this is for.
    186    */
    187   struct OrderContext *oc;
    188 
    189   /**
    190    * Base URL of the exchange.
    191    */
    192   char *url;
    193 
    194   /**
    195    * Request for keys.
    196    */
    197   struct TMH_EXCHANGES_KeysOperation *fo;
    198 
    199 };
    200 
    201 
    202 /**
    203  * Data structure where we evaluate the viability of a given
    204  * wire method for this order.
    205  */
    206 struct WireMethodCandidate
    207 {
    208   /**
    209    * Kept in a DLL.
    210    */
    211   struct WireMethodCandidate *next;
    212 
    213   /**
    214    * Kept in a DLL.
    215    */
    216   struct WireMethodCandidate *prev;
    217 
    218   /**
    219    * The wire method we are evaluating.
    220    */
    221   const struct TMH_WireMethod *wm;
    222 
    223   /**
    224    * List of exchanges to use when we use this wire method.
    225    */
    226   json_t *exchanges;
    227 
    228   /**
    229    * Set of maximum amounts that could be paid over all available exchanges
    230    * for this @a wm. Used to determine if this order creation requests exceeds
    231    * legal limits.
    232    */
    233   struct TALER_AmountSet total_exchange_limits;
    234 
    235 };
    236 
    237 
    238 /**
    239  * Information we keep per order we are processing.
    240  */
    241 struct OrderContext
    242 {
    243   /**
    244    * Information set in the #ORDER_PHASE_PARSE_REQUEST phase.
    245    */
    246   struct
    247   {
    248     /**
    249      * Order field of the request
    250      */
    251     json_t *order;
    252 
    253     /**
    254      * Set to how long refunds will be allowed.
    255      */
    256     struct GNUNET_TIME_Relative refund_delay;
    257 
    258     /**
    259      * RFC8905 payment target type to find a matching merchant account
    260      */
    261     const char *payment_target;
    262 
    263     /**
    264      * Shared key to use with @e pos_algorithm.
    265      */
    266     char *pos_key;
    267 
    268     /**
    269      * Selected algorithm (by template) when we are to
    270      * generate an OTP code for payment confirmation.
    271      */
    272     enum TALER_MerchantConfirmationAlgorithm pos_algorithm;
    273 
    274     /**
    275      * Hash of the POST request data, used to detect
    276      * idempotent requests.
    277      */
    278     struct TALER_MerchantPostDataHashP h_post_data;
    279 
    280     /**
    281      * Length of the @e inventory_products array.
    282      */
    283     unsigned int inventory_products_length;
    284 
    285     /**
    286      * Specifies that some products are to be included in the
    287      * order from the inventory. For these inventory management
    288      * is performed (so the products must be in stock).
    289      */
    290     struct InventoryProduct *inventory_products;
    291 
    292     /**
    293      * Length of the @e uuids array.
    294      */
    295     unsigned int uuids_length;
    296 
    297     /**
    298      * array of UUIDs used to reserve products from @a inventory_products.
    299      */
    300     struct GNUNET_Uuid *uuids;
    301 
    302     /**
    303      * Claim token for the request.
    304      */
    305     struct TALER_ClaimTokenP claim_token;
    306 
    307     /**
    308      * Session ID (optional) to use for the order.
    309      */
    310     const char *session_id;
    311 
    312   } parse_request;
    313 
    314   /**
    315    * Information set in the #ORDER_PHASE_PARSE_ORDER phase.
    316    */
    317   struct
    318   {
    319 
    320     /**
    321      * Our order ID.
    322      */
    323     char *order_id;
    324 
    325     /**
    326      * Summary of the contract.
    327      */
    328     const char *summary;
    329 
    330     /**
    331      * Internationalized summary.
    332      */
    333     const json_t *summary_i18n;
    334 
    335     /**
    336      * URL that will show that the contract was successful
    337      * after it has been paid for.
    338      */
    339     const char *fulfillment_url;
    340 
    341     /**
    342     * Message shown to the customer after paying for the contract.
    343     * Either fulfillment_url or fulfillment_message must be specified.
    344     */
    345     const char *fulfillment_message;
    346 
    347     /**
    348      * Map from IETF BCP 47 language tags to localized fulfillment messages.
    349      */
    350     const json_t *fulfillment_message_i18n;
    351 
    352     /**
    353      * Length of the @e products array.
    354      */
    355     size_t products_len;
    356 
    357     /**
    358      * Array of products that are being sold.
    359      */
    360     struct TALER_MERCHANT_ProductSold *products;
    361 
    362     /**
    363      * URL where the same contract could be ordered again (if available).
    364      */
    365     const char *public_reorder_url;
    366 
    367     /**
    368      * Merchant base URL.
    369      */
    370     char *merchant_base_url;
    371 
    372     /**
    373      * Timestamp of the order.
    374      */
    375     struct GNUNET_TIME_Timestamp timestamp;
    376 
    377     /**
    378      * Deadline for refunds.
    379      */
    380     struct GNUNET_TIME_Timestamp refund_deadline;
    381 
    382     /**
    383      * Payment deadline.
    384      */
    385     struct GNUNET_TIME_Timestamp pay_deadline;
    386 
    387     /**
    388      * Wire transfer deadline.
    389      */
    390     struct GNUNET_TIME_Timestamp wire_deadline;
    391 
    392     /**
    393      * Wire transfer round-up interval to apply.
    394      */
    395     enum GNUNET_TIME_RounderInterval wire_deadline_rounder;
    396 
    397     /**
    398      * Delivery date.
    399      */
    400     struct GNUNET_TIME_Timestamp delivery_date;
    401 
    402     /**
    403      * Delivery location.
    404      */
    405     const json_t *delivery_location;
    406 
    407     /**
    408      * Specifies for how long the wallet should try to get an
    409      * automatic refund for the purchase.
    410      */
    411     struct GNUNET_TIME_Relative auto_refund;
    412 
    413     /**
    414      * Nonce generated by the wallet and echoed by the merchant
    415      * in this field when the proposal is generated.
    416      */
    417     const char *nonce;
    418 
    419     /**
    420      * Extra data that is only interpreted by the merchant frontend.
    421      */
    422     const json_t *extra;
    423 
    424     /**
    425      * Minimum age required by the order.
    426      */
    427     uint32_t minimum_age;
    428 
    429     /**
    430      * Money pot to increment for whatever order payment amount
    431      * is not yet assigned to a pot via the Product.
    432      */
    433     uint64_t order_default_money_pot;
    434 
    435     /**
    436      * Version of the contract terms.
    437      */
    438     enum TALER_MERCHANT_ContractVersion version;
    439 
    440     /**
    441      * Details present depending on @e version.
    442      */
    443     union
    444     {
    445       /**
    446        * Details only present for v0.
    447        */
    448       struct
    449       {
    450         /**
    451          * Gross amount value of the contract. Used to
    452          * compute @e max_stefan_fee.
    453          */
    454         struct TALER_Amount brutto;
    455 
    456         /**
    457          * Tip included by the customer (part of the total amount).
    458          */
    459         struct TALER_Amount tip;
    460 
    461         /**
    462          * True if @e tip was not provided.
    463          */
    464         bool no_tip;
    465 
    466         /**
    467          * Maximum fee as given by the client request.
    468          */
    469         struct TALER_Amount max_fee;
    470       } v0;
    471 
    472       /**
    473        * Details only present for v1.
    474        */
    475       struct
    476       {
    477         /**
    478          * Array of contract choices. Is null for v0 contracts.
    479          */
    480         const json_t *choices;
    481       } v1;
    482     } details;
    483 
    484   } parse_order;
    485 
    486   /**
    487    * Information set in the #ORDER_PHASE_PARSE_CHOICES phase.
    488    */
    489   struct
    490   {
    491     /**
    492      * Array of possible specific contracts the wallet/customer may choose
    493      * from by selecting the respective index when signing the deposit
    494      * confirmation.
    495      */
    496     struct TALER_MERCHANT_ContractChoice *choices;
    497 
    498     /**
    499      * Length of the @e choices array.
    500      */
    501     unsigned int choices_len;
    502 
    503     /**
    504      * Array of token families referenced in the contract.
    505      */
    506     struct TALER_MERCHANT_ContractTokenFamily *token_families;
    507 
    508     /**
    509      * Length of the @e token_families array.
    510      */
    511     unsigned int token_families_len;
    512   } parse_choices;
    513 
    514   /**
    515    * Information set in the #ORDER_PHASE_MERGE_INVENTORY phase.
    516    */
    517   struct
    518   {
    519     /**
    520      * Merged array of products in the @e order.
    521      */
    522     json_t *products;
    523   } merge_inventory;
    524 
    525   /**
    526    * Information set in the #ORDER_PHASE_ADD_PAYMENT_DETAILS phase.
    527    */
    528   struct
    529   {
    530 
    531     /**
    532      * DLL of wire methods under evaluation.
    533      */
    534     struct WireMethodCandidate *wmc_head;
    535 
    536     /**
    537      * DLL of wire methods under evaluation.
    538      */
    539     struct WireMethodCandidate *wmc_tail;
    540 
    541     /**
    542      * Array of maximum amounts that appear in the contract choices
    543      * per currency.
    544      * Determines the maximum amounts that a client could pay for this
    545      * order and which we must thus make sure is acceptable for the
    546      * selected wire method/account if possible.
    547      */
    548     struct TALER_Amount *max_choice_limits;
    549 
    550     /**
    551      * Length of the @e max_choice_limits array.
    552      */
    553     unsigned int num_max_choice_limits;
    554 
    555     /**
    556      * Set to true if we may need an exchange. True if any amount is non-zero.
    557      */
    558     bool need_exchange;
    559 
    560   } add_payment_details;
    561 
    562   /**
    563    * Information set in the #ORDER_PHASE_SELECT_WIRE_METHOD phase.
    564    */
    565   struct
    566   {
    567 
    568     /**
    569      * Array of exchanges we find acceptable for this order and wire method.
    570      */
    571     json_t *exchanges;
    572 
    573     /**
    574      * Wire method (and our bank account) we have selected
    575      * to be included for this order.
    576      */
    577     const struct TMH_WireMethod *wm;
    578 
    579   } select_wire_method;
    580 
    581   /**
    582    * Information set in the #ORDER_PHASE_SET_EXCHANGES phase.
    583    */
    584   struct
    585   {
    586 
    587     /**
    588      * Forced requests to /keys to update our exchange
    589      * information.
    590      */
    591     struct RekeyExchange *pending_reload_head;
    592 
    593     /**
    594      * Forced requests to /keys to update our exchange
    595      * information.
    596      */
    597     struct RekeyExchange *pending_reload_tail;
    598 
    599     /**
    600      * How long do we wait at most until giving up on getting keys?
    601      */
    602     struct GNUNET_TIME_Absolute keys_timeout;
    603 
    604     /**
    605      * Task to wake us up on @e keys_timeout.
    606      */
    607     struct GNUNET_SCHEDULER_Task *wakeup_task;
    608 
    609     /**
    610      * Array of reasons why a particular exchange may be
    611      * limited or not be eligible.
    612      */
    613     json_t *exchange_rejections;
    614 
    615     /**
    616      * Did we previously force reloading of /keys from
    617      * all exchanges? Set to 'true' to prevent us from
    618      * doing it again (and again...).
    619      */
    620     bool forced_reload;
    621 
    622     /**
    623      * Did we find a working exchange?
    624      */
    625     bool exchange_ok;
    626 
    627     /**
    628      * Did we find an exchange that justifies
    629      * reloading keys?
    630      */
    631     bool promising_exchange;
    632 
    633     /**
    634      * Set to true once we have attempted to load exchanges
    635      * for the first time.
    636      */
    637     bool exchanges_tried;
    638 
    639     /**
    640      * Details depending on the contract version.
    641      */
    642     union
    643     {
    644 
    645       /**
    646        * Details for contract v0.
    647        */
    648       struct
    649       {
    650         /**
    651          * Maximum fee for @e order based on STEFAN curves.
    652          * Used to set @e max_fee if not provided as part of
    653          * @e order.
    654          */
    655         struct TALER_Amount max_stefan_fee;
    656 
    657       } v0;
    658 
    659       /**
    660        * Details for contract v1.
    661        */
    662       struct
    663       {
    664         /**
    665          * Maximum fee for @e order based on STEFAN curves by
    666          * contract choice.
    667          * Used to set @e max_fee if not provided as part of
    668          * @e order.
    669          */
    670         struct TALER_Amount *max_stefan_fees;
    671 
    672       } v1;
    673 
    674     } details;
    675 
    676   } set_exchanges;
    677 
    678   /**
    679    * Information set in the #ORDER_PHASE_SET_MAX_FEE phase.
    680    */
    681   struct
    682   {
    683 
    684     /**
    685      * Details depending on the contract version.
    686      */
    687     union
    688     {
    689 
    690       /**
    691        * Details for contract v0.
    692        */
    693       struct
    694       {
    695         /**
    696          * Maximum fee
    697          */
    698         struct TALER_Amount max_fee;
    699       } v0;
    700 
    701       /**
    702        * Details for contract v1.
    703        */
    704       struct
    705       {
    706         /**
    707          * Maximum fees by contract choice.
    708          */
    709         struct TALER_Amount *max_fees;
    710 
    711       } v1;
    712 
    713     } details;
    714   } set_max_fee;
    715 
    716   /**
    717    * Information set in the #ORDER_PHASE_EXECUTE_ORDER phase.
    718    */
    719   struct
    720   {
    721     /**
    722      * Which product (by offset) is out of stock, UINT_MAX if all were in-stock.
    723      */
    724     unsigned int out_of_stock_index;
    725 
    726     /**
    727      * Set to a previous claim token *if* @e idempotent
    728      * is also true.
    729      */
    730     struct TALER_ClaimTokenP token;
    731 
    732     /**
    733      * Set to true if the order was idempotent and there
    734      * was an equivalent one before.
    735      */
    736     bool idempotent;
    737 
    738     /**
    739      * Set to true if the order is in conflict with a
    740      * previous order with the same order ID.
    741      */
    742     bool conflict;
    743   } execute_order;
    744 
    745   struct
    746   {
    747     /**
    748      * Contract terms to store in the database.
    749      */
    750     json_t *contract;
    751   } serialize_order;
    752 
    753   /**
    754    * Connection of the request.
    755    */
    756   struct MHD_Connection *connection;
    757 
    758   /**
    759    * Kept in a DLL while suspended.
    760    */
    761   struct OrderContext *next;
    762 
    763   /**
    764    * Kept in a DLL while suspended.
    765    */
    766   struct OrderContext *prev;
    767 
    768   /**
    769    * Handler context for the request.
    770    */
    771   struct TMH_HandlerContext *hc;
    772 
    773   /**
    774    * #GNUNET_YES if suspended.
    775    */
    776   enum GNUNET_GenericReturnValue suspended;
    777 
    778   /**
    779    * Current phase of setting up the order.
    780    */
    781   enum
    782   {
    783     ORDER_PHASE_PARSE_REQUEST,
    784     ORDER_PHASE_PARSE_ORDER,
    785     ORDER_PHASE_PARSE_CHOICES,
    786     ORDER_PHASE_MERGE_INVENTORY,
    787     ORDER_PHASE_ADD_PAYMENT_DETAILS,
    788     ORDER_PHASE_SET_EXCHANGES,
    789     ORDER_PHASE_SELECT_WIRE_METHOD,
    790     ORDER_PHASE_SET_MAX_FEE,
    791     ORDER_PHASE_SERIALIZE_ORDER,
    792     ORDER_PHASE_SALT_FORGETTABLE,
    793     ORDER_PHASE_CHECK_CONTRACT,
    794     ORDER_PHASE_EXECUTE_ORDER,
    795 
    796     /**
    797      * Processing is done, we should return #MHD_YES.
    798      */
    799     ORDER_PHASE_FINISHED_MHD_YES,
    800 
    801     /**
    802      * Processing is done, we should return #MHD_NO.
    803      */
    804     ORDER_PHASE_FINISHED_MHD_NO
    805   } phase;
    806 
    807 
    808 };
    809 
    810 
    811 /**
    812  * Kept in a DLL while suspended.
    813  */
    814 static struct OrderContext *oc_head;
    815 
    816 /**
    817  * Kept in a DLL while suspended.
    818  */
    819 static struct OrderContext *oc_tail;
    820 
    821 
    822 void
    823 TMH_force_orders_resume ()
    824 {
    825   struct OrderContext *oc;
    826 
    827   while (NULL != (oc = oc_head))
    828   {
    829     GNUNET_CONTAINER_DLL_remove (oc_head,
    830                                  oc_tail,
    831                                  oc);
    832     oc->suspended = GNUNET_SYSERR;
    833     MHD_resume_connection (oc->connection);
    834   }
    835 }
    836 
    837 
    838 /**
    839  * Update the phase of @a oc based on @a mret.
    840  *
    841  * @param[in,out] oc order to update phase for
    842  * @param mret #MHD_NO to close with #MHD_NO
    843  *             #MHD_YES to close with #MHD_YES
    844  */
    845 static void
    846 finalize_order (struct OrderContext *oc,
    847                 enum MHD_Result mret)
    848 {
    849   oc->phase = (MHD_YES == mret)
    850     ? ORDER_PHASE_FINISHED_MHD_YES
    851     : ORDER_PHASE_FINISHED_MHD_NO;
    852 }
    853 
    854 
    855 /**
    856  * Update the phase of @a oc based on @a ret.
    857  *
    858  * @param[in,out] oc order to update phase for
    859  * @param ret #GNUNET_SYSERR to close with #MHD_NO
    860  *            #GNUNET_NO to close with #MHD_YES
    861  *            #GNUNET_OK is not allowed!
    862  */
    863 static void
    864 finalize_order2 (struct OrderContext *oc,
    865                  enum GNUNET_GenericReturnValue ret)
    866 {
    867   GNUNET_assert (GNUNET_OK != ret);
    868   oc->phase = (GNUNET_NO == ret)
    869     ? ORDER_PHASE_FINISHED_MHD_YES
    870     : ORDER_PHASE_FINISHED_MHD_NO;
    871 }
    872 
    873 
    874 /**
    875  * Generate an error response for @a oc.
    876  *
    877  * @param[in,out] oc order context to respond to
    878  * @param http_status HTTP status code to set
    879  * @param ec error code to set
    880  * @param detail error message detail to set
    881  */
    882 static void
    883 reply_with_error (struct OrderContext *oc,
    884                   unsigned int http_status,
    885                   enum TALER_ErrorCode ec,
    886                   const char *detail)
    887 {
    888   enum MHD_Result mret;
    889 
    890   mret = TALER_MHD_reply_with_error (oc->connection,
    891                                      http_status,
    892                                      ec,
    893                                      detail);
    894   finalize_order (oc,
    895                   mret);
    896 }
    897 
    898 
    899 /**
    900  * Clean up memory used by @a wmc.
    901  *
    902  * @param[in,out] oc order context the WMC is part of
    903  * @param[in] wmc wire method candidate to free
    904  */
    905 static void
    906 free_wmc (struct OrderContext *oc,
    907           struct WireMethodCandidate *wmc)
    908 {
    909   GNUNET_CONTAINER_DLL_remove (oc->add_payment_details.wmc_head,
    910                                oc->add_payment_details.wmc_tail,
    911                                wmc);
    912   TALER_amount_set_free (&wmc->total_exchange_limits);
    913   json_decref (wmc->exchanges);
    914   GNUNET_free (wmc);
    915 }
    916 
    917 
    918 /**
    919  * Clean up memory used by @a cls.
    920  *
    921  * @param[in] cls the `struct OrderContext` to clean up
    922  */
    923 static void
    924 clean_order (void *cls)
    925 {
    926   struct OrderContext *oc = cls;
    927   struct RekeyExchange *rx;
    928 
    929   while (NULL != oc->add_payment_details.wmc_head)
    930     free_wmc (oc,
    931               oc->add_payment_details.wmc_head);
    932   while (NULL != (rx = oc->set_exchanges.pending_reload_head))
    933   {
    934     GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
    935                                  oc->set_exchanges.pending_reload_tail,
    936                                  rx);
    937     TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
    938     GNUNET_free (rx->url);
    939     GNUNET_free (rx);
    940   }
    941   GNUNET_array_grow (oc->add_payment_details.max_choice_limits,
    942                      oc->add_payment_details.num_max_choice_limits,
    943                      0);
    944   if (NULL != oc->set_exchanges.wakeup_task)
    945   {
    946     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
    947     oc->set_exchanges.wakeup_task = NULL;
    948   }
    949   if (NULL != oc->select_wire_method.exchanges)
    950   {
    951     json_decref (oc->select_wire_method.exchanges);
    952     oc->select_wire_method.exchanges = NULL;
    953   }
    954   if (NULL != oc->set_exchanges.exchange_rejections)
    955   {
    956     json_decref (oc->set_exchanges.exchange_rejections);
    957     oc->set_exchanges.exchange_rejections = NULL;
    958   }
    959   switch (oc->parse_order.version)
    960   {
    961   case TALER_MERCHANT_CONTRACT_VERSION_0:
    962     break;
    963   case TALER_MERCHANT_CONTRACT_VERSION_1:
    964     GNUNET_free (oc->set_max_fee.details.v1.max_fees);
    965     GNUNET_free (oc->set_exchanges.details.v1.max_stefan_fees);
    966     break;
    967   }
    968   if (NULL != oc->merge_inventory.products)
    969   {
    970     json_decref (oc->merge_inventory.products);
    971     oc->merge_inventory.products = NULL;
    972   }
    973   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
    974   {
    975     TALER_MERCHANT_contract_choice_free (&oc->parse_choices.choices[i]);
    976   }
    977   GNUNET_array_grow (oc->parse_choices.choices,
    978                      oc->parse_choices.choices_len,
    979                      0);
    980   for (size_t i = 0; i<oc->parse_order.products_len; i++)
    981   {
    982     TALER_MERCHANT_product_sold_free (&oc->parse_order.products[i]);
    983   }
    984   GNUNET_free (oc->parse_order.products);
    985   oc->parse_order.products_len = 0;
    986   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
    987   {
    988     struct TALER_MERCHANT_ContractTokenFamily *mctf
    989       = &oc->parse_choices.token_families[i];
    990 
    991     GNUNET_free (mctf->slug);
    992     GNUNET_free (mctf->name);
    993     GNUNET_free (mctf->description);
    994     json_decref (mctf->description_i18n);
    995     switch (mctf->kind)
    996     {
    997     case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
    998       GNUNET_break (0);
    999       break;
   1000     case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
   1001       for (size_t j = 0; j<mctf->details.subscription.trusted_domains_len; j++)
   1002         GNUNET_free (mctf->details.subscription.trusted_domains[j]);
   1003       GNUNET_free (mctf->details.subscription.trusted_domains);
   1004       break;
   1005     case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
   1006       for (size_t j = 0; j<mctf->details.discount.expected_domains_len; j++)
   1007         GNUNET_free (mctf->details.discount.expected_domains[j]);
   1008       GNUNET_free (mctf->details.discount.expected_domains);
   1009       break;
   1010     }
   1011     for (unsigned int j = 0; j<mctf->keys_len; j++)
   1012     {
   1013       GNUNET_CRYPTO_blind_sign_pub_decref (mctf->keys[j].pub.public_key);
   1014     }
   1015     GNUNET_array_grow (mctf->keys,
   1016                        mctf->keys_len,
   1017                        0);
   1018   }
   1019   GNUNET_array_grow (oc->parse_choices.token_families,
   1020                      oc->parse_choices.token_families_len,
   1021                      0);
   1022   GNUNET_array_grow (oc->parse_request.inventory_products,
   1023                      oc->parse_request.inventory_products_length,
   1024                      0);
   1025   GNUNET_array_grow (oc->parse_request.uuids,
   1026                      oc->parse_request.uuids_length,
   1027                      0);
   1028   GNUNET_free (oc->parse_request.pos_key);
   1029   json_decref (oc->parse_request.order);
   1030   json_decref (oc->serialize_order.contract);
   1031   GNUNET_free (oc->parse_order.order_id);
   1032   GNUNET_free (oc->parse_order.merchant_base_url);
   1033   GNUNET_free (oc);
   1034 }
   1035 
   1036 
   1037 /* ***************** ORDER_PHASE_EXECUTE_ORDER **************** */
   1038 
   1039 /**
   1040  * Compute remaining stock (integer and fractional parts) for a product.
   1041  *
   1042  * @param pd product details with current totals/sold/lost
   1043  * @param[out] available_value remaining whole units (normalized, non-negative)
   1044  * @param[out] available_frac remaining fractional units (0..TALER_MERCHANT_UNIT_FRAC_BASE-1)
   1045  */
   1046 static void
   1047 compute_available_quantity (const struct TALER_MERCHANTDB_ProductDetails *pd,
   1048                             uint64_t *available_value,
   1049                             uint32_t *available_frac)
   1050 {
   1051   int64_t value;
   1052   int64_t frac;
   1053 
   1054   GNUNET_assert (NULL != available_value);
   1055   GNUNET_assert (NULL != available_frac);
   1056 
   1057   if ( (INT64_MAX == pd->total_stock) &&
   1058        (INT32_MAX == pd->total_stock_frac) )
   1059   {
   1060     *available_value = pd->total_stock;
   1061     *available_frac = pd->total_stock_frac;
   1062     return;
   1063   }
   1064 
   1065   value = (int64_t) pd->total_stock
   1066           - (int64_t) pd->total_sold
   1067           - (int64_t) pd->total_lost;
   1068   frac = (int64_t) pd->total_stock_frac
   1069          - (int64_t) pd->total_sold_frac
   1070          - (int64_t) pd->total_lost_frac;
   1071 
   1072   if (frac < 0)
   1073   {
   1074     int64_t borrow = ((-frac) + TALER_MERCHANT_UNIT_FRAC_BASE - 1)
   1075                      / TALER_MERCHANT_UNIT_FRAC_BASE;
   1076     value -= borrow;
   1077     frac += borrow * (int64_t) TALER_MERCHANT_UNIT_FRAC_BASE;
   1078   }
   1079   else if (frac >= TALER_MERCHANT_UNIT_FRAC_BASE)
   1080   {
   1081     int64_t carry = frac / TALER_MERCHANT_UNIT_FRAC_BASE;
   1082     value += carry;
   1083     frac -= carry * (int64_t) TALER_MERCHANT_UNIT_FRAC_BASE;
   1084   }
   1085 
   1086   if (value < 0)
   1087   {
   1088     value = 0;
   1089     frac = 0;
   1090   }
   1091 
   1092   *available_value = (uint64_t) value;
   1093   *available_frac = (uint32_t) frac;
   1094 }
   1095 
   1096 
   1097 /**
   1098  * Execute the database transaction to setup the order.
   1099  *
   1100  * @param[in,out] oc order context
   1101  * @return transaction status, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a uuids were insufficient to reserve required inventory
   1102  */
   1103 static enum GNUNET_DB_QueryStatus
   1104 execute_transaction (struct OrderContext *oc)
   1105 {
   1106   enum GNUNET_DB_QueryStatus qs;
   1107   struct GNUNET_TIME_Timestamp timestamp;
   1108   uint64_t order_serial;
   1109 
   1110   if (GNUNET_OK !=
   1111       TALER_MERCHANTDB_start (TMH_db,
   1112                               "insert_order"))
   1113   {
   1114     GNUNET_break (0);
   1115     return GNUNET_DB_STATUS_HARD_ERROR;
   1116   }
   1117 
   1118   /* Test if we already have an order with this id */
   1119   {
   1120     json_t *contract_terms;
   1121     struct TALER_MerchantPostDataHashP orig_post;
   1122 
   1123     qs = TALER_MERCHANTDB_lookup_order (TMH_db,
   1124                                         oc->hc->instance->settings.id,
   1125                                         oc->parse_order.order_id,
   1126                                         &oc->execute_order.token,
   1127                                         &orig_post,
   1128                                         &contract_terms);
   1129     /* If yes, check for idempotency */
   1130     if (0 > qs)
   1131     {
   1132       GNUNET_break (0);
   1133       TALER_MERCHANTDB_rollback (TMH_db);
   1134       return qs;
   1135     }
   1136     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   1137     {
   1138       TALER_MERCHANTDB_rollback (TMH_db);
   1139       json_decref (contract_terms);
   1140       /* Comparing the contract terms is sufficient because all the other
   1141          params get added to it at some point. */
   1142       if (0 == GNUNET_memcmp (&orig_post,
   1143                               &oc->parse_request.h_post_data))
   1144       {
   1145         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1146                     "Order creation idempotent\n");
   1147         oc->execute_order.idempotent = true;
   1148         return qs;
   1149       }
   1150       GNUNET_break_op (0);
   1151       oc->execute_order.conflict = true;
   1152       return qs;
   1153     }
   1154   }
   1155 
   1156   /* Setup order */
   1157   qs = TALER_MERCHANTDB_insert_order (TMH_db,
   1158                                       oc->hc->instance->settings.id,
   1159                                       oc->parse_order.order_id,
   1160                                       oc->parse_request.session_id,
   1161                                       &oc->parse_request.h_post_data,
   1162                                       oc->parse_order.pay_deadline,
   1163                                       &oc->parse_request.claim_token,
   1164                                       oc->serialize_order.contract, /* called 'contract terms' at database. */
   1165                                       oc->parse_request.pos_key,
   1166                                       oc->parse_request.pos_algorithm);
   1167   if (qs <= 0)
   1168   {
   1169     /* qs == 0: probably instance does not exist (anymore) */
   1170     TALER_MERCHANTDB_rollback (TMH_db);
   1171     return qs;
   1172   }
   1173   /* Migrate locks from UUIDs to new order: first release old locks */
   1174   for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   1175   {
   1176     qs = TALER_MERCHANTDB_unlock_inventory (TMH_db,
   1177                                             &oc->parse_request.uuids[i]);
   1178     if (qs < 0)
   1179     {
   1180       TALER_MERCHANTDB_rollback (TMH_db);
   1181       return qs;
   1182     }
   1183     /* qs == 0 is OK here, that just means we did not HAVE any lock under this
   1184        UUID */
   1185   }
   1186   /* Migrate locks from UUIDs to new order: acquire new locks
   1187      (note: this can basically ONLY fail on serializability OR
   1188      because the UUID locks were insufficient for the desired
   1189      quantities). */
   1190   for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   1191   {
   1192     qs = TALER_MERCHANTDB_insert_order_lock (
   1193       TMH_db,
   1194       oc->hc->instance->settings.id,
   1195       oc->parse_order.order_id,
   1196       oc->parse_request.inventory_products[i].product_id,
   1197       oc->parse_request.inventory_products[i].quantity,
   1198       oc->parse_request.inventory_products[i].quantity_frac);
   1199     if (qs < 0)
   1200     {
   1201       TALER_MERCHANTDB_rollback (TMH_db);
   1202       return qs;
   1203     }
   1204     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1205     {
   1206       /* qs == 0: lock acquisition failed due to insufficient stocks */
   1207       TALER_MERCHANTDB_rollback (TMH_db);
   1208       oc->execute_order.out_of_stock_index = i; /* indicate which product is causing the issue */
   1209       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
   1210     }
   1211   }
   1212   oc->execute_order.out_of_stock_index = UINT_MAX;
   1213 
   1214   /* Get the order serial and timestamp for the order we just created to
   1215      update long-poll clients. */
   1216   qs = TALER_MERCHANTDB_lookup_order_summary (TMH_db,
   1217                                               oc->hc->instance->settings.id,
   1218                                               oc->parse_order.order_id,
   1219                                               &timestamp,
   1220                                               &order_serial);
   1221   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   1222   {
   1223     TALER_MERCHANTDB_rollback (TMH_db);
   1224     return qs;
   1225   }
   1226 
   1227   {
   1228     json_t *jhook;
   1229 
   1230     jhook = GNUNET_JSON_PACK (
   1231       GNUNET_JSON_pack_string ("order_id",
   1232                                oc->parse_order.order_id),
   1233       GNUNET_JSON_pack_object_incref ("contract",
   1234                                       oc->serialize_order.contract),
   1235       GNUNET_JSON_pack_string ("instance_id",
   1236                                oc->hc->instance->settings.id)
   1237       );
   1238     GNUNET_assert (NULL != jhook);
   1239     qs = TMH_trigger_webhook (oc->hc->instance->settings.id,
   1240                               "order_created",
   1241                               jhook);
   1242     json_decref (jhook);
   1243     if (0 > qs)
   1244     {
   1245       TALER_MERCHANTDB_rollback (TMH_db);
   1246       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1247         return qs;
   1248       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
   1249       reply_with_error (oc,
   1250                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1251                         TALER_EC_GENERIC_DB_STORE_FAILED,
   1252                         "failed to trigger webhooks");
   1253       return qs;
   1254     }
   1255   }
   1256 
   1257   TMH_notify_order_change (oc->hc->instance,
   1258                            TMH_OSF_NONE,
   1259                            timestamp,
   1260                            order_serial);
   1261   /* finally, commit transaction (note: if it fails, we ALSO re-acquire
   1262      the UUID locks, which is exactly what we want) */
   1263   qs = TALER_MERCHANTDB_commit (TMH_db);
   1264   if (0 > qs)
   1265     return qs;
   1266   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;   /* 1 == success! */
   1267 }
   1268 
   1269 
   1270 /**
   1271  * The request was successful, generate the #MHD_HTTP_OK response.
   1272  *
   1273  * @param[in,out] oc context to update
   1274  * @param claim_token claim token to use, NULL if none
   1275  */
   1276 static void
   1277 yield_success_response (struct OrderContext *oc,
   1278                         const struct TALER_ClaimTokenP *claim_token)
   1279 {
   1280   enum MHD_Result ret;
   1281 
   1282   ret = TALER_MHD_REPLY_JSON_PACK (
   1283     oc->connection,
   1284     MHD_HTTP_OK,
   1285     GNUNET_JSON_pack_string ("order_id",
   1286                              oc->parse_order.order_id),
   1287     GNUNET_JSON_pack_timestamp ("pay_deadline",
   1288                                 oc->parse_order.pay_deadline),
   1289     GNUNET_JSON_pack_allow_null (
   1290       GNUNET_JSON_pack_data_auto (
   1291         "token",
   1292         claim_token)));
   1293   finalize_order (oc,
   1294                   ret);
   1295 }
   1296 
   1297 
   1298 /**
   1299  * Transform an order into a proposal and store it in the
   1300  * database. Write the resulting proposal or an error message
   1301  * of a MHD connection.
   1302  *
   1303  * @param[in,out] oc order context
   1304  */
   1305 static void
   1306 phase_execute_order (struct OrderContext *oc)
   1307 {
   1308   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   1309     &oc->hc->instance->settings;
   1310   enum GNUNET_DB_QueryStatus qs;
   1311 
   1312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1313               "Executing database transaction to create order '%s' for instance '%s'\n",
   1314               oc->parse_order.order_id,
   1315               settings->id);
   1316   for (unsigned int i = 0; i<MAX_RETRIES; i++)
   1317   {
   1318     TALER_MERCHANTDB_preflight (TMH_db);
   1319     qs = execute_transaction (oc);
   1320     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
   1321       break;
   1322   }
   1323   if (0 >= qs)
   1324   {
   1325     /* Special report if retries insufficient */
   1326     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1327     {
   1328       GNUNET_break (0);
   1329       reply_with_error (oc,
   1330                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1331                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1332                         NULL);
   1333       return;
   1334     }
   1335     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1336     {
   1337       /* should be: contract (!) with same order ID
   1338          already exists */
   1339       reply_with_error (
   1340         oc,
   1341         MHD_HTTP_CONFLICT,
   1342         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
   1343         oc->parse_order.order_id);
   1344       return;
   1345     }
   1346     /* Other hard transaction error (disk full, etc.) */
   1347     GNUNET_break (0);
   1348     reply_with_error (
   1349       oc,
   1350       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1351       TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1352       NULL);
   1353     return;
   1354   }
   1355 
   1356   /* DB transaction succeeded, check for idempotent */
   1357   if (oc->execute_order.idempotent)
   1358   {
   1359     yield_success_response (oc,
   1360                             GNUNET_is_zero (&oc->execute_order.token)
   1361                             ? NULL
   1362                             : &oc->execute_order.token);
   1363     return;
   1364   }
   1365   if (oc->execute_order.conflict)
   1366   {
   1367     reply_with_error (
   1368       oc,
   1369       MHD_HTTP_CONFLICT,
   1370       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
   1371       oc->parse_order.order_id);
   1372     return;
   1373   }
   1374 
   1375   /* DB transaction succeeded, check for out-of-stock */
   1376   if (oc->execute_order.out_of_stock_index < UINT_MAX)
   1377   {
   1378     /* We had a product that has insufficient quantities,
   1379        generate the details for the response. */
   1380     struct TALER_MERCHANTDB_ProductDetails pd;
   1381     enum MHD_Result ret;
   1382     const struct InventoryProduct *ip;
   1383     size_t num_categories = 0;
   1384     uint64_t *categories = NULL;
   1385     uint64_t available_quantity;
   1386     uint32_t available_quantity_frac;
   1387     char requested_quantity_buf[64];
   1388     char available_quantity_buf[64];
   1389 
   1390     ip = &oc->parse_request.inventory_products[
   1391       oc->execute_order.out_of_stock_index];
   1392     memset (&pd,
   1393             0,
   1394             sizeof (pd));
   1395     qs = TALER_MERCHANTDB_lookup_product (
   1396       TMH_db,
   1397       oc->hc->instance->settings.id,
   1398       ip->product_id,
   1399       &pd,
   1400       &num_categories,
   1401       &categories);
   1402     switch (qs)
   1403     {
   1404     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1405       GNUNET_free (categories);
   1406       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1407                   "Order creation failed: product out of stock\n");
   1408 
   1409       compute_available_quantity (&pd,
   1410                                   &available_quantity,
   1411                                   &available_quantity_frac);
   1412       TALER_MERCHANT_vk_format_fractional_string (
   1413         TALER_MERCHANT_VK_QUANTITY,
   1414         ip->quantity,
   1415         ip->quantity_frac,
   1416         sizeof (requested_quantity_buf),
   1417         requested_quantity_buf);
   1418       TALER_MERCHANT_vk_format_fractional_string (
   1419         TALER_MERCHANT_VK_QUANTITY,
   1420         available_quantity,
   1421         available_quantity_frac,
   1422         sizeof (available_quantity_buf),
   1423         available_quantity_buf);
   1424       ret = TALER_MHD_REPLY_JSON_PACK (
   1425         oc->connection,
   1426         MHD_HTTP_GONE,
   1427         GNUNET_JSON_pack_string (
   1428           "product_id",
   1429           ip->product_id),
   1430         GNUNET_JSON_pack_uint64 (
   1431           "requested_quantity",
   1432           ip->quantity),
   1433         GNUNET_JSON_pack_string (
   1434           "unit_requested_quantity",
   1435           requested_quantity_buf),
   1436         GNUNET_JSON_pack_uint64 (
   1437           "available_quantity",
   1438           available_quantity),
   1439         GNUNET_JSON_pack_string (
   1440           "unit_available_quantity",
   1441           available_quantity_buf),
   1442         GNUNET_JSON_pack_allow_null (
   1443           GNUNET_JSON_pack_timestamp (
   1444             "restock_expected",
   1445             pd.next_restock)));
   1446       TALER_MERCHANTDB_product_details_free (&pd);
   1447       finalize_order (oc,
   1448                       ret);
   1449       return;
   1450     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1451       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1452                   "Order creation failed: unknown product out of stock\n");
   1453       finalize_order (oc,
   1454                       TALER_MHD_REPLY_JSON_PACK (
   1455                         oc->connection,
   1456                         MHD_HTTP_GONE,
   1457                         GNUNET_JSON_pack_string (
   1458                           "product_id",
   1459                           ip->product_id),
   1460                         GNUNET_JSON_pack_uint64 (
   1461                           "requested_quantity",
   1462                           ip->quantity),
   1463                         GNUNET_JSON_pack_uint64 (
   1464                           "available_quantity",
   1465                           0)));
   1466       return;
   1467     case GNUNET_DB_STATUS_SOFT_ERROR:
   1468       GNUNET_break (0);
   1469       reply_with_error (
   1470         oc,
   1471         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1472         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1473         NULL);
   1474       return;
   1475     case GNUNET_DB_STATUS_HARD_ERROR:
   1476       GNUNET_break (0);
   1477       reply_with_error (
   1478         oc,
   1479         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1480         TALER_EC_GENERIC_DB_FETCH_FAILED,
   1481         NULL);
   1482       return;
   1483     }
   1484     GNUNET_break (0);
   1485     oc->phase = ORDER_PHASE_FINISHED_MHD_NO;
   1486     return;
   1487   } /* end 'out of stock' case */
   1488 
   1489   /* Everything in-stock, generate positive response */
   1490   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1491               "Order creation succeeded\n");
   1492   yield_success_response (oc,
   1493                           GNUNET_is_zero (&oc->parse_request.claim_token)
   1494                           ? NULL
   1495                           : &oc->parse_request.claim_token);
   1496 }
   1497 
   1498 
   1499 /* ***************** ORDER_PHASE_CHECK_CONTRACT **************** */
   1500 
   1501 
   1502 /**
   1503  * Check that the contract is now well-formed. Upon success, continue
   1504  * processing with execute_order().
   1505  *
   1506  * @param[in,out] oc order context
   1507  */
   1508 static void
   1509 phase_check_contract (struct OrderContext *oc)
   1510 {
   1511   struct TALER_PrivateContractHashP h_control;
   1512 
   1513   switch (TALER_JSON_contract_hash (oc->serialize_order.contract,
   1514                                     &h_control))
   1515   {
   1516   case GNUNET_SYSERR:
   1517     GNUNET_break (0);
   1518     reply_with_error (
   1519       oc,
   1520       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1521       TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
   1522       "could not compute hash of serialized order");
   1523     return;
   1524   case GNUNET_NO:
   1525     GNUNET_break_op (0);
   1526     reply_with_error (
   1527       oc,
   1528       MHD_HTTP_BAD_REQUEST,
   1529       TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
   1530       "order contained unallowed values");
   1531     return;
   1532   case GNUNET_OK:
   1533     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1534                 "Contract hash is %s\n",
   1535                 GNUNET_h2s (&h_control.hash));
   1536     oc->phase++;
   1537     return;
   1538   }
   1539   GNUNET_assert (0);
   1540 }
   1541 
   1542 
   1543 /* ***************** ORDER_PHASE_SALT_FORGETTABLE **************** */
   1544 
   1545 
   1546 /**
   1547  * Modify the final contract terms adding salts for
   1548  * items that are forgettable.
   1549  *
   1550  * @param[in,out] oc order context
   1551  */
   1552 static void
   1553 phase_salt_forgettable (struct OrderContext *oc)
   1554 {
   1555   if (GNUNET_OK !=
   1556       TALER_JSON_contract_seed_forgettable (oc->parse_request.order,
   1557                                             oc->serialize_order.contract))
   1558   {
   1559     GNUNET_break_op (0);
   1560     reply_with_error (
   1561       oc,
   1562       MHD_HTTP_BAD_REQUEST,
   1563       TALER_EC_GENERIC_JSON_INVALID,
   1564       "could not compute hash of order due to bogus forgettable fields");
   1565     return;
   1566   }
   1567   oc->phase++;
   1568 }
   1569 
   1570 
   1571 /* ***************** ORDER_PHASE_SERIALIZE_ORDER **************** */
   1572 
   1573 /**
   1574  * Get rounded time interval. @a start is calculated by rounding
   1575  * @a ts down to the nearest multiple of @a precision.
   1576  *
   1577  * @param precision rounding precision.
   1578  *        year, month, day, hour, minute are supported.
   1579  * @param ts timestamp to round
   1580  * @param[out] start start of the interval
   1581  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1582  */
   1583 static enum GNUNET_GenericReturnValue
   1584 get_rounded_time_interval_down (struct GNUNET_TIME_Relative precision,
   1585                                 struct GNUNET_TIME_Timestamp ts,
   1586                                 struct GNUNET_TIME_Timestamp *start)
   1587 {
   1588   enum GNUNET_TIME_RounderInterval ri;
   1589 
   1590   ri = GNUNET_TIME_relative_to_round_interval (precision);
   1591   if ( (GNUNET_TIME_RI_NONE == ri) &&
   1592        (! GNUNET_TIME_relative_is_zero (precision)) )
   1593   {
   1594     *start = ts;
   1595     return GNUNET_SYSERR;
   1596   }
   1597   *start = GNUNET_TIME_absolute_to_timestamp (
   1598     GNUNET_TIME_round_down (ts.abs_time,
   1599                             ri));
   1600   return GNUNET_OK;
   1601 }
   1602 
   1603 
   1604 /**
   1605  * Get rounded time interval. @a start is calculated by rounding
   1606  * @a ts up to the nearest multiple of @a precision.
   1607  *
   1608  * @param precision rounding precision.
   1609  *        year, month, day, hour, minute are supported.
   1610  * @param ts timestamp to round
   1611  * @param[out] start start of the interval
   1612  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1613  */
   1614 static enum GNUNET_GenericReturnValue
   1615 get_rounded_time_interval_up (struct GNUNET_TIME_Relative precision,
   1616                               struct GNUNET_TIME_Timestamp ts,
   1617                               struct GNUNET_TIME_Timestamp *start)
   1618 {
   1619   enum GNUNET_TIME_RounderInterval ri;
   1620 
   1621   ri = GNUNET_TIME_relative_to_round_interval (precision);
   1622   if ( (GNUNET_TIME_RI_NONE == ri) &&
   1623        (! GNUNET_TIME_relative_is_zero (precision)) )
   1624   {
   1625     *start = ts;
   1626     return GNUNET_SYSERR;
   1627   }
   1628   *start = GNUNET_TIME_absolute_to_timestamp (
   1629     GNUNET_TIME_round_up (ts.abs_time,
   1630                           ri));
   1631   return GNUNET_OK;
   1632 }
   1633 
   1634 
   1635 /**
   1636  * Find the family entry for the family of the given @a slug
   1637  * in @a oc.
   1638  *
   1639  * @param[in] oc order context to search
   1640  * @param slug slug to search for
   1641  * @return NULL if @a slug was not found
   1642  */
   1643 static struct TALER_MERCHANT_ContractTokenFamily *
   1644 find_family (const struct OrderContext *oc,
   1645              const char *slug)
   1646 {
   1647   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
   1648   {
   1649     if (0 == strcmp (oc->parse_choices.token_families[i].slug,
   1650                      slug))
   1651     {
   1652       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1653                   "Token family %s already in order\n",
   1654                   slug);
   1655       return &oc->parse_choices.token_families[i];
   1656     }
   1657   }
   1658   return NULL;
   1659 }
   1660 
   1661 
   1662 /**
   1663  * Function called with each applicable family key that should
   1664  * be added to the respective token family of the order.
   1665  *
   1666  * @param cls a `struct OrderContext *` to expand
   1667  * @param tfkd token family key details to add to the contract
   1668  */
   1669 static void
   1670 add_family_key (void *cls,
   1671                 const struct TALER_MERCHANTDB_TokenFamilyKeyDetails *tfkd)
   1672 {
   1673   struct OrderContext *oc = cls;
   1674   const struct TALER_MERCHANTDB_TokenFamilyDetails *tf = &tfkd->token_family;
   1675   struct TALER_MERCHANT_ContractTokenFamily *family;
   1676 
   1677   family = find_family (oc,
   1678                         tf->slug);
   1679   if (NULL == family)
   1680   {
   1681     /* Family not yet in our contract terms, create new entry */
   1682     struct TALER_MERCHANT_ContractTokenFamily new_family = {
   1683       .slug = GNUNET_strdup (tf->slug),
   1684       .name = GNUNET_strdup (tf->name),
   1685       .description = GNUNET_strdup (tf->description),
   1686       .description_i18n = json_incref (tf->description_i18n),
   1687     };
   1688 
   1689     switch (tf->kind)
   1690     {
   1691     case TALER_MERCHANTDB_TFK_Subscription:
   1692       {
   1693         json_t *tdomains = json_object_get (tf->extra_data,
   1694                                             "trusted_domains");
   1695         json_t *dom;
   1696         size_t i;
   1697 
   1698         new_family.kind = TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION;
   1699         new_family.critical = true;
   1700         new_family.details.subscription.trusted_domains_len
   1701           = json_array_size (tdomains);
   1702         GNUNET_assert (new_family.details.subscription.trusted_domains_len
   1703                        < UINT_MAX);
   1704         new_family.details.subscription.trusted_domains
   1705           = GNUNET_new_array (
   1706               new_family.details.subscription.trusted_domains_len,
   1707               char *);
   1708         json_array_foreach (tdomains, i, dom)
   1709         {
   1710           const char *val;
   1711 
   1712           val = json_string_value (dom);
   1713           GNUNET_break (NULL != val);
   1714           if (NULL != val)
   1715             new_family.details.subscription.trusted_domains[i]
   1716               = GNUNET_strdup (val);
   1717         }
   1718         break;
   1719       }
   1720     case TALER_MERCHANTDB_TFK_Discount:
   1721       {
   1722         json_t *edomains = json_object_get (tf->extra_data,
   1723                                             "expected_domains");
   1724         json_t *dom;
   1725         size_t i;
   1726 
   1727         new_family.kind = TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT;
   1728         new_family.critical = false;
   1729         new_family.details.discount.expected_domains_len
   1730           = json_array_size (edomains);
   1731         GNUNET_assert (new_family.details.discount.expected_domains_len
   1732                        < UINT_MAX);
   1733         new_family.details.discount.expected_domains
   1734           = GNUNET_new_array (
   1735               new_family.details.discount.expected_domains_len,
   1736               char *);
   1737         json_array_foreach (edomains, i, dom)
   1738         {
   1739           const char *val;
   1740 
   1741           val = json_string_value (dom);
   1742           GNUNET_break (NULL != val);
   1743           if (NULL != val)
   1744             new_family.details.discount.expected_domains[i]
   1745               = GNUNET_strdup (val);
   1746         }
   1747         break;
   1748       }
   1749     }
   1750     GNUNET_array_append (oc->parse_choices.token_families,
   1751                          oc->parse_choices.token_families_len,
   1752                          new_family);
   1753     family = &oc->parse_choices.token_families[
   1754       oc->parse_choices.token_families_len - 1];
   1755   }
   1756   if (NULL == tfkd->pub.public_key)
   1757     return;
   1758   for (unsigned int i = 0; i<family->keys_len; i++)
   1759   {
   1760     if (TALER_token_issue_pub_cmp (&family->keys[i].pub,
   1761                                    &tfkd->pub))
   1762     {
   1763       /* A matching key is already in the list. */
   1764       return;
   1765     }
   1766   }
   1767 
   1768   {
   1769     struct TALER_MERCHANT_ContractTokenFamilyKey key;
   1770 
   1771     TALER_token_issue_pub_copy (&key.pub,
   1772                                 &tfkd->pub);
   1773     key.valid_after = tfkd->signature_validity_start;
   1774     key.valid_before = tfkd->signature_validity_end;
   1775     GNUNET_array_append (family->keys,
   1776                          family->keys_len,
   1777                          key);
   1778   }
   1779 }
   1780 
   1781 
   1782 /**
   1783  * Check if the token family with the given @a slug is already present in the
   1784  * list of token families for this order. If not, fetch its details and add it
   1785  * to the list.
   1786  *
   1787  * @param[in,out] oc order context
   1788  * @param slug slug of the token family
   1789  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1790  */
   1791 static enum GNUNET_GenericReturnValue
   1792 add_input_token_family (struct OrderContext *oc,
   1793                         const char *slug)
   1794 {
   1795   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   1796   struct GNUNET_TIME_Timestamp end = oc->parse_order.pay_deadline;
   1797   enum GNUNET_DB_QueryStatus qs;
   1798   enum TALER_ErrorCode ec = TALER_EC_INVALID; /* make compiler happy */
   1799   unsigned int http_status = 0; /* make compiler happy */
   1800 
   1801   qs = TALER_MERCHANTDB_lookup_token_family_keys (TMH_db,
   1802                                                   oc->hc->instance->settings.id,
   1803                                                   slug,
   1804                                                   now,
   1805                                                   end,
   1806                                                   &add_family_key,
   1807                                                   oc);
   1808   switch (qs)
   1809   {
   1810   case GNUNET_DB_STATUS_HARD_ERROR:
   1811     GNUNET_break (0);
   1812     http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1813     ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   1814     break;
   1815   case GNUNET_DB_STATUS_SOFT_ERROR:
   1816     GNUNET_break (0);
   1817     http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1818     ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   1819     break;
   1820   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1821     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1822                 "Input token family slug %s unknown\n",
   1823                 slug);
   1824     http_status = MHD_HTTP_NOT_FOUND;
   1825     ec = TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN;
   1826     break;
   1827   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1828     return GNUNET_OK;
   1829   }
   1830   reply_with_error (oc,
   1831                     http_status,
   1832                     ec,
   1833                     slug);
   1834   return GNUNET_SYSERR;
   1835 }
   1836 
   1837 
   1838 /**
   1839  * Find the index of a key in the @a family that is valid at
   1840  * the time @a valid_at.
   1841  *
   1842  * @param family to search
   1843  * @param valid_at time when the key must be valid
   1844  * @param[out] key_index index to initialize
   1845  * @return #GNUNET_OK if a matching key was found
   1846  */
   1847 static enum GNUNET_GenericReturnValue
   1848 find_key_index (struct TALER_MERCHANT_ContractTokenFamily *family,
   1849                 struct GNUNET_TIME_Timestamp valid_at,
   1850                 unsigned int *key_index)
   1851 {
   1852   for (unsigned int i = 0; i<family->keys_len; i++)
   1853   {
   1854     if ( (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_after,
   1855                                      <=,
   1856                                      valid_at)) &&
   1857          (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_before,
   1858                                      >=,
   1859                                      valid_at)) )
   1860     {
   1861       /* The token family and a matching key already exist. */
   1862       *key_index = i;
   1863       return GNUNET_OK;
   1864     }
   1865   }
   1866   return GNUNET_NO;
   1867 }
   1868 
   1869 
   1870 /**
   1871  * Create fresh key pair based on @a cipher_spec.
   1872  *
   1873  * @param cipher_spec which kind of key pair should we generate
   1874  * @param[out] priv set to new private key
   1875  * @param[out] pub set to new public key
   1876  * @return #GNUNET_OK on success
   1877  */
   1878 static enum GNUNET_GenericReturnValue
   1879 create_key (const char *cipher_spec,
   1880             struct TALER_TokenIssuePrivateKey *priv,
   1881             struct TALER_TokenIssuePublicKey *pub)
   1882 {
   1883   unsigned int len;
   1884   char dummy;
   1885 
   1886   if (0 == strcmp ("cs",
   1887                    cipher_spec))
   1888   {
   1889     GNUNET_CRYPTO_blind_sign_keys_create (
   1890       &priv->private_key,
   1891       &pub->public_key,
   1892       GNUNET_CRYPTO_BSA_CS);
   1893     return GNUNET_OK;
   1894   }
   1895   if (1 ==
   1896       sscanf (cipher_spec,
   1897               "rsa(%u)%c",
   1898               &len,
   1899               &dummy))
   1900   {
   1901     GNUNET_CRYPTO_blind_sign_keys_create (
   1902       &priv->private_key,
   1903       &pub->public_key,
   1904       GNUNET_CRYPTO_BSA_RSA,
   1905       len);
   1906     return GNUNET_OK;
   1907   }
   1908   return GNUNET_SYSERR;
   1909 }
   1910 
   1911 
   1912 /**
   1913  * Check if the token family with the given @a slug is already present in the
   1914  * list of token families for this order. If not, fetch its details and add it
   1915  * to the list. Also checks if there is a public key with that expires after
   1916  * the payment deadline.  If not, generates a new key pair and stores it in
   1917  * the database.
   1918  *
   1919  * @param[in,out] oc order context
   1920  * @param slug slug of the token family
   1921  * @param valid_at time when the token returned must be valid
   1922  * @param[out] key_index set to the index of the respective public
   1923  *    key in the @a slug's token family keys array.
   1924  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1925  */
   1926 static enum GNUNET_GenericReturnValue
   1927 add_output_token_family (struct OrderContext *oc,
   1928                          const char *slug,
   1929                          struct GNUNET_TIME_Timestamp valid_at,
   1930                          unsigned int *key_index)
   1931 {
   1932   struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details;
   1933   struct TALER_MERCHANT_ContractTokenFamily *family;
   1934   enum GNUNET_DB_QueryStatus qs;
   1935 
   1936   family = find_family (oc,
   1937                         slug);
   1938   if ( (NULL != family) &&
   1939        (GNUNET_OK ==
   1940         find_key_index (family,
   1941                         valid_at,
   1942                         key_index)) )
   1943     return GNUNET_OK;
   1944   qs = TALER_MERCHANTDB_lookup_token_family_key (TMH_db,
   1945                                                  oc->hc->instance->settings.id,
   1946                                                  slug,
   1947                                                  valid_at,
   1948                                                  oc->parse_order.pay_deadline,
   1949                                                  &key_details);
   1950   switch (qs)
   1951   {
   1952   case GNUNET_DB_STATUS_HARD_ERROR:
   1953     GNUNET_break (0);
   1954     reply_with_error (oc,
   1955                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1956                       TALER_EC_GENERIC_DB_FETCH_FAILED,
   1957                       "lookup_token_family_key");
   1958     return GNUNET_SYSERR;
   1959   case GNUNET_DB_STATUS_SOFT_ERROR:
   1960     /* Single-statement transaction shouldn't possibly cause serialization errors.
   1961        Thus treating like a hard error. */
   1962     GNUNET_break (0);
   1963     reply_with_error (oc,
   1964                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1965                       TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1966                       "lookup_token_family_key");
   1967     return GNUNET_SYSERR;
   1968   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1969     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1970                 "Output token family slug %s unknown\n",
   1971                 slug);
   1972     reply_with_error (oc,
   1973                       MHD_HTTP_NOT_FOUND,
   1974                       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
   1975                       slug);
   1976     return GNUNET_SYSERR;
   1977   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1978     break;
   1979   }
   1980 
   1981   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1982               "Lookup of token family %s at %llu yielded %s\n",
   1983               slug,
   1984               (unsigned long long) valid_at.abs_time.abs_value_us,
   1985               NULL == key_details.pub.public_key ? "no key" : "a key");
   1986 
   1987   if (NULL == family)
   1988   {
   1989     add_family_key (oc,
   1990                     &key_details);
   1991     family = find_family (oc,
   1992                           slug);
   1993     GNUNET_assert (NULL != family);
   1994   }
   1995   /* we don't need the full family details anymore */
   1996   GNUNET_free (key_details.token_family.slug);
   1997   GNUNET_free (key_details.token_family.name);
   1998   GNUNET_free (key_details.token_family.description);
   1999   json_decref (key_details.token_family.description_i18n);
   2000   json_decref (key_details.token_family.extra_data);
   2001 
   2002   if (NULL != key_details.pub.public_key)
   2003   {
   2004     /* lookup_token_family_key must have found a matching key,
   2005        and it must have been added. Find and use the index. */
   2006     GNUNET_CRYPTO_blind_sign_pub_decref (key_details.pub.public_key);
   2007     GNUNET_CRYPTO_blind_sign_priv_decref (key_details.priv.private_key);
   2008     GNUNET_free (key_details.token_family.cipher_spec);
   2009     GNUNET_assert (GNUNET_OK ==
   2010                    find_key_index (family,
   2011                                    valid_at,
   2012                                    key_index));
   2013     return GNUNET_OK;
   2014   }
   2015 
   2016   /* No suitable key exists, create one! */
   2017   {
   2018     struct TALER_MERCHANT_ContractTokenFamilyKey key;
   2019     enum GNUNET_DB_QueryStatus iqs;
   2020     struct TALER_TokenIssuePrivateKey token_priv;
   2021     struct GNUNET_TIME_Timestamp key_expires;
   2022     struct GNUNET_TIME_Timestamp round_start;
   2023 
   2024     if (GNUNET_OK !=
   2025         get_rounded_time_interval_down (
   2026           key_details.token_family.validity_granularity,
   2027           valid_at,
   2028           &round_start))
   2029     {
   2030       GNUNET_break (0);
   2031       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2032                   "Unsupported validity granularity interval %s found in database for token family %s!\n",
   2033                   GNUNET_TIME_relative2s (
   2034                     key_details.token_family.validity_granularity,
   2035                     false),
   2036                   slug);
   2037       GNUNET_free (key_details.token_family.cipher_spec);
   2038       reply_with_error (oc,
   2039                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2040                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   2041                         "get_rounded_time_interval_down failed");
   2042       return GNUNET_SYSERR;
   2043     }
   2044     if (GNUNET_TIME_relative_cmp (
   2045           key_details.token_family.duration,
   2046           <,
   2047           GNUNET_TIME_relative_add (
   2048             key_details.token_family.validity_granularity,
   2049             key_details.token_family.start_offset)))
   2050     {
   2051       GNUNET_break (0);
   2052       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2053                   "Inconsistent duration %s found in database for token family %s (below validity granularity plus start_offset)!\n",
   2054                   GNUNET_TIME_relative2s (key_details.token_family.duration,
   2055                                           false),
   2056                   slug);
   2057       GNUNET_free (key_details.token_family.cipher_spec);
   2058       reply_with_error (oc,
   2059                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2060                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   2061                         "duration, validty_granularity and start_offset inconsistent for token family");
   2062       return GNUNET_SYSERR;
   2063     }
   2064     key.valid_after
   2065       = GNUNET_TIME_timestamp_max (
   2066           GNUNET_TIME_absolute_to_timestamp (
   2067             GNUNET_TIME_absolute_subtract (
   2068               round_start.abs_time,
   2069               key_details.token_family.start_offset)),
   2070           key_details.token_family.valid_after);
   2071     key.valid_before
   2072       = GNUNET_TIME_timestamp_min (
   2073           GNUNET_TIME_absolute_to_timestamp (
   2074             GNUNET_TIME_absolute_add (
   2075               key.valid_after.abs_time,
   2076               key_details.token_family.duration)),
   2077           key_details.token_family.valid_before);
   2078     GNUNET_assert (GNUNET_OK ==
   2079                    get_rounded_time_interval_down (
   2080                      key_details.token_family.validity_granularity,
   2081                      key.valid_before,
   2082                      &key_expires));
   2083     if (GNUNET_TIME_timestamp_cmp (
   2084           key_expires,
   2085           ==,
   2086           round_start))
   2087     {
   2088       /* valid_before does not actually end after the
   2089          next rounded validity period would start;
   2090          determine next rounded validity period
   2091          start point and extend valid_before to cover
   2092          the full validity period */
   2093       GNUNET_assert (
   2094         GNUNET_OK ==
   2095         get_rounded_time_interval_up (
   2096           key_details.token_family.validity_granularity,
   2097           key.valid_before,
   2098           &key_expires));
   2099       /* This should basically always end up being key_expires */
   2100       key.valid_before = GNUNET_TIME_timestamp_max (key.valid_before,
   2101                                                     key_expires);
   2102     }
   2103     if (GNUNET_OK !=
   2104         create_key (key_details.token_family.cipher_spec,
   2105                     &token_priv,
   2106                     &key.pub))
   2107     {
   2108       GNUNET_break (0);
   2109       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2110                   "Unsupported cipher family %s found in database for token family %s!\n",
   2111                   key_details.token_family.cipher_spec,
   2112                   slug);
   2113       GNUNET_free (key_details.token_family.cipher_spec);
   2114       reply_with_error (oc,
   2115                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2116                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   2117                         "invalid cipher stored in local database for token family");
   2118       return GNUNET_SYSERR;
   2119     }
   2120     GNUNET_free (key_details.token_family.cipher_spec);
   2121     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2122                 "Storing new key for slug %s of %s\n",
   2123                 slug,
   2124                 oc->hc->instance->settings.id);
   2125     iqs = TALER_MERCHANTDB_insert_token_family_key (TMH_db,
   2126                                                     oc->hc->instance->settings.id,
   2127                                                     slug,
   2128                                                     &key.pub,
   2129                                                     &token_priv,
   2130                                                     key_expires,
   2131                                                     key.valid_after,
   2132                                                     key.valid_before);
   2133     GNUNET_CRYPTO_blind_sign_priv_decref (token_priv.private_key);
   2134     switch (iqs)
   2135     {
   2136     case GNUNET_DB_STATUS_HARD_ERROR:
   2137       GNUNET_break (0);
   2138       reply_with_error (oc,
   2139                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2140                         TALER_EC_GENERIC_DB_STORE_FAILED,
   2141                         NULL);
   2142       return GNUNET_SYSERR;
   2143     case GNUNET_DB_STATUS_SOFT_ERROR:
   2144       /* Single-statement transaction shouldn't possibly cause serialization errors.
   2145          Thus treating like a hard error. */
   2146       GNUNET_break (0);
   2147       reply_with_error (oc,
   2148                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2149                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   2150                         NULL);
   2151       return GNUNET_SYSERR;
   2152     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   2153       GNUNET_break (0);
   2154       reply_with_error (oc,
   2155                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2156                         TALER_EC_GENERIC_DB_STORE_FAILED,
   2157                         NULL);
   2158       return GNUNET_SYSERR;
   2159     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   2160       break;
   2161     }
   2162     *key_index = family->keys_len;
   2163     GNUNET_array_append (family->keys,
   2164                          family->keys_len,
   2165                          key);
   2166   }
   2167   return GNUNET_OK;
   2168 }
   2169 
   2170 
   2171 /**
   2172  * Build JSON array that represents all of the token families
   2173  * in the contract.
   2174  *
   2175  * @param[in] oc v1-style order context
   2176  * @return JSON array with token families for the contract
   2177  */
   2178 static json_t *
   2179 output_token_families (struct OrderContext *oc)
   2180 {
   2181   json_t *token_families = json_object ();
   2182 
   2183   GNUNET_assert (NULL != token_families);
   2184   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
   2185   {
   2186     const struct TALER_MERCHANT_ContractTokenFamily *family
   2187       = &oc->parse_choices.token_families[i];
   2188     json_t *jfamily;
   2189 
   2190     jfamily = TALER_MERCHANT_json_from_token_family (family);
   2191 
   2192     GNUNET_assert (jfamily != NULL);
   2193 
   2194     GNUNET_assert (0 ==
   2195                    json_object_set_new (token_families,
   2196                                         family->slug,
   2197                                         jfamily));
   2198   }
   2199   return token_families;
   2200 }
   2201 
   2202 
   2203 /**
   2204  * Build JSON array that represents all of the contract choices
   2205  * in the contract.
   2206  *
   2207  * @param[in] oc v1-style order context
   2208  * @return JSON array with token families for the contract
   2209  */
   2210 static json_t *
   2211 output_contract_choices (struct OrderContext *oc)
   2212 {
   2213   json_t *choices = json_array ();
   2214 
   2215   GNUNET_assert (NULL != choices);
   2216   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2217   {
   2218     oc->parse_choices.choices[i].max_fee =
   2219       oc->set_max_fee.details.v1.max_fees[i];
   2220     GNUNET_assert (0 == json_array_append_new (
   2221                      choices,
   2222                      TALER_MERCHANT_json_from_contract_choice (
   2223                        &oc->parse_choices.choices[i],
   2224                        false)));
   2225   }
   2226 
   2227   return choices;
   2228 }
   2229 
   2230 
   2231 /**
   2232  * Serialize order into @a oc->serialize_order.contract,
   2233  * ready to be stored in the database. Upon success, continue
   2234  * processing with check_contract().
   2235  *
   2236  * @param[in,out] oc order context
   2237  */
   2238 static void
   2239 phase_serialize_order (struct OrderContext *oc)
   2240 {
   2241   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2242     &oc->hc->instance->settings;
   2243   json_t *merchant;
   2244 
   2245   merchant = GNUNET_JSON_PACK (
   2246     GNUNET_JSON_pack_string ("name",
   2247                              settings->name),
   2248     GNUNET_JSON_pack_allow_null (
   2249       GNUNET_JSON_pack_string ("website",
   2250                                settings->website)),
   2251     GNUNET_JSON_pack_allow_null (
   2252       GNUNET_JSON_pack_string ("email",
   2253                                settings->email)),
   2254     GNUNET_JSON_pack_allow_null (
   2255       GNUNET_JSON_pack_string ("logo",
   2256                                settings->logo)));
   2257   GNUNET_assert (NULL != merchant);
   2258   {
   2259     json_t *loca;
   2260 
   2261     /* Handle merchant address */
   2262     loca = settings->address;
   2263     if (NULL != loca)
   2264     {
   2265       loca = json_deep_copy (loca);
   2266       GNUNET_assert (NULL != loca);
   2267       GNUNET_assert (0 ==
   2268                      json_object_set_new (merchant,
   2269                                           "address",
   2270                                           loca));
   2271     }
   2272   }
   2273   {
   2274     json_t *juri;
   2275 
   2276     /* Handle merchant jurisdiction */
   2277     juri = settings->jurisdiction;
   2278     if (NULL != juri)
   2279     {
   2280       juri = json_deep_copy (juri);
   2281       GNUNET_assert (NULL != juri);
   2282       GNUNET_assert (0 ==
   2283                      json_object_set_new (merchant,
   2284                                           "jurisdiction",
   2285                                           juri));
   2286     }
   2287   }
   2288 
   2289   oc->serialize_order.contract = GNUNET_JSON_PACK (
   2290     GNUNET_JSON_pack_int64 ("version",
   2291                             oc->parse_order.version),
   2292     GNUNET_JSON_pack_string ("summary",
   2293                              oc->parse_order.summary),
   2294     GNUNET_JSON_pack_allow_null (
   2295       GNUNET_JSON_pack_object_incref (
   2296         "summary_i18n",
   2297         (json_t *) oc->parse_order.summary_i18n)),
   2298     GNUNET_JSON_pack_allow_null (
   2299       GNUNET_JSON_pack_string ("public_reorder_url",
   2300                                oc->parse_order.public_reorder_url)),
   2301     GNUNET_JSON_pack_allow_null (
   2302       GNUNET_JSON_pack_string ("fulfillment_message",
   2303                                oc->parse_order.fulfillment_message)),
   2304     GNUNET_JSON_pack_allow_null (
   2305       GNUNET_JSON_pack_object_incref (
   2306         "fulfillment_message_i18n",
   2307         (json_t *) oc->parse_order.fulfillment_message_i18n)),
   2308     GNUNET_JSON_pack_allow_null (
   2309       GNUNET_JSON_pack_string ("fulfillment_url",
   2310                                oc->parse_order.fulfillment_url)),
   2311     GNUNET_JSON_pack_allow_null (
   2312       GNUNET_JSON_pack_uint64 ("minimum_age",
   2313                                oc->parse_order.minimum_age)),
   2314     GNUNET_JSON_pack_allow_null (
   2315       GNUNET_JSON_pack_uint64 ("default_money_pot",
   2316                                oc->parse_order.order_default_money_pot)),
   2317     GNUNET_JSON_pack_array_incref ("products",
   2318                                    oc->merge_inventory.products),
   2319     GNUNET_JSON_pack_data_auto ("h_wire",
   2320                                 &oc->select_wire_method.wm->h_wire),
   2321     GNUNET_JSON_pack_string ("wire_method",
   2322                              oc->select_wire_method.wm->wire_method),
   2323     GNUNET_JSON_pack_string ("order_id",
   2324                              oc->parse_order.order_id),
   2325     GNUNET_JSON_pack_timestamp ("timestamp",
   2326                                 oc->parse_order.timestamp),
   2327     GNUNET_JSON_pack_timestamp ("pay_deadline",
   2328                                 oc->parse_order.pay_deadline),
   2329     GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
   2330                                 oc->parse_order.wire_deadline),
   2331     GNUNET_JSON_pack_allow_null (
   2332       GNUNET_JSON_pack_timestamp ("delivery_date",
   2333                                   oc->parse_order.delivery_date)),
   2334     GNUNET_JSON_pack_allow_null (
   2335       GNUNET_JSON_pack_object_incref (
   2336         "delivery_location",
   2337         (json_t *) oc->parse_order.delivery_location)),
   2338     GNUNET_JSON_pack_string ("merchant_base_url",
   2339                              oc->parse_order.merchant_base_url),
   2340     GNUNET_JSON_pack_object_steal ("merchant",
   2341                                    merchant),
   2342     GNUNET_JSON_pack_data_auto ("merchant_pub",
   2343                                 &oc->hc->instance->merchant_pub),
   2344     GNUNET_JSON_pack_array_incref ("exchanges",
   2345                                    oc->select_wire_method.exchanges),
   2346     GNUNET_JSON_pack_allow_null (
   2347       GNUNET_JSON_pack_object_incref ("extra",
   2348                                       (json_t *) oc->parse_order.extra))
   2349     );
   2350 
   2351   {
   2352     json_t *xtra;
   2353 
   2354     switch (oc->parse_order.version)
   2355     {
   2356     case TALER_MERCHANT_CONTRACT_VERSION_0:
   2357       xtra = GNUNET_JSON_PACK (
   2358         TALER_JSON_pack_amount ("max_fee",
   2359                                 &oc->set_max_fee.details.v0.max_fee),
   2360         GNUNET_JSON_pack_allow_null (
   2361           TALER_JSON_pack_amount ("tip",
   2362                                   oc->parse_order.details.v0.no_tip
   2363                                   ? NULL
   2364                                   : &oc->parse_order.details.v0.tip)),
   2365         TALER_JSON_pack_amount ("amount",
   2366                                 &oc->parse_order.details.v0.brutto));
   2367       break;
   2368     case TALER_MERCHANT_CONTRACT_VERSION_1:
   2369       {
   2370         json_t *token_families = output_token_families (oc);
   2371         json_t *choices = output_contract_choices (oc);
   2372 
   2373         if ( (NULL == token_families) ||
   2374              (NULL == choices) )
   2375         {
   2376           GNUNET_break (0);
   2377           return;
   2378         }
   2379         xtra = GNUNET_JSON_PACK (
   2380           GNUNET_JSON_pack_array_steal ("choices",
   2381                                         choices),
   2382           GNUNET_JSON_pack_object_steal ("token_families",
   2383                                          token_families));
   2384         break;
   2385       }
   2386     default:
   2387       GNUNET_assert (0);
   2388     }
   2389     GNUNET_assert (0 ==
   2390                    json_object_update (oc->serialize_order.contract,
   2391                                        xtra));
   2392     json_decref (xtra);
   2393   }
   2394 
   2395 
   2396   /* Pack does not work here, because it doesn't set zero-values for timestamps */
   2397   GNUNET_assert (0 ==
   2398                  json_object_set_new (oc->serialize_order.contract,
   2399                                       "refund_deadline",
   2400                                       GNUNET_JSON_from_timestamp (
   2401                                         oc->parse_order.refund_deadline)));
   2402   /* auto_refund should only be set if it is not 0 */
   2403   if (! GNUNET_TIME_relative_is_zero (oc->parse_order.auto_refund))
   2404   {
   2405     /* Pack does not work here, because it sets zero-values for relative times */
   2406     GNUNET_assert (0 ==
   2407                    json_object_set_new (oc->serialize_order.contract,
   2408                                         "auto_refund",
   2409                                         GNUNET_JSON_from_time_rel (
   2410                                           oc->parse_order.auto_refund)));
   2411   }
   2412 
   2413   oc->phase++;
   2414 }
   2415 
   2416 
   2417 /* ***************** ORDER_PHASE_SET_MAX_FEE **************** */
   2418 
   2419 
   2420 /**
   2421  * Set @a max_fee in @a oc based on @a max_stefan_fee value if not overridden
   2422  * by @a client_fee.  If neither is set, set the fee to zero using currency
   2423  * from @a brutto.
   2424  *
   2425  * @param[in,out] oc order context
   2426  * @param brutto brutto amount to compute fee for
   2427  * @param client_fee client-given fee override (or invalid)
   2428  * @param max_stefan_fee maximum STEFAN fee of any exchange
   2429  * @param max_fee set to the maximum stefan fee
   2430  */
   2431 static void
   2432 compute_fee (struct OrderContext *oc,
   2433              const struct TALER_Amount *brutto,
   2434              const struct TALER_Amount *client_fee,
   2435              const struct TALER_Amount *max_stefan_fee,
   2436              struct TALER_Amount *max_fee)
   2437 {
   2438   const struct TALER_MERCHANTDB_InstanceSettings *settings
   2439     = &oc->hc->instance->settings;
   2440 
   2441   if (GNUNET_OK ==
   2442       TALER_amount_is_valid (client_fee))
   2443   {
   2444     *max_fee = *client_fee;
   2445     return;
   2446   }
   2447   if ( (settings->use_stefan) &&
   2448        (NULL != max_stefan_fee) &&
   2449        (GNUNET_OK ==
   2450         TALER_amount_is_valid (max_stefan_fee)) )
   2451   {
   2452     *max_fee = *max_stefan_fee;
   2453     return;
   2454   }
   2455   GNUNET_assert (
   2456     GNUNET_OK ==
   2457     TALER_amount_set_zero (brutto->currency,
   2458                            max_fee));
   2459 }
   2460 
   2461 
   2462 /**
   2463  * Initialize "set_max_fee" in @a oc based on STEFAN value or client
   2464  * preference. Upon success, continue processing in next phase.
   2465  *
   2466  * @param[in,out] oc order context
   2467  */
   2468 static void
   2469 phase_set_max_fee (struct OrderContext *oc)
   2470 {
   2471   switch (oc->parse_order.version)
   2472   {
   2473   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2474     compute_fee (oc,
   2475                  &oc->parse_order.details.v0.brutto,
   2476                  &oc->parse_order.details.v0.max_fee,
   2477                  &oc->set_exchanges.details.v0.max_stefan_fee,
   2478                  &oc->set_max_fee.details.v0.max_fee);
   2479     break;
   2480   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2481     oc->set_max_fee.details.v1.max_fees
   2482       = GNUNET_new_array (oc->parse_choices.choices_len,
   2483                           struct TALER_Amount);
   2484     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2485       compute_fee (oc,
   2486                    &oc->parse_choices.choices[i].amount,
   2487                    &oc->parse_choices.choices[i].max_fee,
   2488                    NULL != oc->set_exchanges.details.v1.max_stefan_fees
   2489                    ? &oc->set_exchanges.details.v1.max_stefan_fees[i]
   2490                    : NULL,
   2491                    &oc->set_max_fee.details.v1.max_fees[i]);
   2492     break;
   2493   default:
   2494     GNUNET_break (0);
   2495     break;
   2496   }
   2497   oc->phase++;
   2498 }
   2499 
   2500 
   2501 /* ***************** ORDER_PHASE_SELECT_WIRE_METHOD **************** */
   2502 
   2503 /**
   2504  * Phase to select a wire method that will be acceptable for the order.
   2505  * If none is "perfect" (allows all choices), might jump back to the
   2506  * previous phase to force "/keys" downloads to see if that helps.
   2507  *
   2508  * @param[in,out] oc order context
   2509  */
   2510 static void
   2511 phase_select_wire_method (struct OrderContext *oc)
   2512 {
   2513   const struct TALER_Amount *ea;
   2514   struct WireMethodCandidate *best = NULL;
   2515   unsigned int max_choices = 0;
   2516   unsigned int want_choices = 0;
   2517 
   2518   for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2519        NULL != wmc;
   2520        wmc = wmc->next)
   2521   {
   2522     unsigned int num_choices = 0;
   2523 
   2524     switch (oc->parse_order.version)
   2525     {
   2526     case TALER_MERCHANT_CONTRACT_VERSION_0:
   2527       want_choices = 1;
   2528       ea = &oc->parse_order.details.v0.brutto;
   2529       if (TALER_amount_is_zero (ea) ||
   2530           TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2531                                        ea))
   2532         num_choices++;
   2533       break;
   2534     case TALER_MERCHANT_CONTRACT_VERSION_1:
   2535       want_choices = oc->parse_choices.choices_len;
   2536       for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2537       {
   2538         ea = &oc->parse_choices.choices[i].amount;
   2539         if (TALER_amount_is_zero (ea) ||
   2540             TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2541                                          ea))
   2542           num_choices++;
   2543       }
   2544       break;
   2545     default:
   2546       GNUNET_assert (0);
   2547     }
   2548     if (num_choices > max_choices)
   2549     {
   2550       best = wmc;
   2551       max_choices = num_choices;
   2552     }
   2553   }
   2554 
   2555   if ( (want_choices > max_choices) &&
   2556        (oc->set_exchanges.promising_exchange) &&
   2557        (! oc->set_exchanges.forced_reload) )
   2558   {
   2559     oc->set_exchanges.exchange_ok = false;
   2560     /* Not all choices in the contract can work with these
   2561        exchanges, try again with forcing /keys download */
   2562     for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2563          NULL != wmc;
   2564          wmc = wmc->next)
   2565     {
   2566       json_array_clear (wmc->exchanges);
   2567       TALER_amount_set_free (&wmc->total_exchange_limits);
   2568     }
   2569     oc->phase = ORDER_PHASE_SET_EXCHANGES;
   2570     return;
   2571   }
   2572 
   2573   if ( (NULL == best) &&
   2574        (NULL != oc->parse_request.payment_target) )
   2575   {
   2576     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2577                 "Cannot create order: lacking suitable exchanges for payment target `%s'\n",
   2578                 oc->parse_request.payment_target);
   2579     reply_with_error (
   2580       oc,
   2581       MHD_HTTP_CONFLICT,
   2582       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
   2583       oc->parse_request.payment_target);
   2584     return;
   2585   }
   2586 
   2587   if (NULL == best)
   2588   {
   2589     enum MHD_Result mret;
   2590 
   2591     /* We actually do not have ANY workable exchange(s) */
   2592     mret = TALER_MHD_reply_json_steal (
   2593       oc->connection,
   2594       GNUNET_JSON_PACK (
   2595         TALER_JSON_pack_ec (
   2596           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS),
   2597         GNUNET_JSON_pack_array_incref (
   2598           "exchange_rejections",
   2599           oc->set_exchanges.exchange_rejections)),
   2600       MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS);
   2601     finalize_order (oc,
   2602                     mret);
   2603     return;
   2604   }
   2605 
   2606   if (want_choices > max_choices)
   2607   {
   2608     /* Some choices are unpayable */
   2609     GNUNET_log (
   2610       GNUNET_ERROR_TYPE_WARNING,
   2611       "Creating order, but some choices do not work with the selected wire method\n");
   2612   }
   2613   if ( (0 == json_array_size (best->exchanges)) &&
   2614        (oc->add_payment_details.need_exchange) )
   2615   {
   2616     /* We did not find any reasonable exchange */
   2617     GNUNET_log (
   2618       GNUNET_ERROR_TYPE_WARNING,
   2619       "Creating order, but only for choices without payment\n");
   2620   }
   2621 
   2622   oc->select_wire_method.wm
   2623     = best->wm;
   2624   oc->select_wire_method.exchanges
   2625     = json_incref (best->exchanges);
   2626   oc->phase++;
   2627 }
   2628 
   2629 
   2630 /* ***************** ORDER_PHASE_SET_EXCHANGES **************** */
   2631 
   2632 /**
   2633  * Exchange `/keys` processing is done, resume handling
   2634  * the order.
   2635  *
   2636  * @param[in,out] oc context to resume
   2637  */
   2638 static void
   2639 resume_with_keys (struct OrderContext *oc)
   2640 {
   2641   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2642               "Resuming order processing after /keys downloads\n");
   2643   GNUNET_assert (GNUNET_YES == oc->suspended);
   2644   GNUNET_CONTAINER_DLL_remove (oc_head,
   2645                                oc_tail,
   2646                                oc);
   2647   oc->suspended = GNUNET_NO;
   2648   MHD_resume_connection (oc->connection);
   2649   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   2650 }
   2651 
   2652 
   2653 /**
   2654  * Given a @a brutto amount for exchange with @a keys, set the
   2655  * @a stefan_fee. Note that @a stefan_fee is updated to the maximum
   2656  * of the input and the computed fee.
   2657  *
   2658  * @param[in,out] keys exchange keys
   2659  * @param brutto some brutto amount the client is to pay
   2660  * @param[in,out] stefan_fee set to STEFAN fee to be paid by the merchant
   2661  */
   2662 static void
   2663 compute_stefan_fee (const struct TALER_EXCHANGE_Keys *keys,
   2664                     const struct TALER_Amount *brutto,
   2665                     struct TALER_Amount *stefan_fee)
   2666 {
   2667   struct TALER_Amount net;
   2668 
   2669   if (GNUNET_SYSERR !=
   2670       TALER_EXCHANGE_keys_stefan_b2n (keys,
   2671                                       brutto,
   2672                                       &net))
   2673   {
   2674     struct TALER_Amount fee;
   2675 
   2676     TALER_EXCHANGE_keys_stefan_round (keys,
   2677                                       &net);
   2678     if (-1 == TALER_amount_cmp (brutto,
   2679                                 &net))
   2680     {
   2681       /* brutto < netto! */
   2682       /* => after rounding, there is no real difference */
   2683       net = *brutto;
   2684     }
   2685     GNUNET_assert (0 <=
   2686                    TALER_amount_subtract (&fee,
   2687                                           brutto,
   2688                                           &net));
   2689     if ( (GNUNET_OK !=
   2690           TALER_amount_is_valid (stefan_fee)) ||
   2691          (-1 == TALER_amount_cmp (stefan_fee,
   2692                                   &fee)) )
   2693     {
   2694       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2695                   "Updated STEFAN-based fee to %s\n",
   2696                   TALER_amount2s (&fee));
   2697       *stefan_fee = fee;
   2698     }
   2699   }
   2700 }
   2701 
   2702 
   2703 /**
   2704  * Update MAX STEFAN fees based on @a keys.
   2705  *
   2706  * @param[in,out] oc order context to update
   2707  * @param keys keys to derive STEFAN fees from
   2708  */
   2709 static void
   2710 update_stefan (struct OrderContext *oc,
   2711                const struct TALER_EXCHANGE_Keys *keys)
   2712 {
   2713   switch (oc->parse_order.version)
   2714   {
   2715   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2716     compute_stefan_fee (keys,
   2717                         &oc->parse_order.details.v0.brutto,
   2718                         &oc->set_exchanges.details.v0.max_stefan_fee);
   2719     break;
   2720   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2721     oc->set_exchanges.details.v1.max_stefan_fees
   2722       = GNUNET_new_array (oc->parse_choices.choices_len,
   2723                           struct TALER_Amount);
   2724     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2725       if (0 == strcasecmp (keys->currency,
   2726                            oc->parse_choices.choices[i].amount.currency))
   2727         compute_stefan_fee (keys,
   2728                             &oc->parse_choices.choices[i].amount,
   2729                             &oc->set_exchanges.details.v1.max_stefan_fees[i]);
   2730     break;
   2731   default:
   2732     GNUNET_assert (0);
   2733   }
   2734 }
   2735 
   2736 
   2737 /**
   2738  * Check our KYC status at all exchanges as our current limit is
   2739  * too low and we failed to create an order.
   2740  *
   2741  * @param oc order context
   2742  * @param wmc wire method candidate to notify for
   2743  * @param exchange_url exchange to notify about
   2744  */
   2745 static void
   2746 notify_kyc_required (const struct OrderContext *oc,
   2747                      const struct WireMethodCandidate *wmc,
   2748                      const char *exchange_url)
   2749 {
   2750   struct GNUNET_DB_EventHeaderP es = {
   2751     .size = htons (sizeof (es)),
   2752     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
   2753   };
   2754   char *hws;
   2755   char *extra;
   2756 
   2757   hws = GNUNET_STRINGS_data_to_string_alloc (
   2758     &wmc->wm->h_wire,
   2759     sizeof (wmc->wm->h_wire));
   2760 
   2761   GNUNET_asprintf (&extra,
   2762                    "%s %s",
   2763                    hws,
   2764                    exchange_url);
   2765   TALER_MERCHANTDB_event_notify (TMH_db,
   2766                                  &es,
   2767                                  extra,
   2768                                  strlen (extra) + 1);
   2769   GNUNET_free (extra);
   2770   GNUNET_free (hws);
   2771 }
   2772 
   2773 
   2774 /**
   2775  * Add a reason why a particular exchange was rejected to our
   2776  * response data.
   2777  *
   2778  * @param[in,out] oc order context to update
   2779  * @param exchange_url exchange this is about
   2780  * @param ec error code to set for the exchange
   2781  */
   2782 static void
   2783 add_rejection (struct OrderContext *oc,
   2784                const char *exchange_url,
   2785                enum TALER_ErrorCode ec)
   2786 {
   2787   if (NULL == oc->set_exchanges.exchange_rejections)
   2788   {
   2789     oc->set_exchanges.exchange_rejections = json_array ();
   2790     GNUNET_assert (NULL != oc->set_exchanges.exchange_rejections);
   2791   }
   2792   GNUNET_assert (0 ==
   2793                  json_array_append_new (
   2794                    oc->set_exchanges.exchange_rejections,
   2795                    GNUNET_JSON_PACK (
   2796                      GNUNET_JSON_pack_string ("exchange_url",
   2797                                               exchange_url),
   2798                      TALER_JSON_pack_ec (ec))));
   2799 }
   2800 
   2801 
   2802 /**
   2803  * Checks the limits that apply for this @a exchange and
   2804  * the @a wmc and if the exchange is acceptable at all, adds it
   2805  * to the list of exchanges for the @a wmc.
   2806  *
   2807  * @param oc context of the order
   2808  * @param exchange internal handle for the exchange
   2809  * @param exchange_url base URL of this exchange
   2810  * @param wmc wire method to evaluate this exchange for
   2811  * @return true if the exchange is acceptable for the contract
   2812  */
   2813 static bool
   2814 get_acceptable (struct OrderContext *oc,
   2815                 const struct TMH_Exchange *exchange,
   2816                 const char *exchange_url,
   2817                 struct WireMethodCandidate *wmc)
   2818 {
   2819   const struct TALER_Amount *max_needed = NULL;
   2820   unsigned int priority = 42; /* make compiler happy */
   2821   json_t *j_exchange;
   2822   enum TMH_ExchangeStatus res;
   2823   struct TALER_Amount max_amount;
   2824 
   2825   for (unsigned int i = 0;
   2826        i<oc->add_payment_details.num_max_choice_limits;
   2827        i++)
   2828   {
   2829     struct TALER_Amount *val = &oc->add_payment_details.max_choice_limits[i];
   2830 
   2831     if (0 == strcasecmp (val->currency,
   2832                          TMH_EXCHANGES_get_currency (exchange)))
   2833     {
   2834       max_needed = val;
   2835       break;
   2836     }
   2837   }
   2838   if (NULL == max_needed)
   2839   {
   2840     /* exchange currency not relevant for any of our choices, skip it */
   2841     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2842                 "Exchange %s with currency `%s' is not applicable to this order\n",
   2843                 exchange_url,
   2844                 TMH_EXCHANGES_get_currency (exchange));
   2845     add_rejection (oc,
   2846                    exchange_url,
   2847                    TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH);
   2848     return false;
   2849   }
   2850 
   2851   max_amount = *max_needed;
   2852   res = TMH_exchange_check_debit (
   2853     oc->hc->instance->settings.id,
   2854     exchange,
   2855     wmc->wm,
   2856     &max_amount);
   2857   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2858               "Exchange %s evaluated at %d with max %s\n",
   2859               exchange_url,
   2860               res,
   2861               TALER_amount2s (&max_amount));
   2862   if (TALER_amount_is_zero (&max_amount))
   2863   {
   2864     if (! TALER_amount_is_zero (max_needed))
   2865     {
   2866       /* Trigger re-checking the current deposit limit when
   2867        * paying non-zero amount with zero deposit limit */
   2868       notify_kyc_required (oc,
   2869                            wmc,
   2870                            exchange_url);
   2871     }
   2872     /* If deposit is impossible, we don't list the
   2873      * exchange in the contract terms. */
   2874     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2875                 "Exchange %s deposit limit is zero, skipping it\n",
   2876                 exchange_url);
   2877     add_rejection (oc,
   2878                    exchange_url,
   2879                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED);
   2880     return false;
   2881   }
   2882   switch (res)
   2883   {
   2884   case TMH_ES_OK:
   2885   case TMH_ES_RETRY_OK:
   2886     priority = 1024;   /* high */
   2887     oc->set_exchanges.exchange_ok = true;
   2888     break;
   2889   case TMH_ES_NO_ACC:
   2890     if (oc->set_exchanges.forced_reload)
   2891       priority = 0;   /* fresh negative response */
   2892     else
   2893       priority = 512; /* stale negative response */
   2894     break;
   2895   case TMH_ES_NO_CURR:
   2896     if (oc->set_exchanges.forced_reload)
   2897       priority = 0;   /* fresh negative response */
   2898     else
   2899       priority = 512; /* stale negative response */
   2900     break;
   2901   case TMH_ES_NO_KEYS:
   2902     if (oc->set_exchanges.forced_reload)
   2903       priority = 256;   /* fresh, no accounts yet */
   2904     else
   2905       priority = 768;  /* stale, no accounts yet */
   2906     break;
   2907   case TMH_ES_NO_ACC_RETRY_OK:
   2908     if (oc->set_exchanges.forced_reload)
   2909     {
   2910       priority = 0;   /* fresh negative response */
   2911     }
   2912     else
   2913     {
   2914       oc->set_exchanges.promising_exchange = true;
   2915       priority = 512; /* stale negative response */
   2916     }
   2917     break;
   2918   case TMH_ES_NO_CURR_RETRY_OK:
   2919     if (oc->set_exchanges.forced_reload)
   2920       priority = 0;   /* fresh negative response */
   2921     else
   2922       priority = 512; /* stale negative response */
   2923     break;
   2924   case TMH_ES_NO_KEYS_RETRY_OK:
   2925     if (oc->set_exchanges.forced_reload)
   2926     {
   2927       priority = 256;   /* fresh, no accounts yet */
   2928     }
   2929     else
   2930     {
   2931       oc->set_exchanges.promising_exchange = true;
   2932       priority = 768;  /* stale, no accounts yet */
   2933     }
   2934     break;
   2935   }
   2936   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2937               "Exchange %s deposit limit is %s, adding it!\n",
   2938               exchange_url,
   2939               TALER_amount2s (&max_amount));
   2940 
   2941   j_exchange = GNUNET_JSON_PACK (
   2942     GNUNET_JSON_pack_string ("url",
   2943                              exchange_url),
   2944     GNUNET_JSON_pack_uint64 ("priority",
   2945                              priority),
   2946     TALER_JSON_pack_amount ("max_contribution",
   2947                             &max_amount),
   2948     GNUNET_JSON_pack_data_auto ("master_pub",
   2949                                 TMH_EXCHANGES_get_master_pub (exchange)));
   2950   GNUNET_assert (NULL != j_exchange);
   2951   /* Add exchange to list of exchanges for this wire method
   2952      candidate */
   2953   GNUNET_assert (0 ==
   2954                  json_array_append_new (wmc->exchanges,
   2955                                         j_exchange));
   2956   GNUNET_assert (0 <=
   2957                  TALER_amount_set_add (&wmc->total_exchange_limits,
   2958                                        &max_amount,
   2959                                        max_needed));
   2960   return true;
   2961 }
   2962 
   2963 
   2964 /**
   2965  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
   2966  * operation.
   2967  *
   2968  * @param cls closure with our `struct RekeyExchange *`
   2969  * @param keys the keys of the exchange
   2970  * @param exchange representation of the exchange
   2971  */
   2972 static void
   2973 keys_cb (
   2974   void *cls,
   2975   struct TALER_EXCHANGE_Keys *keys,
   2976   struct TMH_Exchange *exchange)
   2977 {
   2978   struct RekeyExchange *rx = cls;
   2979   struct OrderContext *oc = rx->oc;
   2980   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2981     &oc->hc->instance->settings;
   2982   bool applicable = false;
   2983 
   2984   rx->fo = NULL;
   2985   GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   2986                                oc->set_exchanges.pending_reload_tail,
   2987                                rx);
   2988   if (NULL == keys)
   2989   {
   2990     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2991                 "Failed to download %skeys\n",
   2992                 rx->url);
   2993     oc->set_exchanges.promising_exchange = true;
   2994     add_rejection (oc,
   2995                    rx->url,
   2996                    TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE);
   2997     goto cleanup;
   2998   }
   2999   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3000               "Got response for %skeys\n",
   3001               rx->url);
   3002 
   3003   /* Evaluate the use of this exchange for each wire method candidate */
   3004   for (unsigned int j = 0; j<keys->accounts_len; j++)
   3005   {
   3006     struct TALER_FullPayto full_payto = keys->accounts[j].fpayto_uri;
   3007     char *wire_method = TALER_payto_get_method (full_payto.full_payto);
   3008 
   3009     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   3010                 "Exchange `%s' has wire method `%s'\n",
   3011                 rx->url,
   3012                 wire_method);
   3013     for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   3014          NULL != wmc;
   3015          wmc = wmc->next)
   3016     {
   3017       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   3018                   "Order could use wire method `%s'\n",
   3019                   wmc->wm->wire_method);
   3020       if (0 == strcmp (wmc->wm->wire_method,
   3021                        wire_method) )
   3022       {
   3023         applicable |= get_acceptable (oc,
   3024                                       exchange,
   3025                                       rx->url,
   3026                                       wmc);
   3027       }
   3028     }
   3029     GNUNET_free (wire_method);
   3030   }
   3031   if ( (! applicable) &&
   3032        (! oc->set_exchanges.forced_reload) )
   3033   {
   3034     /* Checks for 'forced_reload' to not log the error *again*
   3035        if we forced a re-load and are encountering the
   3036        applicability error a 2nd time */
   3037     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3038                 "Exchange `%s' %u wire methods are not applicable to this order\n",
   3039                 rx->url,
   3040                 keys->accounts_len);
   3041     add_rejection (oc,
   3042                    rx->url,
   3043                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED)
   3044     ;
   3045   }
   3046   if (applicable &&
   3047       settings->use_stefan)
   3048     update_stefan (oc,
   3049                    keys);
   3050 cleanup:
   3051   GNUNET_free (rx->url);
   3052   GNUNET_free (rx);
   3053   if (NULL != oc->set_exchanges.pending_reload_head)
   3054     return;
   3055   resume_with_keys (oc);
   3056 }
   3057 
   3058 
   3059 /**
   3060  * Force re-downloading of /keys from @a exchange,
   3061  * we currently have no acceptable exchange, so we
   3062  * should try to get one.
   3063  *
   3064  * @param cls closure with our `struct OrderContext`
   3065  * @param url base URL of the exchange
   3066  * @param exchange internal handle for the exchange
   3067  */
   3068 static void
   3069 get_exchange_keys (void *cls,
   3070                    const char *url,
   3071                    const struct TMH_Exchange *exchange)
   3072 {
   3073   struct OrderContext *oc = cls;
   3074   struct RekeyExchange *rx;
   3075 
   3076   rx = GNUNET_new (struct RekeyExchange);
   3077   rx->oc = oc;
   3078   rx->url = GNUNET_strdup (url);
   3079   GNUNET_CONTAINER_DLL_insert (oc->set_exchanges.pending_reload_head,
   3080                                oc->set_exchanges.pending_reload_tail,
   3081                                rx);
   3082   if (oc->set_exchanges.forced_reload)
   3083     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3084                 "Forcing download of %skeys\n",
   3085                 url);
   3086   rx->fo = TMH_EXCHANGES_keys4exchange (url,
   3087                                         oc->set_exchanges.forced_reload,
   3088                                         &keys_cb,
   3089                                         rx);
   3090 }
   3091 
   3092 
   3093 /**
   3094  * Task run when we are timing out on /keys and will just
   3095  * proceed with what we got.
   3096  *
   3097  * @param cls our `struct OrderContext *` to resume
   3098  */
   3099 static void
   3100 wakeup_timeout (void *cls)
   3101 {
   3102   struct OrderContext *oc = cls;
   3103 
   3104   oc->set_exchanges.wakeup_task = NULL;
   3105   GNUNET_assert (GNUNET_YES == oc->suspended);
   3106   GNUNET_CONTAINER_DLL_remove (oc_head,
   3107                                oc_tail,
   3108                                oc);
   3109   MHD_resume_connection (oc->connection);
   3110   oc->suspended = GNUNET_NO;
   3111   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   3112 }
   3113 
   3114 
   3115 /**
   3116  * Set list of acceptable exchanges in @a oc. Upon success, continues
   3117  * processing with add_payment_details().
   3118  *
   3119  * @param[in,out] oc order context
   3120  * @return true to suspend execution
   3121  */
   3122 static bool
   3123 phase_set_exchanges (struct OrderContext *oc)
   3124 {
   3125   if (NULL != oc->set_exchanges.wakeup_task)
   3126   {
   3127     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
   3128     oc->set_exchanges.wakeup_task = NULL;
   3129   }
   3130 
   3131   if (! oc->add_payment_details.need_exchange)
   3132   {
   3133     /* Total amount is zero, so we don't actually need exchanges! */
   3134     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3135                 "Order total is zero, no need for exchanges\n");
   3136     oc->select_wire_method.exchanges = json_array ();
   3137     GNUNET_assert (NULL != oc->select_wire_method.exchanges);
   3138     /* Pick first one, doesn't matter as the amount is zero */
   3139     oc->select_wire_method.wm = oc->hc->instance->wm_head;
   3140     oc->phase = ORDER_PHASE_SET_MAX_FEE;
   3141     return false;
   3142   }
   3143   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3144               "Trying to find exchanges\n");
   3145   if (NULL == oc->set_exchanges.pending_reload_head)
   3146   {
   3147     if (! oc->set_exchanges.exchanges_tried)
   3148     {
   3149       oc->set_exchanges.exchanges_tried = true;
   3150       oc->set_exchanges.keys_timeout
   3151         = GNUNET_TIME_relative_to_absolute (MAX_KEYS_WAIT);
   3152       TMH_exchange_get_trusted (&get_exchange_keys,
   3153                                 oc);
   3154     }
   3155     else if ( (! oc->set_exchanges.forced_reload) &&
   3156               (oc->set_exchanges.promising_exchange) &&
   3157               (! oc->set_exchanges.exchange_ok) )
   3158     {
   3159       for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   3160            NULL != wmc;
   3161            wmc = wmc->next)
   3162         GNUNET_break (0 ==
   3163                       json_array_clear (wmc->exchanges));
   3164       /* Try one more time with forcing /keys download */
   3165       oc->set_exchanges.forced_reload = true;
   3166       TMH_exchange_get_trusted (&get_exchange_keys,
   3167                                 oc);
   3168     }
   3169   }
   3170   if (GNUNET_TIME_absolute_is_past (oc->set_exchanges.keys_timeout))
   3171   {
   3172     struct RekeyExchange *rx;
   3173 
   3174     while (NULL != (rx = oc->set_exchanges.pending_reload_head))
   3175     {
   3176       GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   3177                                    oc->set_exchanges.pending_reload_tail,
   3178                                    rx);
   3179       TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
   3180       GNUNET_free (rx->url);
   3181       GNUNET_free (rx);
   3182     }
   3183   }
   3184   if (NULL != oc->set_exchanges.pending_reload_head)
   3185   {
   3186     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3187                 "Still trying to (re)load %skeys\n",
   3188                 oc->set_exchanges.pending_reload_head->url);
   3189     oc->set_exchanges.wakeup_task
   3190       = GNUNET_SCHEDULER_add_at (oc->set_exchanges.keys_timeout,
   3191                                  &wakeup_timeout,
   3192                                  oc);
   3193     MHD_suspend_connection (oc->connection);
   3194     oc->suspended = GNUNET_YES;
   3195     GNUNET_CONTAINER_DLL_insert (oc_head,
   3196                                  oc_tail,
   3197                                  oc);
   3198     return true; /* reloads pending */
   3199   }
   3200   oc->phase++;
   3201   return false;
   3202 }
   3203 
   3204 
   3205 /* ***************** ORDER_PHASE_ADD_PAYMENT_DETAILS **************** */
   3206 
   3207 /**
   3208  * Process the @a payment_target and add the details of how the
   3209  * order could be paid to @a order. On success, continue
   3210  * processing with add_payment_fees().
   3211  *
   3212  * @param[in,out] oc order context
   3213  */
   3214 static void
   3215 phase_add_payment_details (struct OrderContext *oc)
   3216 {
   3217   /* First, determine the maximum amounts that could be paid per currency */
   3218   switch (oc->parse_order.version)
   3219   {
   3220   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3221     GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   3222                          oc->add_payment_details.num_max_choice_limits,
   3223                          oc->parse_order.details.v0.brutto);
   3224     if (! TALER_amount_is_zero (
   3225           &oc->parse_order.details.v0.brutto))
   3226     {
   3227       oc->add_payment_details.need_exchange = true;
   3228     }
   3229     break;
   3230   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3231     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3232     {
   3233       const struct TALER_Amount *amount
   3234         = &oc->parse_choices.choices[i].amount;
   3235       bool found = false;
   3236 
   3237       if (! TALER_amount_is_zero (amount))
   3238       {
   3239         oc->add_payment_details.need_exchange = true;
   3240       }
   3241       for (unsigned int j = 0; j<oc->add_payment_details.num_max_choice_limits;
   3242            j++)
   3243       {
   3244         struct TALER_Amount *mx = &oc->add_payment_details.max_choice_limits[j];
   3245         if (GNUNET_YES ==
   3246             TALER_amount_cmp_currency (mx,
   3247                                        amount))
   3248         {
   3249           TALER_amount_max (mx,
   3250                             mx,
   3251                             amount);
   3252           found = true;
   3253           break;
   3254         }
   3255       }
   3256       if (! found)
   3257       {
   3258         GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   3259                              oc->add_payment_details.num_max_choice_limits,
   3260                              *amount);
   3261       }
   3262     }
   3263     break;
   3264   default:
   3265     GNUNET_assert (0);
   3266   }
   3267 
   3268   /* Then, create a candidate for each available wire method */
   3269   for (struct TMH_WireMethod *wm = oc->hc->instance->wm_head;
   3270        NULL != wm;
   3271        wm = wm->next)
   3272   {
   3273     struct WireMethodCandidate *wmc;
   3274 
   3275     /* Locate wire method that has a matching payment target */
   3276     if (! wm->active)
   3277       continue; /* ignore inactive methods */
   3278     if ( (NULL != oc->parse_request.payment_target) &&
   3279          (0 != strcasecmp (oc->parse_request.payment_target,
   3280                            wm->wire_method) ) )
   3281       continue; /* honor client preference */
   3282     wmc = GNUNET_new (struct WireMethodCandidate);
   3283     wmc->wm = wm;
   3284     wmc->exchanges = json_array ();
   3285     GNUNET_assert (NULL != wmc->exchanges);
   3286     GNUNET_CONTAINER_DLL_insert (oc->add_payment_details.wmc_head,
   3287                                  oc->add_payment_details.wmc_tail,
   3288                                  wmc);
   3289   }
   3290 
   3291   if (NULL == oc->add_payment_details.wmc_head)
   3292   {
   3293     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3294                 "No wire method available for instance '%s'\n",
   3295                 oc->hc->instance->settings.id);
   3296     reply_with_error (oc,
   3297                       MHD_HTTP_NOT_FOUND,
   3298                       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE,
   3299                       oc->parse_request.payment_target);
   3300     return;
   3301   }
   3302 
   3303   /* next, we'll evaluate available exchanges */
   3304   oc->phase++;
   3305 }
   3306 
   3307 
   3308 /* ***************** ORDER_PHASE_MERGE_INVENTORY **************** */
   3309 
   3310 
   3311 /**
   3312  * Helper function to sort uint64_t array with qsort().
   3313  *
   3314  * @param a pointer to element to compare
   3315  * @param b pointer to element to compare
   3316  * @return 0 on equal, -1 on smaller, 1 on larger
   3317  */
   3318 static int
   3319 uint64_cmp (const void *a,
   3320             const void *b)
   3321 {
   3322   uint64_t ua = *(const uint64_t *) a;
   3323   uint64_t ub = *(const uint64_t *) b;
   3324 
   3325   if (ua < ub)
   3326     return -1;
   3327   if (ua > ub)
   3328     return 1;
   3329   return 0;
   3330 }
   3331 
   3332 
   3333 /**
   3334  * Merge the inventory products into products, querying the
   3335  * database about the details of those products. Upon success,
   3336  * continue processing by calling add_payment_details().
   3337  *
   3338  * @param[in,out] oc order context to process
   3339  */
   3340 static void
   3341 phase_merge_inventory (struct OrderContext *oc)
   3342 {
   3343   uint64_t pots[oc->parse_order.products_len + 1];
   3344   size_t pots_off = 0;
   3345 
   3346   if (0 != oc->parse_order.order_default_money_pot)
   3347     pots[pots_off++] = oc->parse_order.order_default_money_pot;
   3348   /**
   3349    * parse_request.inventory_products => instructions to add products to contract terms
   3350    * parse_order.products => contains products that are not from the backend-managed inventory.
   3351    */
   3352   oc->merge_inventory.products = json_array ();
   3353   for (size_t i = 0; i<oc->parse_order.products_len; i++)
   3354   {
   3355     GNUNET_assert (
   3356       0 ==
   3357       json_array_append_new (
   3358         oc->merge_inventory.products,
   3359         TALER_MERCHANT_product_sold_serialize (&oc->parse_order.products[i])));
   3360     if (0 != oc->parse_order.products[i].product_money_pot)
   3361       pots[pots_off++] = oc->parse_order.products[i].product_money_pot;
   3362   }
   3363 
   3364   /* make sure pots array only has distinct elements */
   3365   qsort (pots,
   3366          pots_off,
   3367          sizeof (uint64_t),
   3368          &uint64_cmp);
   3369   {
   3370     size_t e = 0;
   3371 
   3372     for (size_t i = 1; i<pots_off; i++)
   3373     {
   3374       if (pots[e] != pots[i])
   3375         pots[++e] = pots[i];
   3376     }
   3377     if (pots_off > 0)
   3378       e++;
   3379     pots_off = e;
   3380   }
   3381   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3382               "Found %u unique money pots in order\n",
   3383               (unsigned int) pots_off);
   3384 
   3385   /* check if all money pots exist; note that we do NOT treat
   3386      the inventory products to this check, as (1) the foreign key
   3387      constraint should ensure this, and (2) if the money pot
   3388      were deleted (concurrently), the value is specified to be
   3389      considered 0 (aka none) and so we can proceed anyway. */
   3390   if (pots_off > 0)
   3391   {
   3392     enum GNUNET_DB_QueryStatus qs;
   3393     uint64_t pot_missing;
   3394 
   3395     qs = TALER_MERCHANTDB_check_money_pots (TMH_db,
   3396                                             oc->hc->instance->settings.id,
   3397                                             pots_off,
   3398                                             pots,
   3399                                             &pot_missing);
   3400     switch (qs)
   3401     {
   3402     case GNUNET_DB_STATUS_HARD_ERROR:
   3403     case GNUNET_DB_STATUS_SOFT_ERROR:
   3404       GNUNET_break (0);
   3405       reply_with_error (oc,
   3406                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3407                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   3408                         "check_money_pots");
   3409       return;
   3410     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3411       /* great, good case! */
   3412       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3413                   "All money pots exist\n");
   3414       break;
   3415     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3416       {
   3417         char mstr[32];
   3418 
   3419         GNUNET_snprintf (mstr,
   3420                          sizeof (mstr),
   3421                          "%llu",
   3422                          (unsigned long long) pot_missing);
   3423         reply_with_error (oc,
   3424                           MHD_HTTP_NOT_FOUND,
   3425                           TALER_EC_MERCHANT_GENERIC_MONEY_POT_UNKNOWN,
   3426                           mstr);
   3427         return;
   3428       }
   3429     }
   3430   }
   3431 
   3432   /* Populate products from inventory product array and database */
   3433   {
   3434     GNUNET_assert (NULL != oc->merge_inventory.products);
   3435     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   3436     {
   3437       struct InventoryProduct *ip
   3438         = &oc->parse_request.inventory_products[i];
   3439       struct TALER_MERCHANTDB_ProductDetails pd;
   3440       enum GNUNET_DB_QueryStatus qs;
   3441       size_t num_categories = 0;
   3442       uint64_t *categories = NULL;
   3443 
   3444       qs = TALER_MERCHANTDB_lookup_product (TMH_db,
   3445                                             oc->hc->instance->settings.id,
   3446                                             ip->product_id,
   3447                                             &pd,
   3448                                             &num_categories,
   3449                                             &categories);
   3450       if (qs <= 0)
   3451       {
   3452         enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   3453         unsigned int http_status = 0;
   3454 
   3455         switch (qs)
   3456         {
   3457         case GNUNET_DB_STATUS_HARD_ERROR:
   3458           GNUNET_break (0);
   3459           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   3460           ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   3461           break;
   3462         case GNUNET_DB_STATUS_SOFT_ERROR:
   3463           GNUNET_break (0);
   3464           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   3465           ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   3466           break;
   3467         case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3468           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3469                       "Product %s from order unknown\n",
   3470                       ip->product_id);
   3471           http_status = MHD_HTTP_NOT_FOUND;
   3472           ec = TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN;
   3473           break;
   3474         case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3475           /* case listed to make compilers happy */
   3476           GNUNET_assert (0);
   3477         }
   3478         reply_with_error (oc,
   3479                           http_status,
   3480                           ec,
   3481                           ip->product_id);
   3482         return;
   3483       }
   3484       GNUNET_free (categories);
   3485       oc->parse_order.minimum_age
   3486         = GNUNET_MAX (oc->parse_order.minimum_age,
   3487                       pd.minimum_age);
   3488       {
   3489         const char *eparam;
   3490 
   3491         if ( (! ip->quantity_missing) &&
   3492              (ip->quantity > (uint64_t) INT64_MAX) )
   3493         {
   3494           GNUNET_break_op (0);
   3495           reply_with_error (oc,
   3496                             MHD_HTTP_BAD_REQUEST,
   3497                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3498                             "quantity");
   3499           TALER_MERCHANTDB_product_details_free (&pd);
   3500           return;
   3501         }
   3502         if (GNUNET_OK !=
   3503             TALER_MERCHANT_vk_process_quantity_inputs (
   3504               TALER_MERCHANT_VK_QUANTITY,
   3505               pd.allow_fractional_quantity,
   3506               ip->quantity_missing,
   3507               (int64_t) ip->quantity,
   3508               ip->unit_quantity_missing,
   3509               ip->unit_quantity,
   3510               &ip->quantity,
   3511               &ip->quantity_frac,
   3512               &eparam))
   3513         {
   3514           GNUNET_break_op (0);
   3515           reply_with_error (oc,
   3516                             MHD_HTTP_BAD_REQUEST,
   3517                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3518                             eparam);
   3519           TALER_MERCHANTDB_product_details_free (&pd);
   3520           return;
   3521         }
   3522       }
   3523       {
   3524         struct TALER_MERCHANT_ProductSold ps = {
   3525           .product_id = (char *) ip->product_id,
   3526           .product_name = pd.product_name,
   3527           .description = pd.description,
   3528           .description_i18n = pd.description_i18n,
   3529           .unit_quantity.integer = ip->quantity,
   3530           .unit_quantity.fractional = ip->quantity_frac,
   3531           .prices_length = pd.price_array_length,
   3532           .prices = GNUNET_new_array (pd.price_array_length,
   3533                                       struct TALER_Amount),
   3534           .prices_are_net = pd.price_is_net,
   3535           .image = pd.image,
   3536           .taxes = pd.taxes,
   3537           .delivery_date = oc->parse_order.delivery_date,
   3538           .product_money_pot = pd.money_pot_id,
   3539           .unit = pd.unit,
   3540 
   3541         };
   3542         json_t *p;
   3543         char unit_quantity_buf[64];
   3544 
   3545         for (size_t j = 0; j<pd.price_array_length; j++)
   3546         {
   3547           struct TALER_Amount atomic_amount;
   3548 
   3549           GNUNET_assert (
   3550             GNUNET_OK ==
   3551             TALER_amount_set_zero (pd.price_array[j].currency,
   3552                                    &atomic_amount));
   3553           atomic_amount.fraction = 1;
   3554           GNUNET_assert (
   3555             GNUNET_OK ==
   3556             TALER_MERCHANT_amount_multiply_by_quantity (
   3557               &ps.prices[j],
   3558               &pd.price_array[j],
   3559               &ps.unit_quantity,
   3560               TALER_MERCHANT_ROUND_UP,
   3561               &atomic_amount));
   3562         }
   3563 
   3564         TALER_MERCHANT_vk_format_fractional_string (
   3565           TALER_MERCHANT_VK_QUANTITY,
   3566           ip->quantity,
   3567           ip->quantity_frac,
   3568           sizeof (unit_quantity_buf),
   3569           unit_quantity_buf);
   3570         if (0 != pd.money_pot_id)
   3571           pots[pots_off++] = pd.money_pot_id;
   3572         p = TALER_MERCHANT_product_sold_serialize (&ps);
   3573         GNUNET_assert (NULL != p);
   3574         GNUNET_free (ps.prices);
   3575         GNUNET_assert (0 ==
   3576                        json_array_append_new (oc->merge_inventory.products,
   3577                                               p));
   3578       }
   3579       TALER_MERCHANTDB_product_details_free (&pd);
   3580     }
   3581   }
   3582 
   3583   /* check if final product list is well-formed */
   3584   if (! TMH_products_array_valid (oc->merge_inventory.products))
   3585   {
   3586     GNUNET_break_op (0);
   3587     reply_with_error (oc,
   3588                       MHD_HTTP_BAD_REQUEST,
   3589                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3590                       "order:products");
   3591     return;
   3592   }
   3593   oc->phase++;
   3594 }
   3595 
   3596 
   3597 /* ***************** ORDER_PHASE_PARSE_CHOICES **************** */
   3598 
   3599 /**
   3600  * Callback function that is called for each donau instance.
   3601  * It simply adds the provided donau_url to the json.
   3602  *
   3603  * @param cls closure with our `struct TALER_MERCHANT_ContractOutput *`
   3604  * @param donau_url the URL of the donau instance
   3605  */
   3606 static void
   3607 add_donau_url (void *cls,
   3608                const char *donau_url)
   3609 {
   3610   struct TALER_MERCHANT_ContractOutput *output = cls;
   3611 
   3612   GNUNET_array_append (output->details.donation_receipt.donau_urls,
   3613                        output->details.donation_receipt.donau_urls_len,
   3614                        GNUNET_strdup (donau_url));
   3615 }
   3616 
   3617 
   3618 /**
   3619  * Add the donau output to the contract output.
   3620  *
   3621  * @param oc order context
   3622  * @param output contract output to add donau URLs to
   3623  */
   3624 static bool
   3625 add_donau_output (struct OrderContext *oc,
   3626                   struct TALER_MERCHANT_ContractOutput *output)
   3627 {
   3628   enum GNUNET_DB_QueryStatus qs;
   3629 
   3630   qs = TALER_MERCHANTDB_select_donau_instances_filtered (
   3631     TMH_db,
   3632     output->details.donation_receipt.amount.currency,
   3633     &add_donau_url,
   3634     output);
   3635   if (qs < 0)
   3636   {
   3637     GNUNET_break (0);
   3638     reply_with_error (oc,
   3639                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   3640                       TALER_EC_GENERIC_DB_FETCH_FAILED,
   3641                       "donau url parsing db call");
   3642     for (unsigned int i = 0;
   3643          i < output->details.donation_receipt.donau_urls_len;
   3644          i++)
   3645       GNUNET_free (output->details.donation_receipt.donau_urls[i]);
   3646     GNUNET_array_grow (output->details.donation_receipt.donau_urls,
   3647                        output->details.donation_receipt.donau_urls_len,
   3648                        0);
   3649     return false;
   3650   }
   3651   return true;
   3652 }
   3653 
   3654 
   3655 /**
   3656  * Parse contract choices. Upon success, continue
   3657  * processing with merge_inventory().
   3658  *
   3659  * @param[in,out] oc order context
   3660  */
   3661 static void
   3662 phase_parse_choices (struct OrderContext *oc)
   3663 {
   3664   const json_t *jchoices;
   3665 
   3666   switch (oc->parse_order.version)
   3667   {
   3668   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3669     oc->phase++;
   3670     return;
   3671   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3672     /* handle below */
   3673     break;
   3674   default:
   3675     GNUNET_assert (0);
   3676   }
   3677 
   3678   jchoices = oc->parse_order.details.v1.choices;
   3679 
   3680   if (! json_is_array (jchoices))
   3681     GNUNET_assert (0);
   3682   if (0 == json_array_size (jchoices))
   3683   {
   3684     reply_with_error (oc,
   3685                       MHD_HTTP_BAD_REQUEST,
   3686                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3687                       "choices");
   3688     return;
   3689   }
   3690   GNUNET_array_grow (oc->parse_choices.choices,
   3691                      oc->parse_choices.choices_len,
   3692                      json_array_size (jchoices));
   3693   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3694   {
   3695     struct TALER_MERCHANT_ContractChoice *choice
   3696       = &oc->parse_choices.choices[i];
   3697     const char *error_name;
   3698     unsigned int error_line;
   3699     const json_t *jinputs;
   3700     const json_t *joutputs;
   3701     bool no_fee;
   3702     struct GNUNET_JSON_Specification spec[] = {
   3703       TALER_JSON_spec_amount_any ("amount",
   3704                                   &choice->amount),
   3705       GNUNET_JSON_spec_mark_optional (
   3706         TALER_JSON_spec_amount_any ("tip",
   3707                                     &choice->tip),
   3708         &choice->no_tip),
   3709       GNUNET_JSON_spec_mark_optional (
   3710         TALER_JSON_spec_amount_any ("max_fee",
   3711                                     &choice->max_fee),
   3712         &no_fee),
   3713       GNUNET_JSON_spec_mark_optional (
   3714         GNUNET_JSON_spec_string_copy ("description",
   3715                                       &choice->description),
   3716         NULL),
   3717       GNUNET_JSON_spec_mark_optional (
   3718         GNUNET_JSON_spec_object_copy ("description_i18n",
   3719                                       &choice->description_i18n),
   3720         NULL),
   3721       GNUNET_JSON_spec_mark_optional (
   3722         GNUNET_JSON_spec_array_const ("inputs",
   3723                                       &jinputs),
   3724         NULL),
   3725       GNUNET_JSON_spec_mark_optional (
   3726         GNUNET_JSON_spec_array_const ("outputs",
   3727                                       &joutputs),
   3728         NULL),
   3729       GNUNET_JSON_spec_end ()
   3730     };
   3731     enum GNUNET_GenericReturnValue ret;
   3732 
   3733     ret = GNUNET_JSON_parse (json_array_get (jchoices,
   3734                                              i),
   3735                              spec,
   3736                              &error_name,
   3737                              &error_line);
   3738     if (GNUNET_OK != ret)
   3739     {
   3740       GNUNET_break_op (0);
   3741       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3742                   "Choice parsing failed: %s:%u\n",
   3743                   error_name,
   3744                   error_line);
   3745       reply_with_error (oc,
   3746                         MHD_HTTP_BAD_REQUEST,
   3747                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3748                         "choice");
   3749       return;
   3750     }
   3751     if ( (! no_fee) &&
   3752          (GNUNET_OK !=
   3753           TALER_amount_cmp_currency (&choice->amount,
   3754                                      &choice->max_fee)) )
   3755     {
   3756       GNUNET_break_op (0);
   3757       GNUNET_JSON_parse_free (spec);
   3758       reply_with_error (oc,
   3759                         MHD_HTTP_BAD_REQUEST,
   3760                         TALER_EC_GENERIC_CURRENCY_MISMATCH,
   3761                         "different currencies used for 'max_fee' and 'amount' currency");
   3762       return;
   3763     }
   3764     if ( (! choice->no_tip) &&
   3765          (GNUNET_OK !=
   3766           TALER_amount_cmp_currency (&choice->amount,
   3767                                      &choice->tip)) )
   3768     {
   3769       GNUNET_break_op (0);
   3770       GNUNET_JSON_parse_free (spec);
   3771       reply_with_error (oc,
   3772                         MHD_HTTP_BAD_REQUEST,
   3773                         TALER_EC_GENERIC_CURRENCY_MISMATCH,
   3774                         "tip and amount");
   3775       return;
   3776     }
   3777 
   3778     if (! TMH_test_exchange_configured_for_currency (
   3779           choice->amount.currency))
   3780     {
   3781       GNUNET_break_op (0);
   3782       GNUNET_JSON_parse_free (spec);
   3783       reply_with_error (oc,
   3784                         MHD_HTTP_CONFLICT,
   3785                         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   3786                         choice->amount.currency);
   3787       return;
   3788     }
   3789 
   3790     if (NULL != jinputs)
   3791     {
   3792       const json_t *jinput;
   3793       size_t idx;
   3794       json_array_foreach ((json_t *) jinputs, idx, jinput)
   3795       {
   3796         struct TALER_MERCHANT_ContractInput input = {
   3797           .details.token.count = 1
   3798         };
   3799 
   3800         if (GNUNET_OK !=
   3801             TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
   3802                                                &input,
   3803                                                idx,
   3804                                                true))
   3805         {
   3806           GNUNET_break_op (0);
   3807           reply_with_error (oc,
   3808                             MHD_HTTP_BAD_REQUEST,
   3809                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3810                             "input");
   3811           return;
   3812         }
   3813 
   3814         switch (input.type)
   3815         {
   3816         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
   3817           GNUNET_assert (0);
   3818           break;
   3819         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
   3820           /* Ignore inputs tokens with 'count' field set to 0 */
   3821           if (0 == input.details.token.count)
   3822             continue;
   3823 
   3824           if (GNUNET_OK !=
   3825               add_input_token_family (oc,
   3826                                       input.details.token.token_family_slug))
   3827 
   3828           {
   3829             GNUNET_break_op (0);
   3830             reply_with_error (oc,
   3831                               MHD_HTTP_BAD_REQUEST,
   3832                               TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
   3833                               input.details.token.token_family_slug);
   3834             return;
   3835           }
   3836 
   3837           GNUNET_array_append (choice->inputs,
   3838                                choice->inputs_len,
   3839                                input);
   3840           continue;
   3841         }
   3842         GNUNET_assert (0);
   3843       }
   3844     }
   3845 
   3846     if (NULL != joutputs)
   3847     {
   3848       const json_t *joutput;
   3849       size_t idx;
   3850       json_array_foreach ((json_t *) joutputs, idx, joutput)
   3851       {
   3852         struct TALER_MERCHANT_ContractOutput output = {
   3853           .details.token.count = 1
   3854         };
   3855 
   3856         if (GNUNET_OK !=
   3857             TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
   3858                                                 &output,
   3859                                                 idx,
   3860                                                 true))
   3861         {
   3862           reply_with_error (oc,
   3863                             MHD_HTTP_BAD_REQUEST,
   3864                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3865                             "output");
   3866           return;
   3867         }
   3868 
   3869         switch (output.type)
   3870         {
   3871         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
   3872           GNUNET_assert (0);
   3873           break;
   3874         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
   3875           output.details.donation_receipt.amount = choice->amount;
   3876           if (! add_donau_output (oc,
   3877                                   &output))
   3878           {
   3879             GNUNET_break (0);
   3880             return;
   3881           }
   3882           GNUNET_array_append (choice->outputs,
   3883                                choice->outputs_len,
   3884                                output);
   3885           continue;
   3886         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
   3887           /* Ignore inputs tokens with 'count' field set to 0 */
   3888           if (0 == output.details.token.count)
   3889             continue;
   3890 
   3891           if (0 == output.details.token.valid_at.abs_time.abs_value_us)
   3892             output.details.token.valid_at
   3893               = GNUNET_TIME_timestamp_get ();
   3894           if (GNUNET_OK !=
   3895               add_output_token_family (oc,
   3896                                        output.details.token.token_family_slug,
   3897                                        output.details.token.valid_at,
   3898                                        &output.details.token.key_index))
   3899 
   3900           {
   3901             /* note: reply_with_error() was already called */
   3902             GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3903                         "Could not handle output token family `%s'\n",
   3904                         output.details.token.token_family_slug);
   3905             return;
   3906           }
   3907 
   3908           GNUNET_array_append (choice->outputs,
   3909                                choice->outputs_len,
   3910                                output);
   3911           continue;
   3912         }
   3913         GNUNET_assert (0);
   3914       }
   3915     }
   3916   }
   3917   oc->phase++;
   3918 }
   3919 
   3920 
   3921 /* ***************** ORDER_PHASE_PARSE_ORDER **************** */
   3922 
   3923 
   3924 /**
   3925  * Parse the order field of the request. Upon success, continue
   3926  * processing with parse_choices().
   3927  *
   3928  * @param[in,out] oc order context
   3929  */
   3930 static void
   3931 phase_parse_order (struct OrderContext *oc)
   3932 {
   3933   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   3934     &oc->hc->instance->settings;
   3935   const char *merchant_base_url = NULL;
   3936   uint64_t version = 0;
   3937   const json_t *jmerchant = NULL;
   3938   const json_t *products = NULL;
   3939   const char *order_id = NULL;
   3940   struct GNUNET_JSON_Specification spec[] = {
   3941     GNUNET_JSON_spec_mark_optional (
   3942       GNUNET_JSON_spec_uint64 ("version",
   3943                                &version),
   3944       NULL),
   3945     GNUNET_JSON_spec_string ("summary",
   3946                              &oc->parse_order.summary),
   3947     GNUNET_JSON_spec_mark_optional (
   3948       GNUNET_JSON_spec_array_const ("products",
   3949                                     &products),
   3950       NULL),
   3951     GNUNET_JSON_spec_mark_optional (
   3952       GNUNET_JSON_spec_object_const ("summary_i18n",
   3953                                      &oc->parse_order.summary_i18n),
   3954       NULL),
   3955     GNUNET_JSON_spec_mark_optional (
   3956       GNUNET_JSON_spec_string ("order_id",
   3957                                &order_id),
   3958       NULL),
   3959     GNUNET_JSON_spec_mark_optional (
   3960       GNUNET_JSON_spec_string ("fulfillment_message",
   3961                                &oc->parse_order.fulfillment_message),
   3962       NULL),
   3963     GNUNET_JSON_spec_mark_optional (
   3964       GNUNET_JSON_spec_object_const ("fulfillment_message_i18n",
   3965                                      &oc->parse_order.fulfillment_message_i18n),
   3966       NULL),
   3967     GNUNET_JSON_spec_mark_optional (
   3968       GNUNET_JSON_spec_string ("fulfillment_url",
   3969                                &oc->parse_order.fulfillment_url),
   3970       NULL),
   3971     GNUNET_JSON_spec_mark_optional (
   3972       GNUNET_JSON_spec_string ("public_reorder_url",
   3973                                &oc->parse_order.public_reorder_url),
   3974       NULL),
   3975     GNUNET_JSON_spec_mark_optional (
   3976       TALER_JSON_spec_web_url ("merchant_base_url",
   3977                                &merchant_base_url),
   3978       NULL),
   3979     /* For sanity check, this field must NOT be present */
   3980     GNUNET_JSON_spec_mark_optional (
   3981       GNUNET_JSON_spec_object_const ("merchant",
   3982                                      &jmerchant),
   3983       NULL),
   3984     GNUNET_JSON_spec_mark_optional (
   3985       GNUNET_JSON_spec_timestamp ("timestamp",
   3986                                   &oc->parse_order.timestamp),
   3987       NULL),
   3988     GNUNET_JSON_spec_mark_optional (
   3989       GNUNET_JSON_spec_timestamp ("refund_deadline",
   3990                                   &oc->parse_order.refund_deadline),
   3991       NULL),
   3992     GNUNET_JSON_spec_mark_optional (
   3993       GNUNET_JSON_spec_timestamp ("pay_deadline",
   3994                                   &oc->parse_order.pay_deadline),
   3995       NULL),
   3996     GNUNET_JSON_spec_mark_optional (
   3997       GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
   3998                                   &oc->parse_order.wire_deadline),
   3999       NULL),
   4000     GNUNET_JSON_spec_mark_optional (
   4001       GNUNET_JSON_spec_object_const ("delivery_location",
   4002                                      &oc->parse_order.delivery_location),
   4003       NULL),
   4004     GNUNET_JSON_spec_mark_optional (
   4005       GNUNET_JSON_spec_timestamp ("delivery_date",
   4006                                   &oc->parse_order.delivery_date),
   4007       NULL),
   4008     GNUNET_JSON_spec_mark_optional (
   4009       GNUNET_JSON_spec_uint32 ("minimum_age",
   4010                                &oc->parse_order.minimum_age),
   4011       NULL),
   4012     GNUNET_JSON_spec_mark_optional (
   4013       GNUNET_JSON_spec_relative_time ("auto_refund",
   4014                                       &oc->parse_order.auto_refund),
   4015       NULL),
   4016     GNUNET_JSON_spec_mark_optional (
   4017       GNUNET_JSON_spec_object_const ("extra",
   4018                                      &oc->parse_order.extra),
   4019       NULL),
   4020     GNUNET_JSON_spec_mark_optional (
   4021       GNUNET_JSON_spec_uint64 ("order_default_money_pot",
   4022                                &oc->parse_order.order_default_money_pot),
   4023       NULL),
   4024     GNUNET_JSON_spec_end ()
   4025   };
   4026   enum GNUNET_GenericReturnValue ret;
   4027   bool computed_refund_deadline = false;
   4028 
   4029   oc->parse_order.refund_deadline = GNUNET_TIME_UNIT_FOREVER_TS;
   4030   oc->parse_order.wire_deadline = GNUNET_TIME_UNIT_FOREVER_TS;
   4031   ret = TALER_MHD_parse_json_data (oc->connection,
   4032                                    oc->parse_request.order,
   4033                                    spec);
   4034   if (GNUNET_OK != ret)
   4035   {
   4036     GNUNET_break_op (0);
   4037     finalize_order2 (oc,
   4038                      ret);
   4039     return;
   4040   }
   4041   if ( (NULL != products) &&
   4042        (0 != (oc->parse_order.products_len = json_array_size (products))) )
   4043   {
   4044     size_t i;
   4045     json_t *p;
   4046 
   4047     oc->parse_order.products
   4048       = GNUNET_new_array (oc->parse_order.products_len,
   4049                           struct TALER_MERCHANT_ProductSold);
   4050     json_array_foreach (products, i, p)
   4051     {
   4052       if (GNUNET_OK !=
   4053           TALER_MERCHANT_parse_product_sold (p,
   4054                                              &oc->parse_order.products[i]))
   4055       {
   4056         GNUNET_break_op (0);
   4057         reply_with_error (oc,
   4058                           MHD_HTTP_BAD_REQUEST,
   4059                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4060                           "order.products");
   4061         return;
   4062       }
   4063     }
   4064   }
   4065   if (NULL != order_id)
   4066   {
   4067     size_t len = strlen (order_id);
   4068 
   4069     for (size_t i = 0; i<len; i++)
   4070     {
   4071       char c = order_id[i];
   4072 
   4073       if (! ( ( (c >= 'A') &&
   4074                 (c <= 'Z') ) ||
   4075               ( (c >= 'a') &&
   4076                 (c <= 'z') ) ||
   4077               ( (c >= '0') &&
   4078                 (c <= '9') ) ||
   4079               (c == '-') ||
   4080               (c == '_') ||
   4081               (c == '.') ||
   4082               (c == ':') ) )
   4083       {
   4084         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4085                     "Invalid character `%c' in order ID `%s'\n",
   4086                     c,
   4087                     order_id);
   4088         reply_with_error (oc,
   4089                           MHD_HTTP_BAD_REQUEST,
   4090                           TALER_EC_GENERIC_CURRENCY_MISMATCH,
   4091                           "Invalid character in order_id");
   4092         return;
   4093       }
   4094     }
   4095   }
   4096   switch (version)
   4097   {
   4098   case 0:
   4099     {
   4100       bool no_fee;
   4101       const json_t *choices = NULL;
   4102       struct GNUNET_JSON_Specification specv0[] = {
   4103         TALER_JSON_spec_amount_any (
   4104           "amount",
   4105           &oc->parse_order.details.v0.brutto),
   4106         GNUNET_JSON_spec_mark_optional (
   4107           TALER_JSON_spec_amount_any (
   4108             "tip",
   4109             &oc->parse_order.details.v0.tip),
   4110           &oc->parse_order.details.v0.no_tip),
   4111         GNUNET_JSON_spec_mark_optional (
   4112           TALER_JSON_spec_amount_any (
   4113             "max_fee",
   4114             &oc->parse_order.details.v0.max_fee),
   4115           &no_fee),
   4116         /* for sanity check, must be *absent*! */
   4117         GNUNET_JSON_spec_mark_optional (
   4118           GNUNET_JSON_spec_array_const ("choices",
   4119                                         &choices),
   4120           NULL),
   4121         GNUNET_JSON_spec_end ()
   4122       };
   4123 
   4124       ret = TALER_MHD_parse_json_data (oc->connection,
   4125                                        oc->parse_request.order,
   4126                                        specv0);
   4127       if (GNUNET_OK != ret)
   4128       {
   4129         GNUNET_break_op (0);
   4130         finalize_order2 (oc,
   4131                          ret);
   4132         return;
   4133       }
   4134       if ( (! no_fee) &&
   4135            (GNUNET_OK !=
   4136             TALER_amount_cmp_currency (&oc->parse_order.details.v0.brutto,
   4137                                        &oc->parse_order.details.v0.max_fee)) )
   4138       {
   4139         GNUNET_break_op (0);
   4140         GNUNET_JSON_parse_free (spec);
   4141         reply_with_error (oc,
   4142                           MHD_HTTP_BAD_REQUEST,
   4143                           TALER_EC_GENERIC_CURRENCY_MISMATCH,
   4144                           "different currencies used for 'max_fee' and 'amount' currency");
   4145         return;
   4146       }
   4147       if ( (! oc->parse_order.details.v0.no_tip) &&
   4148            (GNUNET_OK !=
   4149             TALER_amount_cmp_currency (&oc->parse_order.details.v0.brutto,
   4150                                        &oc->parse_order.details.v0.tip)) )
   4151       {
   4152         GNUNET_break_op (0);
   4153         GNUNET_JSON_parse_free (spec);
   4154         reply_with_error (oc,
   4155                           MHD_HTTP_BAD_REQUEST,
   4156                           TALER_EC_GENERIC_CURRENCY_MISMATCH,
   4157                           "tip and amount");
   4158         return;
   4159       }
   4160       if (! TMH_test_exchange_configured_for_currency (
   4161             oc->parse_order.details.v0.brutto.currency))
   4162       {
   4163         GNUNET_break_op (0);
   4164         GNUNET_JSON_parse_free (spec);
   4165         reply_with_error (oc,
   4166                           MHD_HTTP_CONFLICT,
   4167                           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   4168                           oc->parse_order.details.v0.brutto.currency);
   4169         return;
   4170       }
   4171       if (NULL != choices)
   4172       {
   4173         GNUNET_break_op (0);
   4174         GNUNET_JSON_parse_free (spec);
   4175         reply_with_error (oc,
   4176                           MHD_HTTP_BAD_REQUEST,
   4177                           TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR,
   4178                           "choices array must be null for v0 contracts");
   4179         return;
   4180       }
   4181       oc->parse_order.version = TALER_MERCHANT_CONTRACT_VERSION_0;
   4182       break;
   4183     }
   4184   case 1:
   4185     {
   4186       struct GNUNET_JSON_Specification specv1[] = {
   4187         GNUNET_JSON_spec_array_const (
   4188           "choices",
   4189           &oc->parse_order.details.v1.choices),
   4190         GNUNET_JSON_spec_end ()
   4191       };
   4192 
   4193       ret = TALER_MHD_parse_json_data (oc->connection,
   4194                                        oc->parse_request.order,
   4195                                        specv1);
   4196       if (GNUNET_OK != ret)
   4197       {
   4198         GNUNET_break_op (0);
   4199         finalize_order2 (oc,
   4200                          ret);
   4201         return;
   4202       }
   4203       oc->parse_order.version = TALER_MERCHANT_CONTRACT_VERSION_1;
   4204       break;
   4205     }
   4206   default:
   4207     GNUNET_break_op (0);
   4208     GNUNET_JSON_parse_free (spec);
   4209     reply_with_error (oc,
   4210                       MHD_HTTP_BAD_REQUEST,
   4211                       TALER_EC_GENERIC_VERSION_MALFORMED,
   4212                       "invalid version specified in order, supported are null, '0' or '1'");
   4213     return;
   4214   }
   4215 
   4216   /* Add order_id if it doesn't exist. */
   4217   if (NULL != order_id)
   4218   {
   4219     oc->parse_order.order_id = GNUNET_strdup (order_id);
   4220   }
   4221   else
   4222   {
   4223     char buf[256];
   4224     time_t timer;
   4225     struct tm *tm_info;
   4226     size_t off;
   4227     uint64_t rand;
   4228     char *last;
   4229 
   4230     time (&timer);
   4231     tm_info = localtime (&timer);
   4232     if (NULL == tm_info)
   4233     {
   4234       GNUNET_JSON_parse_free (spec);
   4235       reply_with_error (
   4236         oc,
   4237         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4238         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_LOCALTIME,
   4239         NULL);
   4240       return;
   4241     }
   4242     off = strftime (buf,
   4243                     sizeof (buf) - 1,
   4244                     "%Y.%j",
   4245                     tm_info);
   4246     /* Check for error state of strftime */
   4247     GNUNET_assert (0 != off);
   4248     buf[off++] = '-';
   4249     rand = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
   4250                                      UINT64_MAX);
   4251     last = GNUNET_STRINGS_data_to_string (&rand,
   4252                                           sizeof (uint64_t),
   4253                                           &buf[off],
   4254                                           sizeof (buf) - off);
   4255     GNUNET_assert (NULL != last);
   4256     *last = '\0';
   4257 
   4258     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4259                 "Assigning order ID `%s' server-side\n",
   4260                 buf);
   4261 
   4262     oc->parse_order.order_id = GNUNET_strdup (buf);
   4263     GNUNET_assert (NULL != oc->parse_order.order_id);
   4264   }
   4265 
   4266   /* Patch fulfillment URL with order_id (implements #6467). */
   4267   if (NULL != oc->parse_order.fulfillment_url)
   4268   {
   4269     const char *pos;
   4270 
   4271     pos = strstr (oc->parse_order.fulfillment_url,
   4272                   "${ORDER_ID}");
   4273     if (NULL != pos)
   4274     {
   4275       /* replace ${ORDER_ID} with the real order_id */
   4276       char *nurl;
   4277 
   4278       /* We only allow one placeholder */
   4279       if (strstr (pos + strlen ("${ORDER_ID}"),
   4280                   "${ORDER_ID}"))
   4281       {
   4282         GNUNET_break_op (0);
   4283         reply_with_error (oc,
   4284                           MHD_HTTP_BAD_REQUEST,
   4285                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4286                           "fulfillment_url");
   4287         return;
   4288       }
   4289 
   4290       GNUNET_asprintf (&nurl,
   4291                        "%.*s%s%s",
   4292                        /* first output URL until ${ORDER_ID} */
   4293                        (int) (pos - oc->parse_order.fulfillment_url),
   4294                        oc->parse_order.fulfillment_url,
   4295                        /* replace ${ORDER_ID} with the right order_id */
   4296                        oc->parse_order.order_id,
   4297                        /* append rest of original URL */
   4298                        pos + strlen ("${ORDER_ID}"));
   4299 
   4300       oc->parse_order.fulfillment_url = GNUNET_strdup (nurl);
   4301 
   4302       GNUNET_free (nurl);
   4303     }
   4304   }
   4305 
   4306   if ( (GNUNET_TIME_absolute_is_zero (oc->parse_order.pay_deadline.abs_time)) ||
   4307        (GNUNET_TIME_absolute_is_never (oc->parse_order.pay_deadline.abs_time)) )
   4308   {
   4309     oc->parse_order.pay_deadline = GNUNET_TIME_relative_to_timestamp (
   4310       settings->default_pay_delay);
   4311     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4312                 "Pay deadline was zero (or never), setting to %s\n",
   4313                 GNUNET_TIME_timestamp2s (oc->parse_order.pay_deadline));
   4314   }
   4315   else if (GNUNET_TIME_absolute_is_past (oc->parse_order.pay_deadline.abs_time))
   4316   {
   4317     GNUNET_break_op (0);
   4318     reply_with_error (
   4319       oc,
   4320       MHD_HTTP_BAD_REQUEST,
   4321       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PAY_DEADLINE_IN_PAST,
   4322       NULL);
   4323     return;
   4324   }
   4325   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4326               "Pay deadline is %s\n",
   4327               GNUNET_TIME_timestamp2s (oc->parse_order.pay_deadline));
   4328 
   4329   /* Check soundness of refund deadline, and that a timestamp
   4330    * is actually present.  */
   4331   {
   4332     struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   4333 
   4334     /* Add timestamp if it doesn't exist (or is zero) */
   4335     if (GNUNET_TIME_absolute_is_zero (oc->parse_order.timestamp.abs_time))
   4336     {
   4337       oc->parse_order.timestamp = now;
   4338     }
   4339 
   4340     /* If no refund_deadline given, set one based on refund_delay.  */
   4341     if (GNUNET_TIME_absolute_is_never (
   4342           oc->parse_order.refund_deadline.abs_time))
   4343     {
   4344       if (GNUNET_TIME_relative_is_zero (oc->parse_request.refund_delay))
   4345       {
   4346         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4347                     "Refund delay is zero, no refunds are possible for this order\n");
   4348         oc->parse_order.refund_deadline = GNUNET_TIME_UNIT_ZERO_TS;
   4349       }
   4350       else
   4351       {
   4352         computed_refund_deadline = true;
   4353         oc->parse_order.refund_deadline
   4354           = GNUNET_TIME_absolute_to_timestamp (
   4355               GNUNET_TIME_absolute_add (oc->parse_order.pay_deadline.abs_time,
   4356                                         oc->parse_request.refund_delay));
   4357       }
   4358     }
   4359 
   4360     if ( (! GNUNET_TIME_absolute_is_zero (
   4361             oc->parse_order.delivery_date.abs_time)) &&
   4362          (GNUNET_TIME_absolute_is_past (
   4363             oc->parse_order.delivery_date.abs_time)) )
   4364     {
   4365       GNUNET_break_op (0);
   4366       reply_with_error (
   4367         oc,
   4368         MHD_HTTP_BAD_REQUEST,
   4369         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_DELIVERY_DATE_IN_PAST,
   4370         NULL);
   4371       return;
   4372     }
   4373   }
   4374 
   4375   if ( (! GNUNET_TIME_absolute_is_zero (
   4376           oc->parse_order.refund_deadline.abs_time)) &&
   4377        (GNUNET_TIME_absolute_is_past (
   4378           oc->parse_order.refund_deadline.abs_time)) )
   4379   {
   4380     GNUNET_break_op (0);
   4381     reply_with_error (
   4382       oc,
   4383       MHD_HTTP_BAD_REQUEST,
   4384       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_DEADLINE_IN_PAST,
   4385       NULL);
   4386     return;
   4387   }
   4388 
   4389   if (GNUNET_TIME_absolute_is_never (oc->parse_order.wire_deadline.abs_time))
   4390   {
   4391     struct GNUNET_TIME_Absolute start;
   4392 
   4393     start = GNUNET_TIME_absolute_max (
   4394       oc->parse_order.refund_deadline.abs_time,
   4395       oc->parse_order.pay_deadline.abs_time);
   4396     oc->parse_order.wire_deadline
   4397       = GNUNET_TIME_absolute_to_timestamp (
   4398           GNUNET_TIME_round_up (
   4399             GNUNET_TIME_absolute_add (
   4400               start,
   4401               settings->default_wire_transfer_delay),
   4402             settings->default_wire_transfer_rounding_interval));
   4403     if (GNUNET_TIME_absolute_is_never (
   4404           oc->parse_order.wire_deadline.abs_time))
   4405     {
   4406       GNUNET_break_op (0);
   4407       reply_with_error (
   4408         oc,
   4409         MHD_HTTP_BAD_REQUEST,
   4410         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_WIRE_DEADLINE_IS_NEVER,
   4411         "order:wire_transfer_deadline");
   4412       return;
   4413     }
   4414   }
   4415   else if (computed_refund_deadline)
   4416   {
   4417     /* if we computed the refund_deadline from default settings
   4418        and did have a configured wire_deadline, make sure that
   4419        the refund_deadline is at or below the wire_deadline. */
   4420     oc->parse_order.refund_deadline
   4421       = GNUNET_TIME_timestamp_min (oc->parse_order.refund_deadline,
   4422                                    oc->parse_order.wire_deadline);
   4423   }
   4424   if (GNUNET_TIME_timestamp_cmp (oc->parse_order.wire_deadline,
   4425                                  <,
   4426                                  oc->parse_order.refund_deadline))
   4427   {
   4428     GNUNET_break_op (0);
   4429     reply_with_error (
   4430       oc,
   4431       MHD_HTTP_BAD_REQUEST,
   4432       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_AFTER_WIRE_DEADLINE,
   4433       "order:wire_transfer_deadline;order:refund_deadline");
   4434     return;
   4435   }
   4436 
   4437   if (NULL != merchant_base_url)
   4438   {
   4439     if (('\0' == *merchant_base_url) ||
   4440         ('/' != merchant_base_url[strlen (merchant_base_url) - 1]))
   4441     {
   4442       GNUNET_break_op (0);
   4443       reply_with_error (
   4444         oc,
   4445         MHD_HTTP_BAD_REQUEST,
   4446         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PROPOSAL_PARSE_ERROR,
   4447         "merchant_base_url is not valid");
   4448       return;
   4449     }
   4450     oc->parse_order.merchant_base_url
   4451       = GNUNET_strdup (merchant_base_url);
   4452   }
   4453   else
   4454   {
   4455     char *url;
   4456 
   4457     url = make_merchant_base_url (oc->connection,
   4458                                   settings->id);
   4459     if (NULL == url)
   4460     {
   4461       GNUNET_break_op (0);
   4462       reply_with_error (
   4463         oc,
   4464         MHD_HTTP_BAD_REQUEST,
   4465         TALER_EC_GENERIC_PARAMETER_MISSING,
   4466         "order:merchant_base_url");
   4467       return;
   4468     }
   4469     oc->parse_order.merchant_base_url = url;
   4470   }
   4471 
   4472   /* Merchant information must not already be present */
   4473   if (NULL != jmerchant)
   4474   {
   4475     GNUNET_break_op (0);
   4476     reply_with_error (
   4477       oc,
   4478       MHD_HTTP_BAD_REQUEST,
   4479       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PROPOSAL_PARSE_ERROR,
   4480       "'merchant' field already set, but must be provided by backend");
   4481     return;
   4482   }
   4483 
   4484   if ( (NULL != oc->parse_order.delivery_location) &&
   4485        (! TMH_location_object_valid (oc->parse_order.delivery_location)) )
   4486   {
   4487     GNUNET_break_op (0);
   4488     reply_with_error (oc,
   4489                       MHD_HTTP_BAD_REQUEST,
   4490                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4491                       "delivery_location");
   4492     return;
   4493   }
   4494 
   4495   oc->phase++;
   4496 }
   4497 
   4498 
   4499 /* ***************** ORDER_PHASE_PARSE_REQUEST **************** */
   4500 
   4501 /**
   4502  * Parse the client request. Upon success,
   4503  * continue processing by calling parse_order().
   4504  *
   4505  * @param[in,out] oc order context to process
   4506  */
   4507 static void
   4508 phase_parse_request (struct OrderContext *oc)
   4509 {
   4510   const json_t *ip = NULL;
   4511   const json_t *uuid = NULL;
   4512   const char *otp_id = NULL;
   4513   bool create_token = true; /* default */
   4514   struct GNUNET_JSON_Specification spec[] = {
   4515     GNUNET_JSON_spec_json ("order",
   4516                            &oc->parse_request.order),
   4517     GNUNET_JSON_spec_mark_optional (
   4518       GNUNET_JSON_spec_relative_time ("refund_delay",
   4519                                       &oc->parse_request.refund_delay),
   4520       NULL),
   4521     GNUNET_JSON_spec_mark_optional (
   4522       GNUNET_JSON_spec_string ("payment_target",
   4523                                &oc->parse_request.payment_target),
   4524       NULL),
   4525     GNUNET_JSON_spec_mark_optional (
   4526       GNUNET_JSON_spec_array_const ("inventory_products",
   4527                                     &ip),
   4528       NULL),
   4529     GNUNET_JSON_spec_mark_optional (
   4530       GNUNET_JSON_spec_string ("session_id",
   4531                                &oc->parse_request.session_id),
   4532       NULL),
   4533     GNUNET_JSON_spec_mark_optional (
   4534       GNUNET_JSON_spec_array_const ("lock_uuids",
   4535                                     &uuid),
   4536       NULL),
   4537     GNUNET_JSON_spec_mark_optional (
   4538       GNUNET_JSON_spec_bool ("create_token",
   4539                              &create_token),
   4540       NULL),
   4541     GNUNET_JSON_spec_mark_optional (
   4542       GNUNET_JSON_spec_string ("otp_id",
   4543                                &otp_id),
   4544       NULL),
   4545     GNUNET_JSON_spec_end ()
   4546   };
   4547   enum GNUNET_GenericReturnValue ret;
   4548 
   4549   oc->parse_request.refund_delay
   4550     = oc->hc->instance->settings.default_refund_delay;
   4551   ret = TALER_MHD_parse_json_data (oc->connection,
   4552                                    oc->hc->request_body,
   4553                                    spec);
   4554   if (GNUNET_OK != ret)
   4555   {
   4556     GNUNET_break_op (0);
   4557     finalize_order2 (oc,
   4558                      ret);
   4559     return;
   4560   }
   4561   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   4562               "Refund delay is %s\n",
   4563               GNUNET_TIME_relative2s (oc->parse_request.refund_delay,
   4564                                       false));
   4565   TALER_MERCHANTDB_expire_locks (TMH_db);
   4566   if (NULL != otp_id)
   4567   {
   4568     struct TALER_MERCHANTDB_OtpDeviceDetails td;
   4569     enum GNUNET_DB_QueryStatus qs;
   4570 
   4571     memset (&td,
   4572             0,
   4573             sizeof (td));
   4574     qs = TALER_MERCHANTDB_select_otp (TMH_db,
   4575                                       oc->hc->instance->settings.id,
   4576                                       otp_id,
   4577                                       &td);
   4578     switch (qs)
   4579     {
   4580     case GNUNET_DB_STATUS_HARD_ERROR:
   4581       GNUNET_break (0);
   4582       reply_with_error (oc,
   4583                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4584                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   4585                         "select_otp");
   4586       return;
   4587     case GNUNET_DB_STATUS_SOFT_ERROR:
   4588       GNUNET_break (0);
   4589       reply_with_error (oc,
   4590                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4591                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   4592                         "select_otp");
   4593       return;
   4594     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   4595       reply_with_error (oc,
   4596                         MHD_HTTP_NOT_FOUND,
   4597                         TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
   4598                         otp_id);
   4599       return;
   4600     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   4601       break;
   4602     }
   4603     oc->parse_request.pos_key = td.otp_key;
   4604     oc->parse_request.pos_algorithm = td.otp_algorithm;
   4605     GNUNET_free (td.otp_description);
   4606   }
   4607   if (create_token)
   4608   {
   4609     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
   4610                                 &oc->parse_request.claim_token,
   4611                                 sizeof (oc->parse_request.claim_token));
   4612   }
   4613   /* Compute h_post_data (for idempotency check) */
   4614   {
   4615     char *req_body_enc;
   4616 
   4617     /* Dump normalized JSON to string. */
   4618     if (NULL == (req_body_enc
   4619                    = json_dumps (oc->hc->request_body,
   4620                                  JSON_ENCODE_ANY
   4621                                  | JSON_COMPACT
   4622                                  | JSON_SORT_KEYS)))
   4623     {
   4624       GNUNET_break (0);
   4625       GNUNET_JSON_parse_free (spec);
   4626       reply_with_error (oc,
   4627                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4628                         TALER_EC_GENERIC_ALLOCATION_FAILURE,
   4629                         "request body normalization for hashing");
   4630       return;
   4631     }
   4632     GNUNET_CRYPTO_hash (req_body_enc,
   4633                         strlen (req_body_enc),
   4634                         &oc->parse_request.h_post_data.hash);
   4635     GNUNET_free (req_body_enc);
   4636   }
   4637 
   4638   /* parse the inventory_products (optionally given) */
   4639   if (NULL != ip)
   4640   {
   4641     unsigned int ipl = (unsigned int) json_array_size (ip);
   4642 
   4643     if ( (json_array_size (ip) != (size_t) ipl) ||
   4644          (ipl > MAX_PRODUCTS) )
   4645     {
   4646       GNUNET_break_op (0);
   4647       GNUNET_JSON_parse_free (spec);
   4648       reply_with_error (oc,
   4649                         MHD_HTTP_BAD_REQUEST,
   4650                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4651                         "inventory_products (too many)");
   4652       return;
   4653     }
   4654     GNUNET_array_grow (oc->parse_request.inventory_products,
   4655                        oc->parse_request.inventory_products_length,
   4656                        (unsigned int) json_array_size (ip));
   4657     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   4658     {
   4659       struct InventoryProduct *ipr = &oc->parse_request.inventory_products[i];
   4660       const char *error_name;
   4661       unsigned int error_line;
   4662       struct GNUNET_JSON_Specification ispec[] = {
   4663         GNUNET_JSON_spec_string ("product_id",
   4664                                  &ipr->product_id),
   4665         GNUNET_JSON_spec_mark_optional (
   4666           GNUNET_JSON_spec_uint64 ("quantity",
   4667                                    &ipr->quantity),
   4668           &ipr->quantity_missing),
   4669         GNUNET_JSON_spec_mark_optional (
   4670           GNUNET_JSON_spec_string ("unit_quantity",
   4671                                    &ipr->unit_quantity),
   4672           &ipr->unit_quantity_missing),
   4673         GNUNET_JSON_spec_mark_optional (
   4674           GNUNET_JSON_spec_uint64 ("product_money_pot",
   4675                                    &ipr->product_money_pot),
   4676           NULL),
   4677         GNUNET_JSON_spec_end ()
   4678       };
   4679 
   4680       ret = GNUNET_JSON_parse (json_array_get (ip,
   4681                                                i),
   4682                                ispec,
   4683                                &error_name,
   4684                                &error_line);
   4685       if (GNUNET_OK != ret)
   4686       {
   4687         GNUNET_break_op (0);
   4688         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4689                     "Product parsing failed at #%u: %s:%u\n",
   4690                     i,
   4691                     error_name,
   4692                     error_line);
   4693         reply_with_error (oc,
   4694                           MHD_HTTP_BAD_REQUEST,
   4695                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4696                           "inventory_products");
   4697         return;
   4698       }
   4699       if (ipr->quantity_missing && ipr->unit_quantity_missing)
   4700       {
   4701         ipr->quantity = 1;
   4702         ipr->quantity_missing = false;
   4703       }
   4704     }
   4705   }
   4706 
   4707   /* parse the lock_uuids (optionally given) */
   4708   if (NULL != uuid)
   4709   {
   4710     GNUNET_array_grow (oc->parse_request.uuids,
   4711                        oc->parse_request.uuids_length,
   4712                        json_array_size (uuid));
   4713     for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   4714     {
   4715       json_t *ui = json_array_get (uuid,
   4716                                    i);
   4717 
   4718       if (! json_is_string (ui))
   4719       {
   4720         GNUNET_break_op (0);
   4721         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4722                     "UUID parsing failed at #%u\n",
   4723                     i);
   4724         reply_with_error (oc,
   4725                           MHD_HTTP_BAD_REQUEST,
   4726                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4727                           "lock_uuids");
   4728         return;
   4729       }
   4730       TMH_uuid_from_string (json_string_value (ui),
   4731                             &oc->parse_request.uuids[i]);
   4732     }
   4733   }
   4734   oc->phase++;
   4735 }
   4736 
   4737 
   4738 /* ***************** Main handler **************** */
   4739 
   4740 
   4741 enum MHD_Result
   4742 TMH_private_post_orders (
   4743   const struct TMH_RequestHandler *rh,
   4744   struct MHD_Connection *connection,
   4745   struct TMH_HandlerContext *hc)
   4746 {
   4747   struct OrderContext *oc = hc->ctx;
   4748 
   4749   if (NULL == oc)
   4750   {
   4751     oc = GNUNET_new (struct OrderContext);
   4752     hc->ctx = oc;
   4753     hc->cc = &clean_order;
   4754     oc->connection = connection;
   4755     oc->hc = hc;
   4756   }
   4757   while (1)
   4758   {
   4759     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4760                 "Processing order in phase %d\n",
   4761                 oc->phase);
   4762     switch (oc->phase)
   4763     {
   4764     case ORDER_PHASE_PARSE_REQUEST:
   4765       phase_parse_request (oc);
   4766       break;
   4767     case ORDER_PHASE_PARSE_ORDER:
   4768       phase_parse_order (oc);
   4769       break;
   4770     case ORDER_PHASE_PARSE_CHOICES:
   4771       phase_parse_choices (oc);
   4772       break;
   4773     case ORDER_PHASE_MERGE_INVENTORY:
   4774       phase_merge_inventory (oc);
   4775       break;
   4776     case ORDER_PHASE_ADD_PAYMENT_DETAILS:
   4777       phase_add_payment_details (oc);
   4778       break;
   4779     case ORDER_PHASE_SET_EXCHANGES:
   4780       if (phase_set_exchanges (oc))
   4781         return MHD_YES;
   4782       break;
   4783     case ORDER_PHASE_SELECT_WIRE_METHOD:
   4784       phase_select_wire_method (oc);
   4785       break;
   4786     case ORDER_PHASE_SET_MAX_FEE:
   4787       phase_set_max_fee (oc);
   4788       break;
   4789     case ORDER_PHASE_SERIALIZE_ORDER:
   4790       phase_serialize_order (oc);
   4791       break;
   4792     case ORDER_PHASE_CHECK_CONTRACT:
   4793       phase_check_contract (oc);
   4794       break;
   4795     case ORDER_PHASE_SALT_FORGETTABLE:
   4796       phase_salt_forgettable (oc);
   4797       break;
   4798     case ORDER_PHASE_EXECUTE_ORDER:
   4799       phase_execute_order (oc);
   4800       break;
   4801     case ORDER_PHASE_FINISHED_MHD_YES:
   4802       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4803                   "Finished processing order (1)\n");
   4804       return MHD_YES;
   4805     case ORDER_PHASE_FINISHED_MHD_NO:
   4806       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4807                   "Finished processing order (0)\n");
   4808       return MHD_NO;
   4809     }
   4810   }
   4811 }
   4812 
   4813 
   4814 /* end of taler-merchant-httpd_post-private-orders.c */