commit 34f4337eae99966311f276b59982bd101f9b7b1c
parent 47aec436a6c8a2e7ca13313235b6694ec18702ac
Author: bohdan-potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date: Wed, 25 Dec 2024 20:59:22 +0100
Merge branch 'master' into dev/bohdan-potuzhnyi/donau-integration
Diffstat:
26 files changed, 2303 insertions(+), 1517 deletions(-)
diff --git a/configure.ac b/configure.ac
@@ -18,7 +18,7 @@
# This configure file is in the public domain
AC_PREREQ([2.69])
-AC_INIT([taler-merchant],[0.14.0],[taler-bug@gnunet.org])
+AC_INIT([taler-merchant],[0.14.1],[taler-bug@gnunet.org])
AC_CONFIG_SRCDIR([src/backend/taler-merchant-httpd.c])
AC_CONFIG_HEADERS([taler_merchant_config.h])
# support for non-recursive builds
diff --git a/contrib/ci/jobs/0-codespell/job.sh b/contrib/ci/jobs/0-codespell/job.sh
@@ -20,6 +20,7 @@ ChangeLog
configure*
config.status
config.guess
+config.sub
depcomp
*/contrib/*
*/contrib/hellos/**
diff --git a/contrib/merchant-spa.lock b/contrib/merchant-spa.lock
@@ -1 +1 @@
-0.13.8-dev.1
+0.14.0-dev.3
diff --git a/contrib/uncrustify_precommit b/contrib/uncrustify_precommit
@@ -1,15 +1,18 @@
-#!/bin/sh
+#!/bin/bash
# use as .git/hooks/pre-commit
-
exec 1>&2
RET=0
-# Note: we exclude src/mustach from our indentation rules as
-# this is the virtually unchanged copylib of mustach
-changed=$(git diff --cached --name-only) | grep -v mustach
+changed=$(git diff --cached --name-only | grep -v mustach)
crustified=""
+# If nothing (important) has changed, return here
+[ -z "$changed" ] && exit 0
+
+( echo "$changed" | grep -q '\.[ch] *$*') && \
+ echo "Checking formatting with uncrustify..."
+
for f in $changed;
do
if echo $f | grep \\.[c,h]\$ > /dev/null
@@ -31,7 +34,38 @@ done
if [ $RET = 1 ];
then
echo "Run"
- echo "uncrustify --no-backup -c uncrustify.cfg ${crustified}"
+ echo "uncrustify --replace -c uncrustify.cfg ${crustified}"
echo "before committing."
+ exit $RET
+fi
+
+# Make sure we have no stupid spelling error
+if (which codespell > /dev/null)
+then
+ export REPORT=$(mktemp /tmp/codespellXXXXXX)
+ ( set -o pipefail;
+ echo "Checking for spelling errors with codespell..."
+ contrib/ci/jobs/0-codespell/job.sh src 2> ${REPORT};
+ ) || { echo "Please fix the code spell errors in ${REPORT} first"; exit 2; }
+else
+ echo "No codespell installed, skipping spell check."
+ echo "** Please consider installing codespell! **"
fi
-exit $RET
+
+
+# Make sure doxygen is happy with our annotations
+if (which doxygen > /dev/null)
+then
+ export REPORT=$(mktemp /tmp/doxygenXXXXXX)
+ [ -f doc/doxygen/Makefile ] && \
+ ( set -o pipefail;
+ echo "Checking that doxygen is happy..."
+ cd doc/doxygen;
+ make fast 2>&1 | tee ${REPORT} | (grep error:; exit 0);
+ ) || { echo "Please fix the errors reported by doxygen in ${REPORT} first"; exit 3; }
+else
+ echo "No doxygen installed, skipping check."
+ echo "** Please consider installing doxygen! **"
+fi
+
+echo "Commit is all clear!"
diff --git a/debian/changelog b/debian/changelog
@@ -1,3 +1,9 @@
+taler-merchant (0.14.1) unstable; urgency=low
+
+ * Release version 0.14.1
+
+ -- Christian Grothoff <grothoff@taler.net> Fri, 13 Dec 2024 16:35:43 +0200
+
taler-merchant (0.14.0-1) unstable; urgency=low
* Fix installation of taler-merchant-reconciliation and taler-merchant-exchangekeyupdate service files.
diff --git a/debian/control b/debian/control
@@ -8,8 +8,8 @@ Build-Depends:
autopoint,
debhelper-compat (= 12),
gettext,
- libgnunet-dev (>=0.22),
- libtalerexchange-dev (>=0.14.0),
+ libgnunet-dev (>=0.23.1),
+ libtalerexchange-dev (>=0.14.1),
libpq-dev (>=15.0),
po-debconf,
libqrencode-dev,
@@ -48,7 +48,7 @@ Pre-Depends:
${misc:Pre-Depends}
Depends:
libtalermerchant (= ${binary:Version}),
- libtalerexchange (>= 0.14.0),
+ libtalerexchange (>= 0.14.1),
adduser,
lsb-base,
netbase,
@@ -69,8 +69,8 @@ Package: libtalermerchant-dev
Section: libdevel
Architecture: any
Depends:
- libtalerexchange-dev (>= 0.14.0),
- libgnunet-dev (>=0.22),
+ libtalerexchange-dev (>= 0.14.1),
+ libgnunet-dev (>=0.22.3),
${misc:Depends},
${shlibs:Depends}
Description: libraries to talk to a GNU Taler merchant (development).
diff --git a/doc/doxygen/taler.doxy b/doc/doxygen/taler.doxy
@@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "GNU Taler: Merchant"
-PROJECT_NUMBER = 0.14.0
+PROJECT_NUMBER = 0.14.1
PROJECT_LOGO = logo.svg
OUTPUT_DIRECTORY = .
CREATE_SUBDIRS = YES
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c
@@ -111,9 +111,16 @@ parse_choices (void *cls,
for (unsigned int i = 0; i<*choices_len; i++)
{
+ struct TALER_MerchantContractChoice *choice = &(*choices)[i];
const json_t *jinputs;
const json_t *joutputs;
struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &choice->amount),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any ("max_fee",
+ &choice->max_fee),
+ NULL),
GNUNET_JSON_spec_array_const ("inputs",
&jinputs),
GNUNET_JSON_spec_array_const ("outputs",
@@ -122,7 +129,6 @@ parse_choices (void *cls,
};
const char *error_name;
unsigned int error_line;
- struct TALER_MerchantContractChoice *choice = &(*choices)[i];
if (GNUNET_OK !=
GNUNET_JSON_parse (json_array_get (root, i),
diff --git a/src/backend/taler-merchant-httpd_contract.h b/src/backend/taler-merchant-httpd_contract.h
@@ -231,6 +231,9 @@ struct TALER_MerchantContractOutput
*/
unsigned int count;
+ // FIXME: add support for clients picking a validity
+ // period in the future for output tokens!
+
} token;
} details;
@@ -242,6 +245,18 @@ struct TALER_MerchantContractOutput
*/
struct TALER_MerchantContractChoice
{
+
+ /**
+ * Amount to be paid for this choice.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Maximum fee the merchant is willing to pay for this choice.
+ * Set to an invalid amount to use instance defaults (zero or STEFAN).
+ */
+ struct TALER_Amount max_fee;
+
/**
* List of inputs the wallet must provision (all of them) to satisfy the
* conditions for the contract.
@@ -379,10 +394,9 @@ struct TALER_MerchantContractTokenFamily
} details;
};
+
/**
- * Struct to hold contract terms in v0 and v1 format. v0 contracts are modelled
- * as a v1 contract with a single choice and no inputs and outputs. Use the
- * version field to explicitly differentiate between v0 and v1 contracts.
+ * Struct to hold contract terms.
*/
struct TALER_MerchantContract
{
@@ -435,15 +449,8 @@ struct TALER_MerchantContract
* Jurisdiction of the business
*/
json_t *jurisdiction;
- } merchant;
- /**
- * Price to be paid for the transaction. Could be 0. The price is in addition
- * to other instruments, such as rations and tokens.
- * The exchange will subtract deposit fees from that amount
- * before transferring it to the merchant.
- */
- struct TALER_Amount brutto;
+ } merchant;
/**
* Summary of the contract.
@@ -530,44 +537,81 @@ struct TALER_MerchantContract
enum TALER_MerchantContractVersion version;
/**
- * Array of possible specific contracts the wallet/customer may choose
- * from by selecting the respective index when signing the deposit
- * confirmation.
+ * Details depending on the @e version.
*/
- struct TALER_MerchantContractChoice *choices;
+ union
+ {
- /**
- * Length of the @e choices array.
- */
- unsigned int choices_len;
+ /**
+ * Details for v0 contracts.
+ */
+ struct
+ {
- /**
- * Array of token authorities.
- */
- struct TALER_MerchantContractTokenFamily *token_authorities;
+ /**
+ * Price to be paid for the transaction. Could be 0. The price is in addition
+ * to other instruments, such as rations and tokens.
+ * The exchange will subtract deposit fees from that amount
+ * before transferring it to the merchant.
+ */
+ struct TALER_Amount brutto;
- /**
- * Length of the @e token_authorities array.
- */
- unsigned int token_authorities_len;
+ /**
+ * Maximum fee as given by the client request.
+ */
+ struct TALER_Amount max_fee;
- /**
- * Maximum fee as given by the client request.
- */
- struct TALER_Amount max_fee;
+ } v0;
+
+ /**
+ * Details for v1 contracts.
+ */
+ struct
+ {
+
+ /**
+ * Array of possible specific contracts the wallet/customer may choose
+ * from by selecting the respective index when signing the deposit
+ * confirmation.
+ */
+ struct TALER_MerchantContractChoice *choices;
+
+ /**
+ * Length of the @e choices array.
+ */
+ unsigned int choices_len;
+
+ /**
+ * Array of token authorities.
+ */
+ struct TALER_MerchantContractTokenFamily *token_authorities;
+
+ /**
+ * Length of the @e token_authorities array.
+ */
+ unsigned int token_authorities_len;
+
+ } v1;
+
+ } details;
+
+ // FIXME: Add exchanges array?
- // TODO: Add exchanges array
};
+
enum TALER_MerchantContractInputType
TMH_contract_input_type_from_string (const char *str);
+
enum TALER_MerchantContractOutputType
TMH_contract_output_type_from_string (const char *str);
+
const char *
TMH_string_from_contract_input_type (enum TALER_MerchantContractInputType t);
+
const char *
TMH_string_from_contract_output_type (enum TALER_MerchantContractOutputType t);
@@ -589,12 +633,14 @@ TMH_serialize_contract (const struct TALER_MerchantContract *contract,
json_t *exchanges,
json_t **out);
+
enum GNUNET_GenericReturnValue
TMH_serialize_contract_v0 (const struct TALER_MerchantContract *contract,
const struct TMH_MerchantInstance *instance,
json_t *exchanges,
json_t **out);
+
enum GNUNET_GenericReturnValue
TMH_serialize_contract_v1 (const struct TALER_MerchantContract *contract,
const struct TMH_MerchantInstance *instance,
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c
@@ -679,6 +679,7 @@ TMH_exchange_check_debit (
bool have_kyc = false;
struct TALER_Amount kyc_limit;
bool unlimited = true;
+ bool no_access_token = true;
if (NULL == keys)
return GNUNET_SYSERR;
@@ -686,7 +687,7 @@ TMH_exchange_check_debit (
max_amount->currency))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Currency missmatch: exchange %s uses %s, we need %s\n",
+ "Currency mismatch: exchange %s uses %s, we need %s\n",
exchange->url,
keys->currency,
max_amount->currency);
@@ -717,6 +718,7 @@ TMH_exchange_check_debit (
account at this exchange, if we have any, apply them */
}
GNUNET_free (np.normalized_payto);
+ if (keys->kyc_enabled)
{
bool kyc_ok = false;
json_t *jlimits = NULL;
@@ -727,6 +729,7 @@ TMH_exchange_check_debit (
instance_id,
exchange->url,
&kyc_ok,
+ &no_access_token,
&jlimits);
GNUNET_break (qs >= 0);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -797,45 +800,52 @@ TMH_exchange_check_debit (
TALER_amount_min (max_amount,
max_amount,
&kyc_limit);
- /* apply both deposit and transaction limits */
- if ( (! have_kyc) &&
- (TALER_EXCHANGE_keys_evaluate_zero_limits (
- keys,
- TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
- TALER_EXCHANGE_keys_evaluate_zero_limits (
- keys,
- TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION)) )
+ if (keys->kyc_enabled)
{
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (
- max_amount->currency,
- max_amount));
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Evaluating default limits of %s\n",
- exchange->url);
- TALER_EXCHANGE_keys_evaluate_hard_limits (
- keys,
- TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT,
- max_amount);
- TALER_EXCHANGE_keys_evaluate_hard_limits (
- keys,
- TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION,
- max_amount);
- if (TALER_EXCHANGE_keys_evaluate_zero_limits (
- keys,
- TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
- TALER_EXCHANGE_keys_evaluate_zero_limits (
- keys,
- TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION))
+ /* apply both deposit and transaction limits */
+ if ( (no_access_token) ||
+ ( (! have_kyc) &&
+ (TALER_EXCHANGE_keys_evaluate_zero_limits (
+ keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
+ TALER_EXCHANGE_keys_evaluate_zero_limits (
+ keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION)) ) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Operation is zero-limited by default\n");
+ "KYC requirements of %s not satisfied\n",
+ exchange->url);
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (max_amount->currency,
- max_amount));
+ TALER_amount_set_zero (
+ max_amount->currency,
+ max_amount));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Evaluating default limits of %s\n",
+ exchange->url);
+ TALER_EXCHANGE_keys_evaluate_hard_limits (
+ keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT,
+ max_amount);
+ TALER_EXCHANGE_keys_evaluate_hard_limits (
+ keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION,
+ max_amount);
+ if (TALER_EXCHANGE_keys_evaluate_zero_limits (
+ keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
+ TALER_EXCHANGE_keys_evaluate_zero_limits (
+ keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Operation is zero-limited by default\n");
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (max_amount->currency,
+ max_amount));
+ }
}
}
return account_ok ? GNUNET_YES : GNUNET_NO;
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -107,7 +107,7 @@ enum PayPhase
PP_VALIDATE_TOKENS,
/**
- * Contract has been paid.
+ * Check if contract has been paid.
*/
PP_CONTRACT_PAID,
@@ -365,6 +365,8 @@ struct ExchangeGroup
*/
struct PayContext
{
+ // FIXME: group more entries by phase that initializes them,
+ // like we do for 'validate_tokens'.
/**
* Stored in a DLL.
@@ -404,16 +406,6 @@ struct PayContext
struct TokenEnvelope *token_envelopes;
/**
- * Array with @e choices_len choices from the contract terms.
- */
- struct TALER_MerchantContractChoice *choices;
-
- /**
- * Array with @e token_families_len token families from the contract terms.
- */
- struct TALER_MerchantContractTokenFamily *token_families;
-
- /**
* MHD connection to return to
*/
struct MHD_Connection *connection;
@@ -498,6 +490,7 @@ struct PayContext
*/
struct TALER_PrivateContractHashP h_contract_terms;
+
/**
* "h_wire" from @e contract_terms. Used to identify
* the instance's wire transfer method.
@@ -505,19 +498,83 @@ struct PayContext
struct TALER_MerchantWireHashP h_wire;
/**
- * Maximum fee the merchant is willing to pay, from @e root.
- * Note that IF the total fee of the exchange is higher, that is
- * acceptable to the merchant if the customer is willing to
- * pay the difference
- * (i.e. amount - max_fee <= actual_amount - actual_fee).
+ * Version of the contract terms.
*/
- struct TALER_Amount max_fee;
+ enum TALER_MerchantContractVersion version;
/**
- * Amount from @e root. This is the amount the merchant expects
- * to make, minus @e max_fee.
+ * @e version dependent details from our contract.
*/
- struct TALER_Amount amount;
+ union
+ {
+
+ struct
+ {
+ /**
+ * Maximum fee the merchant is willing to pay, from @e root.
+ * Note that IF the total fee of the exchange is higher, that is
+ * acceptable to the merchant if the customer is willing to
+ * pay the difference
+ * (i.e. amount - max_fee <= actual_amount - actual_fee).
+ */
+ struct TALER_Amount max_fee;
+
+ /**
+ * Amount from @e root. This is the amount the merchant expects
+ * to make, minus @e max_fee.
+ */
+ struct TALER_Amount amount;
+ } v0;
+
+ struct
+ {
+
+ /**
+ * Array with @e choices_len choices from the contract terms.
+ */
+ struct TALER_MerchantContractChoice *choices;
+
+ /**
+ * Array with @e token_families_len token families from the contract terms.
+ */
+ struct TALER_MerchantContractTokenFamily *token_families;
+
+ /**
+ * Length of the @e choices array.
+ */
+ unsigned int choices_len;
+
+ /**
+ * Length of the @e token_families array.
+ */
+ unsigned int token_families_len;
+
+ } v1;
+
+ } details;
+
+ /**
+ * Results from the phase_validate_tokens()
+ */
+ struct
+ {
+
+ /**
+ * Maximum fee the merchant is willing to pay, from @e root.
+ * Note that IF the total fee of the exchange is higher, that is
+ * acceptable to the merchant if the customer is willing to
+ * pay the difference
+ * (i.e. amount - max_fee <= actual_amount - actual_fee).
+ */
+ struct TALER_Amount max_fee;
+
+ /**
+ * Amount from @e root. This is the amount the merchant expects
+ * to make, minus @e max_fee.
+ */
+ struct TALER_Amount brutto;
+
+ } validate_tokens;
/**
* Considering all the coins with the "found_in_db" flag
@@ -600,16 +657,6 @@ struct PayContext
unsigned int output_tokens_len;
/**
- * Length of the @e choices array.
- */
- unsigned int choices_len;
-
- /**
- * Length of the @e token_families array.
- */
- unsigned int token_families_len;
-
- /**
* Number of exchanges involved in the payment. Length
* of the @e eg array.
*/
@@ -879,7 +926,7 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
uint32_t off = 0;
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&total_without_fees));
for (size_t i = 0; i<pc->coins_cnt; i++)
{
@@ -1691,7 +1738,7 @@ phase_success_response (struct PayContext *pc)
? NULL
: TALER_build_pos_confirmation (pc->pos_key,
pc->pos_alg,
- &pc->amount,
+ &pc->validate_tokens.brutto,
pc->timestamp);
token_sigs = (0 >= pc->output_tokens_len)
? NULL
@@ -1903,9 +1950,9 @@ check_payment_sufficient (struct PayContext *pc)
struct TALER_Amount total_needed;
if (0 == pc->coins_cnt)
- return TALER_amount_is_zero (&pc->amount);
+ return TALER_amount_is_zero (&pc->validate_tokens.brutto);
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&total_wire_fee));
for (unsigned int i = 0; i < pc->num_exchanges; i++)
{
@@ -1942,10 +1989,10 @@ check_payment_sufficient (struct PayContext *pc)
* amount with fee / and wire fee, for all the coins.
*/
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&acc_fee));
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&acc_amount));
for (size_t i = 0; i<pc->coins_cnt; i++)
{
@@ -2013,7 +2060,7 @@ check_payment_sufficient (struct PayContext *pc)
TALER_amount2s (&total_wire_fee));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Deposit fee limit for merchant: %s\n",
- TALER_amount2s (&pc->max_fee));
+ TALER_amount2s (&pc->validate_tokens.max_fee));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Total refunded amount: %s\n",
TALER_amount2s (&pc->total_refunded));
@@ -2049,7 +2096,7 @@ check_payment_sufficient (struct PayContext *pc)
"Overflow adding up amounts"));
return false;
}
- if (-1 == TALER_amount_cmp (&pc->max_fee,
+ if (-1 == TALER_amount_cmp (&pc->validate_tokens.max_fee,
&acc_fee))
{
/**
@@ -2063,12 +2110,12 @@ check_payment_sufficient (struct PayContext *pc)
GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
TALER_amount_subtract (&excess_fee,
&acc_fee,
- &pc->max_fee));
+ &pc->validate_tokens.max_fee));
/* add that to the total */
if (0 >
TALER_amount_add (&total_needed,
&excess_fee,
- &pc->amount))
+ &pc->validate_tokens.brutto))
{
GNUNET_break (0);
pay_end (pc,
@@ -2084,7 +2131,7 @@ check_payment_sufficient (struct PayContext *pc)
{
/* Fees are fully covered by the merchant, all we require
is that the total payment is not below the contract's amount */
- total_needed = pc->amount;
+ total_needed = pc->validate_tokens.brutto;
}
/* Do not count refunds towards the payment */
@@ -2123,7 +2170,7 @@ check_payment_sufficient (struct PayContext *pc)
return false;
}
if (-1 < TALER_amount_cmp (&acc_amount,
- &pc->amount))
+ &pc->validate_tokens.brutto))
{
GNUNET_break_op (0);
pay_end (pc,
@@ -2181,13 +2228,13 @@ phase_execute_pay_transaction (struct PayContext *pc)
(used in check_coin_paid(), check_coin_refunded()
and check_payment_sufficient()). */
GNUNET_break (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&pc->total_paid));
GNUNET_break (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&pc->total_fees_paid));
GNUNET_break (GNUNET_OK ==
- TALER_amount_set_zero (pc->amount.currency,
+ TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
&pc->total_refunded));
for (size_t i = 0; i<pc->coins_cnt; i++)
pc->dc[i].found_in_db = false;
@@ -2281,7 +2328,8 @@ phase_execute_pay_transaction (struct PayContext *pc)
TALER_MHD_reply_with_error (pc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- pc->amount.currency));
+ pc->validate_tokens.brutto.currency))
+ ;
return;
}
}
@@ -2647,20 +2695,23 @@ sign_token_envelopes (struct PayContext *pc,
* @param slug slug to search for
* @return NULL if @a slug was not found
*/
-static struct TALER_MerchantContractTokenFamily *
+static const struct TALER_MerchantContractTokenFamily *
find_family (const struct PayContext *pc,
const char *slug)
{
- for (unsigned int i = 0; i<pc->token_families_len; i++)
+ for (unsigned int i = 0; i<pc->details.v1.token_families_len; i++)
{
- if (0 == strcmp (pc->token_families[i].slug,
+ const struct TALER_MerchantContractTokenFamily *tfi
+ = &pc->details.v1.token_families[i];
+
+ if (0 == strcmp (tfi->slug,
slug))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Token family %s found with %u keys\n",
slug,
- pc->token_families[i].keys_len);
- return &pc->token_families[i];
+ tfi->keys_len);
+ return tfi;
}
}
return NULL;
@@ -2678,178 +2729,173 @@ find_family (const struct PayContext *pc,
static void
phase_validate_tokens (struct PayContext *pc)
{
- if (NULL == pc->choices || 0 >= pc->choices_len)
+ switch (pc->version)
{
+ case TALER_MCV_V0:
/* No tokens to validate */
pc->phase = PP_PAY_TRANSACTION;
- return;
- }
-
- if (pc->choice_index < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Order `%s' has non-empty choices array but"
- "request is missing 'choice_index' field\n",
- pc->order_id);
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING,
- NULL));
- return;
- }
-
- if (pc->choice_index >= pc->choices_len)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Order `%s' has choices array with %u elements but "
- "request has 'choice_index' field with value %ld\n",
- pc->order_id,
- pc->choices_len,
- pc->choice_index);
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
- NULL));
- return;
- }
-
- {
- const struct TALER_MerchantContractChoice *selected
- = &pc->choices[pc->choice_index];
-
- for (unsigned int i = 0; i<selected->inputs_len; i++)
+ pc->validate_tokens.max_fee = pc->details.v0.max_fee;
+ pc->validate_tokens.brutto = pc->details.v0.amount;
+ break;
+ case TALER_MCV_V1:
{
- const struct TALER_MerchantContractInput *input
- = &selected->inputs[i];
- const struct TALER_MerchantContractTokenFamily *family;
+ const struct TALER_MerchantContractChoice *selected
+ = &pc->details.v1.choices[pc->choice_index];
- if (input->type != TALER_MCIT_TOKEN)
- {
- /* only validate inputs of type token (for now) */
- continue;
- }
+ pc->validate_tokens.max_fee = selected->max_fee;
+ pc->validate_tokens.brutto = selected->amount;
- family = find_family (pc,
- input->details.token.token_family_slug);
- if (NULL == family)
- {
- /* this should never happen, since the choices and
- token families are validated on insert. */
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "token family not found in order"));
- return;
- }
- if (GNUNET_NO ==
- find_valid_input_tokens (pc,
- family,
- i,
- input->details.token.count))
+ for (unsigned int i = 0; i<selected->inputs_len; i++)
{
- /* Error is already scheduled from find_valid_input_token. */
- return;
- }
- }
+ const struct TALER_MerchantContractInput *input
+ = &selected->inputs[i];
+ const struct TALER_MerchantContractTokenFamily *family;
- GNUNET_array_grow (pc->output_tokens,
- pc->output_tokens_len,
- selected->outputs_len);
-
- for (unsigned int i = 0; i<selected->outputs_len; i++)
- {
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_MERCHANTDB_TokenFamilyKeyDetails details;
- const struct TALER_MerchantContractOutput *output
- = &selected->outputs[i];
- struct TALER_MerchantContractTokenFamily *family;
- struct TALER_MerchantContractTokenFamilyKey *key;
+ if (input->type != TALER_MCIT_TOKEN)
+ {
+ /* only validate inputs of type token (for now) */
+ continue;
+ }
- if (output->type != TALER_MCOT_TOKEN)
- {
- /* only validate outputs of type tokens (for now) */
- continue;
+ family = find_family (pc,
+ input->details.token.token_family_slug);
+ if (NULL == family)
+ {
+ /* this should never happen, since the choices and
+ token families are validated on insert. */
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "token family not found in order"));
+ return;
+ }
+ if (GNUNET_NO ==
+ find_valid_input_tokens (pc,
+ family,
+ i,
+ input->details.token.count))
+ {
+ /* Error is already scheduled from find_valid_input_token. */
+ return;
+ }
}
- family = find_family (pc,
- output->details.token.token_family_slug);
- if (NULL == family)
- {
- /* this should never happen, since the choices and
- token families are validated on insert. */
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "token family not found in order"));
- return;
- }
- if (output->details.token.key_index >= family->keys_len)
- {
- /* this should never happen, since the choices and
- token families are validated on insert. */
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "key index invalid for token family"));
- return;
- }
- key = &family->keys[output->details.token.key_index];
- qs = TMH_db->lookup_token_family_key (
- TMH_db->cls,
- pc->hc->instance->settings.id,
- family->slug,
- pc->timestamp,
- pc->pay_deadline,
- &details);
- if (qs <= 0)
+ GNUNET_array_grow (pc->output_tokens,
+ pc->output_tokens_len,
+ selected->outputs_len);
+
+ for (unsigned int i = 0; i<selected->outputs_len; i++)
{
- GNUNET_log (
- GNUNET_ERROR_TYPE_ERROR,
- "Did not find key for %s at [%llu,%llu]\n",
- family->slug,
- (unsigned long long) pc->timestamp.abs_time.abs_value_us,
- (unsigned long long) pc->pay_deadline.abs_time.abs_value_us);
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL));
- return;
- }
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_MERCHANTDB_TokenFamilyKeyDetails details;
+ const struct TALER_MerchantContractOutput *output
+ = &selected->outputs[i];
+ const struct TALER_MerchantContractTokenFamily *family;
+ struct TALER_MerchantContractTokenFamilyKey *key;
+
+ if (output->type != TALER_MCOT_TOKEN)
+ {
+ /* only validate outputs of type tokens (for now) */
+ continue;
+ }
- GNUNET_assert (NULL != details.priv.private_key);
+ family = find_family (pc,
+ output->details.token.token_family_slug);
+ if (NULL == family)
+ {
+ /* this should never happen, since the choices and
+ token families are validated on insert. */
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "token family not found in order"));
+ return;
+ }
+ if (output->details.token.key_index >= family->keys_len)
+ {
+ /* this should never happen, since the choices and
+ token families are validated on insert. */
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "key index invalid for token family"));
+ return;
+ }
+ key = &family->keys[output->details.token.key_index];
+ qs = TMH_db->lookup_token_family_key (
+ TMH_db->cls,
+ pc->hc->instance->settings.id,
+ family->slug,
+ pc->timestamp,
+ pc->pay_deadline,
+ &details);
+ if (qs <= 0)
+ {
+ GNUNET_log (
+ GNUNET_ERROR_TYPE_ERROR,
+ "Did not find key for %s at [%llu,%llu]\n",
+ family->slug,
+ (unsigned long long) pc->timestamp.abs_time.abs_value_us,
+ (unsigned long long) pc->pay_deadline.abs_time.abs_value_us);
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL));
+ return;
+ }
- if (GNUNET_OK !=
- sign_token_envelopes (pc,
- key,
- &details.priv,
- /* TODO: Use critical field stored in database here instead. */
- details.token_family.kind ==
- TALER_MERCHANTDB_TFK_Subscription,
- i,
- output->details.token.count))
- {
- /* Error is already scheduled from sign_token_envelopes. */
- return;
+ GNUNET_assert (NULL != details.priv.private_key);
+
+ if (GNUNET_OK !=
+ sign_token_envelopes (pc,
+ key,
+ &details.priv,
+ /* TODO: Use critical field stored in database here instead. */
+ details.token_family.kind ==
+ TALER_MERCHANTDB_TFK_Subscription,
+ i,
+ output->details.token.count))
+ {
+ /* Error is already scheduled from sign_token_envelopes. */
+ return;
+ }
}
+ }
+ }
+ for (size_t i = 0; i<pc->coins_cnt; i++)
+ {
+ const struct DepositConfirmation *dc = &pc->dc[i];
+
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&dc->cdd.amount,
+ &pc->validate_tokens.brutto))
+ {
+ GNUNET_break_op (0);
+ fprintf (stderr,
+ "HERE (%u): %s != %s\n",
+ (unsigned int) pc->version,
+ dc->cdd.amount.currency,
+ TALER_amount2s (&pc->validate_tokens.brutto));
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ pc->validate_tokens.brutto.currency));
+ return;
}
}
@@ -3174,16 +3220,17 @@ phase_check_contract (struct PayContext *pc)
/* Get details from contract and check fundamentals */
{
const char *fulfillment_url = NULL;
+ uint64_t version = 0;
struct GNUNET_JSON_Specification espec[] = {
- TALER_JSON_spec_amount_any ("amount",
- &pc->amount),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("version",
+ &version),
+ NULL),
GNUNET_JSON_spec_mark_optional (
/* This one does not have to be a Web URL */
GNUNET_JSON_spec_string ("fulfillment_url",
&fulfillment_url),
NULL),
- TALER_JSON_spec_amount_any ("max_fee",
- &pc->max_fee),
GNUNET_JSON_spec_timestamp ("timestamp",
&pc->timestamp),
GNUNET_JSON_spec_timestamp ("refund_deadline",
@@ -3192,16 +3239,6 @@ phase_check_contract (struct PayContext *pc)
&pc->pay_deadline),
GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
&pc->wire_transfer_deadline),
- GNUNET_JSON_spec_mark_optional (
- TALER_JSON_spec_choices ("choices",
- &pc->choices,
- &pc->choices_len),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- TALER_JSON_spec_token_families ("token_families",
- &pc->token_families,
- &pc->token_families_len),
- NULL),
GNUNET_JSON_spec_fixed_auto ("h_wire",
&pc->h_wire),
GNUNET_JSON_spec_mark_optional (
@@ -3216,8 +3253,6 @@ phase_check_contract (struct PayContext *pc)
res = TALER_MHD_parse_internal_json_data (pc->connection,
pc->contract_terms,
espec);
- if (NULL != fulfillment_url)
- pc->fulfillment_url = GNUNET_strdup (fulfillment_url);
if (GNUNET_YES != res)
{
GNUNET_break (0);
@@ -3227,41 +3262,131 @@ phase_check_contract (struct PayContext *pc)
: MHD_NO);
return;
}
- }
-
- if (GNUNET_OK !=
- TALER_amount_cmp_currency (&pc->max_fee,
- &pc->amount))
- {
- GNUNET_break (0);
- pay_end (pc,
- TALER_MHD_reply_with_error (
- pc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "'max_fee' in database does not match currency of contract price"));
- return;
- }
-
- for (size_t i = 0; i<pc->coins_cnt; i++)
- {
- struct DepositConfirmation *dc = &pc->dc[i];
-
- if (GNUNET_OK !=
- TALER_amount_cmp_currency (&dc->cdd.amount,
- &pc->amount))
+ if (NULL != fulfillment_url)
+ pc->fulfillment_url = GNUNET_strdup (fulfillment_url);
+ switch (version)
{
- GNUNET_break_op (0);
+ case 0:
+ {
+ struct GNUNET_JSON_Specification v0spec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &pc->details.v0.amount),
+ TALER_JSON_spec_amount_any ("max_fee",
+ &pc->details.v0.max_fee),
+ GNUNET_JSON_spec_end ()
+ };
+ res = TALER_MHD_parse_internal_json_data (pc->connection,
+ pc->contract_terms,
+ v0spec);
+ if (GNUNET_YES != res)
+ {
+ GNUNET_break (0);
+ pay_end (pc,
+ (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&pc->details.v0.max_fee,
+ &pc->details.v0.amount))
+ {
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "'max_fee' in database does not match currency of contract price"));
+ return;
+ }
+
+ if (pc->choice_index > 0)
+ {
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
+ "contract terms v0 has no choices"));
+ return;
+ }
+ }
+ pc->version = TALER_MCV_V0;
+ break;
+ case 1:
+ {
+ struct GNUNET_JSON_Specification v1spec[] = {
+ TALER_JSON_spec_choices ("choices",
+ &pc->details.v1.choices,
+ &pc->details.v1.choices_len),
+ TALER_JSON_spec_token_families ("token_families",
+ &pc->details.v1.token_families,
+ &pc->details.v1.token_families_len),
+ GNUNET_JSON_spec_end ()
+ };
+ res = TALER_MHD_parse_internal_json_data (pc->connection,
+ pc->contract_terms,
+ v1spec);
+ if (GNUNET_YES != res)
+ {
+ GNUNET_break (0);
+ pay_end (pc,
+ (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO);
+ return;
+ }
+ if (pc->choice_index < 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Order `%s' has non-empty choices array but"
+ "request is missing 'choice_index' field\n",
+ pc->order_id);
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING,
+ NULL));
+ return;
+ }
+ if (pc->choice_index >= pc->details.v1.choices_len)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Order `%s' has choices array with %u elements but "
+ "request has 'choice_index' field with value %ld\n",
+ pc->order_id,
+ pc->details.v1.choices_len,
+ pc->choice_index);
+ GNUNET_break (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
+ NULL));
+ return;
+ }
+ }
+ pc->version = TALER_MCV_V1;
+ break;
+ default:
+ GNUNET_break (0);
pay_end (pc,
TALER_MHD_reply_with_error (
pc->connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- pc->amount.currency));
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "contract 'version' in database not supported by this backend")
+ );
return;
}
}
+
if (GNUNET_TIME_timestamp_cmp (pc->wire_transfer_deadline,
<,
pc->refund_deadline))
@@ -3288,7 +3413,7 @@ phase_check_contract (struct PayContext *pc)
return;
}
- /* Make sure wire method (still) exists for this instance */
+/* Make sure wire method (still) exists for this instance */
{
struct TMH_WireMethod *wm;
@@ -3753,25 +3878,32 @@ pay_context_cleanup (void *cls)
GNUNET_free (eg);
}
GNUNET_free (pc->egs);
- for (unsigned int i = 0; i< pc->token_families_len; i++)
+ switch (pc->version)
{
- struct TALER_MerchantContractTokenFamily *tf
- = &pc->token_families[i];
-
- GNUNET_free (tf->slug);
- GNUNET_free (tf->name);
- GNUNET_free (tf->description);
- json_decref (tf->description_i18n);
- for (unsigned int j = 0; j<tf->keys_len; j++)
+ case TALER_MCV_V0:
+ break;
+ case TALER_MCV_V1:
+ for (unsigned int i = 0; i< pc->details.v1.token_families_len; i++)
{
- struct TALER_MerchantContractTokenFamilyKey *key
- = &tf->keys[j];
+ struct TALER_MerchantContractTokenFamily *tf
+ = &pc->details.v1.token_families[i];
- TALER_token_issue_pub_free (&key->pub);
+ GNUNET_free (tf->slug);
+ GNUNET_free (tf->name);
+ GNUNET_free (tf->description);
+ json_decref (tf->description_i18n);
+ for (unsigned int j = 0; j<tf->keys_len; j++)
+ {
+ struct TALER_MerchantContractTokenFamilyKey *key
+ = &tf->keys[j];
+
+ TALER_token_issue_pub_free (&key->pub);
+ }
+ GNUNET_free (tf->keys);
}
- GNUNET_free (tf->keys);
+ GNUNET_free (pc->details.v1.token_families);
+ break;
}
- GNUNET_free (pc->token_families);
if (NULL != pc->response)
{
MHD_destroy_response (pc->response);
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -247,10 +247,6 @@ struct OrderContext
*/
struct
{
- /**
- * Version of the contract terms.
- */
- enum TALER_MerchantContractVersion version;
/**
* Our order ID.
@@ -295,11 +291,6 @@ struct OrderContext
const char *public_reorder_url;
/**
- * Array of contract choices. Is null for v0 contracts.
- */
- const json_t *choices;
-
- /**
* Merchant base URL.
*/
char *merchant_base_url;
@@ -335,17 +326,6 @@ struct OrderContext
const json_t *delivery_location;
/**
- * Gross amount value of the contract. Used to
- * compute @e max_stefan_fee.
- */
- struct TALER_Amount brutto;
-
- /**
- * Maximum fee as given by the client request.
- */
- struct TALER_Amount max_fee;
-
- /**
* Specifies for how long the wallet should try to get an
* automatic refund for the purchase.
*/
@@ -367,6 +347,45 @@ struct OrderContext
*/
uint32_t minimum_age;
+ /**
+ * Version of the contract terms.
+ */
+ enum TALER_MerchantContractVersion version;
+
+ /**
+ * Details present depending on @e version.
+ */
+ union
+ {
+ /**
+ * Details only present for v0.
+ */
+ struct
+ {
+ /**
+ * Gross amount value of the contract. Used to
+ * compute @e max_stefan_fee.
+ */
+ struct TALER_Amount brutto;
+
+ /**
+ * Maximum fee as given by the client request.
+ */
+ struct TALER_Amount max_fee;
+ } v0;
+
+ /**
+ * Details only present for v1.
+ */
+ struct
+ {
+ /**
+ * Array of contract choices. Is null for v0 contracts.
+ */
+ const json_t *choices;
+ } v1;
+ } details;
+
} parse_order;
/**
@@ -445,18 +464,16 @@ struct OrderContext
bool exchange_good;
/**
- * Maximum fee for @e order based on STEFAN curves.
- * Used to set @e max_fee if not provided as part of
- * @e order.
+ * Array of maximum amounts that could be paid over all
+ * available exchanges. Used to determine if this
+ * order creation requests exceeds legal limits.
*/
- struct TALER_Amount max_stefan_fee;
+ struct TALER_Amount *total_exchange_limits;
/**
- * Maximum amount that could be paid over all
- * available exchanges. Used to determine if this
- * order creation requests exceeds legal limits.
+ * Length of the @e total_exchange_limits array.
*/
- struct TALER_Amount total_exchange_limit;
+ unsigned int num_total_exchange_limits;
/**
* How long do we wait at most until giving up on getting keys?
@@ -468,6 +485,43 @@ struct OrderContext
*/
struct GNUNET_SCHEDULER_Task *wakeup_task;
+ /**
+ * Details depending on the contract version.
+ */
+ union
+ {
+
+ /**
+ * Details for contract v0.
+ */
+ struct
+ {
+ /**
+ * 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;
+
+ } v0;
+
+ /**
+ * Details for contract v1.
+ */
+ struct
+ {
+ /**
+ * Maximum fee for @e order based on STEFAN curves by
+ * contract choice.
+ * Used to set @e max_fee if not provided as part of
+ * @e order.
+ */
+ struct TALER_Amount *max_stefan_fees;
+
+ } v1;
+
+ } details;
+
} set_exchanges;
/**
@@ -475,10 +529,37 @@ struct OrderContext
*/
struct
{
+
/**
- * Maximum fee
+ * Details depending on the contract version.
*/
- struct TALER_Amount max_fee;
+ union
+ {
+
+ /**
+ * Details for contract v0.
+ */
+ struct
+ {
+ /**
+ * Maximum fee
+ */
+ struct TALER_Amount max_fee;
+ } v0;
+
+ /**
+ * Details for contract v1.
+ */
+ struct
+ {
+ /**
+ * Maximum fees by contract choice.
+ */
+ struct TALER_Amount *max_fees;
+
+ } v1;
+
+ } details;
} set_max_fee;
/**
@@ -693,6 +774,16 @@ clean_order (void *cls)
json_decref (oc->set_exchanges.exchanges);
oc->set_exchanges.exchanges = NULL;
}
+ GNUNET_free (oc->set_exchanges.total_exchange_limits);
+ switch (oc->parse_order.version)
+ {
+ case TALER_MCV_V0:
+ break;
+ case TALER_MCV_V1:
+ GNUNET_free (oc->set_max_fee.details.v1.max_fees);
+ GNUNET_free (oc->set_exchanges.details.v1.max_stefan_fees);
+ break;
+ }
if (NULL != oc->merge_inventory.products)
{
json_decref (oc->merge_inventory.products);
@@ -887,7 +978,6 @@ execute_transaction (struct OrderContext *oc)
}
{
- enum GNUNET_DB_QueryStatus wqs;
json_t *jhook;
jhook = GNUNET_JSON_PACK (
@@ -899,21 +989,21 @@ execute_transaction (struct OrderContext *oc)
oc->hc->instance->settings.id)
);
GNUNET_assert (NULL != jhook);
- wqs = TMH_trigger_webhook (oc->hc->instance->settings.id,
- "order_created",
- jhook);
+ qs = TMH_trigger_webhook (oc->hc->instance->settings.id,
+ "order_created",
+ jhook);
json_decref (jhook);
- if (0 > wqs)
+ if (0 > qs)
{
TMH_db->rollback (TMH_db->cls);
- if (GNUNET_DB_STATUS_SOFT_ERROR == wqs)
- return wqs;
- GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == wqs);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ return qs;
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
reply_with_error (oc,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED,
"failed to trigger webhooks");
- return wqs;
+ return qs;
}
}
@@ -1791,86 +1881,38 @@ add_output_token_family (struct OrderContext *oc,
/**
- * Serialize order into @a oc->serialize_order.contract,
- * ready to be stored in the database. Upon success, continue
- * processing with check_contract().
+ * Build JSON array that represents all of the token families
+ * in the contract.
*
- * @param[in,out] oc order context
+ * @param[in] v1-style order
+ * @return JSON array with token families for the contract
*/
-static void
-serialize_order (struct OrderContext *oc)
+static json_t *
+output_token_families (struct OrderContext *oc)
{
- const struct TALER_MERCHANTDB_InstanceSettings *settings =
- &oc->hc->instance->settings;
- json_t *merchant;
json_t *token_families = json_object ();
- json_t *choices = json_array ();
-
- merchant = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("name",
- settings->name),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("website",
- settings->website)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("email",
- settings->email)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("logo",
- settings->logo)));
- GNUNET_assert (NULL != merchant);
- {
- json_t *loca;
-
- /* Handle merchant address */
- loca = settings->address;
- if (NULL != loca)
- {
- loca = json_deep_copy (loca);
- GNUNET_assert (NULL != loca);
- GNUNET_assert (0 ==
- json_object_set_new (merchant,
- "address",
- loca));
- }
- }
- {
- json_t *juri;
-
- /* Handle merchant jurisdiction */
- juri = settings->jurisdiction;
- if (NULL != juri)
- {
- juri = json_deep_copy (juri);
- GNUNET_assert (NULL != juri);
- GNUNET_assert (0 ==
- json_object_set_new (merchant,
- "jurisdiction",
- juri));
- }
- }
+ GNUNET_assert (NULL != token_families);
for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
{
- json_t *keys = json_array ();
- struct TALER_MerchantContractTokenFamily *family
+ const struct TALER_MerchantContractTokenFamily *family
= &oc->parse_choices.token_families[i];
+ json_t *keys;
json_t *jfamily;
+ keys = json_array ();
+ GNUNET_assert (NULL != keys);
for (unsigned int j = 0; j<family->keys_len; j++)
{
- struct TALER_MerchantContractTokenFamilyKey key = family->keys[j];
-
+ const struct TALER_MerchantContractTokenFamilyKey *key
+ = &family->keys[j];
json_t *jkey = GNUNET_JSON_PACK (
- /* TODO: Remove h_pub. */
- GNUNET_JSON_pack_data_auto ("h_pub",
- &key.pub.public_key->pub_key_hash),
TALER_JSON_pack_token_pub ("public_key",
- &key.pub),
+ &key->pub),
GNUNET_JSON_pack_timestamp ("valid_after",
- key.valid_after),
+ key->valid_after),
GNUNET_JSON_pack_timestamp ("valid_before",
- key.valid_before)
+ key->valid_before)
);
GNUNET_assert (0 ==
@@ -1878,7 +1920,7 @@ serialize_order (struct OrderContext *oc)
jkey));
}
- /* TODO: Add 'details' field. */
+ /* FIXME: Add 'details' field. */
jfamily = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("name",
family->name),
@@ -1893,11 +1935,28 @@ serialize_order (struct OrderContext *oc)
family->critical)
);
- GNUNET_assert (0 == json_object_set_new (token_families,
- family->slug,
- jfamily));
+ GNUNET_assert (0 ==
+ json_object_set_new (token_families,
+ family->slug,
+ jfamily));
}
+ return token_families;
+}
+
+
+/**
+ * Build JSON array that represents all of the contract choices
+ * in the contract.
+ *
+ * @param[in] v1-style order
+ * @return JSON array with token families for the contract
+ */
+static json_t *
+output_contract_choices (struct OrderContext *oc)
+{
+ json_t *choices = json_array ();
+ GNUNET_assert (NULL != choices);
for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
{
const struct TALER_MerchantContractChoice *choice
@@ -1913,15 +1972,15 @@ serialize_order (struct OrderContext *oc)
= &choice->inputs[j];
json_t *jinput;
- /* For now, only tokens are supported */
+ /* For now, only tokens are supported for inputs */
GNUNET_assert (TALER_MCIT_TOKEN == input->type);
jinput = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("kind",
- TMH_string_from_contract_input_type (input->
- type)),
+ TMH_string_from_contract_input_type (
+ input->type)),
GNUNET_JSON_pack_string ("token_family_slug",
input->details.token.token_family_slug),
- GNUNET_JSON_pack_int64 ("number",
+ GNUNET_JSON_pack_int64 ("count",
input->details.token.count)
);
@@ -1936,19 +1995,47 @@ serialize_order (struct OrderContext *oc)
json_t *joutput;
/* For now, only tokens are supported */
- GNUNET_assert (TALER_MCOT_TOKEN == output->type);
-
- joutput = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("kind",
- TMH_string_from_contract_output_type (output->
- type)),
- GNUNET_JSON_pack_string ("token_family_slug",
- output->details.token.token_family_slug),
- GNUNET_JSON_pack_int64 ("number",
- output->details.token.count),
- GNUNET_JSON_pack_int64 ("key_index",
- output->details.token.key_index)
- );
+ switch (output->type)
+ {
+ case TALER_MCOT_INVALID:
+ /* How did we get here? */
+ GNUNET_assert (0);
+ /* mostly to make compiler happy... */
+ finalize_order (oc,
+ MHD_NO);
+ json_decref (choices);
+ return NULL;
+ case TALER_MCOT_TOKEN:
+ joutput = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("kind",
+ TMH_string_from_contract_output_type (
+ output->type)),
+ GNUNET_JSON_pack_string ("token_family_slug",
+ output->details.token.token_family_slug),
+ GNUNET_JSON_pack_int64 ("count",
+ output->details.token.count),
+ GNUNET_JSON_pack_int64 ("key_index",
+ output->details.token.key_index)
+ );
+ break;
+ case TALER_MCOT_COIN:
+ /* Not implemented, how did we get here? */
+ GNUNET_break (0);
+ reply_with_error (oc,
+ MHD_HTTP_NOT_IMPLEMENTED,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "currency conversion not supported");
+ json_decref (choices);
+ return NULL;
+ case TALER_MCOT_TAX_RECEIPT:
+ // FIXME: generate JSON for DONAU here instead of killing
+ // the connection!
+ GNUNET_break (0);
+ finalize_order (oc,
+ MHD_NO);
+ json_decref (choices);
+ return NULL;
+ }
GNUNET_assert (0 ==
json_array_append_new (outputs,
@@ -1958,6 +2045,10 @@ serialize_order (struct OrderContext *oc)
{
json_t *jchoice
= GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("amount",
+ &choice->amount),
+ TALER_JSON_pack_amount ("max_fee",
+ &oc->set_max_fee.details.v1.max_fees[i]),
GNUNET_JSON_pack_array_incref ("inputs",
inputs),
GNUNET_JSON_pack_array_incref ("outputs",
@@ -1968,6 +2059,67 @@ serialize_order (struct OrderContext *oc)
json_array_append_new (choices,
jchoice));
}
+ } /* for all choices */
+ return choices;
+}
+
+
+/**
+ * Serialize order into @a oc->serialize_order.contract,
+ * ready to be stored in the database. Upon success, continue
+ * processing with check_contract().
+ *
+ * @param[in,out] oc order context
+ */
+static void
+serialize_order (struct OrderContext *oc)
+{
+ const struct TALER_MERCHANTDB_InstanceSettings *settings =
+ &oc->hc->instance->settings;
+ json_t *merchant;
+
+ merchant = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("name",
+ settings->name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("website",
+ settings->website)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("email",
+ settings->email)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("logo",
+ settings->logo)));
+ GNUNET_assert (NULL != merchant);
+ {
+ json_t *loca;
+
+ /* Handle merchant address */
+ loca = settings->address;
+ if (NULL != loca)
+ {
+ loca = json_deep_copy (loca);
+ GNUNET_assert (NULL != loca);
+ GNUNET_assert (0 ==
+ json_object_set_new (merchant,
+ "address",
+ loca));
+ }
+ }
+ {
+ json_t *juri;
+
+ /* Handle merchant jurisdiction */
+ juri = settings->jurisdiction;
+ if (NULL != juri)
+ {
+ juri = json_deep_copy (juri);
+ GNUNET_assert (NULL != juri);
+ GNUNET_assert (0 ==
+ json_object_set_new (merchant,
+ "jurisdiction",
+ juri));
+ }
}
oc->serialize_order.contract = GNUNET_JSON_PACK (
@@ -1976,8 +2128,9 @@ serialize_order (struct OrderContext *oc)
GNUNET_JSON_pack_string ("summary",
oc->parse_order.summary),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("summary_i18n",
- (json_t *) oc->parse_order.summary_i18n)),
+ GNUNET_JSON_pack_object_incref (
+ "summary_i18n",
+ (json_t *) oc->parse_order.summary_i18n)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("public_reorder_url",
oc->parse_order.public_reorder_url)),
@@ -1985,10 +2138,9 @@ serialize_order (struct OrderContext *oc)
GNUNET_JSON_pack_string ("fulfillment_message",
oc->parse_order.fulfillment_message)),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("fulfillment_message_i18n",
- (json_t *) oc->parse_order.
- fulfillment_message_i18n))
- ,
+ GNUNET_JSON_pack_object_incref (
+ "fulfillment_message_i18n",
+ (json_t *) oc->parse_order.fulfillment_message_i18n)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_url",
oc->parse_order.fulfillment_url)),
@@ -2013,9 +2165,9 @@ serialize_order (struct OrderContext *oc)
GNUNET_JSON_pack_timestamp ("delivery_date",
oc->parse_order.delivery_date)),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("delivery_location",
- (json_t *) oc->parse_order.
- delivery_location)),
+ GNUNET_JSON_pack_object_incref (
+ "delivery_location",
+ (json_t *) oc->parse_order.delivery_location)),
GNUNET_JSON_pack_string ("merchant_base_url",
oc->parse_order.merchant_base_url),
GNUNET_JSON_pack_object_steal ("merchant",
@@ -2024,43 +2176,61 @@ serialize_order (struct OrderContext *oc)
&oc->hc->instance->merchant_pub),
GNUNET_JSON_pack_array_incref ("exchanges",
oc->set_exchanges.exchanges),
- TALER_JSON_pack_amount ("max_fee",
- &oc->set_max_fee.max_fee),
- TALER_JSON_pack_amount ("amount",
- &oc->parse_order.brutto),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_array_steal ("choices",
- choices)
- ),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_steal ("token_families",
- token_families)
- ),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("extra",
(json_t *) oc->parse_order.extra))
);
+ {
+ json_t *xtra;
+
+ switch (oc->parse_order.version)
+ {
+ case TALER_MCV_V0:
+ xtra = GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("max_fee",
+ &oc->set_max_fee.details.v0.max_fee),
+ TALER_JSON_pack_amount ("amount",
+ &oc->parse_order.details.v0.brutto));
+ break;
+ case TALER_MCV_V1:
+ {
+ json_t *token_families = output_token_families (oc);
+ json_t *choices = output_contract_choices (oc);
+
+ if ( (NULL == token_families) ||
+ (NULL == choices) )
+ {
+ GNUNET_break (0);
+ return;
+ }
+ xtra = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_array_steal ("choices",
+ choices),
+ GNUNET_JSON_pack_object_steal ("token_families",
+ token_families));
+ break;
+ }
+ default:
+ GNUNET_assert (0);
+ }
+ GNUNET_assert (0 ==
+ json_object_update (oc->serialize_order.contract,
+ xtra));
+ json_decref (xtra);
+ }
+
+
/* Pack does not work here, because it doesn't set zero-values for timestamps */
GNUNET_assert (0 ==
json_object_set_new (oc->serialize_order.contract,
"refund_deadline",
GNUNET_JSON_from_timestamp (
oc->parse_order.refund_deadline)));
-
- GNUNET_log (
- GNUNET_ERROR_TYPE_INFO,
- "Refund deadline for contact is %llu\n",
- (unsigned long long) oc->parse_order.refund_deadline.abs_time.abs_value_us);
- GNUNET_log (
- GNUNET_ERROR_TYPE_INFO,
- "Wallet timestamp for contact is %llu\n",
- (unsigned long long) oc->parse_order.timestamp.abs_time.abs_value_us);
-
- /* Pack does not work here, because it sets zero-values for relative times */
/* auto_refund should only be set if it is not 0 */
if (! GNUNET_TIME_relative_is_zero (oc->parse_order.auto_refund))
{
+ /* Pack does not work here, because it sets zero-values for relative times */
GNUNET_assert (0 ==
json_object_set_new (oc->serialize_order.contract,
"auto_refund",
@@ -2073,36 +2243,81 @@ serialize_order (struct OrderContext *oc)
/**
- * Set max_fee in @a oc based on STEFAN value if
- * not yet present. Upon success, continue
- * processing with serialize_order().
+ * Set @a max_fee in @a oc based on @a max_stefan_fee value if not overridden
+ * by @a client_fee. If neither is set, set the fee to zero using currency
+ * from @a brutto.
*
* @param[in,out] oc order context
+ * @param brutto brutto amount to compute fee for
+ * @param client_fee client-given fee override (or invalid)
+ * @param max_stefan_fee maximum STEFAN fee of any exchange
+ * @param max_fee set to the maximum stefan fee
*/
static void
-set_max_fee (struct OrderContext *oc)
+compute_fee (struct OrderContext *oc,
+ const struct TALER_Amount *brutto,
+ const struct TALER_Amount *client_fee,
+ const struct TALER_Amount *max_stefan_fee,
+ struct TALER_Amount *max_fee)
{
- const struct TALER_MERCHANTDB_InstanceSettings *settings =
- &oc->hc->instance->settings;
+ const struct TALER_MERCHANTDB_InstanceSettings *settings
+ = &oc->hc->instance->settings;
- if (GNUNET_OK !=
- TALER_amount_is_valid (&oc->parse_order.max_fee))
+ if (GNUNET_OK ==
+ TALER_amount_is_valid (client_fee))
{
- struct TALER_Amount stefan;
-
- if ( (settings->use_stefan) &&
- (GNUNET_OK ==
- TALER_amount_is_valid (&oc->set_exchanges.max_stefan_fee)) )
- stefan = oc->set_exchanges.max_stefan_fee;
- else
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (oc->parse_order.brutto.currency,
- &stefan));
- oc->set_max_fee.max_fee = stefan;
+ *max_fee = *client_fee;
+ return;
}
- else
+ if ( (settings->use_stefan) &&
+ (NULL != max_stefan_fee) &&
+ (GNUNET_OK ==
+ TALER_amount_is_valid (max_stefan_fee)) )
+ {
+ *max_fee = *max_stefan_fee;
+ return;
+ }
+ GNUNET_assert (
+ GNUNET_OK ==
+ TALER_amount_set_zero (brutto->currency,
+ max_fee));
+}
+
+
+/**
+ * Initialize "set_max_fee" in @a oc based on STEFAN value or client
+ * preference. Upon success, continue processing in next phase.
+ *
+ * @param[in,out] oc order context
+ */
+static void
+set_max_fee (struct OrderContext *oc)
+{
+ switch (oc->parse_order.version)
{
- oc->set_max_fee.max_fee = oc->parse_order.max_fee;
+ case TALER_MCV_V0:
+ compute_fee (oc,
+ &oc->parse_order.details.v0.brutto,
+ &oc->parse_order.details.v0.max_fee,
+ &oc->set_exchanges.details.v0.max_stefan_fee,
+ &oc->set_max_fee.details.v0.max_fee);
+ break;
+ case TALER_MCV_V1:
+ oc->set_max_fee.details.v1.max_fees
+ = GNUNET_new_array (oc->parse_choices.choices_len,
+ struct TALER_Amount);
+ for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
+ compute_fee (oc,
+ &oc->parse_choices.choices[i].amount,
+ &oc->parse_choices.choices[i].max_fee,
+ NULL != oc->set_exchanges.details.v1.max_stefan_fees
+ ? &oc->set_exchanges.details.v1.max_stefan_fees[i]
+ : NULL,
+ &oc->set_max_fee.details.v1.max_fees[i]);
+ break;
+ default:
+ GNUNET_break (0);
+ break;
}
oc->phase++;
}
@@ -2131,63 +2346,103 @@ resume_with_keys (struct OrderContext *oc)
/**
- * Update MAX STEFAN fees based on @a keys.
+ * Given a @a brutto amount for exchange with @a keys, set the
+ * @a stefan_fee. Note that @a stefan_fee is updated to the maximum
+ * of the input and the computed fee.
*
- * @param[in,out] oc order context to update
- * @param keys keys to derive STEFAN fees from
+ * @param[in,out] oc order context
+ * @param brutto some brutto amount the client is to pay
+ * @param[in,out] stefan_fee set to STEFAN fee to be paid by the merchant
*/
static void
-update_stefan (struct OrderContext *oc,
- const struct TALER_EXCHANGE_Keys *keys)
+compute_stefan_fee (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_Amount *brutto,
+ struct TALER_Amount *stefan_fee)
{
struct TALER_Amount net;
if (GNUNET_SYSERR !=
TALER_EXCHANGE_keys_stefan_b2n (keys,
- &oc->parse_order.brutto,
+ brutto,
&net))
{
struct TALER_Amount fee;
TALER_EXCHANGE_keys_stefan_round (keys,
&net);
- if (-1 == TALER_amount_cmp (&oc->parse_order.brutto,
+ if (-1 == TALER_amount_cmp (brutto,
&net))
{
/* brutto < netto! */
/* => after rounding, there is no real difference */
- net = oc->parse_order.brutto;
+ net = *brutto;
}
GNUNET_assert (0 <=
TALER_amount_subtract (&fee,
- &oc->parse_order.brutto,
+ brutto,
&net));
if ( (GNUNET_OK !=
- TALER_amount_is_valid (&oc->set_exchanges.max_stefan_fee)) ||
- (-1 == TALER_amount_cmp (&oc->set_exchanges.max_stefan_fee,
+ TALER_amount_is_valid (stefan_fee)) ||
+ (-1 == TALER_amount_cmp (stefan_fee,
&fee)) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Updated STEFAN-based fee to %s\n",
TALER_amount2s (&fee));
- oc->set_exchanges.max_stefan_fee = fee;
+ *stefan_fee = fee;
}
}
}
/**
+ * 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)
+{
+ switch (oc->parse_order.version)
+ {
+ case TALER_MCV_V0:
+ compute_stefan_fee (keys,
+ &oc->parse_order.details.v0.brutto,
+ &oc->set_exchanges.details.v0.max_stefan_fee);
+ break;
+ case TALER_MCV_V1:
+ oc->set_exchanges.details.v1.max_stefan_fees
+ = GNUNET_new_array (oc->parse_choices.choices_len,
+ struct TALER_Amount);
+ for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
+ if (0 == strcasecmp (keys->currency,
+ oc->parse_choices.choices[i].amount.currency))
+ compute_stefan_fee (keys,
+ &oc->parse_choices.choices[i].amount,
+ &oc->set_exchanges.details.v1.max_stefan_fees[i]);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
* Compute the set of exchanges that would be acceptable
* for this order.
*
* @param cls our `struct OrderContext`
* @param url base URL of an exchange (not used)
* @param exchange internal handle for the exchange
+ * @param max_needed maximum amount needed in this currency
*/
static void
get_acceptable (void *cls,
const char *url,
- const struct TMH_Exchange *exchange)
+ const struct TMH_Exchange *exchange,
+ const struct TALER_Amount *max_needed)
{
struct OrderContext *oc = cls;
unsigned int priority = 42; /* make compiler happy */
@@ -2195,7 +2450,7 @@ get_acceptable (void *cls,
enum GNUNET_GenericReturnValue res;
struct TALER_Amount max_amount;
- max_amount = oc->parse_order.brutto;
+ max_amount = *max_needed;
res = TMH_exchange_check_debit (
oc->hc->instance->settings.id,
exchange,
@@ -2206,8 +2461,7 @@ get_acceptable (void *cls,
url,
res,
TALER_amount2s (&max_amount));
- if ( (! TALER_amount_is_zero (&max_amount)) &&
- (TALER_amount_is_zero (&max_amount)) )
+ if (TALER_amount_is_zero (&max_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Exchange %s deposit limit is zero, skipping it\n",
@@ -2237,17 +2491,44 @@ get_acceptable (void *cls,
"Exchange %s deposit limit is %s, adding it!\n",
url,
TALER_amount2s (&max_amount));
- GNUNET_assert (0 <=
- TALER_amount_add (
- &oc->set_exchanges.total_exchange_limit,
- &oc->set_exchanges.total_exchange_limit,
- &max_amount));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_min (&oc->set_exchanges.total_exchange_limit,
- &oc->set_exchanges.total_exchange_limit,
- &oc->parse_order.brutto));
- j_exchange = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("url",
+ {
+ bool found = false;
+
+ for (unsigned int i = 0; i<oc->set_exchanges.num_total_exchange_limits; i++)
+ {
+ struct TALER_Amount *limit
+ = &oc->set_exchanges.total_exchange_limits[i];
+
+ if (GNUNET_OK ==
+ TALER_amount_cmp_currency (limit,
+ &max_amount))
+ {
+ GNUNET_assert (0 <=
+ TALER_amount_add (limit,
+ limit,
+ &max_amount));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_min (limit,
+ limit,
+ max_needed));
+ found = true;
+ }
+ }
+ if (! found)
+ {
+ struct TALER_Amount limit;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_min (&limit,
+ &max_amount,
+ max_needed));
+ GNUNET_array_append (oc->set_exchanges.total_exchange_limits,
+ oc->set_exchanges.num_total_exchange_limits,
+ limit);
+ }
+ }
+ j_exchange = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("url",
url),
GNUNET_JSON_pack_uint64 ("priority",
priority),
@@ -2293,17 +2574,59 @@ keys_cb (
}
else
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Got response for %skeys\n",
- rx->url);
- if ( (settings->use_stefan) &&
- (GNUNET_OK !=
- TALER_amount_is_valid (&oc->parse_order.max_fee)) )
- update_stefan (oc,
- keys);
- get_acceptable (oc,
- rx->url,
- exchange);
+ bool currency_ok = false;
+ struct TALER_Amount max_needed;
+
+ switch (oc->parse_order.version)
+ {
+ case TALER_MCV_V0:
+ if (0 == strcasecmp (keys->currency,
+ oc->parse_order.details.v0.brutto.currency))
+ {
+ max_needed = oc->parse_order.details.v0.brutto;
+ currency_ok = true;
+ }
+ break;
+ case TALER_MCV_V1:
+ for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
+ {
+ const struct TALER_Amount *amount
+ = &oc->parse_choices.choices[i].amount;
+
+ if (0 == strcasecmp (keys->currency,
+ amount->currency))
+ {
+ if (currency_ok)
+ {
+ TALER_amount_max (&max_needed,
+ &max_needed,
+ amount);
+ }
+ else
+ {
+ max_needed = *amount;
+ currency_ok = true;
+ }
+ }
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ if ( (currency_ok) &&
+ (! TALER_amount_is_zero (&max_needed)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got response for %skeys\n",
+ rx->url);
+ if (settings->use_stefan)
+ update_stefan (oc,
+ keys);
+ get_acceptable (oc,
+ rx->url,
+ exchange,
+ &max_needed);
+ }
}
GNUNET_free (rx->url);
GNUNET_free (rx);
@@ -2411,6 +2734,40 @@ wakeup_timeout (void *cls)
/**
+ * Check that the @a brutto amount is at or below the exchange
+ * limits we have for the respective currency.
+ *
+ * @param oc order context to check
+ * @param brutto amount to check
+ * @param true if the amount is OK, false if it is too high
+ */
+static bool
+check_exchange_limits (const struct OrderContext *oc,
+ struct TALER_Amount *brutto)
+{
+ for (unsigned int i = 0; i<oc->set_exchanges.num_total_exchange_limits; i++)
+ {
+ const struct TALER_Amount *total_exchange_limit
+ = &oc->set_exchanges.total_exchange_limits[i];
+
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (brutto,
+ total_exchange_limit))
+ continue;
+ if (1 !=
+ TALER_amount_cmp (brutto,
+ total_exchange_limit))
+ return true;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot create order: %s is above the sum of hard limits from supported exchanges\n",
+ TALER_amount2s (brutto));
+ return false;
+}
+
+
+/**
* Set list of acceptable exchanges in @a oc. Upon success, continue
* processing with set_max_fee().
*
@@ -2420,12 +2777,32 @@ wakeup_timeout (void *cls)
static bool
set_exchanges (struct OrderContext *oc)
{
+ bool need_exchange;
+
if (NULL != oc->set_exchanges.wakeup_task)
{
GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
oc->set_exchanges.wakeup_task = NULL;
}
- if (TALER_amount_is_zero (&oc->parse_order.brutto))
+ switch (oc->parse_order.version)
+ {
+ case TALER_MCV_V0:
+ need_exchange = ! TALER_amount_is_zero (
+ &oc->parse_order.details.v0.brutto);
+ break;
+ case TALER_MCV_V1:
+ need_exchange = false;
+ for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
+ if (! TALER_amount_is_zero (&oc->parse_choices.choices[i].amount))
+ {
+ need_exchange = true;
+ break;
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ if (! need_exchange)
{
/* Total amount is zero, so we don't actually need exchanges! */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -2436,21 +2813,13 @@ set_exchanges (struct OrderContext *oc)
return false;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Order total is %s, trying to find exchanges\n",
- TALER_amount2s (&oc->parse_order.brutto));
- /* Note: re-building 'oc->set_exchanges.exchanges' every time here might be a
- tad expensive; could likely consider caching the result if it starts to
- matter. */
+ "Trying to find exchanges\n");
if (NULL == oc->set_exchanges.exchanges)
{
oc->set_exchanges.keys_timeout
= GNUNET_TIME_relative_to_absolute (MAX_KEYS_WAIT);
oc->set_exchanges.exchanges = json_array ();
GNUNET_assert (NULL != oc->set_exchanges.exchanges);
- GNUNET_assert (
- GNUNET_OK ==
- TALER_amount_set_zero (oc->parse_order.brutto.currency,
- &oc->set_exchanges.total_exchange_limit));
TMH_exchange_get_trusted (&get_exchange_keys,
oc);
}
@@ -2506,32 +2875,52 @@ set_exchanges (struct OrderContext *oc)
oc->add_payment_details.wm->wire_method);
return false;
}
- if (1 ==
- TALER_amount_cmp (&oc->parse_order.brutto,
- &oc->set_exchanges.total_exchange_limit))
+
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Cannot create order: %s is the sum of hard limits from supported exchanges\n",
- TALER_amount2s (&oc->set_exchanges.total_exchange_limit));
- notify_kyc_required (oc);
- reply_with_error (
- oc,
- MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS,
- TALER_amount2s (&oc->set_exchanges.total_exchange_limit));
- return false;
+ bool ok;
+ struct TALER_Amount ea;
+
+ switch (oc->parse_order.version)
+ {
+ case TALER_MCV_V0:
+ ea = oc->parse_order.details.v0.brutto;
+ ok = check_exchange_limits (oc,
+ &ea);
+ break;
+ case TALER_MCV_V1:
+ ok = true;
+ for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
+ {
+ ea = oc->parse_choices.choices[i].amount;
+ if (! check_exchange_limits (oc,
+ &ea))
+ {
+ ok = false;
+ break;
+ }
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+
+ if (! ok)
+ {
+ notify_kyc_required (oc);
+ reply_with_error (
+ oc,
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
+ TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS,
+ TALER_amount2s (&ea));
+ return false;
+ }
}
+
if (! oc->set_exchanges.exchange_good)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Creating order, but possibly without usable trusted exchanges\n");
}
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Can create order: %s is the sum of hard limits from supported exchanges\n",
- TALER_amount2s (&oc->set_exchanges.total_exchange_limit));
- }
oc->phase++;
return false;
}
@@ -2551,18 +2940,12 @@ parse_order (struct OrderContext *oc)
const char *merchant_base_url = NULL;
uint64_t version = 0;
const json_t *jmerchant = NULL;
- /* auto_refund only needs to be type-checked,
- * mostly because in GNUnet relative times can't
- * be negative. */
- bool no_fee;
- const char *oid;
+ const char *order_id;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_uint64 ("version",
&version),
NULL),
- TALER_JSON_spec_amount_any ("amount",
- &oc->parse_order.brutto),
GNUNET_JSON_spec_string ("summary",
&oc->parse_order.summary),
GNUNET_JSON_spec_mark_optional (
@@ -2575,7 +2958,7 @@ parse_order (struct OrderContext *oc)
NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("order_id",
- &oid),
+ &order_id),
NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("fulfillment_message",
@@ -2594,13 +2977,10 @@ parse_order (struct OrderContext *oc)
&oc->parse_order.public_reorder_url),
NULL),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("choices",
- &oc->parse_order.choices),
- NULL),
- GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_web_url ("merchant_base_url",
&merchant_base_url),
NULL),
+ /* For sanity check, this field must NOT be present */
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("merchant",
&jmerchant),
@@ -2622,10 +3002,6 @@ parse_order (struct OrderContext *oc)
&oc->parse_order.wire_deadline),
NULL),
GNUNET_JSON_spec_mark_optional (
- TALER_JSON_spec_amount_any ("max_fee",
- &oc->parse_order.max_fee),
- &no_fee),
- GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("delivery_location",
&oc->parse_order.delivery_location),
NULL),
@@ -2661,38 +3037,100 @@ parse_order (struct OrderContext *oc)
ret);
return;
}
- if (0 == version)
+ switch (version)
{
- oc->parse_order.version = TALER_MCV_V0;
-
- if (NULL != oc->parse_order.choices)
+ case 0:
{
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR,
- "choices array must be null for v0 contracts");
- return;
- }
- }
- else if (1 == version)
- {
- oc->parse_order.version = TALER_MCV_V1;
+ bool no_fee;
+ const json_t *choices = NULL;
+ struct GNUNET_JSON_Specification specv0[] = {
+ TALER_JSON_spec_amount_any (
+ "amount",
+ &oc->parse_order.details.v0.brutto),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any (
+ "max_fee",
+ &oc->parse_order.details.v0.max_fee),
+ &no_fee),
+ /* for sanity check, must be *absent*! */
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("choices",
+ &choices),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
- if (! json_is_array (oc->parse_order.choices))
+ ret = TALER_MHD_parse_json_data (oc->connection,
+ oc->parse_request.order,
+ specv0);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break_op (0);
+ finalize_order2 (oc,
+ ret);
+ return;
+ }
+ if ( (! no_fee) &&
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&oc->parse_order.details.v0.brutto,
+ &oc->parse_order.details.v0.max_fee)) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ "different currencies used for 'max_fee' and 'amount' currency");
+ return;
+ }
+ if (! TMH_test_exchange_configured_for_currency (
+ oc->parse_order.details.v0.brutto.currency))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ // FIXME: use CONFLICT and a different EC!
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ "no trusted exchange for this currency");
+ return;
+ }
+ if (NULL != choices)
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR,
+ "choices array must be null for v0 contracts");
+ return;
+ }
+ oc->parse_order.version = TALER_MCV_V0;
+ break;
+ }
+ case 1:
{
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "order.choices is not a valid array");
- return;
+ struct GNUNET_JSON_Specification specv1[] = {
+ GNUNET_JSON_spec_array_const (
+ "choices",
+ &oc->parse_order.details.v1.choices),
+ GNUNET_JSON_spec_end ()
+ };
+
+ ret = TALER_MHD_parse_json_data (oc->connection,
+ oc->parse_request.order,
+ specv1);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break_op (0);
+ finalize_order2 (oc,
+ ret);
+ return;
+ }
+ oc->parse_order.version = TALER_MCV_V1;
+ break;
}
- }
- else
- {
+ default:
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
reply_with_error (oc,
@@ -2701,35 +3139,11 @@ parse_order (struct OrderContext *oc)
"invalid version specified in order, supported are null, '0' or '1'");
return;
}
- if (! TMH_test_exchange_configured_for_currency (
- oc->parse_order.brutto.currency))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_CURRENCY_MISMATCH,
- "no trusted exchange for this currency");
- return;
- }
- if ( (! no_fee) &&
- (GNUNET_OK !=
- TALER_amount_cmp_currency (&oc->parse_order.brutto,
- &oc->parse_order.max_fee)) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_CURRENCY_MISMATCH,
- "different currencies used for 'max_fee' and 'amount' currency");
- return;
- }
/* Add order_id if it doesn't exist. */
- if (NULL != oid)
+ if (NULL != order_id)
{
- oc->parse_order.order_id = GNUNET_strdup (oid);
+ oc->parse_order.order_id = GNUNET_strdup (order_id);
}
else
{
@@ -3013,6 +3427,217 @@ parse_donau_instances (struct OrderContext *oc)
#endif
/**
+ * Parse the inputs for a particular choice.
+ *
+ * @param[in,out] oc order context
+ * @param[out] choice to parse inputs for
+ * @param jinputs array of inputs to parse
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR
+ * if an error was encountered (and already handled)
+ */
+static enum GNUNET_GenericReturnValue
+parse_order_inputs (struct OrderContext *oc,
+ struct TALER_MerchantContractChoice *choice,
+ const json_t *jinputs)
+{
+ const json_t *jinput;
+ size_t idx;
+
+ json_array_foreach ((json_t *) jinputs, idx, jinput)
+ {
+ struct TALER_MerchantContractInput input = {
+ .details.token.count = 1
+ };
+ const char *kind;
+ const char *ierror_name;
+ unsigned int ierror_line;
+ struct GNUNET_JSON_Specification ispec[] = {
+ // FIXME: define spec parser for 'kind'...
+ GNUNET_JSON_spec_string ("kind",
+ &kind),
+ GNUNET_JSON_spec_string ("token_family_slug",
+ &input.details.token.token_family_slug),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("count",
+ &input.details.token.count),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (jinput,
+ ispec,
+ &ierror_name,
+ &ierror_line))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid input #%u for field %s\n",
+ (unsigned int) idx,
+ ierror_name);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ ierror_name);
+ return GNUNET_SYSERR;
+ }
+
+ input.type = TMH_contract_input_type_from_string (kind);
+ if (TALER_MCIT_INVALID == input.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Field 'kind' invalid in input #%u\n",
+ (unsigned int) idx);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "kind");
+ return GNUNET_SYSERR;
+ }
+
+ if (0 == input.details.token.count)
+ {
+ /* Ignore inputs with 'number' field set to 0 */
+ continue;
+ }
+
+ if (GNUNET_OK !=
+ add_input_token_family (oc,
+ input.details.token.token_family_slug))
+ {
+ /* error is already scheduled, return. */
+ return GNUNET_SYSERR;
+ }
+
+ GNUNET_array_append (choice->inputs,
+ choice->inputs_len,
+ input);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse the outputs for a particular choice.
+ *
+ * @param[in,out] oc order context
+ * @param[out] choice to parse inputs for
+ * @param joutputs array of outputs to parse
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR
+ * if an error was encountered (and already handled)
+ */
+static enum GNUNET_GenericReturnValue
+parse_order_outputs (struct OrderContext *oc,
+ struct TALER_MerchantContractChoice *choice,
+ const json_t *joutputs)
+{
+ const json_t *joutput;
+ size_t idx;
+
+ json_array_foreach ((json_t *) joutputs, idx, joutput)
+ {
+ struct TALER_MerchantContractOutput output = {
+ .details.token.count = 1
+ };
+ const char *kind;
+ const char *ierror_name;
+ unsigned int ierror_line;
+ bool nots;
+ struct GNUNET_TIME_Timestamp valid_at;
+ struct GNUNET_JSON_Specification ispec[] = {
+ // FIXME: define spec parser for 'kind'...
+ GNUNET_JSON_spec_string ("kind",
+ &kind),
+ GNUNET_JSON_spec_string ("token_family_slug",
+ &output.details.token.token_family_slug),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("count",
+ &output.details.token.count),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_timestamp ("valid_at",
+ &valid_at),
+ ¬s),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (joutput,
+ ispec,
+ &ierror_name,
+ &ierror_line))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid output #%u for field %s\n",
+ (unsigned int) idx,
+ ierror_name);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ ierror_name);
+ return GNUNET_SYSERR;
+ }
+ if (nots)
+ {
+ valid_at = oc->parse_order.pay_deadline;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Looking for output token valid at pay deadline %s\n",
+ GNUNET_TIME_timestamp2s (valid_at));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Looking for output token valid at %s\n",
+ GNUNET_TIME_timestamp2s (valid_at));
+ }
+ if (GNUNET_TIME_timestamp_cmp (valid_at,
+ <,
+ oc->parse_order.pay_deadline))
+ {
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "valid_at before pay_deadline");
+ return GNUNET_SYSERR;
+ }
+
+ output.type = TMH_contract_output_type_from_string (kind);
+ if (TALER_MCOT_INVALID == output.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Field 'kind' invalid in output #%u\n",
+ (unsigned int) idx);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "kind");
+ return GNUNET_SYSERR;
+ }
+
+ if (0 == output.details.token.count)
+ {
+ /* Ignore outputs with 'number' field set to 0. */
+ continue;
+ }
+
+ if (GNUNET_OK !=
+ add_output_token_family (oc,
+ output.details.token.token_family_slug,
+ valid_at,
+ &output.details.token.key_index))
+ {
+ /* Error is already scheduled, return. */
+ return GNUNET_SYSERR;
+ }
+
+ GNUNET_array_append (choice->outputs,
+ choice->outputs_len,
+ output);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
* Parse contract choices. Upon success, continue
* processing with merge_inventory().
*
@@ -3021,22 +3646,40 @@ parse_donau_instances (struct OrderContext *oc)
static void
parse_choices (struct OrderContext *oc)
{
- if (NULL == oc->parse_order.choices)
+ const json_t *choices;
+
+ switch (oc->parse_order.version)
{
+ case TALER_MCV_V0:
oc->phase++;
return;
+ case TALER_MCV_V1:
+ /* handle below */
+ break;
+ default:
+ GNUNET_assert (0);
}
+ choices = oc->parse_order.details.v1.choices;
GNUNET_array_grow (oc->parse_choices.choices,
oc->parse_choices.choices_len,
- json_array_size (oc->parse_order.choices));
+ json_array_size (choices));
for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
{
+ struct TALER_MerchantContractChoice *choice
+ = &oc->parse_choices.choices[i];
const char *error_name;
unsigned int error_line;
const json_t *jinputs;
const json_t *joutputs;
+ bool no_fee;
struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &choice->amount),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any ("max_fee",
+ &choice->max_fee),
+ &no_fee),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_array_const ("inputs",
&jinputs),
@@ -3049,7 +3692,7 @@ parse_choices (struct OrderContext *oc)
};
enum GNUNET_GenericReturnValue ret;
- ret = GNUNET_JSON_parse (json_array_get (oc->parse_order.choices,
+ ret = GNUNET_JSON_parse (json_array_get (choices,
i),
spec,
&error_name,
@@ -3066,6 +3709,33 @@ parse_choices (struct OrderContext *oc)
"choice");
return;
}
+ if ( (! no_fee) &&
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&choice->amount,
+ &choice->max_fee)) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ "different currencies used for 'max_fee' and 'amount' currency");
+ return;
+ }
+
+ if (! TMH_test_exchange_configured_for_currency (
+ choice->amount.currency))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ // FIXME: use CONFLICT and a different EC!
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ "no trusted exchange for this currency");
+ return;
+ }
+
if ( (0 == json_array_size (jinputs)) &&
(0 == json_array_size (joutputs)) )
@@ -3079,195 +3749,17 @@ parse_choices (struct OrderContext *oc)
"choice");
return;
}
-
- {
- // TODO: Maybe move to a separate function
- const json_t *jinput;
- size_t idx;
- json_array_foreach ((json_t *) jinputs, idx, jinput)
- {
- struct TALER_MerchantContractInput input = {
- .details.token.count = 1
- };
- const char *kind;
- const char *ierror_name;
- unsigned int ierror_line;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("kind",
- &kind),
- GNUNET_JSON_spec_string ("token_family_slug",
- &input.details.token.token_family_slug),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("count",
- &input.details.token.count),
- NULL),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (jinput,
- ispec,
- &ierror_name,
- &ierror_line))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Invalid input #%u for field %s\n",
- (unsigned int) idx,
- ierror_name);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- ierror_name);
- return;
- }
-
- input.type = TMH_contract_input_type_from_string (kind);
-
- if (TALER_MCIT_INVALID == input.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Field 'kind' invalid in input #%u\n",
- (unsigned int) idx);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "kind");
- return;
- }
-
- if (0 == input.details.token.count)
- {
- /* Ignore inputs with 'number' field set to 0 */
- continue;
- }
-
- if (GNUNET_OK !=
- add_input_token_family (oc,
- input.details.token.token_family_slug))
- {
- /* error is already scheduled, return. */
- return;
- }
-
- GNUNET_array_append (oc->parse_choices.choices[i].inputs,
- oc->parse_choices.choices[i].inputs_len,
- input);
- }
- }
-
- {
- const json_t *joutput;
- size_t idx;
- json_array_foreach ((json_t *) joutputs, idx, joutput)
- {
- struct TALER_MerchantContractOutput output = {
- .details.token.count = 1
- };
- const char *kind;
- const char *ierror_name;
- unsigned int ierror_line;
- bool nots;
- struct GNUNET_TIME_Timestamp valid_at;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("kind",
- &kind),
- GNUNET_JSON_spec_string ("token_family_slug",
- &output.details.token.token_family_slug),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("count",
- &output.details.token.count),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("valid_at",
- &valid_at),
- ¬s),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (joutput,
- ispec,
- &ierror_name,
- &ierror_line))
- {
- GNUNET_JSON_parse_free (spec);
- GNUNET_JSON_parse_free (ispec);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Invalid output #%u for field %s\n",
- (unsigned int) idx,
- ierror_name);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- ierror_name);
- return;
- }
- if (nots)
- {
- valid_at = oc->parse_order.pay_deadline;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Looking for output token valid at pay deadline %s\n",
- GNUNET_TIME_timestamp2s (valid_at));
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Looking for output token valid at %s\n",
- GNUNET_TIME_timestamp2s (valid_at));
- }
-
-
- if (GNUNET_TIME_timestamp_cmp (valid_at,
- <,
- oc->parse_order.pay_deadline))
- {
- GNUNET_JSON_parse_free (spec);
- GNUNET_JSON_parse_free (ispec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "valid_at before pay_deadline");
- return;
- }
-
- output.type = TMH_contract_output_type_from_string (kind);
- if (TALER_MCOT_INVALID == output.type)
- {
- GNUNET_JSON_parse_free (spec);
- GNUNET_JSON_parse_free (ispec);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Field 'kind' invalid in output #%u\n",
- (unsigned int) idx);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "kind");
- return;
- }
-
- if (0 == output.details.token.count)
- {
- /* Ignore outputs with 'number' field set to 0. */
- continue;
- }
-
- if (GNUNET_OK !=
- add_output_token_family (oc,
- output.details.token.token_family_slug,
- valid_at,
- &output.details.token.key_index))
- {
- /* Error is already scheduled, return. */
- return;
- }
-
- GNUNET_array_append (oc->parse_choices.choices[i].outputs,
- oc->parse_choices.choices[i].outputs_len,
- output);
- }
- }
+ if (GNUNET_OK !=
+ parse_order_inputs (oc,
+ choice,
+ jinputs))
+ return;
+ if (GNUNET_OK !=
+ parse_order_outputs (oc,
+ choice,
+ joutputs))
+ return;
}
-
oc->phase++;
}
diff --git a/src/backenddb/pg_get_kyc_limits.c b/src/backenddb/pg_get_kyc_limits.c
@@ -32,6 +32,7 @@ TMH_PG_get_kyc_limits (
const char *instance_id,
const char *exchange_url,
bool *kyc_ok,
+ bool *no_access_token,
json_t **jlimits)
{
struct PostgresClosure *pg = cls;
@@ -44,6 +45,8 @@ TMH_PG_get_kyc_limits (
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("kyc_ok",
kyc_ok),
+ GNUNET_PQ_result_spec_bool ("no_access_token",
+ no_access_token),
GNUNET_PQ_result_spec_allow_null (
TALER_PQ_result_spec_json ("jaccount_limits",
jlimits),
@@ -57,6 +60,7 @@ TMH_PG_get_kyc_limits (
"SELECT"
" mk.kyc_ok"
",mk.jaccount_limits"
+ ",mk.access_token IS NULL AS no_access_token"
" FROM merchant_kyc mk"
" WHERE mk.exchange_url=$3"
" AND mk.account_serial="
diff --git a/src/backenddb/pg_get_kyc_limits.h b/src/backenddb/pg_get_kyc_limits.h
@@ -33,6 +33,7 @@
* @param instance_id the instance for which to check
* @param exchange_url base URL of the exchange
* @param[out] kyc_ok true if no urgent KYC work must be done for this account
+ * @param[out] no_access_token true if we do not have a valid KYC access token (KYC auth missing)
* @param[out] jlimits set to JSON array with AccountLimits, NULL if unknown (and likely defaults apply or KYC auth is urgently needed, see @a auth_ok)
* @return database result code
*/
@@ -43,6 +44,7 @@ TMH_PG_get_kyc_limits (
const char *instance_id,
const char *exchange_url,
bool *kyc_ok,
+ bool *no_access_token,
json_t **jlimits);
#endif
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
@@ -8,6 +8,7 @@ talerinclude_HEADERS = \
taler_merchant_bank_lib.h \
taler_merchantdb_lib.h \
taler_merchantdb_plugin.h \
+ taler_merchant_util.h \
taler_merchant_service.h \
taler_merchant_testing_lib.h
diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h
@@ -613,7 +613,7 @@ TALER_TESTING_cmd_merchant_post_orders3 (
* @param merchant_url base URL of the merchant serving
* the proposal request.
* @param http_status expected HTTP status.
- * @param token_family_reference label of the POST /tokenfamilies cmd.
+ * @param token_family_slug slug of the token family to use
* @param num_inputs number of input tokens.
* @param num_outputs number of output tokens.
* @param order_id the name of the order to add.
@@ -629,7 +629,7 @@ TALER_TESTING_cmd_merchant_post_orders_choices (
const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *merchant_url,
unsigned int http_status,
- const char *token_family_reference,
+ const char *token_family_slug,
unsigned int num_inputs,
unsigned int num_outputs,
const char *order_id,
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
@@ -1395,7 +1395,7 @@ struct TALER_MERCHANTDB_Plugin
* @param cls closure
*/
enum GNUNET_GenericReturnValue
- (*connect)(void *cls);
+ (*connect)(void *cls);
/**
* Drop merchant tables. Used for testcases and to reset the DB.
@@ -1404,7 +1404,7 @@ struct TALER_MERCHANTDB_Plugin
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
enum GNUNET_GenericReturnValue
- (*drop_tables)(void *cls);
+ (*drop_tables)(void *cls);
/**
* Initialize merchant tables
@@ -1413,7 +1413,7 @@ struct TALER_MERCHANTDB_Plugin
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
enum GNUNET_GenericReturnValue
- (*create_tables)(void *cls);
+ (*create_tables)(void *cls);
/**
* Register callback to be invoked on events of type @a es.
@@ -1476,8 +1476,8 @@ struct TALER_MERCHANTDB_Plugin
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
- (*start)(void *cls,
- const char *name);
+ (*start)(void *cls,
+ const char *name);
/**
* Start a transaction with isolation level 'read committed'.
@@ -1488,8 +1488,8 @@ struct TALER_MERCHANTDB_Plugin
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
- (*start_read_committed)(void *cls,
- const char *name);
+ (*start_read_committed)(void *cls,
+ const char *name);
/**
* Roll back the current transaction of a database connection.
@@ -1506,7 +1506,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*commit)(void *cls);
+ (*commit)(void *cls);
/**
* Lookup all of the instances this backend has configured.
@@ -1517,10 +1517,10 @@ struct TALER_MERCHANTDB_Plugin
* @param cb_cls closure for @a cb
*/
enum GNUNET_DB_QueryStatus
- (*lookup_instances)(void *cls,
- bool active_only,
- TALER_MERCHANTDB_InstanceCallback cb,
- void *cb_cls);
+ (*lookup_instances)(void *cls,
+ bool active_only,
+ TALER_MERCHANTDB_InstanceCallback cb,
+ void *cb_cls);
/**
* Lookup one of the instances this backend has configured.
@@ -1532,11 +1532,11 @@ struct TALER_MERCHANTDB_Plugin
* @param cb_cls closure for @a cb
*/
enum GNUNET_DB_QueryStatus
- (*lookup_instance)(void *cls,
- const char *id,
- bool active_only,
- TALER_MERCHANTDB_InstanceCallback cb,
- void *cb_cls);
+ (*lookup_instance)(void *cls,
+ const char *id,
+ bool active_only,
+ TALER_MERCHANTDB_InstanceCallback cb,
+ void *cb_cls);
/**
* Lookup authentication data of an instance.
@@ -1546,9 +1546,9 @@ struct TALER_MERCHANTDB_Plugin
* @param[out] ias where to store the auth data
*/
enum GNUNET_DB_QueryStatus
- (*lookup_instance_auth)(void *cls,
- const char *instance_id,
- struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
+ (*lookup_instance_auth)(void *cls,
+ const char *instance_id,
+ struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
/**
@@ -1561,11 +1561,11 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_instance)(void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
+ (*insert_instance)(void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
+ const struct TALER_MERCHANTDB_InstanceSettings *is,
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
/**
* Insert information about an instance's account into our database.
@@ -1575,7 +1575,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_account)(
+ (*insert_account)(
void *cls,
const struct TALER_MERCHANTDB_AccountDetails *account_details);
@@ -1592,7 +1592,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_login_token)(
+ (*insert_login_token)(
void *cls,
const char *id,
const struct TALER_MERCHANTDB_LoginTokenP *token,
@@ -1612,7 +1612,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_login_token)(
+ (*select_login_token)(
void *cls,
const char *id,
const struct TALER_MERCHANTDB_LoginTokenP *token,
@@ -1629,7 +1629,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*delete_login_token)(
+ (*delete_login_token)(
void *cls,
const char *id,
const struct TALER_MERCHANTDB_LoginTokenP *token);
@@ -1646,7 +1646,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_account)(
+ (*update_account)(
void *cls,
const char *id,
const struct TALER_MerchantWireHashP *h_wire,
@@ -1664,7 +1664,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_accounts)(
+ (*select_accounts)(
void *cls,
const char *id,
TALER_MERCHANTDB_AccountCallback cb,
@@ -1681,7 +1681,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_account)(
+ (*select_account)(
void *cls,
const char *id,
const struct TALER_MerchantWireHashP *h_wire,
@@ -1698,7 +1698,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_account_by_uri)(
+ (*select_account_by_uri)(
void *cls,
const char *id,
struct TALER_FullPayto payto_uri,
@@ -1713,7 +1713,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*delete_instance_private_key)(
+ (*delete_instance_private_key)(
void *cls,
const char *merchant_id);
@@ -1726,8 +1726,8 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*purge_instance)(void *cls,
- const char *merchant_id);
+ (*purge_instance)(void *cls,
+ const char *merchant_id);
/**
* Update information about an instance into our database.
@@ -1737,8 +1737,8 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_instance)(void *cls,
- const struct TALER_MERCHANTDB_InstanceSettings *is);
+ (*update_instance)(void *cls,
+ const struct TALER_MERCHANTDB_InstanceSettings *is);
/**
* Update information about an instance's authentication settings
@@ -1750,7 +1750,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_instance_auth)(
+ (*update_instance_auth)(
void *cls,
const char *merchant_id,
const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
@@ -1764,9 +1764,9 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*inactivate_account)(void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire);
+ (*inactivate_account)(void *cls,
+ const char *merchant_id,
+ const struct TALER_MerchantWireHashP *h_wire);
/**
@@ -1778,9 +1778,9 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*activate_account)(void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire);
+ (*activate_account)(void *cls,
+ const char *merchant_id,
+ const struct TALER_MerchantWireHashP *h_wire);
/**
@@ -1797,7 +1797,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*account_kyc_get_status)(
+ (*account_kyc_get_status)(
void *cls,
const char *merchant_id,
const struct TALER_MerchantWireHashP *h_wire,
@@ -1823,7 +1823,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*get_kyc_status)(
+ (*get_kyc_status)(
void *cls,
struct TALER_FullPayto merchant_account_uri,
const char *instance_id,
@@ -1846,16 +1846,18 @@ struct TALER_MERCHANTDB_Plugin
* @param instance_id the instance for which to check
* @param exchange_url base URL of the exchange
* @param[out] kyc_ok true if no urgent KYC work must be done for this account
+ * @param[out] no_access_token true if we do not have a valid KYC access token (KYC auth missing)
* @param[out] jlimits set to JSON array with AccountLimits, NULL if unknown (and likely defaults apply or KYC auth is urgently needed, see @a auth_ok)
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*get_kyc_limits)(
+ (*get_kyc_limits)(
void *cls,
struct TALER_FullPayto merchant_account_uri,
const char *instance_id,
const char *exchange_url,
bool *kyc_ok,
+ bool *no_access_token,
json_t **jlimits);
@@ -1876,7 +1878,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*account_kyc_set_status)(
+ (*account_kyc_set_status)(
void *cls,
const char *merchant_id,
const struct TALER_MerchantWireHashP *h_wire,
@@ -1903,7 +1905,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*account_kyc_set_failed) (
+ (*account_kyc_set_failed) (
void *cls,
const char *merchant_id,
const struct TALER_MerchantWireHashP *h_wire,
@@ -1926,12 +1928,12 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_products)(void *cls,
- const char *instance_id,
- uint64_t offset,
- int64_t limit,
- TALER_MERCHANTDB_ProductsCallback cb,
- void *cb_cls);
+ (*lookup_products)(void *cls,
+ const char *instance_id,
+ uint64_t offset,
+ int64_t limit,
+ TALER_MERCHANTDB_ProductsCallback cb,
+ void *cb_cls);
/**
@@ -1944,10 +1946,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_all_products)(void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_ProductCallback cb,
- void *cb_cls);
+ (*lookup_all_products)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_ProductCallback cb,
+ void *cb_cls);
/**
* Lookup details about a particular product.
@@ -1963,12 +1965,12 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_product)(void *cls,
- const char *instance_id,
- const char *product_id,
- struct TALER_MERCHANTDB_ProductDetails *pd,
- size_t *num_categories,
- uint64_t **categories);
+ (*lookup_product)(void *cls,
+ const char *instance_id,
+ const char *product_id,
+ struct TALER_MERCHANTDB_ProductDetails *pd,
+ size_t *num_categories,
+ uint64_t **categories);
/**
* Delete information about a product. Note that the transaction must
@@ -1981,9 +1983,9 @@ struct TALER_MERCHANTDB_Plugin
* if locks prevent deletion OR product unknown
*/
enum GNUNET_DB_QueryStatus
- (*delete_product)(void *cls,
- const char *instance_id,
- const char *product_id);
+ (*delete_product)(void *cls,
+ const char *instance_id,
+ const char *product_id);
/**
* Insert details about a particular product.
@@ -2001,15 +2003,15 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_product)(void *cls,
- const char *instance_id,
- const char *product_id,
- const struct TALER_MERCHANTDB_ProductDetails *pd,
- size_t num_cats,
- const uint64_t *cats,
- bool *no_instance,
- bool *conflict,
- ssize_t *no_cat);
+ (*insert_product)(void *cls,
+ const char *instance_id,
+ const char *product_id,
+ const struct TALER_MERCHANTDB_ProductDetails *pd,
+ size_t num_cats,
+ const uint64_t *cats,
+ bool *no_instance,
+ bool *conflict,
+ ssize_t *no_cat);
/**
* Update details about a particular product. Note that the
@@ -2033,18 +2035,18 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_product)(void *cls,
- const char *instance_id,
- const char *product_id,
- const struct TALER_MERCHANTDB_ProductDetails *pd,
- size_t num_cats,
- const uint64_t *cats,
- bool *no_instance,
- ssize_t *no_cat,
- bool *no_product,
- bool *lost_reduced,
- bool *sold_reduced,
- bool *stocked_reduced);
+ (*update_product)(void *cls,
+ const char *instance_id,
+ const char *product_id,
+ const struct TALER_MERCHANTDB_ProductDetails *pd,
+ size_t num_cats,
+ const uint64_t *cats,
+ bool *no_instance,
+ ssize_t *no_cat,
+ bool *no_product,
+ bool *lost_reduced,
+ bool *sold_reduced,
+ bool *stocked_reduced);
/**
* Lock stocks of a particular product. Note that the transaction must
@@ -2060,12 +2062,12 @@ struct TALER_MERCHANTDB_Plugin
* product is unknown OR if there insufficient stocks remaining
*/
enum GNUNET_DB_QueryStatus
- (*lock_product)(void *cls,
- const char *instance_id,
- const char *product_id,
- const struct GNUNET_Uuid *uuid,
- uint64_t quantity,
- struct GNUNET_TIME_Timestamp expiration_time);
+ (*lock_product)(void *cls,
+ const char *instance_id,
+ const char *product_id,
+ const struct GNUNET_Uuid *uuid,
+ uint64_t quantity,
+ struct GNUNET_TIME_Timestamp expiration_time);
/**
@@ -2077,7 +2079,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*expire_locks)(void *cls);
+ (*expire_locks)(void *cls);
/**
@@ -2092,10 +2094,10 @@ struct TALER_MERCHANTDB_Plugin
* if locks prevent deletion OR order unknown
*/
enum GNUNET_DB_QueryStatus
- (*delete_order)(void *cls,
- const char *instance_id,
- const char *order_id,
- bool force);
+ (*delete_order)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ bool force);
/**
@@ -2112,12 +2114,12 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_order)(void *cls,
- const char *instance_id,
- const char *order_id,
- struct TALER_ClaimTokenP *claim_token,
- struct TALER_MerchantPostDataHashP *h_post_data,
- json_t **contract_terms);
+ (*lookup_order)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct TALER_ClaimTokenP *claim_token,
+ struct TALER_MerchantPostDataHashP *h_post_data,
+ json_t **contract_terms);
/**
@@ -2131,11 +2133,11 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_order_summary)(void *cls,
- const char *instance_id,
- const char *order_id,
- struct GNUNET_TIME_Timestamp *timestamp,
- uint64_t *order_serial);
+ (*lookup_order_summary)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct GNUNET_TIME_Timestamp *timestamp,
+ uint64_t *order_serial);
/**
@@ -2149,11 +2151,11 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_orders)(void *cls,
- const char *instance_id,
- const struct TALER_MERCHANTDB_OrderFilter *of,
- TALER_MERCHANTDB_OrdersCallback cb,
- void *cb_cls);
+ (*lookup_orders)(void *cls,
+ const char *instance_id,
+ const struct TALER_MERCHANTDB_OrderFilter *of,
+ TALER_MERCHANTDB_OrdersCallback cb,
+ void *cb_cls);
/**
@@ -2172,16 +2174,16 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_order)(void *cls,
- const char *instance_id,
- const char *order_id,
- const char *session_id,
- const struct TALER_MerchantPostDataHashP *h_post_data,
- struct GNUNET_TIME_Timestamp pay_deadline,
- const struct TALER_ClaimTokenP *claim_token,
- const json_t *contract_terms,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm pos_algorithm);
+ (*insert_order)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const char *session_id,
+ const struct TALER_MerchantPostDataHashP *h_post_data,
+ struct GNUNET_TIME_Timestamp pay_deadline,
+ const struct TALER_ClaimTokenP *claim_token,
+ const json_t *contract_terms,
+ const char *pos_key,
+ enum TALER_MerchantConfirmationAlgorithm pos_algorithm);
/**
@@ -2195,8 +2197,8 @@ struct TALER_MERCHANTDB_Plugin
* #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
*/
enum GNUNET_DB_QueryStatus
- (*unlock_inventory)(void *cls,
- const struct GNUNET_Uuid *uuid);
+ (*unlock_inventory)(void *cls,
+ const struct GNUNET_Uuid *uuid);
/**
@@ -2212,11 +2214,11 @@ struct TALER_MERCHANTDB_Plugin
* #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
*/
enum GNUNET_DB_QueryStatus
- (*insert_order_lock)(void *cls,
- const char *instance_id,
- const char *order_id,
- const char *product_id,
- uint64_t quantity);
+ (*insert_order_lock)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const char *product_id,
+ uint64_t quantity);
/**
@@ -2234,7 +2236,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_contract_terms2)(
+ (*lookup_contract_terms2)(
void *cls,
const char *instance_id,
const char *order_id,
@@ -2263,7 +2265,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_contract_terms3)(
+ (*lookup_contract_terms3)(
void *cls,
const char *instance_id,
const char *order_id,
@@ -2289,7 +2291,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_contract_terms)(
+ (*lookup_contract_terms)(
void *cls,
const char *instance_id,
const char *order_id,
@@ -2315,7 +2317,7 @@ struct TALER_MERCHANTDB_Plugin
* is malformed
*/
enum GNUNET_DB_QueryStatus
- (*insert_contract_terms)(
+ (*insert_contract_terms)(
void *cls,
const char *instance_id,
const char *order_id,
@@ -2339,10 +2341,10 @@ struct TALER_MERCHANTDB_Plugin
* is malformed
*/
enum GNUNET_DB_QueryStatus
- (*update_contract_terms)(void *cls,
- const char *instance_id,
- const char *order_id,
- json_t *contract_terms);
+ (*update_contract_terms)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t *contract_terms);
/**
@@ -2359,10 +2361,10 @@ struct TALER_MERCHANTDB_Plugin
* if locks prevent deletion OR order unknown
*/
enum GNUNET_DB_QueryStatus
- (*delete_contract_terms)(void *cls,
- const char *instance_id,
- const char *order_id,
- struct GNUNET_TIME_Relative legal_expiration);
+ (*delete_contract_terms)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct GNUNET_TIME_Relative legal_expiration);
/**
@@ -2377,11 +2379,12 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_deposits)(void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_DepositsCallback cb,
- void *cb_cls);
+ (*lookup_deposits)(void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP *h_contract_terms
+ ,
+ TALER_MERCHANTDB_DepositsCallback cb,
+ void *cb_cls);
/**
@@ -2396,7 +2399,7 @@ struct TALER_MERCHANTDB_Plugin
* @param master_sig signature of @a master_pub over the @a exchange_pub and the dates
*/
enum GNUNET_DB_QueryStatus
- (*insert_exchange_signkey)(
+ (*insert_exchange_signkey)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_ExchangePublicKeyP *exchange_pub,
@@ -2424,7 +2427,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_deposit_confirmation)(
+ (*insert_deposit_confirmation)(
void *cls,
const char *instance_id,
struct GNUNET_TIME_Timestamp deposit_timestamp,
@@ -2454,7 +2457,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_deposit)(
+ (*insert_deposit)(
void *cls,
uint32_t offset,
uint64_t deposit_confirmation_serial_id,
@@ -2476,11 +2479,11 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_refunds)(void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_RefundCallback rc,
- void *rc_cls);
+ (*lookup_refunds)(void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ TALER_MERCHANTDB_RefundCallback rc,
+ void *rc_cls);
/**
@@ -2493,10 +2496,10 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_spent_tokens_by_order)(void *cls,
- uint64_t order_serial,
- TALER_MERCHANTDB_UsedTokensCallback cb,
- void *cb_cls);
+ (*lookup_spent_tokens_by_order)(void *cls,
+ uint64_t order_serial,
+ TALER_MERCHANTDB_UsedTokensCallback cb,
+ void *cb_cls);
/**
@@ -2511,7 +2514,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*mark_contract_paid)(
+ (*mark_contract_paid)(
void *cls,
const char *instance_id,
const struct TALER_PrivateContractHashP *h_contract_terms,
@@ -2534,12 +2537,12 @@ struct TALER_MERCHANTDB_Plugin
* regardless of whether it actually increased the refund
*/
enum GNUNET_DB_QueryStatus
- (*refund_coin)(void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- struct GNUNET_TIME_Timestamp refund_timestamp,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const char *reason);
+ (*refund_coin)(void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ struct GNUNET_TIME_Timestamp refund_timestamp,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *reason);
/**
@@ -2553,11 +2556,11 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_order_status)(void *cls,
- const char *instance_id,
- const char *order_id,
- struct TALER_PrivateContractHashP *h_contract_terms,
- bool *paid);
+ (*lookup_order_status)(void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct TALER_PrivateContractHashP *h_contract_terms,
+ bool *paid);
/**
* Retrieve contract terms given its @a order_serial
@@ -2571,13 +2574,13 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_order_status_by_serial)(void *cls,
- const char *instance_id,
- uint64_t order_serial,
- char **order_id,
- struct TALER_PrivateContractHashP *
- h_contract_terms,
- bool *paid);
+ (*lookup_order_status_by_serial)(void *cls,
+ const char *instance_id,
+ uint64_t order_serial,
+ char **order_id,
+ struct TALER_PrivateContractHashP *
+ h_contract_terms,
+ bool *paid);
/**
@@ -2590,10 +2593,10 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_deposits_by_order)(void *cls,
- uint64_t order_serial,
- TALER_MERCHANTDB_DepositedCoinsCallback cb,
- void *cb_cls);
+ (*lookup_deposits_by_order)(void *cls,
+ uint64_t order_serial,
+ TALER_MERCHANTDB_DepositedCoinsCallback cb,
+ void *cb_cls);
/**
@@ -2607,7 +2610,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_transfer_details_by_order)(
+ (*lookup_transfer_details_by_order)(
void *cls,
uint64_t order_serial,
TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
@@ -2627,7 +2630,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
- (*update_transfer_status)(
+ (*update_transfer_status)(
void *cls,
const char *exchange_url,
const struct TALER_WireTransferIdentifierRawP *wtid,
@@ -2648,7 +2651,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*select_open_transfers)(
+ (*select_open_transfers)(
void *cls,
uint64_t limit,
TALER_MERCHANTDB_OpenTransferCallback cb,
@@ -2664,9 +2667,9 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_deposit_to_transfer)(void *cls,
- uint64_t deposit_serial,
- const struct TALER_EXCHANGE_DepositData *dd);
+ (*insert_deposit_to_transfer)(void *cls,
+ uint64_t deposit_serial,
+ const struct TALER_EXCHANGE_DepositData *dd);
/**
@@ -2677,8 +2680,8 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*mark_order_wired)(void *cls,
- uint64_t order_serial);
+ (*mark_order_wired)(void *cls,
+ uint64_t order_serial);
/**
@@ -2704,7 +2707,7 @@ struct TALER_MERCHANTDB_Plugin
* what was already refunded (idempotency!)
*/
enum TALER_MERCHANTDB_RefundStatus
- (*increase_refund)(
+ (*increase_refund)(
void *cls,
const char *instance_id,
const char *order_id,
@@ -2725,7 +2728,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_refunds_detailed)(
+ (*lookup_refunds_detailed)(
void *cls,
const char *instance_id,
const struct TALER_PrivateContractHashP *h_contract_terms,
@@ -2742,7 +2745,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_refund_proof)(
+ (*insert_refund_proof)(
void *cls,
uint64_t refund_serial,
const struct TALER_ExchangeSignatureP *exchange_sig,
@@ -2761,7 +2764,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_spent_token)(
+ (*insert_spent_token)(
void *cls,
const struct TALER_PrivateContractHashP *
h_contract_terms,
@@ -2781,7 +2784,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_issued_token)(
+ (*insert_issued_token)(
void *cls,
const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub,
@@ -2798,7 +2801,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_refund_proof)(
+ (*lookup_refund_proof)(
void *cls,
uint64_t refund_serial,
struct TALER_ExchangeSignatureP *exchange_sig,
@@ -2819,7 +2822,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_order_by_fulfillment)(
+ (*lookup_order_by_fulfillment)(
void *cls,
const char *instance_id,
const char *fulfillment_url,
@@ -2837,7 +2840,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*update_wirewatch_progress)(
+ (*update_wirewatch_progress)(
void *cls,
const char *instance,
struct TALER_FullPayto payto_uri,
@@ -2853,7 +2856,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*select_wirewatch_accounts)(
+ (*select_wirewatch_accounts)(
void *cls,
TALER_MERCHANTDB_WirewatchWorkCallback cb,
void *cb_cls);
@@ -2873,7 +2876,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_transfer)(
+ (*insert_transfer)(
void *cls,
const char *instance_id,
const char *exchange_url,
@@ -2894,9 +2897,9 @@ struct TALER_MERCHANTDB_Plugin
* if deletion is prohibited OR transfer is unknown
*/
enum GNUNET_DB_QueryStatus
- (*delete_transfer)(void *cls,
- const char *instance_id,
- uint64_t transfer_serial_id);
+ (*delete_transfer)(void *cls,
+ const char *instance_id,
+ uint64_t transfer_serial_id);
/**
@@ -2910,9 +2913,9 @@ struct TALER_MERCHANTDB_Plugin
* if the transfer record exists
*/
enum GNUNET_DB_QueryStatus
- (*check_transfer_exists)(void *cls,
- const char *instance_id,
- uint64_t transfer_serial_id);
+ (*check_transfer_exists)(void *cls,
+ const char *instance_id,
+ uint64_t transfer_serial_id);
/**
@@ -2925,10 +2928,10 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_account)(void *cls,
- const char *instance_id,
- struct TALER_FullPayto payto_uri,
- uint64_t *account_serial);
+ (*lookup_account)(void *cls,
+ const char *instance_id,
+ struct TALER_FullPayto payto_uri,
+ uint64_t *account_serial);
/**
@@ -2945,7 +2948,7 @@ struct TALER_MERCHANTDB_Plugin
* #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
*/
enum GNUNET_DB_QueryStatus
- (*insert_transfer_details)(
+ (*insert_transfer_details)(
void *cls,
const char *instance_id,
const char *exchange_url,
@@ -2969,7 +2972,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_wire_fee)(
+ (*lookup_wire_fee)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const char *wire_method,
@@ -2993,7 +2996,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_deposits_by_contract_and_coin)(
+ (*lookup_deposits_by_contract_and_coin)(
void *cls,
const char *instance_id,
const struct TALER_PrivateContractHashP *h_contract_terms,
@@ -3020,7 +3023,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_transfer)(
+ (*lookup_transfer)(
void *cls,
const char *instance_id,
const char *exchange_url,
@@ -3044,7 +3047,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*set_transfer_status_to_confirmed)(
+ (*set_transfer_status_to_confirmed)(
void *cls,
const char *instance_id,
const char *exchange_url,
@@ -3063,7 +3066,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_transfer_summary)(
+ (*lookup_transfer_summary)(
void *cls,
const char *exchange_url,
const struct TALER_WireTransferIdentifierRawP *wtid,
@@ -3082,7 +3085,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_transfer_details)(
+ (*lookup_transfer_details)(
void *cls,
const char *exchange_url,
const struct TALER_WireTransferIdentifierRawP *wtid,
@@ -3107,7 +3110,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_transfers)(
+ (*lookup_transfers)(
void *cls,
const char *instance_id,
struct TALER_FullPayto payto_uri,
@@ -3134,7 +3137,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
- (*store_wire_fee_by_exchange)(
+ (*store_wire_fee_by_exchange)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct GNUNET_HashCode *h_wire_method,
@@ -3152,7 +3155,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
- (*delete_exchange_accounts)(
+ (*delete_exchange_accounts)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub);
@@ -3167,7 +3170,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
- (*select_accounts_by_exchange)(
+ (*select_accounts_by_exchange)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
TALER_MERCHANTDB_ExchangeAccountCallback cb,
@@ -3187,7 +3190,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
- (*insert_exchange_account)(
+ (*insert_exchange_account)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_FullPayto payto_uri,
@@ -3207,10 +3210,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_templates)(void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_TemplatesCallback cb,
- void *cb_cls);
+ (*lookup_templates)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_TemplatesCallback cb,
+ void *cb_cls);
/**
@@ -3224,10 +3227,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_template)(void *cls,
- const char *instance_id,
- const char *template_id,
- struct TALER_MERCHANTDB_TemplateDetails *td);
+ (*lookup_template)(void *cls,
+ const char *instance_id,
+ const char *template_id,
+ struct TALER_MERCHANTDB_TemplateDetails *td);
/**
* Delete information about a template.
@@ -3239,9 +3242,9 @@ struct TALER_MERCHANTDB_Plugin
* if template unknown.
*/
enum GNUNET_DB_QueryStatus
- (*delete_template)(void *cls,
- const char *instance_id,
- const char *template_id);
+ (*delete_template)(void *cls,
+ const char *instance_id,
+ const char *template_id);
/**
@@ -3255,11 +3258,11 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_template)(void *cls,
- const char *instance_id,
- const char *template_id,
- uint64_t otp_serial_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td);
+ (*insert_template)(void *cls,
+ const char *instance_id,
+ const char *template_id,
+ uint64_t otp_serial_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td);
/**
@@ -3274,10 +3277,10 @@ struct TALER_MERCHANTDB_Plugin
* does not yet exist.
*/
enum GNUNET_DB_QueryStatus
- (*update_template)(void *cls,
- const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td);
+ (*update_template)(void *cls,
+ const char *instance_id,
+ const char *template_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td);
/**
@@ -3290,9 +3293,9 @@ struct TALER_MERCHANTDB_Plugin
* if template unknown.
*/
enum GNUNET_DB_QueryStatus
- (*delete_otp)(void *cls,
- const char *instance_id,
- const char *otp_id);
+ (*delete_otp)(void *cls,
+ const char *instance_id,
+ const char *otp_id);
/**
* Insert details about a particular OTP device.
@@ -3304,10 +3307,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_otp)(void *cls,
- const char *instance_id,
- const char *otp_id,
- const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+ (*insert_otp)(void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
/**
@@ -3322,10 +3325,10 @@ struct TALER_MERCHANTDB_Plugin
* does not yet exist.
*/
enum GNUNET_DB_QueryStatus
- (*update_otp)(void *cls,
- const char *instance_id,
- const char *otp_id,
- const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+ (*update_otp)(void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
/**
* Lookup all of the OTP devices the given instance has configured.
@@ -3337,10 +3340,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_otp_devices)(void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_OtpDeviceCallback cb,
- void *cb_cls);
+ (*lookup_otp_devices)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_OtpDeviceCallback cb,
+ void *cb_cls);
/**
@@ -3354,10 +3357,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_otp)(void *cls,
- const char *instance_id,
- const char *otp_id,
- struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+ (*select_otp)(void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ struct TALER_MERCHANTDB_OtpDeviceDetails *td);
/**
@@ -3369,10 +3372,10 @@ struct TALER_MERCHANTDB_Plugin
* @param[out] serial set to the OTP device serial number * @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_otp_serial)(void *cls,
- const char *instance_id,
- const char *otp_id,
- uint64_t *serial);
+ (*select_otp_serial)(void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ uint64_t *serial);
/**
@@ -3385,9 +3388,9 @@ struct TALER_MERCHANTDB_Plugin
* if template unknown.
*/
enum GNUNET_DB_QueryStatus
- (*delete_category)(void *cls,
- const char *instance_id,
- uint64_t category_id);
+ (*delete_category)(void *cls,
+ const char *instance_id,
+ uint64_t category_id);
/**
* Insert new product category.
@@ -3400,11 +3403,11 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_category)(void *cls,
- const char *instance_id,
- const char *category_name,
- const json_t *category_name_i18n,
- uint64_t *category_id);
+ (*insert_category)(void *cls,
+ const char *instance_id,
+ const char *category_name,
+ const json_t *category_name_i18n,
+ uint64_t *category_id);
/**
@@ -3419,11 +3422,11 @@ struct TALER_MERCHANTDB_Plugin
* does not yet exist.
*/
enum GNUNET_DB_QueryStatus
- (*update_category)(void *cls,
- const char *instance_id,
- uint64_t category_id,
- const char *category_name,
- const json_t *category_name_i18n);
+ (*update_category)(void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ const char *category_name,
+ const json_t *category_name_i18n);
/**
* Lookup all of the product categories the given instance has configured.
@@ -3435,10 +3438,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_categories)(void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_CategoriesCallback cb,
- void *cb_cls);
+ (*lookup_categories)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_CategoriesCallback cb,
+ void *cb_cls);
/**
@@ -3454,12 +3457,12 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_category)(void *cls,
- const char *instance_id,
- uint64_t category_id,
- struct TALER_MERCHANTDB_CategoryDetails *cd,
- size_t *num_products,
- char **products);
+ (*select_category)(void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ struct TALER_MERCHANTDB_CategoryDetails *cd,
+ size_t *num_products,
+ char **products);
/**
@@ -3473,11 +3476,11 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*select_category_by_name)(void *cls,
- const char *instance_id,
- const char *category_name,
- json_t **name_i18n,
- uint64_t *category_id);
+ (*select_category_by_name)(void *cls,
+ const char *instance_id,
+ const char *category_name,
+ json_t **name_i18n,
+ uint64_t *category_id);
/**
@@ -3490,10 +3493,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_webhooks)(void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_WebhooksCallback cb,
- void *cb_cls);
+ (*lookup_webhooks)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_WebhooksCallback cb,
+ void *cb_cls);
/**
@@ -3507,10 +3510,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_webhook)(void *cls,
- const char *instance_id,
- const char *webhook_id,
- struct TALER_MERCHANTDB_WebhookDetails *wb);
+ (*lookup_webhook)(void *cls,
+ const char *instance_id,
+ const char *webhook_id,
+ struct TALER_MERCHANTDB_WebhookDetails *wb);
/**
* Delete information about a webhook.
@@ -3522,9 +3525,9 @@ struct TALER_MERCHANTDB_Plugin
* if webhook unknown.
*/
enum GNUNET_DB_QueryStatus
- (*delete_webhook)(void *cls,
- const char *instance_id,
- const char *webhook_id);
+ (*delete_webhook)(void *cls,
+ const char *instance_id,
+ const char *webhook_id);
/**
@@ -3537,10 +3540,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_webhook)(void *cls,
- const char *instance_id,
- const char *webhook_id,
- const struct TALER_MERCHANTDB_WebhookDetails *wb);
+ (*insert_webhook)(void *cls,
+ const char *instance_id,
+ const char *webhook_id,
+ const struct TALER_MERCHANTDB_WebhookDetails *wb);
/**
@@ -3555,10 +3558,10 @@ struct TALER_MERCHANTDB_Plugin
* does not yet exist.
*/
enum GNUNET_DB_QueryStatus
- (*update_webhook)(void *cls,
- const char *instance_id,
- const char *webhook_id,
- const struct TALER_MERCHANTDB_WebhookDetails *wb);
+ (*update_webhook)(void *cls,
+ const char *instance_id,
+ const char *webhook_id,
+ const struct TALER_MERCHANTDB_WebhookDetails *wb);
/**
* Lookup webhook by event
@@ -3571,11 +3574,11 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_webhook_by_event)(void *cls,
- const char *instance_id,
- const char *event_type,
- TALER_MERCHANTDB_WebhookDetailCallback cb,
- void *cb_cls);
+ (*lookup_webhook_by_event)(void *cls,
+ const char *instance_id,
+ const char *event_type,
+ TALER_MERCHANTDB_WebhookDetailCallback cb,
+ void *cb_cls);
/**
* Insert webhook in the pending webhook.
@@ -3590,13 +3593,13 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_pending_webhook)(void *cls,
- const char *instance_id,
- uint64_t webhook_serial,
- const char *url,
- const char *http_method,
- const char *header,
- const char *body);
+ (*insert_pending_webhook)(void *cls,
+ const char *instance_id,
+ uint64_t webhook_serial,
+ const char *url,
+ const char *http_method,
+ const char *header,
+ const char *body);
/**
* Lookup the webhook that need to be send in priority. These webhooks are not successfully
* send.
@@ -3607,9 +3610,9 @@ struct TALER_MERCHANTDB_Plugin
*/
// WHERE next_attempt <= now ORDER BY next_attempt ASC
enum GNUNET_DB_QueryStatus
- (*lookup_pending_webhooks)(void *cls,
- TALER_MERCHANTDB_PendingWebhooksCallback cb,
- void *cb_cls);
+ (*lookup_pending_webhooks)(void *cls,
+ TALER_MERCHANTDB_PendingWebhooksCallback cb,
+ void *cb_cls);
/**
* Lookup future webhook in the pending webhook that need to be send.
@@ -3621,9 +3624,9 @@ struct TALER_MERCHANTDB_Plugin
*/
// ORDER BY next_attempt ASC LIMIT 1
enum GNUNET_DB_QueryStatus
- (*lookup_future_webhook)(void *cls,
- TALER_MERCHANTDB_PendingWebhooksCallback cb,
- void *cb_cls);
+ (*lookup_future_webhook)(void *cls,
+ TALER_MERCHANTDB_PendingWebhooksCallback cb,
+ void *cb_cls);
/**
* Lookup all the webhooks in the pending webhook.
@@ -3638,12 +3641,12 @@ struct TALER_MERCHANTDB_Plugin
*/
// WHERE webhook_pending_serial > min_row ORDER BY webhook_pending_serial ASC LIMIT max_results
enum GNUNET_DB_QueryStatus
- (*lookup_all_webhooks)(void *cls,
- const char *instance_id,
- uint64_t min_row,
- uint32_t max_results,
- TALER_MERCHANTDB_PendingWebhooksCallback cb,
- void *cb_cls);
+ (*lookup_all_webhooks)(void *cls,
+ const char *instance_id,
+ uint64_t min_row,
+ uint32_t max_results,
+ TALER_MERCHANTDB_PendingWebhooksCallback cb,
+ void *cb_cls);
/**
@@ -3655,9 +3658,9 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_pending_webhook)(void *cls,
- uint64_t webhook_pending_serial,
- struct GNUNET_TIME_Absolute next_attempt);
+ (*update_pending_webhook)(void *cls,
+ uint64_t webhook_pending_serial,
+ struct GNUNET_TIME_Absolute next_attempt);
// maybe add: http status of failure?
@@ -3670,8 +3673,8 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*delete_pending_webhook)(void *cls,
- uint64_t webhook_pending_serial);
+ (*delete_pending_webhook)(void *cls,
+ uint64_t webhook_pending_serial);
/**
@@ -3683,9 +3686,9 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*select_exchange_keys)(void *cls,
- const char *exchange_url,
- struct TALER_EXCHANGE_Keys **keys);
+ (*select_exchange_keys)(void *cls,
+ const char *exchange_url,
+ struct TALER_EXCHANGE_Keys **keys);
/**
@@ -3696,8 +3699,8 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*insert_exchange_keys)(void *cls,
- const struct TALER_EXCHANGE_Keys *keys);
+ (*insert_exchange_keys)(void *cls,
+ const struct TALER_EXCHANGE_Keys *keys);
/**
@@ -3710,10 +3713,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_token_families)(void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_TokenFamiliesCallback cb,
- void *cb_cls);
+ (*lookup_token_families)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_TokenFamiliesCallback cb,
+ void *cb_cls);
/**
* Lookup details about a particular token family.
@@ -3726,10 +3729,10 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_token_family)(void *cls,
- const char *instance_id,
- const char *token_family_slug,
- struct TALER_MERCHANTDB_TokenFamilyDetails *details);
+ (*lookup_token_family)(void *cls,
+ const char *instance_id,
+ const char *token_family_slug,
+ struct TALER_MERCHANTDB_TokenFamilyDetails *details);
/**
* Delete information about a token family.
@@ -3740,9 +3743,9 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*delete_token_family)(void *cls,
- const char *instance_id,
- const char *token_family_slug);
+ (*delete_token_family)(void *cls,
+ const char *instance_id,
+ const char *token_family_slug);
/**
* Update details about a particular token family.
@@ -3755,7 +3758,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_token_family)(
+ (*update_token_family)(
void *cls,
const char *instance_id,
const char *token_family_slug,
@@ -3772,7 +3775,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_token_family)(
+ (*insert_token_family)(
void *cls,
const char *instance_id,
const char *token_family_slug,
@@ -3792,7 +3795,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_token_family_key)(
+ (*lookup_token_family_key)(
void *cls,
const char *instance_id,
const char *token_family_slug,
@@ -3814,7 +3817,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*lookup_token_family_keys)(
+ (*lookup_token_family_keys)(
void *cls,
const char *instance_id,
const char *token_family_slug,
@@ -3839,7 +3842,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*insert_token_family_key)(
+ (*insert_token_family_key)(
void *cls,
const char *merchant_id,
const char *token_family_slug,
@@ -3861,7 +3864,7 @@ struct TALER_MERCHANTDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*lookup_pending_deposits)(
+ (*lookup_pending_deposits)(
void *cls,
const char *exchange_url,
uint64_t limit,
@@ -3883,7 +3886,7 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*update_deposit_confirmation_status)(
+ (*update_deposit_confirmation_status)(
void *cls,
uint64_t deposit_serial,
bool wire_pending,
diff --git a/src/merchant-tools/taler-merchant-benchmark.c b/src/merchant-tools/taler-merchant-benchmark.c
@@ -539,12 +539,13 @@ main (int argc,
}
}
if (NULL == exchange_bank_section)
- exchange_bank_section = "exchange-account-1";
+ exchange_bank_section = GNUNET_strdup ("exchange-account-1");
if (NULL == loglev)
- loglev = "INFO";
+ loglev = GNUNET_strdup ("INFO");
GNUNET_log_setup ("taler-merchant-benchmark",
loglev,
logfile);
+ GNUNET_free (loglev);
if ( (! ordinary) &&
(! corner) )
{
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
@@ -241,7 +241,6 @@ EXTRA_DIST = \
test_merchant_api_twisted-rsa.conf \
test_merchant_api_proxy_merchant.conf \
test_merchant_api_proxy_exchange.conf \
- test_merchant_api_home/.local/share/taler/exchange-offline/master.priv \
test_merchant.priv \
test_template.conf \
$(check_SCRIPTS)
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
@@ -191,6 +191,48 @@ run (void *cls,
"create-reserve-1",
"EUR:0",
MHD_HTTP_OK),
+
+ /* KYC: we don't even know the legitimization UUID yet */
+ TALER_TESTING_cmd_merchant_kyc_get (
+ "kyc-pending-early",
+ merchant_url,
+ NULL,
+ NULL,
+ EXCHANGE_URL,
+ TALER_EXCHANGE_KLPT_NONE,
+ MHD_HTTP_OK,
+ true),
+ /* now we get the legi UUID by running taler-merchant-depositcheck */
+ TALER_TESTING_cmd_depositcheck (
+ "deposit-check",
+ CONFIG_FILE),
+
+ TALER_TESTING_cmd_merchant_get_instance (
+ "get-default-instance",
+ merchant_url,
+ NULL,
+ MHD_HTTP_OK,
+ "instance-create-default-setup"),
+ TALER_TESTING_cmd_admin_add_kycauth (
+ "merchant-kyc-auth-transfer",
+ "EUR:0.01",
+ &cred.ba,
+ merchant_payto,
+ "get-default-instance"),
+ CMD_EXEC_WIREWATCH (
+ "import-kyc-account-withdraw"),
+
+ TALER_TESTING_cmd_merchant_kyc_get (
+ "kyc-auth-done-check",
+ merchant_url,
+ NULL, /* default instance */
+ "instance-create-default-account", /* h_wire_ref: which account to query */
+ EXCHANGE_URL,
+ TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER,
+ MHD_HTTP_OK,
+ true),
+
+
TALER_TESTING_cmd_merchant_post_orders2 (
"create-proposal-1",
cred.cfg,
@@ -211,20 +253,7 @@ run (void *cls,
MHD_HTTP_OK,
"create-proposal-1",
NULL),
- TALER_TESTING_cmd_merchant_get_instance (
- "get-default-instance",
- merchant_url,
- NULL,
- MHD_HTTP_OK,
- "instance-create-default-setup"),
- TALER_TESTING_cmd_admin_add_kycauth (
- "merchant-kyc-auth-transfer",
- "EUR:0.01",
- &cred.ba,
- merchant_payto,
- "get-default-instance"),
- CMD_EXEC_WIREWATCH (
- "import-kyc-account-withdraw"),
+
TALER_TESTING_cmd_merchant_pay_order (
"deposit-simple",
merchant_url,
@@ -247,21 +276,6 @@ run (void *cls,
/* KYC: hence nothing happened at the bank yet: */
TALER_TESTING_cmd_check_bank_empty (
"check_bank_empty-2"),
- /* KYC: we don't even know the legitimization UUID yet */
- TALER_TESTING_cmd_merchant_kyc_get (
- "kyc-pending-early",
- merchant_url,
- NULL,
- NULL,
- EXCHANGE_URL,
- TALER_EXCHANGE_KLPT_NONE,
- MHD_HTTP_OK,
- true),
- /* now we get the legi UUID by running taler-merchant-depositcheck */
- TALER_TESTING_cmd_depositcheck (
- "deposit-check",
- CONFIG_FILE),
- /* Now we should get a status of pending */
TALER_TESTING_cmd_merchant_kyc_get (
"kyc-pending",
merchant_url,
diff --git a/src/testing/test_kyc_api.conf b/src/testing/test_kyc_api.conf
@@ -167,10 +167,15 @@ CONTEXT = {}
CHECK_NAME = skip
# AML program that freezes the account and flags
# it for investigation.
-PROGRAM = taler-exchange-helper-measure-freeze
+PROGRAM = freeze
# Context to provide for check and program; empty.
CONTEXT = {}
+[aml-program-freeze]
+DESCRIPTION = "Freeze the account"
+COMMAND = taler-exchange-helper-measure-freeze
+FALLBACK = manual-freeze
+
[kyc-rule-aggregate-any]
ENABLED = YES
EXPOSED = YES
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
@@ -1714,7 +1714,7 @@ run (void *cls,
cred.cfg,
merchant_url,
MHD_HTTP_OK,
- "create-upcoming-tokenfamily",
+ "subscription-upcoming",
0,
1,
"5-upcoming-output",
@@ -1740,7 +1740,7 @@ run (void *cls,
cred.cfg,
merchant_url,
MHD_HTTP_OK,
- "create-tokenfamily",
+ "subscription-1",
0,
1,
"5-output",
@@ -1763,7 +1763,7 @@ run (void *cls,
cred.cfg,
merchant_url,
MHD_HTTP_OK,
- "create-tokenfamily",
+ "subscription-1",
1,
1,
"5-input-output",
@@ -1796,7 +1796,7 @@ run (void *cls,
cred.cfg,
merchant_url,
MHD_HTTP_OK,
- "create-tokenfamily",
+ "subscription-1",
1,
1,
"5-input-output-2",
diff --git a/src/testing/test_merchant_api.conf b/src/testing/test_merchant_api.conf
@@ -49,11 +49,11 @@ CURRENCY = EUR
[exchange]
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
-AML_THRESHOLD = EUR:1000000
PORT = 8081
MASTER_PUBLIC_KEY = KHA6YSPRQV1ZFCF144SY8KJNR588XA8DA0F6510FKJW30DJFJNAG
BASE_URL = "http://localhost:8081/"
STEFAN_ABS = "EUR:5"
+ENABLE_KYC = NO
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
diff --git a/src/testing/test_merchant_order_creation.sh b/src/testing/test_merchant_order_creation.sh
@@ -266,11 +266,11 @@ fi
echo " OK"
echo "curl 'http://localhost:9966/private/orders' \
- -d '{\"order\":{\"version\":1,\"amount\":\"TESTKUDOS:7\",\"summary\":\"with_subscription\",\"fulfillment_message\":\"Paid successfully\",\"choices\":[{\"inputs\":[{\"kind\":\"token\",\"count\":1,\"token_family_slug\":\"test-sub\",\"valid_after\":{\"t_s\":'$NOW'}}],\"outputs\":[{\"kind\":\"token\",\"count\":1,\"token_family_slug\":\"test-sub\",\"valid_after\":{\"t_s\":'$NOW'}}]}]}}'"
+ -d '{\"order\":{\"version\":1,\"summary\":\"with_subscription\",\"fulfillment_message\":\"Paid successfully\",\"choices\":[\{\"amount\":\"TESTKUDOS:7","inputs\":[{\"kind\":\"token\",\"count\":1,\"token_family_slug\":\"test-sub\",\"valid_after\":{\"t_s\":'$NOW'}}],\"outputs\":[{\"kind\":\"token\",\"count\":1,\"token_family_slug\":\"test-sub\",\"valid_after\":{\"t_s\":'$NOW'}}]}]}}'"
echo -n "Creating v1 order with token family ..."
STATUS=$(curl 'http://localhost:9966/private/orders' \
- -d '{"order":{"version":1,"amount":"TESTKUDOS:7","summary":"with_subscription","fulfillment_message":"Paid successfully","choices":[{"inputs":[{"kind":"token","count":1,"token_family_slug":"test-sub","valid_after":{"t_s":'$NOW'}}],"outputs":[{"kind":"token","count":1,"token_family_slug":"test-sub","valid_after":{"t_s":'$NOW'}}]}]}}' \
+ -d '{"order":{"version":1,"summary":"with_subscription","fulfillment_message":"Paid successfully","choices":[{"amount":"TESTKUDOS:7","inputs":[{"kind":"token","count":1,"token_family_slug":"test-sub","valid_after":{"t_s":'$NOW'}}],"outputs":[{"kind":"token","count":1,"token_family_slug":"test-sub","valid_after":{"t_s":'$NOW'}}]}]}}' \
-w "%{http_code}" -s -o "$LAST_RESPONSE")
if [ "$STATUS" != "200" ]
diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c
@@ -559,8 +559,6 @@ pay_run (void *cls,
struct TALER_MerchantWireHashP h_wire;
const struct TALER_PrivateContractHashP *h_proposal;
struct TALER_Amount max_fee;
- const json_t *choices = NULL;
- const json_t *token_families = NULL;
const char *error_name = NULL;
unsigned int error_line = 0;
struct TALER_MERCHANT_PayCoin *pay_coins;
@@ -598,7 +596,12 @@ pay_run (void *cls,
{
/* Get information that needs to be put verbatim in the
* deposit permission */
+ uint64_t version = 0;
struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("version",
+ &version),
+ NULL),
GNUNET_JSON_spec_string ("order_id",
&order_id),
GNUNET_JSON_spec_timestamp ("refund_deadline",
@@ -611,18 +614,6 @@ pay_run (void *cls,
&merchant_pub),
GNUNET_JSON_spec_fixed_auto ("h_wire",
&h_wire),
- TALER_JSON_spec_amount_any ("amount",
- &ps->total_amount),
- TALER_JSON_spec_amount_any ("max_fee",
- &max_fee),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_const ("token_families",
- &token_families),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("choices",
- &choices),
- NULL),
/* FIXME oec: parse minimum age, use data later? */
GNUNET_JSON_spec_end ()
};
@@ -645,6 +636,221 @@ pay_run (void *cls,
free (js);
TALER_TESTING_FAIL (is);
}
+ switch (version)
+ {
+ case 0:
+ {
+ struct GNUNET_JSON_Specification v0spec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &ps->total_amount),
+ TALER_JSON_spec_amount_any ("max_fee",
+ &max_fee),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (contract_terms,
+ v0spec,
+ &error_name,
+ &error_line))
+ {
+ char *js;
+
+ js = json_dumps (contract_terms,
+ JSON_INDENT (1));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Parser failed on %s:%u for input `%s'\n",
+ error_name,
+ error_line,
+ js);
+ free (js);
+ TALER_TESTING_FAIL (is);
+ }
+ }
+ if (0 < ps->choice_index)
+ TALER_TESTING_FAIL (is);
+ break;
+ case 1:
+ {
+ const json_t *choices;
+ const json_t *token_families;
+ struct GNUNET_JSON_Specification v1spec[] = {
+ GNUNET_JSON_spec_object_const ("token_families",
+ &token_families),
+ GNUNET_JSON_spec_array_const ("choices",
+ &choices),
+ GNUNET_JSON_spec_end ()
+ };
+ const json_t *outputs;
+ json_t *output;
+ unsigned int output_index;
+ const json_t *choice;
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (contract_terms,
+ v1spec,
+ &error_name,
+ &error_line))
+ {
+ char *js;
+
+ js = json_dumps (contract_terms,
+ JSON_INDENT (1));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Parser failed on %s:%u for input `%s'\n",
+ error_name,
+ error_line,
+ js);
+ free (js);
+ TALER_TESTING_FAIL (is);
+ }
+
+ choice = json_array_get (choices,
+ ps->choice_index);
+ if (NULL == choice)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No choice found at index %d\n",
+ ps->choice_index);
+ TALER_TESTING_FAIL (is);
+ }
+
+ {
+ const char *ierror_name = NULL;
+ unsigned int ierror_line = 0;
+
+ struct GNUNET_JSON_Specification ispec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &ps->total_amount),
+ TALER_JSON_spec_amount_any ("max_fee",
+ &max_fee),
+ GNUNET_JSON_spec_array_const ("outputs",
+ &outputs),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (choice,
+ ispec,
+ &ierror_name,
+ &ierror_line))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Parser failed on %s:%u for input `%s'\n",
+ ierror_name,
+ ierror_line,
+ json_dumps (choice,
+ JSON_INDENT (2)));
+ TALER_TESTING_FAIL (is);
+ }
+ }
+
+ json_array_foreach (outputs, output_index, output)
+ {
+ const char *slug;
+ const char *kind;
+ uint32_t key_index;
+ uint32_t count = 1;
+ const char *ierror_name = NULL;
+ unsigned int ierror_line = 0;
+
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_string ("kind",
+ &kind),
+ GNUNET_JSON_spec_string ("token_family_slug",
+ &slug),
+ GNUNET_JSON_spec_uint32 ("key_index",
+ &key_index),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("count",
+ &count),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (output,
+ ispec,
+ &ierror_name,
+ &ierror_line))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Parser failed on %s:%u for input `%s'\n",
+ ierror_name,
+ ierror_line,
+ json_dumps (output,
+ JSON_INDENT (2)));
+ TALER_TESTING_FAIL (is);
+ }
+
+ if (0 != strcmp ("token", kind))
+ {
+ continue;
+ }
+
+ GNUNET_array_grow (ps->issued_tokens,
+ ps->num_issued_tokens,
+ ps->num_issued_tokens + count);
+
+ for (unsigned int k = 0; k < count; k++)
+ {
+ struct TALER_MERCHANT_PrivateTokenDetails *details =
+ &ps->issued_tokens[ps->num_issued_tokens - count + k];
+
+ if (GNUNET_OK !=
+ find_token_public_key (token_families,
+ slug,
+ key_index,
+ &details->issue_pub))
+ {
+ TALER_TESTING_FAIL (is);
+ }
+
+ /* Only RSA is supported for now. */
+ GNUNET_assert (GNUNET_CRYPTO_BSA_RSA ==
+ details->issue_pub.public_key->cipher);
+
+ TALER_token_blind_input_copy (&details->blinding_inputs,
+ TALER_token_blind_input_rsa_singleton ()
+ );
+ /* TODO: Where to get details->blinding_inputs from? */
+ TALER_token_use_setup_random (&details->master);
+ TALER_token_use_setup_priv (&details->master,
+ &details->blinding_inputs,
+ &details->token_priv);
+ TALER_token_use_blinding_secret_create (&details->master,
+ &details->blinding_inputs,
+ &details->blinding_secret);
+ GNUNET_CRYPTO_eddsa_key_get_public (&details->token_priv.private_key
+ ,
+ &details->token_pub.public_key);
+ GNUNET_CRYPTO_hash (&details->token_pub.public_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ &details->h_token_pub.hash);
+ details->envelope.blinded_pub = GNUNET_CRYPTO_message_blind_to_sign
+ (
+ details->issue_pub.public_key,
+ &details->blinding_secret,
+ NULL, /* TODO: Add session nonce to support CS tokens */
+ &details->h_token_pub.hash,
+ sizeof (details->h_token_pub.hash),
+ details->blinding_inputs.blinding_inputs);
+
+ if (NULL == details->envelope.blinded_pub)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_FAIL (is);
+ }
+ }
+ }
+ }
+
+ break;
+ default:
+ TALER_TESTING_FAIL (is);
+ }
+
+
}
{
@@ -688,143 +894,6 @@ pay_run (void *cls,
}
GNUNET_free (tr);
}
- if (0 <= ps->choice_index)
- {
- const json_t *outputs;
- json_t *output;
- unsigned int output_index;
- const json_t *choice = json_array_get (choices, ps->choice_index);
-
- if (NULL == choice)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No choice found at index %d\n",
- ps->choice_index);
- TALER_TESTING_FAIL (is);
- }
-
- {
- const char *ierror_name = NULL;
- unsigned int ierror_line = 0;
-
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_array_const ("outputs",
- &outputs),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (choice,
- ispec,
- &ierror_name,
- &ierror_line))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Parser failed on %s:%u for input `%s'\n",
- ierror_name,
- ierror_line,
- json_dumps (choice,
- JSON_INDENT (2)));
- TALER_TESTING_FAIL (is);
- }
- }
-
- json_array_foreach (outputs, output_index, output)
- {
- const char *slug;
- const char *kind;
- uint32_t key_index;
- uint32_t count = 1;
- const char *ierror_name = NULL;
- unsigned int ierror_line = 0;
-
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("kind",
- &kind),
- GNUNET_JSON_spec_string ("token_family_slug",
- &slug),
- GNUNET_JSON_spec_uint32 ("key_index",
- &key_index),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("count",
- &count),
- NULL),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (output,
- ispec,
- &ierror_name,
- &ierror_line))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Parser failed on %s:%u for input `%s'\n",
- ierror_name,
- ierror_line,
- json_dumps (output,
- JSON_INDENT (2)));
- TALER_TESTING_FAIL (is);
- }
-
- if (0 != strcmp ("token", kind))
- {
- continue;
- }
-
- GNUNET_array_grow (ps->issued_tokens,
- ps->num_issued_tokens,
- ps->num_issued_tokens + count);
-
- for (unsigned int k = 0; k < count; k++)
- {
- struct TALER_MERCHANT_PrivateTokenDetails *details =
- &ps->issued_tokens[ps->num_issued_tokens - count + k];
-
- if (GNUNET_OK !=
- find_token_public_key (token_families,
- slug,
- key_index,
- &details->issue_pub))
- {
- TALER_TESTING_FAIL (is);
- }
-
- /* Only RSA is supported for now. */
- GNUNET_assert (GNUNET_CRYPTO_BSA_RSA ==
- details->issue_pub.public_key->cipher);
-
- TALER_token_blind_input_copy (&details->blinding_inputs,
- TALER_token_blind_input_rsa_singleton ());
- /* TODO: Where to get details->blinding_inputs from? */
- TALER_token_use_setup_random (&details->master);
- TALER_token_use_setup_priv (&details->master,
- &details->blinding_inputs,
- &details->token_priv);
- TALER_token_use_blinding_secret_create (&details->master,
- &details->blinding_inputs,
- &details->blinding_secret);
- GNUNET_CRYPTO_eddsa_key_get_public (&details->token_priv.private_key,
- &details->token_pub.public_key);
- GNUNET_CRYPTO_hash (&details->token_pub.public_key,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &details->h_token_pub.hash);
- details->envelope.blinded_pub = GNUNET_CRYPTO_message_blind_to_sign (
- details->issue_pub.public_key,
- &details->blinding_secret,
- NULL, /* TODO: Add session nonce to support CS tokens */
- &details->h_token_pub.hash,
- sizeof (details->h_token_pub.hash),
- details->blinding_inputs.blinding_inputs);
-
- if (NULL == details->envelope.blinded_pub)
- {
- GNUNET_break (0);
- TALER_TESTING_FAIL (is);
- }
- }
- }
- }
GNUNET_array_grow (output_tokens,
len_output_tokens,
diff --git a/src/testing/testing_api_cmd_post_orders.c b/src/testing/testing_api_cmd_post_orders.c
@@ -60,23 +60,6 @@ struct OrdersState
const char *expected_order_id;
/**
- * Reference to a POST /tokenfamilies command. Can be NULL.
- */
- const char *token_family_reference;
-
- /**
- * How many tokens of the token family created in
- * @a token_family_reference are required as inputs.
- */
- unsigned int num_inputs;
-
- /**
- * How many tokens of the token family created in
- * @a token_family_reference should be issued as outputs.
- */
- unsigned int num_outputs;
-
- /**
* Contract terms obtained from the backend.
*/
json_t *contract_terms;
@@ -87,11 +70,6 @@ struct OrdersState
json_t *order_terms;
/**
- * Choices array with inputs and outputs for v1 order.
- */
- json_t *choices;
-
- /**
* Contract terms hash code.
*/
struct TALER_PrivateContractHashP h_contract_terms;
@@ -589,48 +567,6 @@ orders_run2 (void *cls,
/**
- * Constructs the json for a the choices of an order request.
- *
- * @param input_slug the name of the token family to use for input, can be NULL
- * @param output_slug the name of the token family to use for the output, can be NULL.
- * @param input_count number of token inputs to require
- * @param output_count number of tokens to output
- * @param input_valid_after validity date for the input token.
- * @param output_valid_after validity date for the output token.
- * @param[out] choices where to write the json string.
- */
-static void
-make_choices_json (
- const char *input_slug,
- const char *output_slug,
- uint16_t input_count,
- uint16_t output_count,
- struct GNUNET_TIME_Timestamp input_valid_after,
- struct GNUNET_TIME_Timestamp output_valid_after,
- json_t **choices)
-{
- /* FIXME: ugly code should return c, use GNUNET_JSON_PACK() for more type-safety */
- json_t *c;
-
- c = json_pack ("[{s:o, s:o}]",
- "inputs", json_pack ("[{s:s, s:i, s:s, s:o}]",
- "kind", "token",
- "count", input_count,
- "token_family_slug", input_slug,
- "valid_after", GNUNET_JSON_from_timestamp
- (input_valid_after)),
- "outputs", json_pack ("[{s:s, s:i, s:s, s:o}]",
- "kind", "token",
- "count", output_count,
- "token_family_slug", output_slug,
- "valid_after", GNUNET_JSON_from_timestamp
- (output_valid_after)));
-
- *choices = c;
-}
-
-
-/**
* Run a "orders" CMD.
*
* @param cls closure.
@@ -644,7 +580,6 @@ orders_run3 (void *cls,
{
struct OrdersState *ps = cls;
struct GNUNET_TIME_Absolute now;
- const char *slug;
ps->is = is;
now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
@@ -663,37 +598,6 @@ orders_run3 (void *cls,
GNUNET_free (order_id);
}
- {
- const struct TALER_TESTING_Command *token_family_cmd;
- token_family_cmd =
- TALER_TESTING_interpreter_lookup_command (is,
- ps->token_family_reference);
- if (NULL == token_family_cmd)
- TALER_TESTING_FAIL (is);
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_token_family_slug (token_family_cmd,
- &slug))
- TALER_TESTING_FAIL (is);
- }
- make_choices_json (slug, slug,
- ps->num_inputs,
- ps->num_outputs,
- GNUNET_TIME_absolute_to_timestamp (now),
- GNUNET_TIME_absolute_to_timestamp (now),
- &ps->choices);
-
- GNUNET_assert (0 ==
- json_object_set_new (ps->order_terms,
- "choices",
- ps->choices)
- );
- GNUNET_assert (0 ==
- json_object_set_new (ps->order_terms,
- "version",
- json_integer (1))
- );
-
-
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&ps->nonce,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
@@ -770,7 +674,7 @@ mark_forgettable (void *cls,
* @param order_id the name of the order to add, can be NULL.
* @param refund_deadline the deadline for refunds on this order.
* @param pay_deadline the deadline for payment on this order.
- * @param amount the amount this order is for.
+ * @param amount the amount this order is for, NULL for v1 orders
* @param[out] order where to write the json string.
*/
static void
@@ -786,7 +690,7 @@ make_order_json (const char *order_id,
/* Include required fields and some dummy objects to test forgetting. */
contract_terms = json_pack (
- "{s:s, s:s?, s:s, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
+ "{s:s, s:s?, s:s?, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
"summary", "merchant-lib testcase",
"order_id", order_id,
"amount", amount,
@@ -981,7 +885,7 @@ TALER_TESTING_cmd_merchant_post_orders_choices (
const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *merchant_url,
unsigned int http_status,
- const char *token_family_reference,
+ const char *token_family_slug,
unsigned int num_inputs,
unsigned int num_outputs,
const char *order_id,
@@ -990,18 +894,75 @@ TALER_TESTING_cmd_merchant_post_orders_choices (
const char *amount)
{
struct OrdersState *ps;
+ struct TALER_Amount brutto;
+ json_t *choice;
+ json_t *choices;
+ json_t *inputs;
+ json_t *outputs;
ps = GNUNET_new (struct OrdersState);
ps->cfg = cfg;
make_order_json (order_id,
refund_deadline,
pay_deadline,
- amount,
+ NULL,
&ps->order_terms);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (amount,
+ &brutto));
+ inputs = json_array ();
+ GNUNET_assert (NULL != inputs);
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ inputs,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("kind",
+ "token"),
+ GNUNET_JSON_pack_uint64 ("count",
+ num_inputs),
+ GNUNET_JSON_pack_string ("token_family_slug",
+ token_family_slug)
+ )));
+ outputs = json_array ();
+ GNUNET_assert (NULL != outputs);
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ outputs,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("kind",
+ "token"),
+ GNUNET_JSON_pack_uint64 ("count",
+ num_outputs),
+ GNUNET_JSON_pack_string ("token_family_slug",
+ token_family_slug)
+ )));
+ choice
+ = GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("amount",
+ &brutto),
+ GNUNET_JSON_pack_array_steal ("inputs",
+ inputs),
+ GNUNET_JSON_pack_array_steal ("outputs",
+ outputs));
+ choices = json_array ();
+ GNUNET_assert (NULL != choices);
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ choices,
+ choice));
+ GNUNET_assert (0 ==
+ json_object_set_new (ps->order_terms,
+ "choices",
+ choices)
+ );
+ GNUNET_assert (0 ==
+ json_object_set_new (ps->order_terms,
+ "version",
+ json_integer (1))
+ );
+
+
ps->http_status = http_status;
- ps->token_family_reference = token_family_reference;
- ps->num_inputs = num_inputs;
- ps->num_outputs = num_outputs;
ps->expected_order_id = order_id;
ps->merchant_url = merchant_url;
ps->with_claim = true;