summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcello Stanisci <marcello.stanisci@inria.fr>2015-09-30 09:00:21 +0200
committerMarcello Stanisci <marcello.stanisci@inria.fr>2015-09-30 09:00:21 +0200
commitae89e08fd7d59cd81c69221c723c64c05dfacf3f (patch)
tree8fbe1d2dbf94a9e5c0f19a62be1d57418e4ac902
parentd28fc4e6fc458573e3dc58f3f68b694337bc2384 (diff)
downloadmerchant-ae89e08fd7d59cd81c69221c723c64c05dfacf3f.tar.gz
merchant-ae89e08fd7d59cd81c69221c723c64c05dfacf3f.tar.bz2
merchant-ae89e08fd7d59cd81c69221c723c64c05dfacf3f.zip
adding error code for primary key violation
-rw-r--r--src/backend-lib/merchant_db.c44
-rw-r--r--src/backend-lib/taler-merchant-httpd_contract.c73
-rw-r--r--src/backend-lib/taler_merchant_contract_lib.h51
-rw-r--r--src/backend/taler-merchant-httpd.c25
-rw-r--r--src/tests/Makefile.am10
-rw-r--r--src/tests/test_contract.c (renamed from src/tests/merchant-contract-test.c)46
6 files changed, 108 insertions, 141 deletions
diff --git a/src/backend-lib/merchant_db.c b/src/backend-lib/merchant_db.c
index 6c67eb9d..befb2c48 100644
--- 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
index 1f9d095a..5a937e66 100644
--- 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
index cc02f70d..692c849d 100644
--- 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
index 15f72586..bd74405a 100644
--- 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
index dc88fc08..8dd350e7 100644
--- 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/test_contract.c
index 20f8d2ba..47b3b0e6 100644
--- a/src/tests/merchant-contract-test.c
+++ b/src/tests/test_contract.c
@@ -24,6 +24,7 @@
#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>
@@ -107,11 +108,13 @@ run (void *cls, char *const *args, const char *cfgfile,
#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;
+ char *aa;
+ char *fancy_time;
+ uint32_t ret;
db_conn = NULL;
keyfile = NULL;
@@ -150,7 +153,8 @@ run (void *cls, char *const *args, const char *cfgfile,
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 = (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);
@@ -276,38 +280,38 @@ run (void *cls, char *const *args, const char *cfgfile,
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");
+ 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");
- /* try to get from DB the generated contract
-
- printf ("contract string : %s\n", contract_tmp_str);
- return;
-
- */
+ printf ("contract string : %s\n", aa);
- GNUNET_CRYPTO_hash (contract_tmp_str, strlen (contract_tmp_str) + 1, &h_contract_str);
+ 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
{
- char *late = GNUNET_STRINGS_absolute_time_to_string (edate);
+ fancy_time = GNUNET_STRINGS_absolute_time_to_string (edate);
printf ("hash found!, nounce is : %llu\n", nounce);
- printf ("hash found!, time is : %s\n", late);
+ printf ("hash found!, time is : %s\n", fancy_time);
}
+ return;
}