merchant

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

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


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