merchant

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

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


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