merchant

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

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


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