merchant

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

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


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