merchant

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

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


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