diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-11-27 20:58:48 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-11-27 20:58:48 +0100 |
commit | cd1bc15c6cc942be27db20ab3ab5ba76eb90849a (patch) | |
tree | 22cc4cffb8743e9d774d4c107c84ecaec2456d73 | |
parent | 77872e19eab28632b6b803c03ad06ca63761085d (diff) | |
download | merchant-cd1bc15c6cc942be27db20ab3ab5ba76eb90849a.tar.gz merchant-cd1bc15c6cc942be27db20ab3ab5ba76eb90849a.tar.bz2 merchant-cd1bc15c6cc942be27db20ab3ab5ba76eb90849a.zip |
finish rudimenary pluggable merchant postgres backend
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 632 | ||||
-rw-r--r-- | src/include/taler_merchantdb_plugin.h | 6 |
2 files changed, 135 insertions, 503 deletions
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 02e6884b..f8502773 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -13,10 +13,9 @@ 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 + * @file merchant/plugin_merchantdb_postgres.c + * @brief database helper functions for postgres used by the merchant * @author Sree Harsha Totakura <sreeharsha@totakura.in> */ #include "platform.h" @@ -26,14 +25,25 @@ #include <taler/taler_pq_lib.h> #include "taler_merchantdb_plugin.h" + /** - * Shorthand for exit jumps. + * Type of the "cls" argument given to each of the functions in + * our API. */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) +struct PostgresClosure +{ + /** + * Postgres connection handle. + */ + PGconn *conn; + + /** + * Database connection string, as read from + * the configuration. + */ + char *connection_cfg_str; +}; #define PQSQL_strerror(kind, cmd, res) \ @@ -41,397 +51,117 @@ "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 * -TALER_MERCHANTDB_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 -TALER_MERCHANTDB_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 + * @param cls closure our `struct Plugin` + * @param tmp #GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the database connection is closed + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ -int -TALER_MERCHANTDB_initialize (PGconn *conn, int tmp) +static int +postgres_initialize (void *cls, + int tmp) { + struct PostgresClosure *pg = cls; 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," - "hash BYTEA NOT NULL," - "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," - "timestamp INT8 NOT NULL," - "expiry INT8 NOT NULL," - "edate INT8 NOT NULL," - "refund_deadline 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);" - "CREATE %1$s TABLE IF NOT EXISTS deposits (" - "dep_perm VARCHAR NOT NULL," - "transaction_id INT8," - "pending INT4 NOT NULL," - "mint_url VARCHAR NOT NULL);", - tmp_str); - ret = GNUNET_POSTGRES_exec (conn, sql); - (void) GNUNET_POSTGRES_exec (conn, - (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK;"); + GNUNET_asprintf (&sql, + "CREATE %1$s TABLE IF NOT EXISTS payments (" + "h_contract BYTEA NOT NULL," + "h_wire BYTEA NOT NULL," + "transaction_id INT8 PRIMARY KEY," + "timestamp INT8 NOT NULL," + "refund_deadline INT8 NOT NULL," + "amount_without_fee_val INT8 NOT NULL," + "amount_without_fee_frac INT4 NOT NULL," + "amount_without_fee_curr VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," + "coin_pub BYTEA NOT NULL," + "mint_sig BYTEA NOT NULL);", + tmp_str); + ret = GNUNET_POSTGRES_exec (pg->conn, + sql); 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, hash, timestamp, expiry, edate," - "refund_deadline, amount, amount_fraction, amount_currency," - "description, nounce, product) VALUES" - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", - 12, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - - /* Query aimed to get the contract's nounce and edate which will be - both used for regenerating a 'wire' JSON object to insert into the - deposit permission. Implicitly, this query will tell whether a contract - was created or not */ - - EXITIF (NULL == (res = PQprepare - (conn, - "get_contract_hash", - "SELECT " - "nounce, edate " - "FROM contracts " - "WHERE (" - "hash=$1" - ")", - 1, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "get_contract_set", - "SELECT " - "contract_id, nounce, timestamp, edate, " - "refund_deadline FROM contracts " - "WHERE (" - "hash=$1" - ")", - 1, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "store_deposit_permission", - "INSERT INTO deposits" - "(dep_perm, transaction_id, pending, mint_url) " - "VALUES ($1, $2, $3, $4);", 4, NULL))); - - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - - EXITIF (NULL == (res = PQprepare - (conn, - "update_deposit_permission", - "UPDATE deposits " - "SET pending = $1 " - "WHERE transaction_id = $2", 2, 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; -} - - -/** - * Update the pending column of a deposit permission - * @param conn handle to DB - * @param transaction_id identification number of the deposit to - * update - * @param pending true if still pending, false otherwise (i.e. the - * mint did respond something) - * @return #GNUNET_OK if successful, #GNUNET_SYSERR upon errors - */ -uint32_t -TALER_MERCHANTDB_deposit_permission_update (PGconn *conn, - uint64_t transaction_id, - unsigned int pending) -{ - PGresult *res; - ExecStatusType status; - - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint32 (&pending), - TALER_PQ_query_param_uint64 (&transaction_id), - TALER_PQ_query_param_end - }; - - res = TALER_PQ_exec_prepared (conn, "update_deposit_permission", params); - status = PQresultStatus (res); - - if (PGRES_COMMAND_OK != status) + if ( (NULL == (res = PQprepare (pg->conn, + "insert_payment", + "INSERT INTO payments" + "(h_contract" + ",h_wire" + ",transaction_id" + ",timestamp" + ",refund_deadline" + ",amount_without_fee_val" + ",amount_without_fee_frac" + ",amount_without_fee_curr" + ",coin_pub" + ",mint_sig) VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + 10, NULL))) || + (PGRES_COMMAND_OK != (status = PQresultStatus(res))) ) { - - const char *sqlstate; - - sqlstate = PQresultErrorField (res, PG_DIAG_SQLSTATE); - if (NULL == sqlstate) + if (NULL != res) { - /* very unexpected... */ - GNUNET_break (0); + PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res); PQclear (res); - return GNUNET_SYSERR; } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Database commit failure: %s\n", - sqlstate); - PQclear (res); return GNUNET_SYSERR; } + PQclear (res); return GNUNET_OK; } /** - * Store a deposit permission in DB. To be mainly used if /deposit should - * be retried; also, the merchant can benefit from this information in case - * he needs to later investigate about some @a transaction_id. - * - * @param conn DB handle - * @param transaction_id identification number of this payment (which is the - * same id of the related contract) - * @param pending if true, this payment got to a persistent state - * @param which mint is to get this deposit permission - * @return #GNUNET_OK if successful, #GNUNET_SYSERR upon errors - */ -uint32_t -TALER_MERCHANTDB_deposit_permission_store (PGconn *conn, - const char *deposit_permission, - uint64_t transaction_id, - unsigned int pending, - const char *mint_url) -{ - PGresult *res; - ExecStatusType status; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_fixed_size (deposit_permission, strlen (deposit_permission)), - TALER_PQ_query_param_uint64 (&transaction_id), - TALER_PQ_query_param_uint32 (&pending), - TALER_PQ_query_param_fixed_size (mint_url, strlen (mint_url)), - TALER_PQ_query_param_end - }; - - res = TALER_PQ_exec_prepared (conn, "store_deposit_permission", params); - status = PQresultStatus (res); - - 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"))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Inserting same transaction id twice\n"); - /* Primary key violation */ - PQclear (res); - return GNUNET_SYSERR; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Database commit failure: %s\n", - sqlstate); - PQclear (res); - return GNUNET_SYSERR; - } - - PQclear (res); - return GNUNET_OK; -} - - -/** - * Insert a contract record into the database and if successfull - * return the serial number of the inserted row. + * Insert payment confirmation from the mint into the database. * - * @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 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_NO if attempting to insert an - * already inserted @a c_id, #GNUNET_SYSERR for other errors. + * @param cls our plugin handle + * @param h_contract hash of the contract + * @param h_wire hash of our wire details + * @param transaction_id of the contract + * @param timestamp time of the confirmation + * @param refund refund deadline + * @param amount_without_fee amount the mint will deposit + * @param coin_pub public key of the coin + * @param merchant_pub our public key + * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error */ -uint32_t -TALER_MERCHANTDB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute timestamp, - const struct GNUNET_TIME_Absolute expiry, - struct GNUNET_TIME_Absolute edate, - struct GNUNET_TIME_Absolute refund, - const struct TALER_Amount *amount, - const struct GNUNET_HashCode *h_contract, - uint64_t c_id, - const char *desc, - uint64_t nounce, - uint64_t product) +static int +postgres_store_payment (void *cls, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + uint64_t transaction_id, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute refund, + const struct TALER_Amount *amount_without_fee, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MintSignatureP *mint_sig) { + struct PostgresClosure *pg = cls; PGresult *res; -#if 0 - uint64_t expiry_ms_nbo; - uint64_t value_nbo; - uint32_t fraction_nbo; - uint64_t nounce_nbo; -#endif ExecStatusType status; struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint64 (&c_id), - TALER_PQ_query_param_fixed_size (h_contract, sizeof (struct GNUNET_HashCode)), + TALER_PQ_query_param_auto_from_type (h_contract), + TALER_PQ_query_param_auto_from_type (h_wire), + TALER_PQ_query_param_uint64 (&transaction_id), TALER_PQ_query_param_absolute_time (×tamp), - TALER_PQ_query_param_absolute_time (&expiry), - TALER_PQ_query_param_absolute_time (&edate), TALER_PQ_query_param_absolute_time (&refund), - TALER_PQ_query_param_amount (amount), - /* A *string* is being put in the following statement, - though the column is declared as *blob*. Will this be - liked by the DB ? */ - TALER_PQ_query_param_fixed_size (desc, strlen (desc)), - TALER_PQ_query_param_uint64 (&nounce), - TALER_PQ_query_param_uint64 (&product), + TALER_PQ_query_param_amount (amount_without_fee), + TALER_PQ_query_param_auto_from_type (coin_pub), + TALER_PQ_query_param_auto_from_type (mint_sig), TALER_PQ_query_param_end }; - /* NOTE: the statement is prepared by TALER_MERCHANTDB_initialize function */ - res = TALER_PQ_exec_prepared (conn, "contract_create", params); + res = TALER_PQ_exec_prepared (pg->conn, + "insert_payment", + params); status = PQresultStatus (res); if (PGRES_COMMAND_OK != status) @@ -466,154 +196,56 @@ TALER_MERCHANTDB_contract_create (PGconn *conn, } -long long -TALER_MERCHANTDB_contract_get_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 -TALER_MERCHANTDB_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 -TALER_MERCHANTDB_checkout_get_product (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub) +/** + * Initialize Postgres database subsystem. + * + * @param cls a configuration instance + * @return NULL on error, otherwise a `struct TALER_MERCHANTDB_Plugin` + */ +void * +libtaler_plugin_merchantdb_postgres_init (void *cls) { - 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)) + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct PostgresClosure *pg; + struct TALER_MERCHANTDB_Plugin *plugin; + + pg = GNUNET_new (struct PostgresClosure); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "merchantdb-postgres", + "db_conn_str", + &pg->connection_cfg_str)) { - TALER_LOG_DEBUG ("Checkout not found for given coin"); - goto EXITIF_exit; + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "merchant", + "db_conn_str"); + return NULL; } - EXITIF (1 != PQntuples (res)); - EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); - PQclear (res); - return GNUNET_ntohll ((uint64_t) product); + pg->conn = GNUNET_POSTGRES_connect (cfg, "merchant-db"); + plugin = GNUNET_new (struct TALER_MERCHANTDB_Plugin); + plugin->cls = pg; + plugin->initialize = &postgres_initialize; + plugin->store_payment = &postgres_store_payment; - EXITIF_exit: - PQclear (res); - return -1; + return plugin; } /** - * The query gets a contract's nounce and edate used to reproduce - * a 'wire' JSON object. This function is also useful to check whether - * a claimed contract existed or not. + * Shutdown Postgres database subsystem. * - * @param conn handle to the DB - * @param h_contract the parameter for the row to match against - * @param nounce where to store the found nounce - * @param edate where to store the found edate - * @return #GNUNET_OK on success, #GNUNET_SYSERR upon errors + * @param cls a `struct TALER_MERCHANTDB_Plugin` + * @return NULL (always) */ -uint32_t -TALER_MERCHANTDB_contract_get_values (PGconn *conn, - const struct GNUNET_HashCode *h_contract, - uint64_t *nounce, - struct GNUNET_TIME_Absolute *edate) +void * +libtaler_plugin_merchantdb_postgres_done (void *cls) { - PGresult *res; - ExecStatusType status; - - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_fixed_size (h_contract, sizeof (struct GNUNET_HashCode)), - TALER_PQ_query_param_end - }; - struct TALER_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_uint64 ("nounce", nounce), - TALER_PQ_result_spec_absolute_time ("edate", edate), - TALER_PQ_result_spec_end - }; - - res = TALER_PQ_exec_prepared (conn, "get_contract_hash", params); - - status = PQresultStatus (res); - EXITIF (PGRES_TUPLES_OK != status); - if (0 == PQntuples (res)) - { - TALER_LOG_DEBUG ("Contract not found"); - goto EXITIF_exit; - } - - EXITIF (1 != PQntuples (res)); - EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); - PQclear (res); - return GNUNET_OK; - - EXITIF_exit: - PQclear (res); - return GNUNET_SYSERR; + struct TALER_MERCHANTDB_Plugin *plugin = cls; + struct PostgresClosure *pg = plugin->cls; + + GNUNET_free (pg->connection_cfg_str); + PQfinish (pg->conn); + GNUNET_free (pg); + GNUNET_free (plugin); + return NULL; } diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h index 9350ccb9..b6e378c6 100644 --- a/src/include/taler_merchantdb_plugin.h +++ b/src/include/taler_merchantdb_plugin.h @@ -49,7 +49,7 @@ struct TALER_MERCHANTDB_Plugin /** * Initialize merchant tables * - * @param conn the connection handle to postgres db. + * @param cls closure * @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 @@ -59,9 +59,9 @@ struct TALER_MERCHANTDB_Plugin int tmp); /** - * Inserts a contract record into the database. + * Insert payment confirmation from the mint into the database. * - * @param dbh the database connection + * @param cls closure * @param h_contract hash of the contract * @param h_wire hash of our wire details * @param transaction_id of the contract |