diff options
26 files changed, 1822 insertions, 150 deletions
diff --git a/configure.ac b/configure.ac index f32d7fdd..55d1e196 100644 --- a/configure.ac +++ b/configure.ac @@ -180,5 +180,7 @@ AC_CHECK_FUNCS([strdup]) AC_CONFIG_FILES([Makefile src/Makefile src/include/Makefile -src/backend/Makefile]) +src/tests/Makefile +src/backend/Makefile +src/backend-lib/Makefile]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 46fa8eba..bebdae8c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,2 +1,2 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include -SUBDIRS = include backend +SUBDIRS = include backend backend-lib diff --git a/src/backend-lib/Makefile.am b/src/backend-lib/Makefile.am new file mode 100644 index 00000000..61867e41 --- /dev/null +++ b/src/backend-lib/Makefile.am @@ -0,0 +1,24 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +lib_LTLIBRARIES = \ + libtalermerchant.la + +include_HEADERS = \ + taler_merchant_lib.h \ + taler_merchant_contract_lib.h + +libtalermerchant_la_SOURCES = \ + taler-merchant-httpd_contract.c \ + taler_merchant_contract_lib.h \ + merchant_db.c merchant_db.h \ + merchant.h + +libtalermerchant_la_LIBADD = \ + $(LIBGCRYPT_LIBS) \ + -ltalerutil \ + -lgnunetutil \ + -ltalerpq \ + -lgnunetpostgres \ + -lpq \ + -lpthread diff --git a/src/backend-lib/merchant_db.c b/src/backend-lib/merchant_db.c new file mode 100644 index 00000000..274de25a --- /dev/null +++ b/src/backend-lib/merchant_db.c @@ -0,0 +1,354 @@ +/* + 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/merchant_db.c + * @brief database helper functions used by the merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <taler/taler_util.h> +#include <taler/taler_pq_lib.h> +#include "merchant_db.h" + + +#define PQSQL_strerror(kind, cmd, res) \ + GNUNET_log_from (kind, "merchant-db", \ + "SQL %s failed at %s:%u with error: %s", \ + cmd, __FILE__, __LINE__, PQresultErrorMessage (res)); + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Connect to postgresql database + * + * @param cfg the configuration handle + * @return connection to the postgresql database; NULL upon error + */ +PGconn * +MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + return GNUNET_POSTGRES_connect (cfg, "merchant-db"); +} + + +/** + * Disconnect from the database + * + * @param conn database handle to close + */ +void +MERCHANT_DB_disconnect (PGconn *conn) +{ + PQfinish (conn); +} + + +/** + * Initialize merchant tables + * + * @param conn the connection handle to postgres db. + * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the @a conn is closed + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +MERCHANT_DB_initialize (PGconn *conn, int tmp) +{ + const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; + char *sql; + PGresult *res; + ExecStatusType status; + int ret; + + res = NULL; + (void) GNUNET_asprintf (&sql, + "BEGIN TRANSACTION;" + "CREATE %1$s TABLE IF NOT EXISTS contracts (" + "contract_id INT8 PRIMARY KEY," + "amount INT8 NOT NULL," + "amount_fraction INT4 NOT NULL," + "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," + "description TEXT NOT NULL," + "nounce INT8 NOT NULL," + "expiry INT8 NOT NULL," + "product INT8 NOT NULL);" + "CREATE %1$s TABLE IF NOT EXISTS checkouts (" + "coin_pub BYTEA PRIMARY KEY," + "contract_id INT8 REFERENCES contracts(contract_id)," + "amount INT4 NOT NULL," + "amount_fraction INT4 NOT NULL," + "coin_sig BYTEA NOT NULL);", + tmp_str); + ret = GNUNET_POSTGRES_exec (conn, sql); + (void) GNUNET_POSTGRES_exec (conn, + (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK;"); + GNUNET_free (sql); + if (GNUNET_OK != ret) + return ret; + + while (NULL != (res = PQgetResult (conn))) + { + status = PQresultStatus (res); + PQclear (res); + } + + EXITIF (NULL == (res = PQprepare + (conn, + "contract_create", + "INSERT INTO contracts" + "(contract_id, amount, amount_fraction, amount_currency," + "description, nounce, expiry, product) VALUES" + "($1, $2, $3, $4, $5, $6, $7, $8)", + 8, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "get_contract_product", + "SELECT (" + "product" + ") FROM contracts " + "WHERE (" + "contract_id=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "checkout_create", + "INSERT INTO checkouts (" + "coin_pub," + "contract_id," + "amount," + "amount_fraction," + "coin_sig" + ") VALUES (" + "$1, $2, $3, $4, $5" + ")", + 5, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "get_checkout_product", + "SELECT (" + "product" + ") FROM contracts " + "WHERE " + "contract_id IN (" + "SELECT (contract_id) FROM checkouts " + "WHERE coin_pub=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); + PQclear (res); + + return GNUNET_OK; + + EXITIF_exit: + if (NULL != res) + { + PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res); + PQclear (res); + } + return GNUNET_SYSERR; +} + + +/** + * Inserts a contract record into the database and if successfull returns the + * serial number of the inserted row. + * + * @param conn the database connection + * @param expiry the time when the contract will expire + * @param amount the taler amount corresponding to the 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 + */ + +uint32_t +MERCHANT_DB_contract_create (PGconn *conn, + const struct GNUNET_TIME_Absolute *expiry, + const struct TALER_Amount *amount, + uint64_t c_id, + const char *desc, + uint64_t nounce, + uint64_t product) +{ + PGresult *res; + #if 0 + uint64_t expiry_ms_nbo; + uint64_t value_nbo; + uint32_t fraction_nbo; + uint64_t nounce_nbo; + #endif + ExecStatusType status; + + #if 0 + /* + NOTE: the conversion to nl(l) happens *inside* the query param helpers; since + the policy imposes this format for storing values. */ + value_nbo = GNUNET_htonll (amount->value); + fraction_nbo = GNUNET_htonll (amount->fraction); + nounce_nbo = GNUNET_htonll (nounce); + expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); + product = GNUNET_htonll (product); + #endif + + /* ported. To be tested/compiled */ + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_uint64 (&c_id), + TALER_PQ_query_param_amount (amount), + /* a *string* is being put in the following statement, + though the API talks about a *blob*. Will this be liked by + the DB ? */ + // the following inserts a string as a blob. Will Taler provide a param-from-string helper? + TALER_PQ_query_param_fixed_size (desc, strlen(desc)), + TALER_PQ_query_param_uint64 (&nounce), + TALER_PQ_query_param_absolute_time (expiry), + TALER_PQ_query_param_uint64 (&product), + TALER_PQ_query_param_end + }; + + /* 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); + PQclear (res); + return GNUNET_OK; + + EXITIF_exit: + PQclear (res); + return GNUNET_SYSERR; +} + +long long +MERCHANT_DB_get_contract_product (PGconn *conn, + uint64_t contract_id) +{ + PGresult *res; + uint64_t product; + ExecStatusType status; + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_uint64 (&contract_id), + TALER_PQ_query_param_end + }; + struct TALER_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_uint64 ("product", &product), + TALER_PQ_result_spec_end + }; + + contract_id = GNUNET_htonll (contract_id); + res = TALER_PQ_exec_prepared (conn, "get_contract_product", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) product); + + EXITIF_exit: + PQclear (res); + return -1; +} + +unsigned int +MERCHANT_DB_checkout_create (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, + uint64_t transaction_id, + struct TALER_Amount *amount, + struct GNUNET_CRYPTO_rsa_Signature *coin_sig) +{ + PGresult *res; + ExecStatusType status; + uint32_t value_nbo; + uint32_t fraction_nbo; + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_rsa_public_key (coin_pub), + TALER_PQ_query_param_uint64 (&transaction_id), + TALER_PQ_query_param_uint32 (&value_nbo), + TALER_PQ_query_param_uint32 (&fraction_nbo), + TALER_PQ_query_param_rsa_signature (coin_sig), + TALER_PQ_query_param_end + }; + + transaction_id = GNUNET_htonll (transaction_id); + value_nbo = htonl (amount->value); + fraction_nbo = htonl (amount->fraction); + res = TALER_PQ_exec_prepared (conn, "checkout_create", params); + status = PQresultStatus (res); + EXITIF (PGRES_COMMAND_OK != status); + PQclear (res); + return GNUNET_OK; + + EXITIF_exit: + PQclear (res); + return GNUNET_SYSERR; +} + + +long long +MERCHANT_DB_get_checkout_product (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub) +{ + PGresult *res; + ExecStatusType status; + uint64_t product; + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_rsa_public_key (coin_pub), + TALER_PQ_query_param_end + }; + struct TALER_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_uint64 ("product", &product), + TALER_PQ_result_spec_end + }; + + product = -1; + res = TALER_PQ_exec_prepared (conn, "get_checkout_product", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + if (0 == PQntuples (res)) + { + TALER_LOG_DEBUG ("Checkout not found for given coin"); + goto EXITIF_exit; + } + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) product); + + EXITIF_exit: + PQclear (res); + return -1; +} +/* end of merchant-db.c */ diff --git a/src/backend-lib/merchant_db.h b/src/backend-lib/merchant_db.h new file mode 100644 index 00000000..a723b229 --- /dev/null +++ b/src/backend-lib/merchant_db.h @@ -0,0 +1,101 @@ +/* + 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/merchant_db.h + * @brief database helper functions used by the merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#ifndef MERCHANT_DB_H +#define MERCHANT_DB_H + +#include <gnunet/gnunet_postgres_lib.h> +#include <taler/taler_util.h> + +/** + * Connect to postgresql database + * + * @param cfg the configuration handle + * @return connection to the postgresql database; NULL upon error + */ +PGconn * +MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Disconnect from the database + * + * @param conn database handle to close + */ +void +MERCHANT_DB_disconnect (PGconn *conn); + + +/** + * Initialize merchant tables + * + * @param conn the connection handle to postgres db. + * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the @a conn is closed + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +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. + * + * @param conn the database connection + * @param expiry the time when the contract will expire + * @param amount the taler amount corresponding to the contract + * @param c_id this contract's identification number + * @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 + */ + +uint32_t +MERCHANT_DB_contract_create (PGconn *conn, + const struct GNUNET_TIME_Absolute *expiry, + const struct TALER_Amount *amount, + uint64_t c_id, + const char *desc, + uint64_t nounce, + uint64_t product); + +long long +MERCHANT_DB_get_contract_product (PGconn *conn, + uint64_t contract_id); + +unsigned int +MERCHANT_DB_checkout_create (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, + uint64_t transaction_id, + struct TALER_Amount *amount, + struct GNUNET_CRYPTO_rsa_Signature *coin_sig); + + +long long +MERCHANT_DB_get_checkout_product (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub); + +#endif /* MERCHANT_DB_H */ + +/* end of merchant-db.h */ diff --git a/src/backend-lib/taler-merchant-httpd_contract.c b/src/backend-lib/taler-merchant-httpd_contract.c new file mode 100644 index 00000000..55c56e0a --- /dev/null +++ b/src/backend-lib/taler-merchant-httpd_contract.c @@ -0,0 +1,144 @@ +#include "platform.h" +#include <jansson.h> +#include <taler/taler_signatures.h> +#include <gnunet/gnunet_util_lib.h> +#include "merchant.h" +#include "merchant_db.h" +#include "taler_merchant_contract_lib.h" + + +/* TODO: make this file a library, and programmatically call the following + * functions */ + +/** + * Macro to round microseconds to seconds in GNUNET_TIME_* structs. + */ +#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000) + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } 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 from the frontend the (partly) generated contract and fill +* the missing values in it; for example, the SEPA-aware values. +* Moreover, it stores the contract in the DB and does the signature of it. +* @param contract parsed contract, originated by the frontend +* @param db_conn the handle to the local DB +* @param kpriv merchant's private key +* @param wire merchant's bank's details +* @param sig where to store the signature +* @return pointer to the complete JSON; NULL upon errors +*/ + +/* TODO: this handles a simplified version (for debugging purposes) + of the contract. To expand to the full fledged version */ + +json_t * +MERCHANT_handle_contract (json_t *contract, + PGconn *db_conn, + struct GNUNET_CRYPTO_EddsaPrivateKey *kpriv, + const struct MERCHANT_WIREFORMAT_Sepa *wire, + struct GNUNET_CRYPTO_EddsaSignature *sig) +{ + json_t *root; + json_t *j_timestamp; + json_t *jh_wire; + json_t *j_amount; + json_int_t j_trans_id; + + uint64_t nounce; + uint64_t product_id; + char *a; + char *h_wire_enc; + char *str; + struct GNUNET_HashCode h_wire; + struct GNUNET_TIME_Absolute timestamp; + struct TALER_Amount amount; + struct TALER_AmountNBO amount_nbo; + struct ContractNBO contract_nbo; + + nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + // timing mgmt + timestamp = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_UNIT_DAYS); + ROUND_TO_SECS (timestamp, abs_value_us); + j_timestamp = TALER_json_from_abs (timestamp); + + // wireformat mgmt + h_wire = hash_wireformat (nounce, wire); + h_wire_enc = GNUNET_STRINGS_data_to_string_alloc (&h_wire, + sizeof (struct GNUNET_HashCode)); + + jh_wire = json_string (h_wire_enc); + + str = json_dumps (contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER); + + + json_unpack (contract, "{s:o, s:I}", + "amount", &j_amount, + "trans_id", &j_trans_id); + + /* needed for DB stuff */ + TALER_json_to_amount (j_amount, &amount); + /* temporary way of getting this value. To be adapted to the expanded contract + format. See 'TODO' above. */ + product_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + /* adding the generated values in this JSON */ + root = json_pack ("{s:o, s:I, s:s, s:o}", + "amount", j_amount, + "trans_id", j_trans_id, + "h_wire", jh_wire, + "timestamp", j_timestamp); + a = json_dumps (root, JSON_COMPACT | JSON_PRESERVE_ORDER); + + // DB mgmt + if (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn, + ×tamp, + &amount, + (uint64_t) j_trans_id, // safe? + a, + nounce, + product_id)); + contract_nbo.h_wire = h_wire; + TALER_amount_hton (&amount_nbo, &amount); + contract_nbo.amount = amount_nbo; + contract_nbo.t = GNUNET_TIME_absolute_hton (timestamp); + contract_nbo.m = GNUNET_htonll ((uint64_t) j_trans_id); // safe? + GNUNET_CRYPTO_hash (a, strlen (a) + 1, &contract_nbo.h_contract_details); + free (a); + contract_nbo.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); + contract_nbo.purpose.size = htonl (sizeof (struct ContractNBO)); + GNUNET_CRYPTO_eddsa_sign (kpriv, &contract_nbo.purpose, sig); + + return root; +} diff --git a/src/backend-lib/taler_merchant_contract_lib.h b/src/backend-lib/taler_merchant_contract_lib.h new file mode 100644 index 00000000..4e345703 --- /dev/null +++ b/src/backend-lib/taler_merchant_contract_lib.h @@ -0,0 +1,62 @@ + +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 from the frontend the (partly) generated contract and fill +* the missing values in it; for example, the SEPA-aware values. +* Moreover, it stores the contract in the DB and does the signature of it. +* @param contract parsed contract, originated by the frontend +* @param db_conn the handle to the local DB +* @param kpriv merchant's private key +* @param wire merchant's bank's details +* @param sig where to store the signature +* @return pointer to the complete JSON; NULL upon errors +*/ + +/* TODO: this handles a simplified version (for debugging purposes) + of the contract. To expand to the full fledged version */ + +json_t * +MERCHANT_handle_contract (json_t *contract, + PGconn *db_conn, + struct GNUNET_CRYPTO_EddsaPrivateKey *kpriv, + const struct MERCHANT_WIREFORMAT_Sepa *wire, + struct GNUNET_CRYPTO_EddsaSignature *sig); diff --git a/src/backend-lib/taler_merchant_lib.h b/src/backend-lib/taler_merchant_lib.h new file mode 100644 index 00000000..41891783 --- /dev/null +++ b/src/backend-lib/taler_merchant_lib.h @@ -0,0 +1 @@ +#include "taler_merchant_contract_lib.h" diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 836656b5..c0eacfae 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -9,7 +9,8 @@ taler_merchant_httpd_SOURCES = \ merchant.c merchant.h \ merchant_db.c merchant_db.h \ taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \ - taler-mint-httpd_responses.c taler-mint-httpd_responses.h + taler-mint-httpd_responses.c taler-mint-httpd_responses.h \ + ../backend-lib/taler-merchant-httpd_contract.h taler_merchant_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ @@ -17,6 +18,7 @@ taler_merchant_httpd_LDADD = \ -lmicrohttpd \ -ljansson \ -lgnunetutil \ + -ltalermerchant \ -ltalermint \ -ltalerpq \ -lgnunetpostgres \ diff --git a/src/backend/QUESTIONS b/src/backend/QUESTIONS new file mode 100644 index 00000000..b992e96f --- /dev/null +++ b/src/backend/QUESTIONS @@ -0,0 +1,6 @@ +1. why does the merchant daemon appears to be some executable under some +.libs directory even though it gets launched through an executable located +elsewhere? + +2. why does the httpd prints three times the URL corresponding to GET /some/url +? diff --git a/src/backend/merchant.priv b/src/backend/merchant.priv new file mode 100644 index 00000000..9c18c358 --- /dev/null +++ b/src/backend/merchant.priv @@ -0,0 +1 @@ +`&-./ jxGݢO:6l,ζXT4
\ No newline at end of file diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 900b2a1a..69353ea8 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -27,11 +27,10 @@ #include <gnunet/gnunet_util_lib.h> #include <taler/taler_json_lib.h> #include <taler/taler_mint_service.h> -#include <taler/taler_signatures.h> #include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_responses.h" +#include "taler_merchant_lib.h" #include "merchant.h" -#include "merchant_db.h" extern struct MERCHANT_WIREFORMAT_Sepa * TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg); @@ -45,11 +44,6 @@ TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle * } while (0) /** - * Macro to round microseconds to seconds in GNUNET_TIME_* structs. - */ -#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000) - -/** * Our hostname */ static char *hostname; @@ -104,44 +98,6 @@ static int dry; */ static int result; -GNUNET_NETWORK_STRUCT_BEGIN - -struct Contract -{ - /** - * 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 preferred wire format + nounce - */ - struct GNUNET_HashCode h_wire; - - /** - * The contract data - */ - char *a; -}; - -GNUNET_NETWORK_STRUCT_END - /** * Mint context */ @@ -307,98 +263,6 @@ request</h3></center></body></html>"; /** -* 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 -* @return the hash to be included in the contract's blob -* -*/ - -static struct GNUNET_HashCode -hash_wireformat (uint64_t nounce) -{ - 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; -} - - - -/* -* Make a binary blob representing a contract, store it into the DB, sign it -* and return a pointer to it. -* @param a 0-terminated string representing the description of this -* @param c_id contract id provided by the frontend -* purchase (it should contain a human readable description of the good -* in question) -* @param product some product numerical id. Its indended use is to link the -* good, or service being sold to some entry in the DB managed by the frontend -* @param price the cost of this good or service -* @param sig the pointer to the contract signature's location -* @return pointer to the allocated memory which will hold a 'struct Contract' -* followed by a deal's description string, NULL upon errors -* -*/ - -void * -generate_and_store_contract (const char *a, - uint64_t c_id, - uint64_t product, - const struct TALER_Amount *price, - struct GNUNET_CRYPTO_EddsaSignature *sig) -{ - - void *contract_and_desc; - struct Contract *contract; - struct GNUNET_TIME_Absolute expiry; - uint64_t nounce; - uint64_t contract_id_nbo; - - expiry = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - GNUNET_TIME_UNIT_DAYS); - ROUND_TO_SECS (expiry, abs_value_us); - nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); - EXITIF (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn, - &expiry, - price, - c_id, - a, - nounce, - product)); - contract_id_nbo = GNUNET_htonll ((uint64_t) c_id); - contract_and_desc = GNUNET_malloc (sizeof (struct Contract) + strlen (a) + 1); - contract = (struct Contract *) contract_and_desc; - contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); - contract->purpose.size = htonl (sizeof (struct Contract) + strlen (a) + 1); - contract->a = (char *) &contract->a + 4; - contract->m = contract_id_nbo; - contract->t = GNUNET_TIME_absolute_hton (expiry); - strcpy (contract->a, a); - printf ("msg in stored contract : %s\n", contract->a); - contract->h_wire = hash_wireformat (nounce); - TALER_amount_hton (&contract->amount, price); - GNUNET_CRYPTO_eddsa_sign (privkey, &contract->purpose, sig); - return contract_and_desc; - - /* legacy from old merchant */ - EXITIF_exit: - if (NULL != contract) - { - GNUNET_free (contract_and_desc); - } - return NULL; -} - - -/** * A client has requested the given url using the given method * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback @@ -542,6 +406,7 @@ url_handler (void *cls, else { /* Let's generate this contract! */ + /* FIXME : change this. Not existent anymore */ if (NULL == (contract_and_desc = generate_and_store_contract (desc, contract_id, prod_id, @@ -622,6 +487,8 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) MERCHANT_DB_disconnect (db_conn); db_conn = NULL; } + if (keyfile != NULL) + GNUNET_free (privkey); } @@ -640,8 +507,7 @@ void keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys) { /* which kind of mint's keys a merchant should need? Sign - keys? It has already the mint's (master?) public key from - the conf file */ + keys? It has already the mint's master key from the conf file */ return; } @@ -675,7 +541,7 @@ run (void *cls, char *const *args, const char *cfgfile, &do_shutdown, NULL); EXITIF (GNUNET_SYSERR == (nmints = TALER_MERCHANT_parse_mints (config, &mint_infos))); - EXITIF (NULL == (wire = TALER_MERCHANT_parse_wireformat_sepa (config))); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config, "merchant", "KEYFILE", diff --git a/src/frontend/checkout.php b/src/frontend/checkout.php index d2ebd814..d9542c3b 100644 --- a/src/frontend/checkout.php +++ b/src/frontend/checkout.php @@ -92,12 +92,12 @@ function taler_pay(form) if (contract_request.status == 200) { /* display contract_requestificate (i.e. it sends the JSON string - to the (XUL) extension) */ + to the extension) */ handle_contract(contract_request.responseText); } else { - alert("Failed to receive contract from server. Status was " + contract_request.status); + alert("No contract got from merchant.\n" + contract_request.responseText); } } }; @@ -118,7 +118,6 @@ function pay(form) for (var cnt=0; cnt < form.payment_system.length; cnt++) { var choice = form.payment_system[cnt]; - if (choice.checked) { if (choice.value == "taler") @@ -143,8 +142,7 @@ function has_taler_wallet_cb(aEvent) // enable the Taler payment option from the form var tbutton = document.getElementById("taler-radio-button-id"); tbutton.removeAttribute("disabled"); - - + if (aEvent.type == "taler-wallet-wfirst"){ var eve = new Event('taler-payment-wfirst'); document.body.dispatchEvent(eve); @@ -161,12 +159,21 @@ function taler_wallet_unload_cb(aEvent) tbutton.setAttribute("disabled", "true"); }; +/* The merchant signals its taler-friendlyness to the client */ function signal_me() { var eve = new Event('taler-payment-mfirst'); document.body.dispatchEvent(eve); }; + +function test_without_wallet(){ + var tbutton = document.getElementById("taler-radio-button-id"); + tbutton.removeAttribute("disabled"); +}; + +// test_without_wallet(); + // Register event to be triggered by the wallet as a response to our // first event document.body.addEventListener("taler-wallet-mfirst", has_taler_wallet_cb, false); diff --git a/src/frontend/generate_taler_contract.php b/src/frontend/generate_taler_contract.php index ea118303..15c0841f 100644 --- a/src/frontend/generate_taler_contract.php +++ b/src/frontend/generate_taler_contract.php @@ -25,8 +25,6 @@ to the wallet */ -// --- FIXME: by not commenting out the following test and trying to get -// 'receiver' and 'amount' from the session, it gets 404 always. // 1) recover the session information session_start(); if ( (! isset($_SESSION['receiver'])) || @@ -34,6 +32,7 @@ if ( (! isset($_SESSION['receiver'])) || { http_response_code (404); echo "Please select a contract before getting to this page..."; + echo "attempted : " . $_SESSION['receiver']; exit (0); } diff --git a/src/frontend/index.html b/src/frontend/index.html index 27ab281f..02545475 100644 --- a/src/frontend/index.html +++ b/src/frontend/index.html @@ -159,6 +159,11 @@ b.style.display = 'none'; }; + function test_without_wallet(){ + wallet_installed_cb(); + } + + // test_without_wallet(); /* Set up a listener to be called whenever a Wallet gets installed so that the user is led towards the demo's steps progressively */ diff --git a/src/backend/merchant.h b/src/include/merchant.h index c66131ed..c66131ed 100644 --- a/src/backend/merchant.h +++ b/src/include/merchant.h diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 00000000..7c531405 --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,26 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +bin_PROGRAMS = \ + merchant-contract-test + +#merchant_contract_test_CFLAGS = \ +# -Wl,--verbose + +merchant_contract_test_SOURCES = \ + merchant-contract-test.c \ + merchant.c \ + merchant_db.c merchant_db.h + +merchant_contract_test_LDADD = \ + $(LIBGCRYPT_LIBS) \ + -ltalerutil \ + -ltalermerchant \ + -ljansson \ + -lgnunetutil \ + -ltalermint \ + -ltalerpq \ + -lgnunetpostgres \ + -lpq \ + -ltalermerchant \ + -lpthread diff --git a/src/tests/merchant-contract-test b/src/tests/merchant-contract-test Binary files differnew file mode 100755 index 00000000..d6e3063c --- /dev/null +++ b/src/tests/merchant-contract-test diff --git a/src/tests/merchant-contract-test.c b/src/tests/merchant-contract-test.c new file mode 100644 index 00000000..f11b67f9 --- /dev/null +++ b/src/tests/merchant-contract-test.c @@ -0,0 +1,207 @@ +/* + 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; + } +} + +/** + * 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_root; + json_t *j_details; + json_t *j_item; + json_t *j_amount; + json_t *j_tax_amount; + json_t *j_item_price; + json_t *j_teatax; + json_t *j_id; // trans id + json_t *j_pid; // product id + json_t *j_quantity; + char *str; + char *desc = "Fake purchase"; + struct TALER_Amount amount; + int64_t t_id; + int64_t p_id; + struct GNUNET_CRYPTO_EddsaSignature c_sig; + + 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); + + /* Amount */ + TALER_amount_get_zero ("KUDOS", &amount); + j_amount = TALER_json_from_amount (&amount); + j_item_price = TALER_json_from_amount (&amount); + j_tax_amount = 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); + + /* Quantity */ + j_quantity = json_integer (3); + + /* 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); + + /* Preparing the 'details' sub-object: an array of 'item' objects */ + + j_teatax = json_pack ("{s:o}", + "teatax", j_tax_amount); + if (NULL == (j_item = json_pack ("{s:s, s:I, s:o, s:I}", + "description", desc, + "quantity", json_integer_value (j_quantity), + "itemprice", j_item_price, + "product_id", json_integer_value (j_pid)))) + { + printf ("error in packing [j_item: %p]\n", j_item); + return; + } + + printf ("[j_item address: %p]\n", j_item); + + str = json_dumps (j_item, JSON_INDENT(2) | JSON_PRESERVE_ORDER); + printf ("a %s\n", str); + return; + + + j_fake_contract = json_pack ("{s:o, s:i}", + "amount", j_amount, + "trans_id", json_integer_value (j_id)); + + j_root = MERCHANT_handle_contract (j_fake_contract, + db_conn, + privkey, + wire, + &c_sig); + +} + + +/** + * 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/merchant.c b/src/tests/merchant.c new file mode 100644 index 00000000..f124a030 --- /dev/null +++ b/src/tests/merchant.c @@ -0,0 +1,173 @@ +/* + 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/merchant.c + * @brief Common utility functions for merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "merchant.h" + + +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Parses mints from the configuration. + * + * @param cfg the configuration + * @param mints the array of mints upon successful parsing. Will be NULL upon + * error. + * @return the number of mints in the above array; GNUNET_SYSERR upon error in + * parsing. + */ +int +TALER_MERCHANT_parse_mints (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct MERCHANT_MintInfo **mints) +{ + char *mints_str; + char *token_nf; /* do no free (nf) */ + char *mint_section; + char *mint_hostname; + char *mint_pubkey_enc; + struct MERCHANT_MintInfo *r_mints; + struct MERCHANT_MintInfo mint; + unsigned long long mint_port; + unsigned int cnt; + int OK; + + OK = 0; + mints_str = NULL; + token_nf = NULL; + mint_section = NULL; + mint_hostname = NULL; + mint_pubkey_enc = NULL; + r_mints = NULL; + cnt = 0; + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "merchant", + "TRUSTED_MINTS", + &mints_str)); + for (token_nf = strtok (mints_str, " "); + NULL != token_nf; + token_nf = strtok (NULL, " ")) + { + GNUNET_assert (0 < GNUNET_asprintf (&mint_section, + "mint-%s", token_nf)); + EXITIF (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + mint_section, + "HOSTNAME", + &mint_hostname)); + EXITIF (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + mint_section, + "PORT", + &mint_port)); + EXITIF (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + mint_section, + "PUBKEY", + &mint_pubkey_enc)); + EXITIF (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (mint_pubkey_enc, + strlen (mint_pubkey_enc), + &mint.pubkey)); + mint.hostname = mint_hostname; + mint.port = (uint16_t) mint_port; + GNUNET_array_append (r_mints, cnt, mint); + mint_hostname = NULL; + GNUNET_free (mint_pubkey_enc); + mint_pubkey_enc = NULL; + GNUNET_free (mint_section); + mint_section = NULL; + } + OK = 1; + + EXITIF_exit: + GNUNET_free_non_null (mints_str); + GNUNET_free_non_null (mint_section); + GNUNET_free_non_null (mint_hostname); + GNUNET_free_non_null (mint_pubkey_enc); + if (!OK) + { + GNUNET_free_non_null (r_mints); + return GNUNET_SYSERR; + } + + *mints = r_mints; + return cnt; +} + + +/** + * Parse the SEPA information from the configuration. If any of the required + * fileds is missing return NULL. + * + * @param cfg the configuration + * @return Sepa details as a structure; NULL upon error + */ +struct MERCHANT_WIREFORMAT_Sepa * +TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct MERCHANT_WIREFORMAT_Sepa *wf; + + wf = GNUNET_new (struct MERCHANT_WIREFORMAT_Sepa); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "wire-sepa", + "IBAN", + &wf->iban)); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "wire-sepa", + "NAME", + &wf->name)); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "wire-sepa", + "BIC", + &wf->bic)); + return wf; + + EXITIF_exit: + GNUNET_free_non_null (wf->iban); + GNUNET_free_non_null (wf->name); + GNUNET_free_non_null (wf->bic); + GNUNET_free (wf); + return NULL; + +} + + +/** + * Destroy and free resouces occupied by the wireformat structure + * + * @param wf the wireformat structure + */ +void +TALER_MERCHANT_destroy_wireformat_sepa (struct MERCHANT_WIREFORMAT_Sepa *wf) +{ + GNUNET_free_non_null (wf->iban); + GNUNET_free_non_null (wf->name); + GNUNET_free_non_null (wf->bic); + GNUNET_free (wf); +} + +/* end of merchant.c */ diff --git a/src/tests/merchant.conf b/src/tests/merchant.conf new file mode 100644 index 00000000..3b637448 --- /dev/null +++ b/src/tests/merchant.conf @@ -0,0 +1,18 @@ +[merchant] +PORT = 9966 +HOSTNAME = localhost +TRUSTED_MINTS = taler +KEYFILE = merchant.priv + +[mint-taler] +HOSTNAME = demo.taler.net +PORT = 80 +PUBKEY = Q1WVGRGC1F4W7RYC6M23AEGFEXQEHQ730K3GG0B67VPHQSRR75H0 + +[merchant-db] +CONFIG = postgres:///taler + +[wire-sepa] +IBAN = DE67830654080004822650 +NAME = GNUNET E.V +BIC = GENODEF1SRL diff --git a/src/tests/merchant.priv b/src/tests/merchant.priv new file mode 100644 index 00000000..2101f677 --- /dev/null +++ b/src/tests/merchant.priv @@ -0,0 +1 @@ +{|ic?"`J0pkvTW
\ No newline at end of file diff --git a/src/tests/merchant_db.c b/src/tests/merchant_db.c new file mode 100644 index 00000000..274de25a --- /dev/null +++ b/src/tests/merchant_db.c @@ -0,0 +1,354 @@ +/* + 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/merchant_db.c + * @brief database helper functions used by the merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <taler/taler_util.h> +#include <taler/taler_pq_lib.h> +#include "merchant_db.h" + + +#define PQSQL_strerror(kind, cmd, res) \ + GNUNET_log_from (kind, "merchant-db", \ + "SQL %s failed at %s:%u with error: %s", \ + cmd, __FILE__, __LINE__, PQresultErrorMessage (res)); + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Connect to postgresql database + * + * @param cfg the configuration handle + * @return connection to the postgresql database; NULL upon error + */ +PGconn * +MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + return GNUNET_POSTGRES_connect (cfg, "merchant-db"); +} + + +/** + * Disconnect from the database + * + * @param conn database handle to close + */ +void +MERCHANT_DB_disconnect (PGconn *conn) +{ + PQfinish (conn); +} + + +/** + * Initialize merchant tables + * + * @param conn the connection handle to postgres db. + * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the @a conn is closed + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +MERCHANT_DB_initialize (PGconn *conn, int tmp) +{ + const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; + char *sql; + PGresult *res; + ExecStatusType status; + int ret; + + res = NULL; + (void) GNUNET_asprintf (&sql, + "BEGIN TRANSACTION;" + "CREATE %1$s TABLE IF NOT EXISTS contracts (" + "contract_id INT8 PRIMARY KEY," + "amount INT8 NOT NULL," + "amount_fraction INT4 NOT NULL," + "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," + "description TEXT NOT NULL," + "nounce INT8 NOT NULL," + "expiry INT8 NOT NULL," + "product INT8 NOT NULL);" + "CREATE %1$s TABLE IF NOT EXISTS checkouts (" + "coin_pub BYTEA PRIMARY KEY," + "contract_id INT8 REFERENCES contracts(contract_id)," + "amount INT4 NOT NULL," + "amount_fraction INT4 NOT NULL," + "coin_sig BYTEA NOT NULL);", + tmp_str); + ret = GNUNET_POSTGRES_exec (conn, sql); + (void) GNUNET_POSTGRES_exec (conn, + (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK;"); + GNUNET_free (sql); + if (GNUNET_OK != ret) + return ret; + + while (NULL != (res = PQgetResult (conn))) + { + status = PQresultStatus (res); + PQclear (res); + } + + EXITIF (NULL == (res = PQprepare + (conn, + "contract_create", + "INSERT INTO contracts" + "(contract_id, amount, amount_fraction, amount_currency," + "description, nounce, expiry, product) VALUES" + "($1, $2, $3, $4, $5, $6, $7, $8)", + 8, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "get_contract_product", + "SELECT (" + "product" + ") FROM contracts " + "WHERE (" + "contract_id=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "checkout_create", + "INSERT INTO checkouts (" + "coin_pub," + "contract_id," + "amount," + "amount_fraction," + "coin_sig" + ") VALUES (" + "$1, $2, $3, $4, $5" + ")", + 5, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "get_checkout_product", + "SELECT (" + "product" + ") FROM contracts " + "WHERE " + "contract_id IN (" + "SELECT (contract_id) FROM checkouts " + "WHERE coin_pub=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); + PQclear (res); + + return GNUNET_OK; + + EXITIF_exit: + if (NULL != res) + { + PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res); + PQclear (res); + } + return GNUNET_SYSERR; +} + + +/** + * Inserts a contract record into the database and if successfull returns the + * serial number of the inserted row. + * + * @param conn the database connection + * @param expiry the time when the contract will expire + * @param amount the taler amount corresponding to the 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 + */ + +uint32_t +MERCHANT_DB_contract_create (PGconn *conn, + const struct GNUNET_TIME_Absolute *expiry, + const struct TALER_Amount *amount, + uint64_t c_id, + const char *desc, + uint64_t nounce, + uint64_t product) +{ + PGresult *res; + #if 0 + uint64_t expiry_ms_nbo; + uint64_t value_nbo; + uint32_t fraction_nbo; + uint64_t nounce_nbo; + #endif + ExecStatusType status; + + #if 0 + /* + NOTE: the conversion to nl(l) happens *inside* the query param helpers; since + the policy imposes this format for storing values. */ + value_nbo = GNUNET_htonll (amount->value); + fraction_nbo = GNUNET_htonll (amount->fraction); + nounce_nbo = GNUNET_htonll (nounce); + expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); + product = GNUNET_htonll (product); + #endif + + /* ported. To be tested/compiled */ + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_uint64 (&c_id), + TALER_PQ_query_param_amount (amount), + /* a *string* is being put in the following statement, + though the API talks about a *blob*. Will this be liked by + the DB ? */ + // the following inserts a string as a blob. Will Taler provide a param-from-string helper? + TALER_PQ_query_param_fixed_size (desc, strlen(desc)), + TALER_PQ_query_param_uint64 (&nounce), + TALER_PQ_query_param_absolute_time (expiry), + TALER_PQ_query_param_uint64 (&product), + TALER_PQ_query_param_end + }; + + /* 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); + PQclear (res); + return GNUNET_OK; + + EXITIF_exit: + PQclear (res); + return GNUNET_SYSERR; +} + +long long +MERCHANT_DB_get_contract_product (PGconn *conn, + uint64_t contract_id) +{ + PGresult *res; + uint64_t product; + ExecStatusType status; + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_uint64 (&contract_id), + TALER_PQ_query_param_end + }; + struct TALER_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_uint64 ("product", &product), + TALER_PQ_result_spec_end + }; + + contract_id = GNUNET_htonll (contract_id); + res = TALER_PQ_exec_prepared (conn, "get_contract_product", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) product); + + EXITIF_exit: + PQclear (res); + return -1; +} + +unsigned int +MERCHANT_DB_checkout_create (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, + uint64_t transaction_id, + struct TALER_Amount *amount, + struct GNUNET_CRYPTO_rsa_Signature *coin_sig) +{ + PGresult *res; + ExecStatusType status; + uint32_t value_nbo; + uint32_t fraction_nbo; + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_rsa_public_key (coin_pub), + TALER_PQ_query_param_uint64 (&transaction_id), + TALER_PQ_query_param_uint32 (&value_nbo), + TALER_PQ_query_param_uint32 (&fraction_nbo), + TALER_PQ_query_param_rsa_signature (coin_sig), + TALER_PQ_query_param_end + }; + + transaction_id = GNUNET_htonll (transaction_id); + value_nbo = htonl (amount->value); + fraction_nbo = htonl (amount->fraction); + res = TALER_PQ_exec_prepared (conn, "checkout_create", params); + status = PQresultStatus (res); + EXITIF (PGRES_COMMAND_OK != status); + PQclear (res); + return GNUNET_OK; + + EXITIF_exit: + PQclear (res); + return GNUNET_SYSERR; +} + + +long long +MERCHANT_DB_get_checkout_product (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub) +{ + PGresult *res; + ExecStatusType status; + uint64_t product; + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_rsa_public_key (coin_pub), + TALER_PQ_query_param_end + }; + struct TALER_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_uint64 ("product", &product), + TALER_PQ_result_spec_end + }; + + product = -1; + res = TALER_PQ_exec_prepared (conn, "get_checkout_product", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + if (0 == PQntuples (res)) + { + TALER_LOG_DEBUG ("Checkout not found for given coin"); + goto EXITIF_exit; + } + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) product); + + EXITIF_exit: + PQclear (res); + return -1; +} +/* end of merchant-db.c */ diff --git a/src/tests/merchant_db.h b/src/tests/merchant_db.h new file mode 100644 index 00000000..a723b229 --- /dev/null +++ b/src/tests/merchant_db.h @@ -0,0 +1,101 @@ +/* + 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/merchant_db.h + * @brief database helper functions used by the merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#ifndef MERCHANT_DB_H +#define MERCHANT_DB_H + +#include <gnunet/gnunet_postgres_lib.h> +#include <taler/taler_util.h> + +/** + * Connect to postgresql database + * + * @param cfg the configuration handle + * @return connection to the postgresql database; NULL upon error + */ +PGconn * +MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Disconnect from the database + * + * @param conn database handle to close + */ +void +MERCHANT_DB_disconnect (PGconn *conn); + + +/** + * Initialize merchant tables + * + * @param conn the connection handle to postgres db. + * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the @a conn is closed + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +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. + * + * @param conn the database connection + * @param expiry the time when the contract will expire + * @param amount the taler amount corresponding to the contract + * @param c_id this contract's identification number + * @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 + */ + +uint32_t +MERCHANT_DB_contract_create (PGconn *conn, + const struct GNUNET_TIME_Absolute *expiry, + const struct TALER_Amount *amount, + uint64_t c_id, + const char *desc, + uint64_t nounce, + uint64_t product); + +long long +MERCHANT_DB_get_contract_product (PGconn *conn, + uint64_t contract_id); + +unsigned int +MERCHANT_DB_checkout_create (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, + uint64_t transaction_id, + struct TALER_Amount *amount, + struct GNUNET_CRYPTO_rsa_Signature *coin_sig); + + +long long +MERCHANT_DB_get_checkout_product (PGconn *conn, + struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub); + +#endif /* MERCHANT_DB_H */ + +/* end of merchant-db.h */ diff --git a/src/tests/test.debug b/src/tests/test.debug new file mode 100644 index 00000000..1817f7f0 --- /dev/null +++ b/src/tests/test.debug @@ -0,0 +1,37 @@ +==5558== Memcheck, a memory error detector +==5558== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. +==5558== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info +==5558== Command: ./merchant-contract-test -c merchant.conf +==5558== Parent PID: 483 +==5558== +==5558== +==5558== Process terminating with default action of signal 11 (SIGSEGV) +==5558== Bad permissions for mapped region at address 0x804AB80 +==5558== at 0x4108DAA: ??? (in /usr/lib/i386-linux-gnu/libjansson.so.4.7.0) +==5558== by 0x4108E7A: ??? (in /usr/lib/i386-linux-gnu/libjansson.so.4.7.0) +==5558== by 0x410DAFB: json_delete (in /usr/lib/i386-linux-gnu/libjansson.so.4.7.0) +==5558== by 0x410C28F: ??? (in /usr/lib/i386-linux-gnu/libjansson.so.4.7.0) +==5558== by 0x410C42B: json_vpack_ex (in /usr/lib/i386-linux-gnu/libjansson.so.4.7.0) +==5558== by 0x410C530: json_pack (in /usr/lib/i386-linux-gnu/libjansson.so.4.7.0) +==5558== by 0x80494CE: run (merchant-contract-test.c:148) +==5558== by 0x41543EE: program_main (program.c:84) +==5558== by 0x41592ED: run_ready (scheduler.c:587) +==5558== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==5558== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==5558== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==5558== by 0x8049210: main (merchant-contract-test.c:195) +==5558== +==5558== HEAP SUMMARY: +==5558== in use at exit: 133,271 bytes in 2,334 blocks +==5558== total heap usage: 5,082 allocs, 2,748 frees, 277,172 bytes allocated +==5558== +==5558== LEAK SUMMARY: +==5558== definitely lost: 149 bytes in 4 blocks +==5558== indirectly lost: 293 bytes in 10 blocks +==5558== possibly lost: 359 bytes in 18 blocks +==5558== still reachable: 132,470 bytes in 2,302 blocks +==5558== suppressed: 0 bytes in 0 blocks +==5558== Rerun with --leak-check=full to see details of leaked memory +==5558== +==5558== For counts of detected and suppressed errors, rerun with: -v +==5558== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/src/tests/test.valgrind b/src/tests/test.valgrind new file mode 100644 index 00000000..751899b1 --- /dev/null +++ b/src/tests/test.valgrind @@ -0,0 +1,181 @@ +==1908== Memcheck, a memory error detector +==1908== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. +==1908== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info +==1908== Command: ./merchant-contract-test -c merchant.conf +==1908== Parent PID: 483 +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x40B084A: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x402DDB8: is_overlap (vg_replace_strmem.c:128) +==1908== by 0x402DDB8: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x402DDBE: is_overlap (vg_replace_strmem.c:131) +==1908== by 0x402DDBE: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x402DDCD: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x402DE1C: is_overlap (vg_replace_strmem.c:119) +==1908== by 0x402DE1C: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x402DF8F: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Conditional jump or move depends on uninitialised value(s) +==1908== at 0x402E000: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Use of uninitialised value of size 4 +==1908== at 0x402E023: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== +==1908== Invalid write of size 2 +==1908== at 0x402E023: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== Address 0xa is not stack'd, malloc'd or (recently) free'd +==1908== +==1908== +==1908== Process terminating with default action of signal 11 (SIGSEGV) +==1908== Access not within mapped region at address 0xA +==1908== at 0x402E023: memcpy (vg_replace_strmem.c:916) +==1908== by 0x40B0881: ??? (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x404E8E7: gcry_mpi_print (in /lib/i386-linux-gnu/libgcrypt.so.20.0.3) +==1908== by 0x414117D: GNUNET_CRYPTO_mpi_print_unsigned (crypto_mpi.c:103) +==1908== by 0x413B27E: GNUNET_CRYPTO_eddsa_sign (crypto_ecc.c:824) +==1908== by 0x41E57F7: MERCHANT_handle_contract (taler-merchant-httpd_contract.c:142) +==1908== by 0x80494D6: run (merchant-contract-test.c:126) +==1908== by 0x41543EE: program_main (program.c:84) +==1908== by 0x41592ED: run_ready (scheduler.c:587) +==1908== by 0x41592ED: GNUNET_SCHEDULER_run (scheduler.c:868) +==1908== by 0x4154B09: GNUNET_PROGRAM_run2 (program.c:302) +==1908== by 0x4154E01: GNUNET_PROGRAM_run (program.c:341) +==1908== by 0x8049250: main (merchant-contract-test.c:158) +==1908== If you believe this happened as a result of a stack +==1908== overflow in your program's main thread (unlikely but +==1908== possible), you can try to increase the size of the +==1908== main thread stack using the --main-stacksize= flag. +==1908== The main thread stack size used in this run was 8388608. +==1908== +==1908== HEAP SUMMARY: +==1908== in use at exit: 133,296 bytes in 2,329 blocks +==1908== total heap usage: 38,415 allocs, 36,086 frees, 1,274,533 bytes allocated +==1908== +==1908== LEAK SUMMARY: +==1908== definitely lost: 314 bytes in 3 blocks +==1908== indirectly lost: 0 bytes in 0 blocks +==1908== possibly lost: 357 bytes in 17 blocks +==1908== still reachable: 132,625 bytes in 2,309 blocks +==1908== suppressed: 0 bytes in 0 blocks +==1908== Rerun with --leak-check=full to see details of leaked memory +==1908== +==1908== For counts of detected and suppressed errors, rerun with: -v +==1908== Use --track-origins=yes to see where uninitialised values come from +==1908== ERROR SUMMARY: 10 errors from 9 contexts (suppressed: 0 from 0) |