aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-08-24 22:09:13 +0200
committerChristian Grothoff <christian@grothoff.org>2023-08-24 22:09:13 +0200
commitb4dbf7bcf38e183c0ddd39b48e911221bdd9d36c (patch)
tree5c3db74a94f0c8fb1eacbbce13b032645c34d187 /src/backend
parentd4cbd450a5eb55a33e753ff28e85debe8016577a (diff)
add merchant backend support for STEFAN curves
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.h2
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c211
2 files changed, 152 insertions, 61 deletions
diff --git a/src/backend/taler-merchant-httpd_exchanges.h b/src/backend/taler-merchant-httpd_exchanges.h
index b0f2d879..d8202922 100644
--- a/src/backend/taler-merchant-httpd_exchanges.h
+++ b/src/backend/taler-merchant-httpd_exchanges.h
@@ -125,6 +125,7 @@ void
TMH_exchange_get_trusted (TMH_ExchangeCallback cb,
void *cb_cls);
+
/**
* Return the master public key of the given @a exchange.
* Will be returned from configuration for trusted
@@ -137,6 +138,7 @@ const struct TALER_MasterPublicKeyP *
TMH_EXCHANGES_get_master_pub (
const struct TMH_Exchange *exchange);
+
/**
* Lookup current wire fee by @a exchange_url and
* @a wire_method.
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 370050d4..409c3eec 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -176,6 +176,24 @@ struct OrderContext
json_t *order;
/**
+ * Maximum fee for @e order based on STEFAN curves.
+ * Used to set @e max_fee if not provided as part of
+ * @e order.
+ */
+ struct TALER_Amount max_stefan_fee;
+
+ /**
+ * Maximum fee as given by the client request.
+ */
+ struct TALER_Amount max_fee;
+
+ /**
+ * Gross amount value of the contract. Used to
+ * compute @e max_stefan_fee.
+ */
+ struct TALER_Amount brutto;
+
+ /**
* Array of exchanges we find acceptable for this
* order.
*/
@@ -265,6 +283,7 @@ struct OrderContext
ORDER_PHASE_ADD_PAYMENT_DETAILS,
ORDER_PHASE_PATCH_ORDER,
ORDER_PHASE_SET_EXCHANGES,
+ ORDER_PHASE_SET_MAX_FEE,
ORDER_PHASE_CHECK_CONTRACT,
ORDER_PHASE_EXECUTE_ORDER,
@@ -532,7 +551,6 @@ execute_order (struct OrderContext *oc)
{
const struct TALER_MERCHANTDB_InstanceSettings *settings =
&oc->hc->instance->settings;
- struct TALER_Amount total;
const char *summary;
const char *fulfillment_msg = NULL;
const json_t *products;
@@ -541,9 +559,6 @@ execute_order (struct OrderContext *oc)
struct GNUNET_TIME_Timestamp refund_deadline = { 0 };
struct GNUNET_TIME_Timestamp wire_transfer_deadline;
struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount ("amount",
- TMH_currency,
- &total),
GNUNET_JSON_spec_string ("order_id",
&oc->order_id),
TALER_JSON_spec_i18n_str ("summary",
@@ -857,6 +872,47 @@ check_contract (struct OrderContext *oc)
/**
+ * Update MAX STEFAN fees based on @a keys.
+ *
+ * @param[in,out] oc order context to update
+ * @param keys keys to derive STEFAN fees from
+ */
+static void
+update_stefan (struct OrderContext *oc,
+ const struct TALER_EXCHANGE_Keys *keys)
+{
+ struct TALER_Amount net;
+
+ if (0 == keys->num_denom_keys)
+ sleep (600);
+ if (GNUNET_SYSERR !=
+ TALER_EXCHANGE_keys_stefan_b2n (keys,
+ &oc->brutto,
+ &net))
+ {
+ struct TALER_Amount fee;
+
+ TALER_EXCHANGE_keys_stefan_round (keys,
+ &net);
+ GNUNET_assert (0 <=
+ TALER_amount_subtract (&fee,
+ &oc->brutto,
+ &net));
+ if ( (GNUNET_OK !=
+ TALER_amount_is_valid (&oc->max_stefan_fee)) ||
+ (-1 == TALER_amount_cmp (&oc->max_stefan_fee,
+ &fee)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Updated STEFAN-based fee to %s\n",
+ TALER_amount2s (&fee));
+ oc->max_stefan_fee = fee;
+ }
+ }
+}
+
+
+/**
* Compute the set of exchanges that would be acceptable
* for this order.
*
@@ -918,13 +974,15 @@ get_acceptable (void *cls,
* @param exchange representation of the exchange
*/
static void
-keys_forced (
+keys_cb (
void *cls,
struct TALER_EXCHANGE_Keys *keys,
struct TMH_Exchange *exchange)
{
struct RekeyExchange *rx = cls;
struct OrderContext *oc = rx->oc;
+ const struct TALER_MERCHANTDB_InstanceSettings *settings =
+ &oc->hc->instance->settings;
rx->fo = NULL;
GNUNET_CONTAINER_DLL_remove (oc->pending_reload_head,
@@ -936,6 +994,14 @@ keys_forced (
"Failed to download %s/keys\n",
rx->url);
}
+ else
+ {
+ if ( (settings->use_stefan) &&
+ (GNUNET_OK !=
+ TALER_amount_is_valid (&oc->max_fee)) )
+ update_stefan (oc,
+ keys);
+ }
get_acceptable (oc,
rx->url,
exchange);
@@ -966,9 +1032,9 @@ keys_forced (
* @param exchange internal handle for the exchange
*/
static void
-rekey_exchanges (void *cls,
- const char *url,
- const struct TMH_Exchange *exchange)
+get_exchange_keys (void *cls,
+ const char *url,
+ const struct TMH_Exchange *exchange)
{
struct OrderContext *oc = cls;
struct RekeyExchange *rx;
@@ -983,13 +1049,49 @@ rekey_exchanges (void *cls,
"Forcing download of %s/keys\n",
url);
rx->fo = TMH_EXCHANGES_keys4exchange (url,
- true,
- &keys_forced,
+ oc->forced_reload,
+ &keys_cb,
rx);
}
/**
+ * Set max_fee in @a oc based on STEFAN value if
+ * not yet present.
+ *
+ * @param[in,out] oc order context
+ */
+static void
+set_max_fee (struct OrderContext *oc)
+{
+ const struct TALER_MERCHANTDB_InstanceSettings *settings =
+ &oc->hc->instance->settings;
+
+ if (GNUNET_OK !=
+ TALER_amount_is_valid (&oc->max_fee))
+ {
+ struct TALER_Amount stefan;
+
+ if ( (settings->use_stefan) &&
+ (GNUNET_OK ==
+ TALER_amount_is_valid (&oc->max_stefan_fee)) )
+ stefan = oc->max_stefan_fee;
+ else
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (TMH_currency,
+ &stefan));
+ GNUNET_assert (0 ==
+ json_object_set_new (
+ oc->order,
+ "max_fee",
+ TALER_JSON_from_amount (&stefan)));
+ }
+
+ oc->phase++;
+}
+
+
+/**
* Set list of acceptable exchanges in @a oc.
*
* @param[in,out] oc order context
@@ -1002,41 +1104,46 @@ set_exchanges (struct OrderContext *oc)
expensive; could likely consider caching the result if it starts to
matter. */
if (NULL == oc->exchanges)
+ {
oc->exchanges = json_array ();
- TMH_exchange_get_trusted (&get_acceptable,
- oc);
- if (! oc->exchange_good)
+ TMH_exchange_get_trusted (&get_exchange_keys,
+ oc);
+ }
+ else if (! oc->exchange_good)
{
if (! oc->forced_reload)
{
oc->forced_reload = true;
GNUNET_assert (0 ==
json_array_clear (oc->exchanges));
- TMH_exchange_get_trusted (&rekey_exchanges,
+ TMH_exchange_get_trusted (&get_exchange_keys,
oc);
}
- if (NULL != oc->pending_reload_head)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Still trying to re-load /keys\n");
- MHD_suspend_connection (oc->connection);
- oc->suspended = GNUNET_YES;
- GNUNET_CONTAINER_DLL_insert (oc_head,
- oc_tail,
- oc);
- return true; /* reloads pending */
- }
- if (0 == json_array_size (oc->exchanges))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Cannot create order: lacking trusted exchanges\n");
- reply_with_error (
- oc,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
- oc->wm->wire_method);
- return false;
- }
+ }
+ if (NULL != oc->pending_reload_head)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Still trying to re-load /keys\n");
+ MHD_suspend_connection (oc->connection);
+ oc->suspended = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert (oc_head,
+ oc_tail,
+ oc);
+ return true; /* reloads pending */
+ }
+ if (0 == json_array_size (oc->exchanges))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot create order: lacking trusted exchanges\n");
+ reply_with_error (
+ oc,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
+ oc->wm->wire_method);
+ return false;
+ }
+ if (! oc->exchange_good)
+ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Creating order, but possibly without usable trusted exchanges\n");
}
@@ -1066,7 +1173,6 @@ patch_order (struct OrderContext *oc)
const char *merchant_base_url = NULL;
const json_t *jmerchant = NULL;
const json_t *delivery_location = NULL;
- struct TALER_Amount max_fee = { 0 };
struct GNUNET_TIME_Timestamp timestamp
= GNUNET_TIME_UNIT_ZERO_TS;
struct GNUNET_TIME_Timestamp delivery_date
@@ -1092,6 +1198,9 @@ patch_order (struct OrderContext *oc)
GNUNET_JSON_spec_string ("order_id",
&order_id),
NULL),
+ TALER_JSON_spec_amount ("amount",
+ TMH_currency,
+ &oc->brutto),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("fulfillment_url",
&fulfillment_url),
@@ -1115,7 +1224,7 @@ patch_order (struct OrderContext *oc)
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount ("max_fee",
TMH_currency,
- &max_fee),
+ &oc->max_fee),
NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("delivery_date",
@@ -1352,29 +1461,6 @@ patch_order (struct OrderContext *oc)
return;
}
- /* Note: total amount currency match checked
- later in execute_order() */
- if (GNUNET_OK !=
- TALER_amount_is_valid (&max_fee))
- {
- struct TALER_Amount stefan;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
- &stefan));
- if (settings->use_stefan)
- {
- /* FIXME: update amount from stefan curve! */
- stefan.value = 5; // FIXME!
- }
-
- GNUNET_assert (0 ==
- json_object_set_new (
- oc->order,
- "max_fee",
- TALER_JSON_from_amount (&stefan)));
- }
-
if (NULL == merchant_base_url)
{
char *url;
@@ -1868,6 +1954,9 @@ TMH_private_post_orders_with_pos_secrets (
if (set_exchanges (oc))
return MHD_YES;
break;
+ case ORDER_PHASE_SET_MAX_FEE:
+ set_max_fee (oc);
+ break;
case ORDER_PHASE_CHECK_CONTRACT:
check_contract (oc);
break;