merchant

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

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


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