commit ae89e08fd7d59cd81c69221c723c64c05dfacf3f
parent d28fc4e6fc458573e3dc58f3f68b694337bc2384
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date: Wed, 30 Sep 2015 09:00:21 +0200
adding error code for primary key violation
Diffstat:
7 files changed, 430 insertions(+), 463 deletions(-)
diff --git a/src/backend-lib/merchant_db.c b/src/backend-lib/merchant_db.c
@@ -208,22 +208,25 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp)
/**
-* Inserts a contract record into the database and if successfull returns the
-* serial number of the inserted row.
+* Insert a contract record into the database and if successfull
+* return the serial number of the inserted row.
*
* @param conn the database connection
* @param timestamp the timestamp of this contract
* @param expiry the time when the contract will expire
-* @param edate when the merchant wants to receive the wire transfer corresponding
-* to this deal (this value is also a field inside the 'wire' JSON format)
-* @param refund deadline until which the merchant can return the paid amount
+* @param edate when the merchant wants to receive the wire transfer
+* corresponding to this deal (this value is also a field inside the
+* 'wire' JSON format)
+* @param refund deadline until which the merchant can return the paid
+* amount
* @param amount the taler amount corresponding to the contract
* @param hash of the stringified JSON corresponding to this contract
* @param c_id contract's id
* @param desc descripition of the contract
* @param nounce a random 64-bit nounce
* @param product description to identify a product
-* @return GNUNET_OK on success, GNUNET_SYSERR upon error
+* @return GNUNET_OK on success, GNUNET_NO if attempting to insert an
+* already inserted @a c_id, GNUNET_SYSERR for other errors.
*/
uint32_t
@@ -268,7 +271,34 @@ MERCHANT_DB_contract_create (PGconn *conn,
/* NOTE: the statement is prepared by MERCHANT_DB_initialize function */
res = TALER_PQ_exec_prepared (conn, "contract_create", params);
status = PQresultStatus (res);
- EXITIF (PGRES_COMMAND_OK != status);
+
+ if (PGRES_COMMAND_OK != status)
+ {
+ const char *sqlstate;
+
+ sqlstate = PQresultErrorField (res, PG_DIAG_SQLSTATE);
+ if (NULL == sqlstate)
+ {
+ /* very unexpected... */
+ GNUNET_break (0);
+ PQclear (res);
+ return GNUNET_SYSERR;
+ }
+ /* 40P01: deadlock, 40001: serialization failure */
+ if ( (0 == strcmp (sqlstate,
+ "23505")))
+ {
+ /* Primary key violation */
+ PQclear (res);
+ return GNUNET_NO;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Database commit failure: %s\n",
+ sqlstate);
+ PQclear (res);
+ return GNUNET_SYSERR;
+ }
+
PQclear (res);
return GNUNET_OK;
diff --git a/src/backend-lib/taler-merchant-httpd_contract.c b/src/backend-lib/taler-merchant-httpd_contract.c
@@ -24,31 +24,6 @@
} while (0)
/**
-* Generate the hash containing the information (= a nounce + merchant's IBAN) to
-* redeem money from mint in a subsequent /deposit operation
-* @param nounce the nounce
-* @param wire the merchant's wire details
-* @return the hash to be included in the contract's blob
-*
-*/
-
-static struct GNUNET_HashCode
-hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire)
-{
- struct GNUNET_HashContext *hc;
- struct GNUNET_HashCode hash;
-
- hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc, wire->iban, strlen (wire->iban));
- GNUNET_CRYPTO_hash_context_read (hc, wire->name, strlen (wire->name));
- GNUNET_CRYPTO_hash_context_read (hc, wire->bic, strlen (wire->bic));
- nounce = GNUNET_htonll (nounce);
- GNUNET_CRYPTO_hash_context_read (hc, &nounce, sizeof (nounce));
- GNUNET_CRYPTO_hash_context_finish (hc, &hash);
- return hash;
-}
-
-/**
* Take the global wire details and return a JSON containing them,
* compliantly with the Taler's API.
* @param wire the merchant's wire details
@@ -99,22 +74,24 @@ MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire,
* to this deal (this value is also a field inside the 'wire' JSON format)
* @param refund deadline until which the merchant can return the paid amount
* @param nounce the nounce used to hash the wire details
-* @param contract_str where to store
-* @return pointer to the (stringified) contract; NULL upon errors
+* @param a will be pointed to the (allocated) stringified 0-terminated contract
+* @return GNUNET_OK on success, GNUNET_NO if attempting to double insert the
+* same contract, GNUNET_SYSERR in case of other (mostly DB related) errors.
*/
/**
* TODO: inspect reference counting and, accordingly, free those json_t*(s)
* still allocated */
-char *
-MERCHANT_handle_contract (const json_t *j_contract,
+uint32_t
+MERCHANT_handle_contract (json_t *j_contract,
PGconn *db_conn,
struct Contract *contract,
struct GNUNET_TIME_Absolute timestamp,
struct GNUNET_TIME_Absolute expiry,
struct GNUNET_TIME_Absolute edate,
struct GNUNET_TIME_Absolute refund,
+ char **a,
uint64_t nounce)
{
json_t *j_amount;
@@ -135,39 +112,27 @@ MERCHANT_handle_contract (const json_t *j_contract,
&j_product_id))
{
printf ("no unpacking\n");
- return NULL;
+ return GNUNET_SYSERR;
}
- /* DB will store the amount -- WARNING: this call produces a
- 'protocol violation' in json.c */
-
- #if 0
- char *str = json_dumps (j_amount, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
- printf ("extracted amount : %s\n", str);
- #endif
-
-
TALER_json_to_amount (j_amount, &amount);
contract_str = json_dumps (j_contract, JSON_COMPACT | JSON_PRESERVE_ORDER);
+ *a = contract_str;
GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 1,
&contract->h_contract_details);
contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
contract->purpose.size = htonl (sizeof (struct Contract));
// DB mgmt
- if (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn,
- timestamp,
- expiry,
- edate,
- refund,
- &amount,
- &contract->h_contract_details,
- (uint64_t) j_trans_id, // safe?
- contract_str,
- nounce,
- (uint64_t) j_product_id))
- return NULL;
- return contract_str;
+ return MERCHANT_DB_contract_create (db_conn,
+ timestamp,
+ expiry,
+ edate,
+ refund,
+ &amount,
+ &contract->h_contract_details,
+ (uint64_t) j_trans_id, // safe?
+ contract_str,
+ nounce,
+ (uint64_t) j_product_id);
}
-
-
diff --git a/src/backend-lib/taler_merchant_contract_lib.h b/src/backend-lib/taler_merchant_contract_lib.h
@@ -17,47 +17,6 @@ struct Contract
};
-GNUNET_NETWORK_STRUCT_BEGIN
-
-struct ContractNBO
-{
- /**
- * Purpose header for the signature over contract
- */
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
-
- /**
- * The transaction identifier. NOTE: it was m[13]. TODO:
- * change the API accordingly!
- */
- uint64_t m;
-
- /**
- * Expiry time
- */
- struct GNUNET_TIME_AbsoluteNBO t;
-
- /**
- * The invoice amount
- */
- struct TALER_AmountNBO amount;
-
- /**
- * The hash of the merchant's wire details (bank account information), with a nounce
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * Hash of the JSON contract in UTF-8 including 0-termination,
- * using JSON_COMPACT encoding with sorted fields.
- */
- struct GNUNET_HashCode h_contract_details;
-
-};
-
-GNUNET_NETWORK_STRUCT_END
-
-
/**
* Take the global wire details and return a JSON containing them,
* compliantly with the Taler's API.
@@ -86,20 +45,22 @@ MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire,
* to this deal (this value is also a field inside the 'wire' JSON format)
* @param refund deadline until which the merchant can return the paid amount
* @param nounce the nounce used to hash the wire details
-* @param contract_str where to store
-* @return pointer to the (stringified) contract; NULL upon errors
+* @param a will be pointed to the (allocated) stringified 0-terminated contract
+* @return GNUNET_OK on success, GNUNET_NO if attempting to double insert the
+* same contract, GNUNET_SYSERR in case of other (mostly DB related) errors.
*/
/**
* TODO: inspect reference counting and, accordingly, free those json_t*(s)
* still allocated */
-char *
-MERCHANT_handle_contract (const json_t *j_contract,
+uint32_t
+MERCHANT_handle_contract (json_t *j_contract,
PGconn *db_conn,
struct Contract *contract,
struct GNUNET_TIME_Absolute timestamp,
struct GNUNET_TIME_Absolute expiry,
struct GNUNET_TIME_Absolute edate,
struct GNUNET_TIME_Absolute refund,
+ char **a,
uint64_t nounce);
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
@@ -366,7 +366,7 @@ url_handler (void *cls,
CURL *curl;
CURLcode curl_res;
- int res = GNUNET_SYSERR;
+ uint32_t res = GNUNET_SYSERR;
#define URL_HELLO "/hello"
#define URL_CONTRACT "/contract"
@@ -588,18 +588,25 @@ url_handler (void *cls,
goto end;
}
- if (NULL == (contract_str = MERCHANT_handle_contract (root,
- db_conn,
- &contract,
- now,
- expiry,
- edate,
- refund,
- nounce)))
+ res = MERCHANT_handle_contract (root,
+ db_conn,
+ &contract,
+ now,
+ expiry,
+ edate,
+ refund,
+ &contract_str,
+ nounce);
+ if (GNUNET_SYSERR == res)
{
status = MHD_HTTP_INTERNAL_SERVER_ERROR;
goto end;
}
+ if (GNUNET_NO == res)
+ {
+ status = MHD_HTTP_METHOD_NOT_ACCEPTABLE;
+ goto end;
+ }
GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &c_sig);
GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 1, &h_contract_str);
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
@@ -2,17 +2,17 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend-lib/
bin_PROGRAMS = \
- merchant-contract-test
+ test-contract
#merchant_contract_test_CFLAGS = \
# -Wl,--verbose
-merchant_contract_test_SOURCES = \
- merchant-contract-test.c \
+test_contract_SOURCES = \
+ test_contract.c \
merchant.c \
../backend-lib/merchant_db.c ../backend-lib/merchant_db.h
-merchant_contract_test_LDADD = \
+test_contract_LDADD = \
$(LIBGCRYPT_LIBS) \
-ltalerutil \
-ltalermerchant \
@@ -22,5 +22,5 @@ merchant_contract_test_LDADD = \
-ltalerpq \
-lgnunetpostgres \
-lpq \
- -ltalermerchant \
+ $(top_srcdir)/src/backend-lib/libtalermerchant.la \
-lpthread
diff --git a/src/tests/merchant-contract-test.c b/src/tests/merchant-contract-test.c
@@ -1,343 +0,0 @@
-/*
- This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
-* @file merchant/tests/merchant-non-http-test.c
-* @brief test for various merchant's capabilities
-* @author Marcello Stanisci
-*/
-
-#include "platform.h"
-#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include <taler/taler_json_lib.h>
-#include "merchant_db.h"
-#include <taler_merchant_lib.h>
-
-PGconn *db_conn;
-
-static int dry;
-struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
-char *keyfile;
-static int result;
-static struct MERCHANT_WIREFORMAT_Sepa *wire;
-static struct GNUNET_SCHEDULER_Task *shutdown_task;
-
-extern
-struct MERCHANT_WIREFORMAT_Sepa *
-TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-/**
- * Shutdown task (magically invoked when the application is being
- * quit)
- *
- * @param cls NULL
- * @param tc scheduler task context
- */
-static void
-do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-
- if (NULL != db_conn)
- {
- MERCHANT_DB_disconnect (db_conn);
- db_conn = NULL;
- }
-}
-
-extern uint32_t
-MERCHANT_DB_get_contract_values (PGconn *conn,
- const struct GNUNET_HashCode *h_contract,
- uint64_t *nounce,
- struct GNUNET_TIME_Absolute *edate);
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param config configuration
- */
-static void
-run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *config)
-
-{
- json_t *j_fake_contract;
- json_t *j_wire;
- json_t *j_details;
- json_t *j_mints;
- json_t *j_item;
- json_t *j_amount;
- json_t *j_tax_amount;
- json_t *j_item_price;
- json_t *j_max_fee;
- json_t *j_teatax;
- json_t *j_id; // trans id
- json_t *j_pid; // product id
- json_t *j_quantity;
- json_t *j_delloc;
- json_t *j_merchant;
- json_t *j_merchant_jurisdiction;
- json_t *j_merchant_zipcode;
- json_t *j_lnames;
- json_t *j_deldate;
- char *contract_tmp_str;
- char *desc;
- struct TALER_Amount amount;
- int64_t t_id;
- int64_t p_id;
- #ifdef OBSOLETE
- struct ContractNBO contract;
- #else
- struct Contract contract;
- #endif
- struct GNUNET_TIME_Absolute deldate;
- struct GNUNET_TIME_Absolute edate;
- struct GNUNET_TIME_Absolute now;
- uint64_t nounce;
- struct GNUNET_HashCode h_contract_str;
-
- db_conn = NULL;
- keyfile = NULL;
- privkey = NULL;
- wire = NULL;
-
-
- db_conn = MERCHANT_DB_connect (config);
- if (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_NO))
- {
- printf ("no db init'd\n");
- result = GNUNET_SYSERR;
- }
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config,
- "merchant",
- "KEYFILE",
- &keyfile))
- {
- printf ("no keyfile entry in cfg file\n");
- result = GNUNET_SYSERR;
- }
-
- privkey = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
- wire = TALER_MERCHANT_parse_wireformat_sepa (config);
- shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown, NULL);
-
- /**
- * 'Root' object of the contract, leaving some holes to bi filled
- * up by the merchant library.
- *
- */
-
- /* Amount */
- TALER_amount_get_zero ("EUR", &amount);
- j_amount = TALER_json_from_amount (&amount);
-
- /* Transaction ID*/
- t_id = (int32_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
-
- if (t_id < 0)
- j_id = json_integer ((-1) * t_id);
- else
- j_id = json_integer (t_id);
-
- /**
- * Holes:
- *
- * - 'h_wire'
- * - 'timestamp'
- *
- */
-
- /**
- *
- * Preparing the 'details' sub-object: an array of 'item' objects
- * plus some juridical and delivery-aware informations
- *
- */
-
- /**
- *
- * Preparing a 'item' sub-object
- */
-
- /* Description */
- desc = "Fake purchase";
-
- j_max_fee = TALER_json_from_amount (&amount);
- /* Quantity: OPTIONAL FIELD */
- j_quantity = json_integer (3);
-
- /* item price: OPTIONAL FIELD*/
- j_item_price = TALER_json_from_amount (&amount);
-
- /* Product ID */
- p_id = (int32_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
-
- if (p_id < 0)
- j_pid = json_integer ((-1) * p_id);
- else
- j_pid = json_integer (p_id);
-
- /* Taxes: array of "tax_name" : {tax amount} */
- j_tax_amount = TALER_json_from_amount (&amount);
- j_teatax = json_pack ("{s:o}",
- "teatax", j_tax_amount);
-
- if (NULL == (j_item = json_pack ("{s:s, s:I, s:o, s:[o]}",
- "description", desc,
- "quantity", json_integer_value (j_quantity),
- "itemprice", j_item_price,
- "taxes", j_teatax)))
- {
- printf ("error in packing [j_item: %p]\n", j_item);
- return;
- }
-
- /* End of 'item' object definition */
-
- /* Delivery date: OPTIONAL FIELD */
- now = GNUNET_TIME_absolute_get ();
- TALER_round_abs_time (&now);
-// deldate = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS);
- j_deldate = TALER_json_from_abs (now);
-
- /* Delivery location: OPTIONAL FIELD */
- j_delloc = json_string ("MALTK"); /* just a 'tag' which points to some well defined location */
-
-
- /* Merchant jurisdiction: OPTIONAL FIELD (with its fields from 3rd to the last being optional)
- * for another optional field */
- j_merchant_zipcode = json_integer (9468);
- j_merchant_jurisdiction = json_pack ("{s:s, s:s, s:s, s:s, s:s, s:I}",
- "country", "Test Country",
- "city", "Test City",
- "state", "NA",
- "region", "NA",
- "province", "NA",
- "ZIP code", json_integer_value (j_merchant_zipcode));
-
- /* Merchant details */
- j_merchant = json_pack ("{s:s, s:s, s:o}",
- "address", "UALMP",
- "name", "test merchant",
- "jurisdiction", j_merchant_jurisdiction);
-
-
- /* L-names mapping */
- j_lnames = json_pack ("[{s:s}, {s:s}]",
- "MALTK", "Test Address 1",
- "UALMP", "Second Test Address");
-
-
-
- j_details = json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o}",
- "product_id", json_integer_value (j_pid),
- "items", j_item,
- "delivery date", j_deldate,
- "delivery location", j_delloc,
- "merchant", j_merchant,
- "L-names", j_lnames);
-
- /* Faking out the mints' list */
- j_mints = json_pack ("[{s:s}]",
- "demo.taler.net",
- "Q1WVGRGC1F4W7RYC6M23AEGFEXQEHQ730K3GG0B67VPHQSRR75H0");
-
- j_fake_contract = json_pack ("{s:o, s:o, s:I, s:o, s:o}",
- "amount", j_amount,
- "max fee", j_max_fee,
- "trans_id", json_integer_value (j_id),
- "mints", j_mints,
- "details", j_details);
- #if 0
- str = json_dumps (j_fake_contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
- printf ("%s\n", str);
- return;
- #endif
-
- nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
-
- j_wire = MERCHANT_get_wire_json (wire, nounce, now);
-
- if (NULL == (contract_tmp_str = MERCHANT_handle_contract (j_fake_contract,
- db_conn,
- &contract,
- now,
- now,
- now,
- now,
- nounce)))
-
- printf ("errors in contract handling\n");
- else
- printf ("handling contract fine\n");
-
-
- /* try to get from DB the generated contract
-
- printf ("contract string : %s\n", contract_tmp_str);
- return;
-
- */
-
- GNUNET_CRYPTO_hash (contract_tmp_str, strlen (contract_tmp_str) + 1, &h_contract_str);
- if (GNUNET_SYSERR == MERCHANT_DB_get_contract_values (db_conn, &h_contract_str, &nounce, &edate))
- printf ("no hash found\n");
- else
- {
-
- char *late = GNUNET_STRINGS_absolute_time_to_string (edate);
- printf ("hash found!, nounce is : %llu\n", nounce);
- printf ("hash found!, time is : %s\n", late);
- }
-
-}
-
-
-/**
- * The main function of the test tool
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc, char *const *argv)
-{
-
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'t', "temp", NULL,
- gettext_noop ("Use temporary database tables"), GNUNET_NO,
- &GNUNET_GETOPT_set_one, &dry},
- GNUNET_GETOPT_OPTION_END
- };
-
-
- if (GNUNET_OK !=
- GNUNET_PROGRAM_run (argc, argv,
- "merchant-contract-test",
- "Test for contracts mgmt",
- options, &run, NULL))
- return 3;
- return (GNUNET_OK == result) ? 0 : 1;
-
-
-
-}
diff --git a/src/tests/test_contract.c b/src/tests/test_contract.c
@@ -0,0 +1,347 @@
+/*
+ This file is part of TALER
+ (C) 2014 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+* @file merchant/tests/merchant-non-http-test.c
+* @brief test for various merchant's capabilities
+* @author Marcello Stanisci
+*/
+
+#include "platform.h"
+#include <jansson.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <taler/taler_json_lib.h>
+#include "merchant.h"
+#include "merchant_db.h"
+#include <taler_merchant_lib.h>
+
+PGconn *db_conn;
+
+static int dry;
+struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
+char *keyfile;
+static int result;
+static struct MERCHANT_WIREFORMAT_Sepa *wire;
+static struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+extern
+struct MERCHANT_WIREFORMAT_Sepa *
+TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+/**
+ * Shutdown task (magically invoked when the application is being
+ * quit)
+ *
+ * @param cls NULL
+ * @param tc scheduler task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+ if (NULL != db_conn)
+ {
+ MERCHANT_DB_disconnect (db_conn);
+ db_conn = NULL;
+ }
+}
+
+extern uint32_t
+MERCHANT_DB_get_contract_values (PGconn *conn,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t *nounce,
+ struct GNUNET_TIME_Absolute *edate);
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param config configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+
+{
+ json_t *j_fake_contract;
+ json_t *j_wire;
+ json_t *j_details;
+ json_t *j_mints;
+ json_t *j_item;
+ json_t *j_amount;
+ json_t *j_tax_amount;
+ json_t *j_item_price;
+ json_t *j_max_fee;
+ json_t *j_teatax;
+ json_t *j_id; // trans id
+ json_t *j_pid; // product id
+ json_t *j_quantity;
+ json_t *j_delloc;
+ json_t *j_merchant;
+ json_t *j_merchant_jurisdiction;
+ json_t *j_merchant_zipcode;
+ json_t *j_lnames;
+ json_t *j_deldate;
+ char *contract_tmp_str;
+ char *desc;
+ struct TALER_Amount amount;
+ int64_t t_id;
+ int64_t p_id;
+ #ifdef OBSOLETE
+ struct ContractNBO contract;
+ #else
+ struct Contract contract;
+ #endif
+ struct GNUNET_TIME_Absolute edate;
+ struct GNUNET_TIME_Absolute now;
+ uint64_t nounce;
+ struct GNUNET_HashCode h_contract_str;
+ char *aa;
+ char *fancy_time;
+ uint32_t ret;
+
+ db_conn = NULL;
+ keyfile = NULL;
+ privkey = NULL;
+ wire = NULL;
+
+
+ db_conn = MERCHANT_DB_connect (config);
+ if (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_NO))
+ {
+ printf ("no db init'd\n");
+ result = GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config,
+ "merchant",
+ "KEYFILE",
+ &keyfile))
+ {
+ printf ("no keyfile entry in cfg file\n");
+ result = GNUNET_SYSERR;
+ }
+
+ privkey = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
+ wire = TALER_MERCHANT_parse_wireformat_sepa (config);
+ shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
+
+ /**
+ * 'Root' object of the contract, leaving some holes to bi filled
+ * up by the merchant library.
+ *
+ */
+
+ /* Amount */
+ TALER_amount_get_zero ("EUR", &amount);
+ j_amount = TALER_json_from_amount (&amount);
+
+ /* Transaction ID*/
+ //t_id = (int32_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
+ t_id = 321;
+
+ if (t_id < 0)
+ j_id = json_integer ((-1) * t_id);
+ else
+ j_id = json_integer (t_id);
+
+ /**
+ * Holes:
+ *
+ * - 'h_wire'
+ * - 'timestamp'
+ *
+ */
+
+ /**
+ *
+ * Preparing the 'details' sub-object: an array of 'item' objects
+ * plus some juridical and delivery-aware informations
+ *
+ */
+
+ /**
+ *
+ * Preparing a 'item' sub-object
+ */
+
+ /* Description */
+ desc = "Fake purchase";
+
+ j_max_fee = TALER_json_from_amount (&amount);
+ /* Quantity: OPTIONAL FIELD */
+ j_quantity = json_integer (3);
+
+ /* item price: OPTIONAL FIELD*/
+ j_item_price = TALER_json_from_amount (&amount);
+
+ /* Product ID */
+ p_id = (int32_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
+
+ if (p_id < 0)
+ j_pid = json_integer ((-1) * p_id);
+ else
+ j_pid = json_integer (p_id);
+
+ /* Taxes: array of "tax_name" : {tax amount} */
+ j_tax_amount = TALER_json_from_amount (&amount);
+ j_teatax = json_pack ("{s:o}",
+ "teatax", j_tax_amount);
+
+ if (NULL == (j_item = json_pack ("{s:s, s:I, s:o, s:[o]}",
+ "description", desc,
+ "quantity", json_integer_value (j_quantity),
+ "itemprice", j_item_price,
+ "taxes", j_teatax)))
+ {
+ printf ("error in packing [j_item: %p]\n", j_item);
+ return;
+ }
+
+ /* End of 'item' object definition */
+
+ /* Delivery date: OPTIONAL FIELD */
+ now = GNUNET_TIME_absolute_get ();
+ TALER_round_abs_time (&now);
+// deldate = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS);
+ j_deldate = TALER_json_from_abs (now);
+
+ /* Delivery location: OPTIONAL FIELD */
+ j_delloc = json_string ("MALTK"); /* just a 'tag' which points to some well defined location */
+
+
+ /* Merchant jurisdiction: OPTIONAL FIELD (with its fields from 3rd to the last being optional)
+ * for another optional field */
+ j_merchant_zipcode = json_integer (9468);
+ j_merchant_jurisdiction = json_pack ("{s:s, s:s, s:s, s:s, s:s, s:I}",
+ "country", "Test Country",
+ "city", "Test City",
+ "state", "NA",
+ "region", "NA",
+ "province", "NA",
+ "ZIP code", json_integer_value (j_merchant_zipcode));
+
+ /* Merchant details */
+ j_merchant = json_pack ("{s:s, s:s, s:o}",
+ "address", "UALMP",
+ "name", "test merchant",
+ "jurisdiction", j_merchant_jurisdiction);
+
+
+ /* L-names mapping */
+ j_lnames = json_pack ("[{s:s}, {s:s}]",
+ "MALTK", "Test Address 1",
+ "UALMP", "Second Test Address");
+
+
+
+ j_details = json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o}",
+ "product_id", json_integer_value (j_pid),
+ "items", j_item,
+ "delivery date", j_deldate,
+ "delivery location", j_delloc,
+ "merchant", j_merchant,
+ "L-names", j_lnames);
+
+ /* Faking out the mints' list */
+ j_mints = json_pack ("[{s:s}]",
+ "demo.taler.net",
+ "Q1WVGRGC1F4W7RYC6M23AEGFEXQEHQ730K3GG0B67VPHQSRR75H0");
+
+ j_fake_contract = json_pack ("{s:o, s:o, s:I, s:o, s:o}",
+ "amount", j_amount,
+ "max fee", j_max_fee,
+ "trans_id", json_integer_value (j_id),
+ "mints", j_mints,
+ "details", j_details);
+ #if 0
+ str = json_dumps (j_fake_contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
+ printf ("%s\n", str);
+ return;
+ #endif
+
+ nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
+
+ j_wire = MERCHANT_get_wire_json (wire, nounce, now);
+
+ ret = MERCHANT_handle_contract (j_fake_contract,
+ db_conn,
+ &contract,
+ now,
+ now,
+ now,
+ now,
+ &aa,
+ nounce);
+ if (ret == GNUNET_NO)
+ {
+ printf ("Failed, contract already in DB\n");
+ return;
+ }
+ else
+ printf ("handling contract fine\n");
+
+
+ printf ("contract string : %s\n", aa);
+
+ GNUNET_CRYPTO_hash (aa, strlen (aa) + 1, &h_contract_str);
+ if (GNUNET_SYSERR == MERCHANT_DB_get_contract_values (db_conn, &h_contract_str, &nounce, &edate))
+ printf ("no hash found\n");
+ else
+ {
+
+ fancy_time = GNUNET_STRINGS_absolute_time_to_string (edate);
+ printf ("hash found!, nounce is : %llu\n", nounce);
+ printf ("hash found!, time is : %s\n", fancy_time);
+ }
+
+ return;
+}
+
+
+/**
+ * The main function of the test tool
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'t', "temp", NULL,
+ gettext_noop ("Use temporary database tables"), GNUNET_NO,
+ &GNUNET_GETOPT_set_one, &dry},
+ GNUNET_GETOPT_OPTION_END
+ };
+
+
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run (argc, argv,
+ "merchant-contract-test",
+ "Test for contracts mgmt",
+ options, &run, NULL))
+ return 3;
+ return (GNUNET_OK == result) ? 0 : 1;
+
+
+
+}