merchant

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

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


      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   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2124     &oc->hc->instance->settings;
   2125   json_t *merchant;
   2126 
   2127   merchant = GNUNET_JSON_PACK (
   2128     GNUNET_JSON_pack_string ("name",
   2129                              settings->name),
   2130     GNUNET_JSON_pack_allow_null (
   2131       GNUNET_JSON_pack_string ("website",
   2132                                settings->website)),
   2133     GNUNET_JSON_pack_allow_null (
   2134       GNUNET_JSON_pack_string ("email",
   2135                                settings->email)),
   2136     GNUNET_JSON_pack_allow_null (
   2137       GNUNET_JSON_pack_string ("logo",
   2138                                settings->logo)));
   2139   GNUNET_assert (NULL != merchant);
   2140   {
   2141     json_t *loca;
   2142 
   2143     /* Handle merchant address */
   2144     loca = settings->address;
   2145     if (NULL != loca)
   2146     {
   2147       loca = json_deep_copy (loca);
   2148       GNUNET_assert (NULL != loca);
   2149       GNUNET_assert (0 ==
   2150                      json_object_set_new (merchant,
   2151                                           "address",
   2152                                           loca));
   2153     }
   2154   }
   2155   {
   2156     json_t *juri;
   2157 
   2158     /* Handle merchant jurisdiction */
   2159     juri = settings->jurisdiction;
   2160     if (NULL != juri)
   2161     {
   2162       juri = json_deep_copy (juri);
   2163       GNUNET_assert (NULL != juri);
   2164       GNUNET_assert (0 ==
   2165                      json_object_set_new (merchant,
   2166                                           "jurisdiction",
   2167                                           juri));
   2168     }
   2169   }
   2170 
   2171   oc->serialize_order.contract = GNUNET_JSON_PACK (
   2172     GNUNET_JSON_pack_string (
   2173       "order_id",
   2174       oc->parse_order.order->order_id),
   2175     GNUNET_JSON_pack_object_steal (
   2176       NULL,
   2177       TALER_MERCHANT_base_terms_serialize (oc->parse_order.order->base)),
   2178     GNUNET_JSON_pack_array_incref (
   2179       "products",
   2180       oc->merge_inventory.products),
   2181     GNUNET_JSON_pack_data_auto (
   2182       "h_wire",
   2183       &oc->select_wire_method.wm->h_wire),
   2184     GNUNET_JSON_pack_string (
   2185       "wire_method",
   2186       oc->select_wire_method.wm->wire_method),
   2187     GNUNET_JSON_pack_timestamp (
   2188       "timestamp",
   2189       oc->parse_order.order->timestamp),
   2190     GNUNET_JSON_pack_timestamp (
   2191       "pay_deadline",
   2192       oc->parse_order.order->pay_deadline),
   2193     GNUNET_JSON_pack_timestamp (
   2194       "wire_transfer_deadline",
   2195       oc->parse_order.order->wire_transfer_deadline),
   2196     GNUNET_JSON_pack_string (
   2197       "merchant_base_url",
   2198       oc->parse_order.merchant_base_url),
   2199     GNUNET_JSON_pack_object_steal (
   2200       "merchant",
   2201       merchant),
   2202     GNUNET_JSON_pack_data_auto (
   2203       "merchant_pub",
   2204       &oc->hc->instance->merchant_pub),
   2205     GNUNET_JSON_pack_array_incref (
   2206       "exchanges",
   2207       oc->select_wire_method.exchanges));
   2208 
   2209   {
   2210     json_t *xtra;
   2211 
   2212     switch (oc->parse_order.order->base->version)
   2213     {
   2214     case TALER_MERCHANT_CONTRACT_VERSION_0:
   2215       xtra = GNUNET_JSON_PACK (
   2216         TALER_JSON_pack_amount ("max_fee",
   2217                                 &oc->set_max_fee.details.v0.max_fee),
   2218         GNUNET_JSON_pack_allow_null (
   2219           TALER_JSON_pack_amount (
   2220             "tip",
   2221             oc->parse_order.order->details.v0.no_tip
   2222                                   ? NULL
   2223                                   : &oc->parse_order.order->details.v0.tip)),
   2224         TALER_JSON_pack_amount (
   2225           "amount",
   2226           &oc->parse_order.order->details.v0.brutto));
   2227       break;
   2228     case TALER_MERCHANT_CONTRACT_VERSION_1:
   2229       {
   2230         json_t *token_families = output_token_families (oc);
   2231         json_t *choices = output_contract_choices (oc);
   2232 
   2233         if ( (NULL == token_families) ||
   2234              (NULL == choices) )
   2235         {
   2236           GNUNET_break (0);
   2237           return;
   2238         }
   2239         xtra = GNUNET_JSON_PACK (
   2240           GNUNET_JSON_pack_array_steal ("choices",
   2241                                         choices),
   2242           GNUNET_JSON_pack_object_steal ("token_families",
   2243                                          token_families));
   2244         break;
   2245       }
   2246     default:
   2247       GNUNET_assert (0);
   2248     }
   2249     GNUNET_assert (0 ==
   2250                    json_object_update (oc->serialize_order.contract,
   2251                                        xtra));
   2252     json_decref (xtra);
   2253   }
   2254 
   2255 
   2256   /* Pack does not work here, because it doesn't set zero-values for timestamps */
   2257   GNUNET_assert (0 ==
   2258                  json_object_set_new (
   2259                    oc->serialize_order.contract,
   2260                    "refund_deadline",
   2261                    GNUNET_JSON_from_timestamp (
   2262                      oc->parse_order.order->refund_deadline)));
   2263   /* auto_refund should only be set if it is not 0 */
   2264   if (! GNUNET_TIME_relative_is_zero (
   2265         oc->parse_order.order->base->auto_refund))
   2266   {
   2267     /* Pack does not work here, because it sets zero-values for relative times */
   2268     GNUNET_assert (0 ==
   2269                    json_object_set_new (
   2270                      oc->serialize_order.contract,
   2271                      "auto_refund",
   2272                      GNUNET_JSON_from_time_rel (
   2273                        oc->parse_order.order->base->auto_refund)));
   2274   }
   2275 
   2276   oc->phase++;
   2277 }
   2278 
   2279 
   2280 /* ***************** ORDER_PHASE_SET_MAX_FEE **************** */
   2281 
   2282 
   2283 /**
   2284  * Set @a max_fee in @a oc based on @a max_stefan_fee value if not overridden
   2285  * by @a client_fee.  If neither is set, set the fee to zero using currency
   2286  * from @a brutto.
   2287  *
   2288  * @param[in,out] oc order context
   2289  * @param brutto brutto amount to compute fee for
   2290  * @param client_fee client-given fee override (or invalid)
   2291  * @param max_stefan_fee maximum STEFAN fee of any exchange
   2292  * @param max_fee set to the maximum stefan fee
   2293  */
   2294 static void
   2295 compute_fee (struct OrderContext *oc,
   2296              const struct TALER_Amount *brutto,
   2297              const struct TALER_Amount *client_fee,
   2298              const struct TALER_Amount *max_stefan_fee,
   2299              struct TALER_Amount *max_fee)
   2300 {
   2301   const struct TALER_MERCHANTDB_InstanceSettings *settings
   2302     = &oc->hc->instance->settings;
   2303 
   2304   if (GNUNET_OK ==
   2305       TALER_amount_is_valid (client_fee))
   2306   {
   2307     *max_fee = *client_fee;
   2308     return;
   2309   }
   2310   if ( (settings->use_stefan) &&
   2311        (NULL != max_stefan_fee) &&
   2312        (GNUNET_OK ==
   2313         TALER_amount_is_valid (max_stefan_fee)) )
   2314   {
   2315     *max_fee = *max_stefan_fee;
   2316     return;
   2317   }
   2318   GNUNET_assert (
   2319     GNUNET_OK ==
   2320     TALER_amount_set_zero (brutto->currency,
   2321                            max_fee));
   2322 }
   2323 
   2324 
   2325 /**
   2326  * Initialize "set_max_fee" in @a oc based on STEFAN value or client
   2327  * preference. Upon success, continue processing in next phase.
   2328  *
   2329  * @param[in,out] oc order context
   2330  */
   2331 static void
   2332 phase_set_max_fee (struct OrderContext *oc)
   2333 {
   2334   switch (oc->parse_order.order->base->version)
   2335   {
   2336   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2337     compute_fee (oc,
   2338                  &oc->parse_order.order->details.v0.brutto,
   2339                  &oc->parse_order.order->details.v0.max_fee,
   2340                  &oc->set_exchanges.details.v0.max_stefan_fee,
   2341                  &oc->set_max_fee.details.v0.max_fee);
   2342     break;
   2343   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2344     oc->set_max_fee.details.v1.max_fees
   2345       = GNUNET_new_array (oc->parse_choices.choices_len,
   2346                           struct TALER_Amount);
   2347     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2348       compute_fee (oc,
   2349                    &oc->parse_choices.choices[i].amount,
   2350                    &oc->parse_choices.choices[i].max_fee,
   2351                    NULL != oc->set_exchanges.details.v1.max_stefan_fees
   2352                    ? &oc->set_exchanges.details.v1.max_stefan_fees[i]
   2353                    : NULL,
   2354                    &oc->set_max_fee.details.v1.max_fees[i]);
   2355     break;
   2356   default:
   2357     GNUNET_break (0);
   2358     break;
   2359   }
   2360   oc->phase++;
   2361 }
   2362 
   2363 
   2364 /* ***************** ORDER_PHASE_SELECT_WIRE_METHOD **************** */
   2365 
   2366 /**
   2367  * Phase to select a wire method that will be acceptable for the order.
   2368  * If none is "perfect" (allows all choices), might jump back to the
   2369  * previous phase to force "/keys" downloads to see if that helps.
   2370  *
   2371  * @param[in,out] oc order context
   2372  */
   2373 static void
   2374 phase_select_wire_method (struct OrderContext *oc)
   2375 {
   2376   const struct TALER_Amount *ea;
   2377   struct WireMethodCandidate *best = NULL;
   2378   unsigned int max_choices = 0;
   2379   unsigned int want_choices = 0;
   2380   bool zero_amount = false;
   2381 
   2382   switch (oc->parse_order.order->base->version)
   2383   {
   2384   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2385     ea = &oc->parse_order.order->details.v0.brutto;
   2386     if (TALER_amount_is_zero (ea))
   2387       zero_amount = true;
   2388     break;
   2389   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2390     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2391     {
   2392       ea = &oc->parse_choices.choices[i].amount;
   2393       if (TALER_amount_is_zero (ea))
   2394         zero_amount = true;
   2395     }
   2396     break;
   2397   default:
   2398     GNUNET_assert (0);
   2399   }
   2400 
   2401   for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2402        NULL != wmc;
   2403        wmc = wmc->next)
   2404   {
   2405     unsigned int num_choices = 0;
   2406 
   2407     switch (oc->parse_order.order->base->version)
   2408     {
   2409     case TALER_MERCHANT_CONTRACT_VERSION_0:
   2410       want_choices = 1;
   2411       ea = &oc->parse_order.order->details.v0.brutto;
   2412       if (TALER_amount_is_zero (ea) ||
   2413           TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2414                                        ea))
   2415         num_choices++;
   2416       break;
   2417     case TALER_MERCHANT_CONTRACT_VERSION_1:
   2418       want_choices = oc->parse_choices.choices_len;
   2419       for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2420       {
   2421         ea = &oc->parse_choices.choices[i].amount;
   2422         if (TALER_amount_is_zero (ea) ||
   2423             TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2424                                          ea))
   2425           num_choices++;
   2426       }
   2427       break;
   2428     default:
   2429       GNUNET_assert (0);
   2430     }
   2431     if (num_choices > max_choices)
   2432     {
   2433       best = wmc;
   2434       max_choices = num_choices;
   2435     }
   2436   }
   2437 
   2438   if ( (want_choices > max_choices) &&
   2439        (oc->set_exchanges.promising_exchange) &&
   2440        (! oc->set_exchanges.forced_reload) )
   2441   {
   2442     oc->set_exchanges.exchange_ok = false;
   2443     /* Not all choices in the contract can work with these
   2444        exchanges, try again with forcing /keys download */
   2445     for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2446          NULL != wmc;
   2447          wmc = wmc->next)
   2448     {
   2449       json_array_clear (wmc->exchanges);
   2450       TALER_amount_set_free (&wmc->total_exchange_limits);
   2451     }
   2452     oc->phase = ORDER_PHASE_SET_EXCHANGES;
   2453     return;
   2454   }
   2455 
   2456   if ( (NULL == best) &&
   2457        (! zero_amount) &&
   2458        (NULL != oc->parse_request.payment_target) )
   2459   {
   2460     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2461                 "Cannot create order: lacking suitable exchanges for payment target `%s'\n",
   2462                 oc->parse_request.payment_target);
   2463     reply_with_error (
   2464       oc,
   2465       MHD_HTTP_CONFLICT,
   2466       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
   2467       oc->parse_request.payment_target);
   2468     return;
   2469   }
   2470 
   2471   if ( (NULL == best) &&
   2472        (! zero_amount) )
   2473   {
   2474     enum MHD_Result mret;
   2475 
   2476     /* We actually do not have ANY workable exchange(s) */
   2477     mret = TALER_MHD_reply_json_steal (
   2478       oc->connection,
   2479       GNUNET_JSON_PACK (
   2480         TALER_JSON_pack_ec (
   2481           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS),
   2482         GNUNET_JSON_pack_allow_null (
   2483           GNUNET_JSON_pack_array_incref (
   2484             "exchange_rejections",
   2485             oc->set_exchanges.exchange_rejections))),
   2486       MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS);
   2487     finalize_order (oc,
   2488                     mret);
   2489     return;
   2490   }
   2491 
   2492   if (want_choices > max_choices)
   2493   {
   2494     /* Some choices are unpayable */
   2495     GNUNET_log (
   2496       GNUNET_ERROR_TYPE_WARNING,
   2497       "Creating order, but some choices do not work with the selected wire method\n");
   2498   }
   2499   if ( (0 == json_array_size (best->exchanges)) &&
   2500        (oc->add_payment_details.need_exchange) )
   2501   {
   2502     /* We did not find any reasonable exchange */
   2503     GNUNET_log (
   2504       GNUNET_ERROR_TYPE_WARNING,
   2505       "Creating order, but only for choices without payment\n");
   2506   }
   2507 
   2508   oc->select_wire_method.wm
   2509     = best->wm;
   2510   oc->select_wire_method.exchanges
   2511     = json_incref (best->exchanges);
   2512   oc->phase++;
   2513 }
   2514 
   2515 
   2516 /* ***************** ORDER_PHASE_SET_EXCHANGES **************** */
   2517 
   2518 /**
   2519  * Exchange `/keys` processing is done, resume handling
   2520  * the order.
   2521  *
   2522  * @param[in,out] oc context to resume
   2523  */
   2524 static void
   2525 resume_with_keys (struct OrderContext *oc)
   2526 {
   2527   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2528               "Resuming order processing after /keys downloads\n");
   2529   GNUNET_assert (GNUNET_YES == oc->suspended);
   2530   GNUNET_CONTAINER_DLL_remove (oc_head,
   2531                                oc_tail,
   2532                                oc);
   2533   oc->suspended = GNUNET_NO;
   2534   MHD_resume_connection (oc->connection);
   2535   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   2536 }
   2537 
   2538 
   2539 /**
   2540  * Given a @a brutto amount for exchange with @a keys, set the
   2541  * @a stefan_fee. Note that @a stefan_fee is updated to the maximum
   2542  * of the input and the computed fee.
   2543  *
   2544  * @param[in,out] keys exchange keys
   2545  * @param brutto some brutto amount the client is to pay
   2546  * @param[in,out] stefan_fee set to STEFAN fee to be paid by the merchant
   2547  */
   2548 static void
   2549 compute_stefan_fee (const struct TALER_EXCHANGE_Keys *keys,
   2550                     const struct TALER_Amount *brutto,
   2551                     struct TALER_Amount *stefan_fee)
   2552 {
   2553   struct TALER_Amount net;
   2554 
   2555   if (GNUNET_SYSERR !=
   2556       TALER_EXCHANGE_keys_stefan_b2n (keys,
   2557                                       brutto,
   2558                                       &net))
   2559   {
   2560     struct TALER_Amount fee;
   2561 
   2562     TALER_EXCHANGE_keys_stefan_round (keys,
   2563                                       &net);
   2564     if (-1 == TALER_amount_cmp (brutto,
   2565                                 &net))
   2566     {
   2567       /* brutto < netto! */
   2568       /* => after rounding, there is no real difference */
   2569       net = *brutto;
   2570     }
   2571     GNUNET_assert (0 <=
   2572                    TALER_amount_subtract (&fee,
   2573                                           brutto,
   2574                                           &net));
   2575     if ( (GNUNET_OK !=
   2576           TALER_amount_is_valid (stefan_fee)) ||
   2577          (-1 == TALER_amount_cmp (stefan_fee,
   2578                                   &fee)) )
   2579     {
   2580       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2581                   "Updated STEFAN-based fee to %s\n",
   2582                   TALER_amount2s (&fee));
   2583       *stefan_fee = fee;
   2584     }
   2585   }
   2586 }
   2587 
   2588 
   2589 /**
   2590  * Update MAX STEFAN fees based on @a keys.
   2591  *
   2592  * @param[in,out] oc order context to update
   2593  * @param keys keys to derive STEFAN fees from
   2594  */
   2595 static void
   2596 update_stefan (struct OrderContext *oc,
   2597                const struct TALER_EXCHANGE_Keys *keys)
   2598 {
   2599   switch (oc->parse_order.order->base->version)
   2600   {
   2601   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2602     compute_stefan_fee (keys,
   2603                         &oc->parse_order.order->details.v0.brutto,
   2604                         &oc->set_exchanges.details.v0.max_stefan_fee);
   2605     break;
   2606   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2607     oc->set_exchanges.details.v1.max_stefan_fees
   2608       = GNUNET_new_array (oc->parse_choices.choices_len,
   2609                           struct TALER_Amount);
   2610     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2611       if (0 == strcasecmp (keys->currency,
   2612                            oc->parse_choices.choices[i].amount.currency))
   2613         compute_stefan_fee (keys,
   2614                             &oc->parse_choices.choices[i].amount,
   2615                             &oc->set_exchanges.details.v1.max_stefan_fees[i]);
   2616     break;
   2617   default:
   2618     GNUNET_assert (0);
   2619   }
   2620 }
   2621 
   2622 
   2623 /**
   2624  * Check our KYC status at all exchanges as our current limit is
   2625  * too low and we failed to create an order.
   2626  *
   2627  * @param oc order context
   2628  * @param wmc wire method candidate to notify for
   2629  * @param exchange_url exchange to notify about
   2630  */
   2631 static void
   2632 notify_kyc_required (const struct OrderContext *oc,
   2633                      const struct WireMethodCandidate *wmc,
   2634                      const char *exchange_url)
   2635 {
   2636   struct GNUNET_DB_EventHeaderP es = {
   2637     .size = htons (sizeof (es)),
   2638     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
   2639   };
   2640   char *hws;
   2641   char *extra;
   2642 
   2643   hws = GNUNET_STRINGS_data_to_string_alloc (
   2644     &wmc->wm->h_wire,
   2645     sizeof (wmc->wm->h_wire));
   2646 
   2647   GNUNET_asprintf (&extra,
   2648                    "%s %s",
   2649                    hws,
   2650                    exchange_url);
   2651   TALER_MERCHANTDB_event_notify (TMH_db,
   2652                                  &es,
   2653                                  extra,
   2654                                  strlen (extra) + 1);
   2655   GNUNET_free (extra);
   2656   GNUNET_free (hws);
   2657 }
   2658 
   2659 
   2660 /**
   2661  * Add a reason why a particular exchange was rejected to our
   2662  * response data.
   2663  *
   2664  * @param[in,out] oc order context to update
   2665  * @param exchange_url exchange this is about
   2666  * @param ec error code to set for the exchange
   2667  */
   2668 static void
   2669 add_rejection (struct OrderContext *oc,
   2670                const char *exchange_url,
   2671                enum TALER_ErrorCode ec)
   2672 {
   2673   if (NULL == oc->set_exchanges.exchange_rejections)
   2674   {
   2675     oc->set_exchanges.exchange_rejections = json_array ();
   2676     GNUNET_assert (NULL != oc->set_exchanges.exchange_rejections);
   2677   }
   2678   GNUNET_assert (0 ==
   2679                  json_array_append_new (
   2680                    oc->set_exchanges.exchange_rejections,
   2681                    GNUNET_JSON_PACK (
   2682                      GNUNET_JSON_pack_string ("exchange_url",
   2683                                               exchange_url),
   2684                      TALER_JSON_pack_ec (ec))));
   2685 }
   2686 
   2687 
   2688 /**
   2689  * Checks the limits that apply for this @a exchange and
   2690  * the @a wmc and if the exchange is acceptable at all, adds it
   2691  * to the list of exchanges for the @a wmc.
   2692  *
   2693  * @param oc context of the order
   2694  * @param exchange internal handle for the exchange
   2695  * @param exchange_url base URL of this exchange
   2696  * @param wmc wire method to evaluate this exchange for
   2697  * @return true if the exchange is acceptable for the contract
   2698  */
   2699 static bool
   2700 get_acceptable (struct OrderContext *oc,
   2701                 const struct TMH_Exchange *exchange,
   2702                 const char *exchange_url,
   2703                 struct WireMethodCandidate *wmc)
   2704 {
   2705   const struct TALER_Amount *max_needed = NULL;
   2706   unsigned int priority = 42; /* make compiler happy */
   2707   json_t *j_exchange;
   2708   enum TMH_ExchangeStatus res;
   2709   struct TALER_Amount max_amount;
   2710 
   2711   for (unsigned int i = 0;
   2712        i<oc->add_payment_details.num_max_choice_limits;
   2713        i++)
   2714   {
   2715     const struct TALER_Amount *val
   2716       = &oc->add_payment_details.max_choice_limits[i];
   2717 
   2718     if (0 == strcasecmp (val->currency,
   2719                          TMH_EXCHANGES_get_currency (exchange)))
   2720     {
   2721       max_needed = val;
   2722       break;
   2723     }
   2724   }
   2725   if (NULL == max_needed)
   2726   {
   2727     /* exchange currency not relevant for any of our choices, skip it */
   2728     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2729                 "Exchange %s with currency `%s' is not applicable to this order\n",
   2730                 exchange_url,
   2731                 TMH_EXCHANGES_get_currency (exchange));
   2732     add_rejection (oc,
   2733                    exchange_url,
   2734                    TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH);
   2735     return false;
   2736   }
   2737 
   2738   max_amount = *max_needed;
   2739   res = TMH_exchange_check_debit (
   2740     oc->hc->instance->settings.id,
   2741     exchange,
   2742     wmc->wm,
   2743     &max_amount);
   2744   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2745               "Exchange %s evaluated at %d with max %s\n",
   2746               exchange_url,
   2747               res,
   2748               TALER_amount2s (&max_amount));
   2749   if (TALER_amount_is_zero (&max_amount))
   2750   {
   2751     if (! TALER_amount_is_zero (max_needed))
   2752     {
   2753       /* Trigger re-checking the current deposit limit when
   2754        * paying non-zero amount with zero deposit limit */
   2755       notify_kyc_required (oc,
   2756                            wmc,
   2757                            exchange_url);
   2758     }
   2759     /* If deposit is impossible, we don't list the
   2760      * exchange in the contract terms. */
   2761     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2762                 "Exchange %s deposit limit is zero, skipping it\n",
   2763                 exchange_url);
   2764     add_rejection (oc,
   2765                    exchange_url,
   2766                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED);
   2767     return false;
   2768   }
   2769   switch (res)
   2770   {
   2771   case TMH_ES_OK:
   2772   case TMH_ES_RETRY_OK:
   2773     priority = 1024;   /* high */
   2774     oc->set_exchanges.exchange_ok = true;
   2775     break;
   2776   case TMH_ES_NO_ACC:
   2777     if (oc->set_exchanges.forced_reload)
   2778       priority = 0;   /* fresh negative response */
   2779     else
   2780       priority = 512; /* stale negative response */
   2781     break;
   2782   case TMH_ES_NO_CURR:
   2783     if (oc->set_exchanges.forced_reload)
   2784       priority = 0;   /* fresh negative response */
   2785     else
   2786       priority = 512; /* stale negative response */
   2787     break;
   2788   case TMH_ES_NO_KEYS:
   2789     if (oc->set_exchanges.forced_reload)
   2790       priority = 256;   /* fresh, no accounts yet */
   2791     else
   2792       priority = 768;  /* stale, no accounts yet */
   2793     break;
   2794   case TMH_ES_NO_ACC_RETRY_OK:
   2795     if (oc->set_exchanges.forced_reload)
   2796     {
   2797       priority = 0;   /* fresh negative response */
   2798     }
   2799     else
   2800     {
   2801       oc->set_exchanges.promising_exchange = true;
   2802       priority = 512; /* stale negative response */
   2803     }
   2804     break;
   2805   case TMH_ES_NO_CURR_RETRY_OK:
   2806     if (oc->set_exchanges.forced_reload)
   2807       priority = 0;   /* fresh negative response */
   2808     else
   2809       priority = 512; /* stale negative response */
   2810     break;
   2811   case TMH_ES_NO_KEYS_RETRY_OK:
   2812     if (oc->set_exchanges.forced_reload)
   2813     {
   2814       priority = 256;   /* fresh, no accounts yet */
   2815     }
   2816     else
   2817     {
   2818       oc->set_exchanges.promising_exchange = true;
   2819       priority = 768;  /* stale, no accounts yet */
   2820     }
   2821     break;
   2822   }
   2823   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2824               "Exchange %s deposit limit is %s, adding it!\n",
   2825               exchange_url,
   2826               TALER_amount2s (&max_amount));
   2827 
   2828   j_exchange = GNUNET_JSON_PACK (
   2829     GNUNET_JSON_pack_string ("url",
   2830                              exchange_url),
   2831     GNUNET_JSON_pack_uint64 ("priority",
   2832                              priority),
   2833     TALER_JSON_pack_amount ("max_contribution",
   2834                             &max_amount),
   2835     GNUNET_JSON_pack_data_auto ("master_pub",
   2836                                 TMH_EXCHANGES_get_master_pub (exchange)));
   2837   GNUNET_assert (NULL != j_exchange);
   2838   /* Add exchange to list of exchanges for this wire method
   2839      candidate */
   2840   GNUNET_assert (0 ==
   2841                  json_array_append_new (wmc->exchanges,
   2842                                         j_exchange));
   2843   GNUNET_assert (0 <=
   2844                  TALER_amount_set_add (&wmc->total_exchange_limits,
   2845                                        &max_amount,
   2846                                        max_needed));
   2847   return true;
   2848 }
   2849 
   2850 
   2851 /**
   2852  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
   2853  * operation.
   2854  *
   2855  * @param cls closure with our `struct RekeyExchange *`
   2856  * @param keys the keys of the exchange
   2857  * @param exchange representation of the exchange
   2858  */
   2859 static void
   2860 keys_cb (
   2861   void *cls,
   2862   struct TALER_EXCHANGE_Keys *keys,
   2863   struct TMH_Exchange *exchange)
   2864 {
   2865   struct RekeyExchange *rx = cls;
   2866   struct OrderContext *oc = rx->oc;
   2867   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2868     &oc->hc->instance->settings;
   2869   bool applicable = false;
   2870 
   2871   rx->fo = NULL;
   2872   GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   2873                                oc->set_exchanges.pending_reload_tail,
   2874                                rx);
   2875   if (NULL == keys)
   2876   {
   2877     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2878                 "Failed to download %skeys\n",
   2879                 rx->url);
   2880     oc->set_exchanges.promising_exchange = true;
   2881     add_rejection (oc,
   2882                    rx->url,
   2883                    TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE);
   2884     goto cleanup;
   2885   }
   2886   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2887               "Got response for %skeys\n",
   2888               rx->url);
   2889 
   2890   /* Evaluate the use of this exchange for each wire method candidate.
   2891      Note that the exchange may have *several* accounts sharing the same
   2892      wire method; as get_acceptable() judges the exchange as a whole (and
   2893      not the individual account), it must be called at most once per wire
   2894      method candidate, or we would list the exchange more than once in the
   2895      contract terms and count its deposit limit more than once. */
   2896   for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2897        NULL != wmc;
   2898        wmc = wmc->next)
   2899   {
   2900     bool matches = false;
   2901 
   2902     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2903                 "Order could use wire method `%s'\n",
   2904                 wmc->wm->wire_method);
   2905     for (unsigned int j = 0; j<keys->accounts_len; j++)
   2906     {
   2907       struct TALER_FullPayto full_payto = keys->accounts[j].fpayto_uri;
   2908       char *wire_method = TALER_payto_get_method (full_payto.full_payto);
   2909 
   2910       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2911                   "Exchange `%s' has wire method `%s'\n",
   2912                   rx->url,
   2913                   wire_method);
   2914       matches = (0 == strcmp (wmc->wm->wire_method,
   2915                               wire_method));
   2916       GNUNET_free (wire_method);
   2917       if (matches)
   2918         break;
   2919     }
   2920     if (matches)
   2921       applicable |= get_acceptable (oc,
   2922                                     exchange,
   2923                                     rx->url,
   2924                                     wmc);
   2925   }
   2926   if ( (! applicable) &&
   2927        (! oc->set_exchanges.forced_reload) )
   2928   {
   2929     /* Checks for 'forced_reload' to not log the error *again*
   2930        if we forced a re-load and are encountering the
   2931        applicability error a 2nd time */
   2932     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2933                 "Exchange `%s' %u wire methods are not applicable to this order\n",
   2934                 rx->url,
   2935                 keys->accounts_len);
   2936     add_rejection (oc,
   2937                    rx->url,
   2938                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED);
   2939   }
   2940   if (applicable &&
   2941       settings->use_stefan)
   2942     update_stefan (oc,
   2943                    keys);
   2944 cleanup:
   2945   GNUNET_free (rx->url);
   2946   GNUNET_free (rx);
   2947   if (NULL != oc->set_exchanges.pending_reload_head)
   2948     return;
   2949   resume_with_keys (oc);
   2950 }
   2951 
   2952 
   2953 /**
   2954  * Force re-downloading of /keys from @a exchange,
   2955  * we currently have no acceptable exchange, so we
   2956  * should try to get one.
   2957  *
   2958  * @param cls closure with our `struct OrderContext`
   2959  * @param url base URL of the exchange
   2960  * @param exchange internal handle for the exchange
   2961  */
   2962 static void
   2963 get_exchange_keys (void *cls,
   2964                    const char *url,
   2965                    const struct TMH_Exchange *exchange)
   2966 {
   2967   struct OrderContext *oc = cls;
   2968   struct RekeyExchange *rx;
   2969 
   2970   rx = GNUNET_new (struct RekeyExchange);
   2971   rx->oc = oc;
   2972   rx->url = GNUNET_strdup (url);
   2973   GNUNET_CONTAINER_DLL_insert (oc->set_exchanges.pending_reload_head,
   2974                                oc->set_exchanges.pending_reload_tail,
   2975                                rx);
   2976   if (oc->set_exchanges.forced_reload)
   2977     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2978                 "Forcing download of %skeys\n",
   2979                 url);
   2980   rx->fo = TMH_EXCHANGES_keys4exchange (url,
   2981                                         oc->set_exchanges.forced_reload,
   2982                                         &keys_cb,
   2983                                         rx);
   2984 }
   2985 
   2986 
   2987 /**
   2988  * Task run when we are timing out on /keys and will just
   2989  * proceed with what we got.
   2990  *
   2991  * @param cls our `struct OrderContext *` to resume
   2992  */
   2993 static void
   2994 wakeup_timeout (void *cls)
   2995 {
   2996   struct OrderContext *oc = cls;
   2997 
   2998   oc->set_exchanges.wakeup_task = NULL;
   2999   GNUNET_assert (GNUNET_YES == oc->suspended);
   3000   GNUNET_CONTAINER_DLL_remove (oc_head,
   3001                                oc_tail,
   3002                                oc);
   3003   MHD_resume_connection (oc->connection);
   3004   oc->suspended = GNUNET_NO;
   3005   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   3006 }
   3007 
   3008 
   3009 /**
   3010  * Set list of acceptable exchanges in @a oc. Upon success, continues
   3011  * processing with add_payment_details().
   3012  *
   3013  * @param[in,out] oc order context
   3014  * @return true to suspend execution
   3015  */
   3016 static bool
   3017 phase_set_exchanges (struct OrderContext *oc)
   3018 {
   3019   if (NULL != oc->set_exchanges.wakeup_task)
   3020   {
   3021     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
   3022     oc->set_exchanges.wakeup_task = NULL;
   3023   }
   3024 
   3025   if (! oc->add_payment_details.need_exchange)
   3026   {
   3027     /* Total amount is zero, so we don't actually need exchanges! */
   3028     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3029                 "Order total is zero, no need for exchanges\n");
   3030     oc->select_wire_method.exchanges = json_array ();
   3031     GNUNET_assert (NULL != oc->select_wire_method.exchanges);
   3032     /* Pick first one, doesn't matter as the amount is zero */
   3033     oc->select_wire_method.wm = oc->hc->instance->wm_head;
   3034     oc->phase = ORDER_PHASE_SET_MAX_FEE;
   3035     return false;
   3036   }
   3037   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3038               "Trying to find exchanges\n");
   3039   if (NULL == oc->set_exchanges.pending_reload_head)
   3040   {
   3041     if (! oc->set_exchanges.exchanges_tried)
   3042     {
   3043       oc->set_exchanges.exchanges_tried = true;
   3044       oc->set_exchanges.keys_timeout
   3045         = GNUNET_TIME_relative_to_absolute (MAX_KEYS_WAIT);
   3046       TMH_exchange_get_trusted (&get_exchange_keys,
   3047                                 oc);
   3048     }
   3049     else if ( (! oc->set_exchanges.forced_reload) &&
   3050               (oc->set_exchanges.promising_exchange) &&
   3051               (! oc->set_exchanges.exchange_ok) )
   3052     {
   3053       for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   3054            NULL != wmc;
   3055            wmc = wmc->next)
   3056         GNUNET_break (0 ==
   3057                       json_array_clear (wmc->exchanges));
   3058       /* Try one more time with forcing /keys download */
   3059       oc->set_exchanges.forced_reload = true;
   3060       TMH_exchange_get_trusted (&get_exchange_keys,
   3061                                 oc);
   3062     }
   3063   }
   3064   if (GNUNET_TIME_absolute_is_past (oc->set_exchanges.keys_timeout))
   3065   {
   3066     struct RekeyExchange *rx;
   3067 
   3068     while (NULL != (rx = oc->set_exchanges.pending_reload_head))
   3069     {
   3070       GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   3071                                    oc->set_exchanges.pending_reload_tail,
   3072                                    rx);
   3073       TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
   3074       GNUNET_free (rx->url);
   3075       GNUNET_free (rx);
   3076     }
   3077   }
   3078   if (NULL != oc->set_exchanges.pending_reload_head)
   3079   {
   3080     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3081                 "Still trying to (re)load %skeys\n",
   3082                 oc->set_exchanges.pending_reload_head->url);
   3083     oc->set_exchanges.wakeup_task
   3084       = GNUNET_SCHEDULER_add_at (oc->set_exchanges.keys_timeout,
   3085                                  &wakeup_timeout,
   3086                                  oc);
   3087     MHD_suspend_connection (oc->connection);
   3088     oc->suspended = GNUNET_YES;
   3089     GNUNET_CONTAINER_DLL_insert (oc_head,
   3090                                  oc_tail,
   3091                                  oc);
   3092     return true; /* reloads pending */
   3093   }
   3094   oc->phase++;
   3095   return false;
   3096 }
   3097 
   3098 
   3099 /* ***************** ORDER_PHASE_ADD_PAYMENT_DETAILS **************** */
   3100 
   3101 /**
   3102  * Process the @a payment_target and add the details of how the
   3103  * order could be paid to @a order. On success, continue
   3104  * processing with add_payment_fees().
   3105  *
   3106  * @param[in,out] oc order context
   3107  */
   3108 static void
   3109 phase_add_payment_details (struct OrderContext *oc)
   3110 {
   3111   /* First, determine the maximum amounts that could be paid per currency */
   3112   switch (oc->parse_order.order->base->version)
   3113   {
   3114   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3115     GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   3116                          oc->add_payment_details.num_max_choice_limits,
   3117                          oc->parse_order.order->details.v0.brutto);
   3118     if (! TALER_amount_is_zero (
   3119           &oc->parse_order.order->details.v0.brutto))
   3120     {
   3121       oc->add_payment_details.need_exchange = true;
   3122     }
   3123     break;
   3124   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3125     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3126     {
   3127       const struct TALER_Amount *amount
   3128         = &oc->parse_choices.choices[i].amount;
   3129       bool found = false;
   3130 
   3131       if (! TALER_amount_is_zero (amount))
   3132       {
   3133         oc->add_payment_details.need_exchange = true;
   3134       }
   3135       for (unsigned int j = 0;
   3136            j<oc->add_payment_details.num_max_choice_limits;
   3137            j++)
   3138       {
   3139         struct TALER_Amount *mx = &oc->add_payment_details.max_choice_limits[j];
   3140         if (GNUNET_YES ==
   3141             TALER_amount_cmp_currency (mx,
   3142                                        amount))
   3143         {
   3144           TALER_amount_max (mx,
   3145                             mx,
   3146                             amount);
   3147           found = true;
   3148           break;
   3149         }
   3150       }
   3151       if (! found)
   3152       {
   3153         GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   3154                              oc->add_payment_details.num_max_choice_limits,
   3155                              *amount);
   3156       }
   3157     }
   3158     break;
   3159   default:
   3160     GNUNET_assert (0);
   3161   }
   3162 
   3163   /* Then, create a candidate for each available wire method */
   3164   for (struct TMH_WireMethod *wm = oc->hc->instance->wm_head;
   3165        NULL != wm;
   3166        wm = wm->next)
   3167   {
   3168     struct WireMethodCandidate *wmc;
   3169 
   3170     /* Locate wire method that has a matching payment target */
   3171     if (! wm->active)
   3172       continue; /* ignore inactive methods */
   3173     if ( (NULL != oc->parse_request.payment_target) &&
   3174          (0 != strcasecmp (oc->parse_request.payment_target,
   3175                            wm->wire_method) ) )
   3176       continue; /* honor client preference */
   3177     wmc = GNUNET_new (struct WireMethodCandidate);
   3178     wmc->wm = wm;
   3179     wmc->exchanges = json_array ();
   3180     GNUNET_assert (NULL != wmc->exchanges);
   3181     GNUNET_CONTAINER_DLL_insert (oc->add_payment_details.wmc_head,
   3182                                  oc->add_payment_details.wmc_tail,
   3183                                  wmc);
   3184   }
   3185 
   3186   if (NULL == oc->add_payment_details.wmc_head)
   3187   {
   3188     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3189                 "No wire method available for instance '%s'\n",
   3190                 oc->hc->instance->settings.id);
   3191     reply_with_error (oc,
   3192                       MHD_HTTP_NOT_FOUND,
   3193                       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE,
   3194                       oc->parse_request.payment_target);
   3195     return;
   3196   }
   3197 
   3198   /* next, we'll evaluate available exchanges */
   3199   oc->phase++;
   3200 }
   3201 
   3202 
   3203 /* ***************** ORDER_PHASE_MERGE_INVENTORY **************** */
   3204 
   3205 
   3206 /**
   3207  * Helper function to sort uint64_t array with qsort().
   3208  *
   3209  * @param a pointer to element to compare
   3210  * @param b pointer to element to compare
   3211  * @return 0 on equal, -1 on smaller, 1 on larger
   3212  */
   3213 static int
   3214 uint64_cmp (const void *a,
   3215             const void *b)
   3216 {
   3217   uint64_t ua = *(const uint64_t *) a;
   3218   uint64_t ub = *(const uint64_t *) b;
   3219 
   3220   if (ua < ub)
   3221     return -1;
   3222   if (ua > ub)
   3223     return 1;
   3224   return 0;
   3225 }
   3226 
   3227 
   3228 /**
   3229  * Merge the inventory products into products, querying the
   3230  * database about the details of those products. Upon success,
   3231  * continue processing by calling add_payment_details().
   3232  *
   3233  * @param[in,out] oc order context to process
   3234  */
   3235 static void
   3236 phase_merge_inventory (struct OrderContext *oc)
   3237 {
   3238   uint64_t pots[oc->parse_order.order->products_len + 1];
   3239   size_t pots_off = 0;
   3240 
   3241   if (0 != oc->parse_order.order->base->default_money_pot)
   3242     pots[pots_off++] = oc->parse_order.order->base->default_money_pot;
   3243   /**
   3244    * parse_request.inventory_products => instructions to add products to contract terms
   3245    * parse_order.products => contains products that are not from the backend-managed inventory.
   3246    */
   3247   oc->merge_inventory.products = json_array ();
   3248   for (size_t i = 0; i<oc->parse_order.order->products_len; i++)
   3249   {
   3250     GNUNET_assert (
   3251       0 ==
   3252       json_array_append_new (
   3253         oc->merge_inventory.products,
   3254         TALER_MERCHANT_product_sold_serialize (
   3255           &oc->parse_order.order->products[i])));
   3256     if (0 != oc->parse_order.order->products[i].product_money_pot)
   3257       pots[pots_off++] = oc->parse_order.order->products[i].product_money_pot;
   3258   }
   3259 
   3260   /* make sure pots array only has distinct elements */
   3261   qsort (pots,
   3262          pots_off,
   3263          sizeof (uint64_t),
   3264          &uint64_cmp);
   3265   {
   3266     size_t e = 0;
   3267 
   3268     for (size_t i = 1; i<pots_off; i++)
   3269     {
   3270       if (pots[e] != pots[i])
   3271         pots[++e] = pots[i];
   3272     }
   3273     if (pots_off > 0)
   3274       e++;
   3275     pots_off = e;
   3276   }
   3277   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3278               "Found %u unique money pots in order\n",
   3279               (unsigned int) pots_off);
   3280 
   3281   /* check if all money pots exist; note that we do NOT treat
   3282      the inventory products to this check, as (1) the foreign key
   3283      constraint should ensure this, and (2) if the money pot
   3284      were deleted (concurrently), the value is specified to be
   3285      considered 0 (aka none) and so we can proceed anyway. */
   3286   if (pots_off > 0)
   3287   {
   3288     enum GNUNET_DB_QueryStatus qs;
   3289     uint64_t pot_missing;
   3290 
   3291     qs = TALER_MERCHANTDB_get_missing_money_pot (TMH_db,
   3292                                                  oc->hc->instance->settings.id,
   3293                                                  pots_off,
   3294                                                  pots,
   3295                                                  &pot_missing);
   3296     switch (qs)
   3297     {
   3298     case GNUNET_DB_STATUS_HARD_ERROR:
   3299     case GNUNET_DB_STATUS_SOFT_ERROR:
   3300       GNUNET_break (0);
   3301       reply_with_error (oc,
   3302                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3303                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   3304                         "get_missing_money_pot");
   3305       return;
   3306     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3307       /* great, good case! */
   3308       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3309                   "All money pots exist\n");
   3310       break;
   3311     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3312       {
   3313         char mstr[32];
   3314 
   3315         GNUNET_snprintf (mstr,
   3316                          sizeof (mstr),
   3317                          "%llu",
   3318                          (unsigned long long) pot_missing);
   3319         reply_with_error (oc,
   3320                           MHD_HTTP_NOT_FOUND,
   3321                           TALER_EC_MERCHANT_GENERIC_MONEY_POT_UNKNOWN,
   3322                           mstr);
   3323         return;
   3324       }
   3325     }
   3326   }
   3327 
   3328   /* Populate products from inventory product array and database */
   3329   {
   3330     GNUNET_assert (NULL != oc->merge_inventory.products);
   3331     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   3332     {
   3333       struct InventoryProduct *ip
   3334         = &oc->parse_request.inventory_products[i];
   3335       struct TALER_MERCHANTDB_ProductDetails pd;
   3336       enum GNUNET_DB_QueryStatus qs;
   3337       size_t num_categories = 0;
   3338       uint64_t *categories = NULL;
   3339 
   3340       qs = TALER_MERCHANTDB_get_product (TMH_db,
   3341                                          oc->hc->instance->settings.id,
   3342                                          ip->product_id,
   3343                                          &pd,
   3344                                          &num_categories,
   3345                                          &categories);
   3346       if (qs <= 0)
   3347       {
   3348         enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   3349         unsigned int http_status = 0;
   3350 
   3351         switch (qs)
   3352         {
   3353         case GNUNET_DB_STATUS_HARD_ERROR:
   3354           GNUNET_break (0);
   3355           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   3356           ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   3357           break;
   3358         case GNUNET_DB_STATUS_SOFT_ERROR:
   3359           GNUNET_break (0);
   3360           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   3361           ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   3362           break;
   3363         case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3364           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3365                       "Product %s from order unknown\n",
   3366                       ip->product_id);
   3367           http_status = MHD_HTTP_NOT_FOUND;
   3368           ec = TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN;
   3369           break;
   3370         case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3371           /* case listed to make compilers happy */
   3372           GNUNET_assert (0);
   3373         }
   3374         reply_with_error (oc,
   3375                           http_status,
   3376                           ec,
   3377                           ip->product_id);
   3378         return;
   3379       }
   3380       GNUNET_free (categories);
   3381       oc->parse_order.order->base->minimum_age
   3382         = GNUNET_MAX (oc->parse_order.order->base->minimum_age,
   3383                       pd.minimum_age);
   3384       {
   3385         const char *eparam;
   3386 
   3387         if ( (! ip->quantity_missing) &&
   3388              (ip->quantity > (uint64_t) INT64_MAX) )
   3389         {
   3390           GNUNET_break_op (0);
   3391           reply_with_error (oc,
   3392                             MHD_HTTP_BAD_REQUEST,
   3393                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3394                             "quantity");
   3395           TALER_MERCHANTDB_product_details_free (&pd);
   3396           return;
   3397         }
   3398         if (GNUNET_OK !=
   3399             TALER_MERCHANT_vk_process_quantity_inputs (
   3400               TALER_MERCHANT_VK_QUANTITY,
   3401               pd.allow_fractional_quantity,
   3402               ip->quantity_missing,
   3403               (int64_t) ip->quantity,
   3404               ip->unit_quantity_missing,
   3405               ip->unit_quantity,
   3406               &ip->quantity,
   3407               &ip->quantity_frac,
   3408               &eparam))
   3409         {
   3410           GNUNET_break_op (0);
   3411           reply_with_error (oc,
   3412                             MHD_HTTP_BAD_REQUEST,
   3413                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3414                             eparam);
   3415           TALER_MERCHANTDB_product_details_free (&pd);
   3416           return;
   3417         }
   3418       }
   3419       {
   3420         struct TALER_MERCHANT_ProductSold ps = {
   3421           .product_id = (char *) ip->product_id,
   3422           .product_name = pd.product_name,
   3423           .description = pd.description,
   3424           .description_i18n = pd.description_i18n,
   3425           .unit_quantity.integer = ip->quantity,
   3426           .unit_quantity.fractional = ip->quantity_frac,
   3427           .prices_length = pd.price_array_length,
   3428           .prices = GNUNET_new_array (pd.price_array_length,
   3429                                       struct TALER_Amount),
   3430           .prices_are_net = pd.price_is_net,
   3431           .image = pd.image,
   3432           .taxes = pd.taxes,
   3433           .delivery_date = oc->parse_order.order->base->delivery_date,
   3434           .product_money_pot = pd.money_pot_id,
   3435           .unit = pd.unit,
   3436 
   3437         };
   3438         json_t *p;
   3439         char unit_quantity_buf[64];
   3440 
   3441         for (size_t j = 0; j<pd.price_array_length; j++)
   3442         {
   3443           struct TALER_Amount atomic_amount;
   3444 
   3445           GNUNET_assert (
   3446             GNUNET_OK ==
   3447             TALER_amount_set_zero (pd.price_array[j].currency,
   3448                                    &atomic_amount));
   3449           atomic_amount.fraction = 1;
   3450           GNUNET_assert (
   3451             GNUNET_OK ==
   3452             TALER_MERCHANT_amount_multiply_by_quantity (
   3453               &ps.prices[j],
   3454               &pd.price_array[j],
   3455               &ps.unit_quantity,
   3456               TALER_MERCHANT_ROUND_UP,
   3457               &atomic_amount));
   3458         }
   3459 
   3460         TALER_MERCHANT_vk_format_fractional_string (
   3461           TALER_MERCHANT_VK_QUANTITY,
   3462           ip->quantity,
   3463           ip->quantity_frac,
   3464           sizeof (unit_quantity_buf),
   3465           unit_quantity_buf);
   3466         if (0 != pd.money_pot_id)
   3467           pots[pots_off++] = pd.money_pot_id;
   3468         p = TALER_MERCHANT_product_sold_serialize (&ps);
   3469         GNUNET_assert (NULL != p);
   3470         GNUNET_free (ps.prices);
   3471         GNUNET_assert (0 ==
   3472                        json_array_append_new (oc->merge_inventory.products,
   3473                                               p));
   3474       }
   3475       TALER_MERCHANTDB_product_details_free (&pd);
   3476     }
   3477   }
   3478 
   3479   /* check if final product list is well-formed */
   3480   if (! TMH_products_array_valid (oc->merge_inventory.products))
   3481   {
   3482     GNUNET_break_op (0);
   3483     reply_with_error (oc,
   3484                       MHD_HTTP_BAD_REQUEST,
   3485                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3486                       "order:products");
   3487     return;
   3488   }
   3489   oc->phase++;
   3490 }
   3491 
   3492 
   3493 /* ***************** ORDER_PHASE_PARSE_CHOICES **************** */
   3494 
   3495 /**
   3496  * Callback function that is called for each donau instance.
   3497  * It simply adds the provided donau_url to the json.
   3498  *
   3499  * @param cls closure with our `struct TALER_MERCHANT_ContractOutput *`
   3500  * @param donau_url the URL of the donau instance
   3501  */
   3502 static void
   3503 add_donau_url (void *cls,
   3504                const char *donau_url)
   3505 {
   3506   struct TALER_MERCHANT_ContractOutput *output = cls;
   3507 
   3508   GNUNET_array_append (output->details.donation_receipt.donau_urls,
   3509                        output->details.donation_receipt.donau_urls_len,
   3510                        GNUNET_strdup (donau_url));
   3511 }
   3512 
   3513 
   3514 /**
   3515  * Add the donau output to the contract output.
   3516  *
   3517  * @param oc order context
   3518  * @param output contract output to add donau URLs to
   3519  */
   3520 static bool
   3521 add_donau_output (struct OrderContext *oc,
   3522                   struct TALER_MERCHANT_ContractOutput *output)
   3523 {
   3524   enum GNUNET_DB_QueryStatus qs;
   3525 
   3526   qs = TALER_MERCHANTDB_iterate_donau_instances_filtered (
   3527     TMH_db,
   3528     output->details.donation_receipt.amount.currency,
   3529     &add_donau_url,
   3530     output);
   3531   if (qs < 0)
   3532   {
   3533     GNUNET_break (0);
   3534     reply_with_error (oc,
   3535                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   3536                       TALER_EC_GENERIC_DB_FETCH_FAILED,
   3537                       "donau url parsing db call");
   3538     for (unsigned int i = 0;
   3539          i < output->details.donation_receipt.donau_urls_len;
   3540          i++)
   3541       GNUNET_free (output->details.donation_receipt.donau_urls[i]);
   3542     GNUNET_array_grow (output->details.donation_receipt.donau_urls,
   3543                        output->details.donation_receipt.donau_urls_len,
   3544                        0);
   3545     return false;
   3546   }
   3547   return true;
   3548 }
   3549 
   3550 
   3551 /**
   3552  * Parse contract choices. Upon success, continue
   3553  * processing with merge_inventory().
   3554  *
   3555  * @param[in,out] oc order context
   3556  */
   3557 static void
   3558 phase_parse_choices (struct OrderContext *oc)
   3559 {
   3560   switch (oc->parse_order.order->base->version)
   3561   {
   3562   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3563     oc->phase++;
   3564     return;
   3565   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3566     /* handle below */
   3567     break;
   3568   default:
   3569     GNUNET_assert (0);
   3570   }
   3571 
   3572   /* Convert order choices to contract choices */
   3573   GNUNET_array_grow (oc->parse_choices.choices,
   3574                      oc->parse_choices.choices_len,
   3575                      oc->parse_order.order->details.v1.choices_len);
   3576   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3577   {
   3578     const struct TALER_MERCHANT_OrderChoice *ochoice
   3579       = &oc->parse_order.order->details.v1.choices[i];
   3580     struct TALER_MERCHANT_ContractChoice *cchoice
   3581       = &oc->parse_choices.choices[i];
   3582     unsigned int off;
   3583 
   3584     if (! TMH_test_exchange_configured_for_currency (
   3585           ochoice->amount.currency))
   3586     {
   3587       GNUNET_break_op (0);
   3588       reply_with_error (oc,
   3589                         MHD_HTTP_CONFLICT,
   3590                         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   3591                         ochoice->amount.currency);
   3592       return;
   3593     }
   3594     cchoice->amount = ochoice->amount;
   3595     cchoice->tip = ochoice->tip;
   3596     cchoice->no_tip = ochoice->no_tip;
   3597     if (NULL != ochoice->description)
   3598       cchoice->description = GNUNET_strdup (ochoice->description);
   3599     if (NULL != ochoice->description_i18n)
   3600       cchoice->description_i18n = json_incref (ochoice->description_i18n);
   3601     cchoice->max_fee = ochoice->max_fee;
   3602 
   3603     /* convert inputs */
   3604     GNUNET_array_grow (cchoice->inputs,
   3605                        cchoice->inputs_len,
   3606                        ochoice->inputs_len);
   3607     off = 0;
   3608     for (unsigned int j = 0; j < ochoice->inputs_len; j++)
   3609     {
   3610       const struct TALER_MERCHANT_OrderInput *order_input
   3611         = &ochoice->inputs[j];
   3612       struct TALER_MERCHANT_ContractInput *contract_input
   3613         = &cchoice->inputs[off];
   3614 
   3615       contract_input->type = order_input->type;
   3616       switch (order_input->type)
   3617       {
   3618       case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
   3619         GNUNET_assert (0);
   3620         break;
   3621       case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
   3622         /* Ignore inputs tokens with 'count' field set to 0 */
   3623         if (0 == order_input->details.token.count)
   3624           continue;
   3625         contract_input->details.token.count
   3626           = order_input->details.token.count;
   3627         contract_input->details.token.token_family_slug
   3628           = order_input->details.token.token_family_slug;
   3629         if (GNUNET_OK !=
   3630             add_input_token_family (oc,
   3631                                     contract_input->details.token.token_family_slug))
   3632         {
   3633           GNUNET_break_op (0);
   3634           return;
   3635         }
   3636         off++;
   3637         continue;
   3638       } /* switch input type */
   3639       GNUNET_assert (0);
   3640     } /* for all inputs */
   3641     GNUNET_array_grow (cchoice->inputs,
   3642                        cchoice->inputs_len,
   3643                        off);
   3644 
   3645     /* convert outputs */
   3646     GNUNET_array_grow (cchoice->outputs,
   3647                        cchoice->outputs_len,
   3648                        ochoice->outputs_len);
   3649     off = 0;
   3650     for (unsigned int j = 0; j < ochoice->outputs_len; j++)
   3651     {
   3652       const struct TALER_MERCHANT_OrderOutput *order_output
   3653         = &ochoice->outputs[j];
   3654       struct TALER_MERCHANT_ContractOutput *contract_output
   3655         = &cchoice->outputs[off];
   3656 
   3657       contract_output->type = order_output->type;
   3658       switch (order_output->type)
   3659       {
   3660       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
   3661         GNUNET_assert (0);
   3662         break;
   3663       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
   3664         if (order_output->details.donation_receipt.no_amount)
   3665         {
   3666           contract_output->details.donation_receipt.amount
   3667             = ochoice->amount;
   3668         }
   3669         else
   3670         {
   3671           contract_output->details.donation_receipt.amount
   3672             = order_output->details.donation_receipt.amount;
   3673         }
   3674         if (! add_donau_output (oc,
   3675                                 contract_output))
   3676         {
   3677           GNUNET_break (0);
   3678           return;
   3679         }
   3680         off++;
   3681         continue;
   3682       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
   3683         /* Ignore inputs tokens with 'count' field set to 0 */
   3684         if (0 == order_output->details.token.count)
   3685           continue;
   3686 
   3687         contract_output->details.token.token_family_slug
   3688           = order_output->details.token.token_family_slug;
   3689         contract_output->details.token.count
   3690           = order_output->details.token.count;
   3691         if (0 == order_output->details.token.valid_at.abs_time.abs_value_us)
   3692           contract_output->details.token.valid_at
   3693             = GNUNET_TIME_timestamp_get ();
   3694         else
   3695           contract_output->details.token.valid_at
   3696             = order_output->details.token.valid_at;
   3697         if (GNUNET_OK !=
   3698             add_output_token_family (
   3699               oc,
   3700               contract_output->details.token.token_family_slug,
   3701               contract_output->details.token.valid_at,
   3702               &contract_output->details.token.key_index))
   3703 
   3704         {
   3705           /* note: reply_with_error() was already called */
   3706           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3707                       "Could not handle output token family `%s'\n",
   3708                       contract_output->details.token.token_family_slug);
   3709           return;
   3710         }
   3711         off++;
   3712         continue;
   3713       } /* end switch */
   3714       GNUNET_assert (0);
   3715     } /* for outputs */
   3716     GNUNET_array_grow (cchoice->outputs,
   3717                        cchoice->outputs_len,
   3718                        off);
   3719   } /* for all choices */
   3720   oc->phase++;
   3721 }
   3722 
   3723 
   3724 /* ***************** ORDER_PHASE_PARSE_ORDER **************** */
   3725 
   3726 
   3727 /**
   3728  * Parse the order field of the request. Upon success, continue
   3729  * processing with parse_choices().
   3730  *
   3731  * @param[in,out] oc order context
   3732  */
   3733 static void
   3734 phase_parse_order (struct OrderContext *oc)
   3735 {
   3736   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   3737     &oc->hc->instance->settings;
   3738   bool computed_refund_deadline = false;
   3739 
   3740   oc->parse_order.order
   3741     = TALER_MERCHANT_order_parse (
   3742         oc->parse_request.order);
   3743   if (NULL == oc->parse_order.order)
   3744   {
   3745     GNUNET_break_op (0);
   3746     reply_with_error (oc,
   3747                       MHD_HTTP_BAD_REQUEST,
   3748                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3749                       "order");
   3750     return;
   3751   }
   3752 
   3753   switch (oc->parse_order.order->base->version)
   3754   {
   3755   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3756     if (! TMH_test_exchange_configured_for_currency (
   3757           oc->parse_order.order->details.v0.brutto.currency))
   3758     {
   3759       GNUNET_break_op (0);
   3760       reply_with_error (
   3761         oc,
   3762         MHD_HTTP_CONFLICT,
   3763         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   3764         oc->parse_order.order->details.v0.brutto.currency);
   3765       return;
   3766     }
   3767     break;
   3768   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3769     break;
   3770   default:
   3771     GNUNET_break_op (0);
   3772     reply_with_error (oc,
   3773                       MHD_HTTP_BAD_REQUEST,
   3774                       TALER_EC_GENERIC_VERSION_MALFORMED,
   3775                       "invalid version specified in order, supported are null, '0' or '1'");
   3776     return;
   3777   }
   3778 
   3779   /* Add order_id if it doesn't exist. */
   3780   if (NULL == oc->parse_order.order->order_id)
   3781   {
   3782     char buf[256];
   3783     time_t timer;
   3784     struct tm *tm_info;
   3785     size_t off;
   3786     uint64_t rand;
   3787     char *last;
   3788 
   3789     time (&timer);
   3790     tm_info = localtime (&timer);
   3791     if (NULL == tm_info)
   3792     {
   3793       reply_with_error (
   3794         oc,
   3795         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3796         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_LOCALTIME,
   3797         NULL);
   3798       return;
   3799     }
   3800     off = strftime (buf,
   3801                     sizeof (buf) - 1,
   3802                     "%Y.%j",
   3803                     tm_info);
   3804     /* Check for error state of strftime */
   3805     GNUNET_assert (0 != off);
   3806     buf[off++] = '-';
   3807     rand = GNUNET_CRYPTO_random_u64 (UINT64_MAX);
   3808     last = GNUNET_STRINGS_data_to_string (&rand,
   3809                                           sizeof (uint64_t),
   3810                                           &buf[off],
   3811                                           sizeof (buf) - off);
   3812     GNUNET_assert (NULL != last);
   3813     *last = '\0';
   3814 
   3815     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3816                 "Assigning order ID `%s' server-side\n",
   3817                 buf);
   3818     oc->parse_order.order->order_id = GNUNET_strdup (buf);
   3819   }
   3820 
   3821   /* Patch fulfillment URL with order_id (implements #6467). */
   3822   if (NULL != oc->parse_order.order->base->fulfillment_url)
   3823   {
   3824     const char *pos;
   3825 
   3826     pos = strstr (oc->parse_order.order->base->fulfillment_url,
   3827                   "${ORDER_ID}");
   3828     if (NULL != pos)
   3829     {
   3830       /* replace ${ORDER_ID} with the real order_id */
   3831       char *nurl;
   3832 
   3833       /* We only allow one placeholder */
   3834       if (strstr (pos + strlen ("${ORDER_ID}"),
   3835                   "${ORDER_ID}"))
   3836       {
   3837         GNUNET_break_op (0);
   3838         reply_with_error (oc,
   3839                           MHD_HTTP_BAD_REQUEST,
   3840                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3841                           "fulfillment_url");
   3842         return;
   3843       }
   3844 
   3845       GNUNET_asprintf (
   3846         &nurl,
   3847         "%.*s%s%s",
   3848         /* first output URL until ${ORDER_ID} */
   3849         (int) (pos - oc->parse_order.order->base->fulfillment_url),
   3850         oc->parse_order.order->base->fulfillment_url,
   3851         /* replace ${ORDER_ID} with the right order_id */
   3852         oc->parse_order.order->order_id,
   3853         /* append rest of original URL */
   3854         pos + strlen ("${ORDER_ID}"));
   3855       oc->parse_order.order->base->fulfillment_url = GNUNET_strdup (nurl);
   3856       GNUNET_free (nurl);
   3857     }
   3858   }
   3859 
   3860   if ( (GNUNET_TIME_absolute_is_zero (
   3861           oc->parse_order.order->pay_deadline.abs_time)) ||
   3862        (GNUNET_TIME_absolute_is_never (
   3863           oc->parse_order.order->pay_deadline.abs_time)) )
   3864   {
   3865     oc->parse_order.order->pay_deadline
   3866       = GNUNET_TIME_relative_to_timestamp (
   3867           settings->default_pay_delay);
   3868     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3869                 "Pay deadline was zero (or never), setting to %s\n",
   3870                 GNUNET_TIME_timestamp2s (
   3871                   oc->parse_order.order->pay_deadline));
   3872   }
   3873   else if (GNUNET_TIME_absolute_is_past (
   3874              oc->parse_order.order->pay_deadline.abs_time))
   3875   {
   3876     GNUNET_break_op (0);
   3877     reply_with_error (
   3878       oc,
   3879       MHD_HTTP_BAD_REQUEST,
   3880       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PAY_DEADLINE_IN_PAST,
   3881       NULL);
   3882     return;
   3883   }
   3884   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3885               "Pay deadline is %s\n",
   3886               GNUNET_TIME_timestamp2s (
   3887                 oc->parse_order.order->pay_deadline));
   3888 
   3889   /* Check soundness of refund deadline, and that a timestamp
   3890    * is actually present.  */
   3891   {
   3892     struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   3893 
   3894     /* Add timestamp if it doesn't exist (or is zero) */
   3895     if (GNUNET_TIME_absolute_is_zero (
   3896           oc->parse_order.order->timestamp.abs_time))
   3897     {
   3898       oc->parse_order.order->timestamp = now;
   3899     }
   3900 
   3901     /* If no refund_deadline given, set one based on refund_delay.  */
   3902     if (GNUNET_TIME_absolute_is_never (
   3903           oc->parse_order.order->refund_deadline.abs_time))
   3904     {
   3905       if (GNUNET_TIME_relative_is_zero (
   3906             oc->parse_request.refund_delay))
   3907       {
   3908         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3909                     "Refund delay is zero, no refunds are possible for this order\n");
   3910         oc->parse_order.order->refund_deadline = GNUNET_TIME_UNIT_ZERO_TS;
   3911       }
   3912       else
   3913       {
   3914         computed_refund_deadline = true;
   3915         oc->parse_order.order->refund_deadline
   3916           = GNUNET_TIME_absolute_to_timestamp (
   3917               GNUNET_TIME_absolute_add (
   3918                 oc->parse_order.order->pay_deadline.abs_time,
   3919                 oc->parse_request.refund_delay));
   3920       }
   3921     }
   3922 
   3923     if ( (! GNUNET_TIME_absolute_is_zero (
   3924             oc->parse_order.order->base->delivery_date.abs_time)) &&
   3925          (GNUNET_TIME_absolute_is_past (
   3926             oc->parse_order.order->base->delivery_date.abs_time)) )
   3927     {
   3928       GNUNET_break_op (0);
   3929       reply_with_error (
   3930         oc,
   3931         MHD_HTTP_BAD_REQUEST,
   3932         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_DELIVERY_DATE_IN_PAST,
   3933         NULL);
   3934       return;
   3935     }
   3936   }
   3937 
   3938   if ( (! GNUNET_TIME_absolute_is_zero (
   3939           oc->parse_order.order->refund_deadline.abs_time)) &&
   3940        (GNUNET_TIME_absolute_is_past (
   3941           oc->parse_order.order->refund_deadline.abs_time)) )
   3942   {
   3943     GNUNET_break_op (0);
   3944     reply_with_error (
   3945       oc,
   3946       MHD_HTTP_BAD_REQUEST,
   3947       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_DEADLINE_IN_PAST,
   3948       NULL);
   3949     return;
   3950   }
   3951 
   3952   if (GNUNET_TIME_absolute_is_never (
   3953         oc->parse_order.order->wire_transfer_deadline.abs_time))
   3954   {
   3955     struct GNUNET_TIME_Absolute start;
   3956 
   3957     start = GNUNET_TIME_absolute_max (
   3958       oc->parse_order.order->refund_deadline.abs_time,
   3959       oc->parse_order.order->pay_deadline.abs_time);
   3960     oc->parse_order.order->wire_transfer_deadline
   3961       = GNUNET_TIME_absolute_to_timestamp (
   3962           GNUNET_TIME_round_up (
   3963             GNUNET_TIME_absolute_add (
   3964               start,
   3965               settings->default_wire_transfer_delay),
   3966             settings->default_wire_transfer_rounding_interval));
   3967     if (GNUNET_TIME_absolute_is_never (
   3968           oc->parse_order.order->wire_transfer_deadline.abs_time))
   3969     {
   3970       GNUNET_break_op (0);
   3971       reply_with_error (
   3972         oc,
   3973         MHD_HTTP_BAD_REQUEST,
   3974         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_WIRE_DEADLINE_IS_NEVER,
   3975         "order:wire_transfer_deadline");
   3976       return;
   3977     }
   3978   }
   3979   else if (computed_refund_deadline)
   3980   {
   3981     /* if we computed the refund_deadline from default settings
   3982        and did have a configured wire_deadline, make sure that
   3983        the refund_deadline is at or below the wire_deadline. */
   3984     oc->parse_order.order->refund_deadline
   3985       = GNUNET_TIME_timestamp_min (
   3986           oc->parse_order.order->refund_deadline,
   3987           oc->parse_order.order->wire_transfer_deadline);
   3988   }
   3989   if (GNUNET_TIME_timestamp_cmp (
   3990         oc->parse_order.order->wire_transfer_deadline,
   3991         <,
   3992         oc->parse_order.order->refund_deadline))
   3993   {
   3994     GNUNET_break_op (0);
   3995     reply_with_error (
   3996       oc,
   3997       MHD_HTTP_BAD_REQUEST,
   3998       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_AFTER_WIRE_DEADLINE,
   3999       "order:wire_transfer_deadline;order:refund_deadline");
   4000     return;
   4001   }
   4002 
   4003   {
   4004     char *url;
   4005 
   4006     url = make_merchant_base_url (oc->connection,
   4007                                   settings->id);
   4008     if (NULL == url)
   4009     {
   4010       GNUNET_break_op (0);
   4011       reply_with_error (
   4012         oc,
   4013         MHD_HTTP_BAD_REQUEST,
   4014         TALER_EC_GENERIC_PARAMETER_MISSING,
   4015         "order:merchant_base_url");
   4016       return;
   4017     }
   4018     oc->parse_order.merchant_base_url = url;
   4019   }
   4020 
   4021   // FIXME: move to util during parsing!
   4022   if ( (NULL != oc->parse_order.order->base->delivery_location) &&
   4023        (! TMH_location_object_valid (oc->parse_order.order->base->delivery_location)) )
   4024   {
   4025     GNUNET_break_op (0);
   4026     reply_with_error (oc,
   4027                       MHD_HTTP_BAD_REQUEST,
   4028                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4029                       "delivery_location");
   4030     return;
   4031   }
   4032 
   4033   oc->phase++;
   4034 }
   4035 
   4036 
   4037 /* ***************** ORDER_PHASE_PARSE_REQUEST **************** */
   4038 
   4039 /**
   4040  * Parse the client request. Upon success,
   4041  * continue processing by calling parse_order().
   4042  *
   4043  * @param[in,out] oc order context to process
   4044  */
   4045 static void
   4046 phase_parse_request (struct OrderContext *oc)
   4047 {
   4048   const json_t *ip = NULL;
   4049   const json_t *uuid = NULL;
   4050   const char *otp_id = NULL;
   4051   bool create_token = true; /* default */
   4052   struct GNUNET_JSON_Specification spec[] = {
   4053     GNUNET_JSON_spec_json ("order",
   4054                            &oc->parse_request.order),
   4055     GNUNET_JSON_spec_mark_optional (
   4056       GNUNET_JSON_spec_relative_time ("refund_delay",
   4057                                       &oc->parse_request.refund_delay),
   4058       NULL),
   4059     GNUNET_JSON_spec_mark_optional (
   4060       GNUNET_JSON_spec_string ("payment_target",
   4061                                &oc->parse_request.payment_target),
   4062       NULL),
   4063     GNUNET_JSON_spec_mark_optional (
   4064       GNUNET_JSON_spec_array_const ("inventory_products",
   4065                                     &ip),
   4066       NULL),
   4067     GNUNET_JSON_spec_mark_optional (
   4068       GNUNET_JSON_spec_string ("session_id",
   4069                                &oc->parse_request.session_id),
   4070       NULL),
   4071     GNUNET_JSON_spec_mark_optional (
   4072       GNUNET_JSON_spec_array_const ("lock_uuids",
   4073                                     &uuid),
   4074       NULL),
   4075     GNUNET_JSON_spec_mark_optional (
   4076       GNUNET_JSON_spec_bool ("create_token",
   4077                              &create_token),
   4078       NULL),
   4079     GNUNET_JSON_spec_mark_optional (
   4080       GNUNET_JSON_spec_string ("otp_id",
   4081                                &otp_id),
   4082       NULL),
   4083     GNUNET_JSON_spec_end ()
   4084   };
   4085   enum GNUNET_GenericReturnValue ret;
   4086 
   4087   oc->parse_request.refund_delay
   4088     = oc->hc->instance->settings.default_refund_delay;
   4089   ret = TALER_MHD_parse_json_data (oc->connection,
   4090                                    oc->hc->request_body,
   4091                                    spec);
   4092   if (GNUNET_OK != ret)
   4093   {
   4094     GNUNET_break_op (0);
   4095     finalize_order2 (oc,
   4096                      ret);
   4097     return;
   4098   }
   4099   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   4100               "Refund delay is %s\n",
   4101               GNUNET_TIME_relative2s (oc->parse_request.refund_delay,
   4102                                       false));
   4103   TALER_MERCHANTDB_do_expire_locks (TMH_db);
   4104   if (NULL != otp_id)
   4105   {
   4106     struct TALER_MERCHANTDB_OtpDeviceDetails td;
   4107     enum GNUNET_DB_QueryStatus qs;
   4108 
   4109     memset (&td,
   4110             0,
   4111             sizeof (td));
   4112     qs = TALER_MERCHANTDB_get_otp_device (TMH_db,
   4113                                           oc->hc->instance->settings.id,
   4114                                           otp_id,
   4115                                           &td);
   4116     switch (qs)
   4117     {
   4118     case GNUNET_DB_STATUS_HARD_ERROR:
   4119       GNUNET_break (0);
   4120       reply_with_error (oc,
   4121                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4122                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   4123                         "get_otp_device");
   4124       return;
   4125     case GNUNET_DB_STATUS_SOFT_ERROR:
   4126       GNUNET_break (0);
   4127       reply_with_error (oc,
   4128                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4129                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   4130                         "get_otp_device");
   4131       return;
   4132     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   4133       reply_with_error (oc,
   4134                         MHD_HTTP_NOT_FOUND,
   4135                         TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
   4136                         otp_id);
   4137       return;
   4138     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   4139       break;
   4140     }
   4141     oc->parse_request.pos_key = td.otp_key;
   4142     oc->parse_request.pos_algorithm = td.otp_algorithm;
   4143     GNUNET_free (td.otp_description);
   4144   }
   4145   if (create_token)
   4146   {
   4147     GNUNET_CRYPTO_random_block (&oc->parse_request.claim_token,
   4148                                 sizeof (oc->parse_request.claim_token));
   4149   }
   4150   /* Compute h_post_data (for idempotency check) */
   4151   {
   4152     char *req_body_enc;
   4153 
   4154     /* Dump normalized JSON to string. */
   4155     if (NULL == (req_body_enc
   4156                    = json_dumps (oc->hc->request_body,
   4157                                  JSON_ENCODE_ANY
   4158                                  | JSON_COMPACT
   4159                                  | JSON_SORT_KEYS)))
   4160     {
   4161       GNUNET_break (0);
   4162       GNUNET_JSON_parse_free (spec);
   4163       reply_with_error (oc,
   4164                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4165                         TALER_EC_GENERIC_ALLOCATION_FAILURE,
   4166                         "request body normalization for hashing");
   4167       return;
   4168     }
   4169     GNUNET_CRYPTO_hash (req_body_enc,
   4170                         strlen (req_body_enc),
   4171                         &oc->parse_request.h_post_data.hash);
   4172     GNUNET_free (req_body_enc);
   4173   }
   4174 
   4175   /* parse the inventory_products (optionally given) */
   4176   if (NULL != ip)
   4177   {
   4178     unsigned int ipl = (unsigned int) json_array_size (ip);
   4179 
   4180     if ( (json_array_size (ip) != (size_t) ipl) ||
   4181          (ipl > MAX_PRODUCTS) )
   4182     {
   4183       GNUNET_break_op (0);
   4184       GNUNET_JSON_parse_free (spec);
   4185       reply_with_error (oc,
   4186                         MHD_HTTP_BAD_REQUEST,
   4187                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4188                         "inventory_products (too many)");
   4189       return;
   4190     }
   4191     GNUNET_array_grow (oc->parse_request.inventory_products,
   4192                        oc->parse_request.inventory_products_length,
   4193                        (unsigned int) json_array_size (ip));
   4194     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   4195     {
   4196       struct InventoryProduct *ipr = &oc->parse_request.inventory_products[i];
   4197       const char *error_name;
   4198       unsigned int error_line;
   4199       struct GNUNET_JSON_Specification ispec[] = {
   4200         GNUNET_JSON_spec_string ("product_id",
   4201                                  &ipr->product_id),
   4202         GNUNET_JSON_spec_mark_optional (
   4203           GNUNET_JSON_spec_uint64 ("quantity",
   4204                                    &ipr->quantity),
   4205           &ipr->quantity_missing),
   4206         GNUNET_JSON_spec_mark_optional (
   4207           GNUNET_JSON_spec_string ("unit_quantity",
   4208                                    &ipr->unit_quantity),
   4209           &ipr->unit_quantity_missing),
   4210         GNUNET_JSON_spec_mark_optional (
   4211           GNUNET_JSON_spec_uint64 ("product_money_pot",
   4212                                    &ipr->product_money_pot),
   4213           NULL),
   4214         GNUNET_JSON_spec_end ()
   4215       };
   4216 
   4217       ret = GNUNET_JSON_parse (json_array_get (ip,
   4218                                                i),
   4219                                ispec,
   4220                                &error_name,
   4221                                &error_line);
   4222       if (GNUNET_OK != ret)
   4223       {
   4224         GNUNET_break_op (0);
   4225         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4226                     "Product parsing failed at #%u: %s:%u\n",
   4227                     i,
   4228                     error_name,
   4229                     error_line);
   4230         reply_with_error (oc,
   4231                           MHD_HTTP_BAD_REQUEST,
   4232                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4233                           "inventory_products");
   4234         return;
   4235       }
   4236       if (ipr->quantity_missing && ipr->unit_quantity_missing)
   4237       {
   4238         ipr->quantity = 1;
   4239         ipr->quantity_missing = false;
   4240       }
   4241     }
   4242   }
   4243 
   4244   /* parse the lock_uuids (optionally given) */
   4245   if (NULL != uuid)
   4246   {
   4247     GNUNET_array_grow (oc->parse_request.uuids,
   4248                        oc->parse_request.uuids_length,
   4249                        json_array_size (uuid));
   4250     for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   4251     {
   4252       json_t *ui = json_array_get (uuid,
   4253                                    i);
   4254 
   4255       if (! json_is_string (ui))
   4256       {
   4257         GNUNET_break_op (0);
   4258         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4259                     "UUID parsing failed at #%u\n",
   4260                     i);
   4261         reply_with_error (oc,
   4262                           MHD_HTTP_BAD_REQUEST,
   4263                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4264                           "lock_uuids");
   4265         return;
   4266       }
   4267       TMH_uuid_from_string (json_string_value (ui),
   4268                             &oc->parse_request.uuids[i]);
   4269     }
   4270   }
   4271   oc->phase++;
   4272 }
   4273 
   4274 
   4275 /* ***************** Main handler **************** */
   4276 
   4277 
   4278 enum MHD_Result
   4279 TMH_private_post_orders (
   4280   const struct TMH_RequestHandler *rh,
   4281   struct MHD_Connection *connection,
   4282   struct TMH_HandlerContext *hc)
   4283 {
   4284   struct OrderContext *oc = hc->ctx;
   4285 
   4286   if (NULL == oc)
   4287   {
   4288     oc = GNUNET_new (struct OrderContext);
   4289     hc->ctx = oc;
   4290     hc->cc = &clean_order;
   4291     oc->connection = connection;
   4292     oc->hc = hc;
   4293   }
   4294   while (1)
   4295   {
   4296     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4297                 "Processing order in phase %d\n",
   4298                 oc->phase);
   4299     switch (oc->phase)
   4300     {
   4301     case ORDER_PHASE_PARSE_REQUEST:
   4302       phase_parse_request (oc);
   4303       break;
   4304     case ORDER_PHASE_PARSE_ORDER:
   4305       phase_parse_order (oc);
   4306       break;
   4307     case ORDER_PHASE_PARSE_CHOICES:
   4308       phase_parse_choices (oc);
   4309       break;
   4310     case ORDER_PHASE_MERGE_INVENTORY:
   4311       phase_merge_inventory (oc);
   4312       break;
   4313     case ORDER_PHASE_ADD_PAYMENT_DETAILS:
   4314       phase_add_payment_details (oc);
   4315       break;
   4316     case ORDER_PHASE_SET_EXCHANGES:
   4317       if (phase_set_exchanges (oc))
   4318         return MHD_YES;
   4319       break;
   4320     case ORDER_PHASE_SELECT_WIRE_METHOD:
   4321       phase_select_wire_method (oc);
   4322       break;
   4323     case ORDER_PHASE_SET_MAX_FEE:
   4324       phase_set_max_fee (oc);
   4325       break;
   4326     case ORDER_PHASE_SERIALIZE_ORDER:
   4327       phase_serialize_order (oc);
   4328       break;
   4329     case ORDER_PHASE_CHECK_CONTRACT:
   4330       phase_check_contract (oc);
   4331       break;
   4332     case ORDER_PHASE_SALT_FORGETTABLE:
   4333       phase_salt_forgettable (oc);
   4334       break;
   4335     case ORDER_PHASE_EXECUTE_ORDER:
   4336       phase_execute_order (oc);
   4337       break;
   4338     case ORDER_PHASE_FINISHED_MHD_YES:
   4339       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4340                   "Finished processing order (1)\n");
   4341       return MHD_YES;
   4342     case ORDER_PHASE_FINISHED_MHD_NO:
   4343       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4344                   "Finished processing order (0)\n");
   4345       return MHD_NO;
   4346     }
   4347   }
   4348 }
   4349 
   4350 
   4351 /* end of taler-merchant-httpd_post-private-orders.c */