From c3a1a4ecbea0c8df729b7a29da5d31c1f9dab9c9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 1 Sep 2021 00:59:34 +0200 Subject: separate DB creation from plugin loading; fix misc. Debian package issues --- debian/anastasis-httpd.postinst | 6 + debian/db/install/pgsql | 2 +- debian/etc/anastasis/anastasis.conf | 21 + debian/rules | 2 +- doc/sphinx/manpages/anastasis.conf.5.rst | 3 + .../anastasis-helper-authorization-iban.c | 10 + src/backend/anastasis-httpd.c | 8 + src/include/anastasis_database_plugin.h | 22 +- src/stasis/anastasis-dbinit.c | 8 +- src/stasis/plugin_anastasis_postgres.c | 1408 ++++++++++---------- src/stasis/test_anastasis_db.c | 10 +- 11 files changed, 805 insertions(+), 695 deletions(-) diff --git a/debian/anastasis-httpd.postinst b/debian/anastasis-httpd.postinst index fe89acb..994b06b 100644 --- a/debian/anastasis-httpd.postinst +++ b/debian/anastasis-httpd.postinst @@ -20,6 +20,12 @@ configure) adduser --quiet --system --ingroup ${_GROUPNAME} --no-create-home --home ${TALER_HOME} ${_USERNAME} fi + if ! dpkg-statoverride --list /etc/anastasis/secrets/anastasis-db.secret.conf >/dev/null 2>&1; then + dpkg-statoverride --add --update \ + anastasis-httpd root 460 \ + /etc/anastasis/secrets/anastasis-db.secret.conf + fi + # Setup postgres database (needs dbconfig-pgsql package) if [ -f /usr/share/dbconfig-common/dpkg/postinst.pgsql ]; then . /usr/share/dbconfig-common/dpkg/postinst.pgsql diff --git a/debian/db/install/pgsql b/debian/db/install/pgsql index dab5d1e..f695fed 100755 --- a/debian/db/install/pgsql +++ b/debian/db/install/pgsql @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -eu diff --git a/debian/etc/anastasis/anastasis.conf b/debian/etc/anastasis/anastasis.conf index e662a43..4d0deda 100644 --- a/debian/etc/anastasis/anastasis.conf +++ b/debian/etc/anastasis/anastasis.conf @@ -1,5 +1,26 @@ [anastasis] DATABASE = postgres +SERVE = unix + +# You must set each of the following options +# before starting anastasis-httpd! +# +# Storage fee for policies (per year) +#ANNUAL_FEE = KUDOS:0 +# +# Storage fee for truth +#TRUTH_UPLOAD_FEE = KUDOS:0 + +# Name of your business +#BUSINESS_NAME = "" + +# Random server salt. Use output of 'uuidgen' +#SERVER_SALT = "" + +# How high is the per key share insurance offered +# by your business? +#INSURANCE = KUDOS:0 + [taler] # Currency accepted by anastasis via GNU Taler payments. diff --git a/debian/rules b/debian/rules index e3c7db5..cfd43c7 100755 --- a/debian/rules +++ b/debian/rules @@ -34,7 +34,7 @@ override_dh_install: dh_install # Done manually for debhelper-compat<13 dh_installtmpfiles -# Remove files already present in libtalerexchange from main taler-exchange package +# Remove files already present in libanastasis-dev/cli from anastasis-httpd/libanastasis packages cd debian/libanastasis-dev; find . -type f,l -exec rm -f ../anastasis-httpd/{} \; cd debian/anastasis-cli; find . -type f -exec rm -f ../anastasis-httpd/{} \; cd debian/libanastasis-dev; find . -type f,l -exec rm -f ../libanastasis/{} \; diff --git a/doc/sphinx/manpages/anastasis.conf.5.rst b/doc/sphinx/manpages/anastasis.conf.5.rst index 1f6b49e..000d8f0 100644 --- a/doc/sphinx/manpages/anastasis.conf.5.rst +++ b/doc/sphinx/manpages/anastasis.conf.5.rst @@ -67,6 +67,9 @@ ANNUAL_FEE TRUTH_UPLOAD_FEE Annual fee to be paid for truth uploads, i.e. "EUR:1.5". +INSURANCE + Amount up to which key shares are warranted, i.e. "EUR:1000000". + DB Database backend to use, only ``postgres`` is supported right now. diff --git a/src/authorization/anastasis-helper-authorization-iban.c b/src/authorization/anastasis-helper-authorization-iban.c index 04dfa03..c6e5335 100644 --- a/src/authorization/anastasis-helper-authorization-iban.c +++ b/src/authorization/anastasis-helper-authorization-iban.c @@ -389,6 +389,16 @@ run (void *cls, global_ret = EXIT_NOTCONFIGURED; return; } + if (GNUNET_OK != + db_plugin->connect (db_plugin->cls)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database not set up. Did you run anastasis-dbinit?\n"); + global_ret = EXIT_NOTCONFIGURED; + ANASTASIS_DB_plugin_unload (db_plugin); + db_plugin = NULL; + return; + } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "authorization-iban", diff --git a/src/backend/anastasis-httpd.c b/src/backend/anastasis-httpd.c index fdf17ff..9f5c87b 100644 --- a/src/backend/anastasis-httpd.c +++ b/src/backend/anastasis-httpd.c @@ -888,6 +888,14 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } + if (GNUNET_OK != + db->connect (db->cls)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database not setup. Did you run anastasis-dbinit?\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } fh = TALER_MHD_bind (config, "anastasis", diff --git a/src/include/anastasis_database_plugin.h b/src/include/anastasis_database_plugin.h index 565ad69..bc4b0e6 100644 --- a/src/include/anastasis_database_plugin.h +++ b/src/include/anastasis_database_plugin.h @@ -187,8 +187,26 @@ struct ANASTASIS_DatabasePlugin * @param cls closure * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ - int - (*drop_tables) (void *cls); + enum GNUNET_GenericReturnValue + (*drop_tables)(void *cls); + + /** + * Connect to the database. + * + * @param cls closure + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + enum GNUNET_GenericReturnValue + (*connect)(void *cls); + + /** + * Initialize merchant tables + * + * @param cls closure + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + enum GNUNET_GenericReturnValue + (*create_tables)(void *cls); /** * Function called to perform "garbage collection" on the diff --git a/src/stasis/anastasis-dbinit.c b/src/stasis/anastasis-dbinit.c index 038fb7c..17b3c56 100644 --- a/src/stasis/anastasis-dbinit.c +++ b/src/stasis/anastasis-dbinit.c @@ -54,7 +54,7 @@ run (void *cls, { fprintf (stderr, "Failed to initialize database plugin.\n"); - global_ret = 1; + global_ret = EXIT_FAILURE; return; } if (reset_db) @@ -63,6 +63,12 @@ run (void *cls, ANASTASIS_DB_plugin_unload (plugin); plugin = ANASTASIS_DB_plugin_load (cfg); } + if (GNUNET_OK != + plugin->create_tables (plugin->cls)) + { + global_ret = EXIT_FAILURE; + return; + } ANASTASIS_DB_plugin_unload (plugin); } diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c index 8ee16ad..b78dbdb 100644 --- a/src/stasis/plugin_anastasis_postgres.c +++ b/src/stasis/plugin_anastasis_postgres.c @@ -81,7 +81,7 @@ struct PostgresClosure * @param cls closure our `struct Plugin` * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ -static int +static enum GNUNET_GenericReturnValue postgres_drop_tables (void *cls) { struct PostgresClosure *pg = cls; @@ -100,266 +100,676 @@ postgres_drop_tables (void *cls) /** - * Check that the database connection is still up. - * - * @param cls a `struct PostgresClosure` with connection to check - */ -static void -check_connection (void *cls) -{ - struct PostgresClosure *pg = cls; - - GNUNET_PQ_reconnect_if_down (pg->conn); -} - - -/** - * Do a pre-flight check that we are not in an uncommitted transaction. - * If we are, try to commit the previous transaction and output a warning. - * Does not return anything, as we will continue regardless of the outcome. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - */ -static void -postgres_preflight (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("COMMIT"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - if (NULL == pg->transaction_name) - return; /* all good */ - if (GNUNET_OK == - GNUNET_PQ_exec_statements (pg->conn, - es)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "BUG: Preflight check committed transaction `%s'!\n", - pg->transaction_name); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "BUG: Preflight check failed to commit transaction `%s'!\n", - pg->transaction_name); - } - pg->transaction_name = NULL; -} - - -/** - * Start a transaction. + * Initialize tables. * * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param name unique name identifying the transaction (for debugging), - * must point to a constant - * @return #GNUNET_OK on success + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ -static int -begin_transaction (void *cls, - const char *name) +static enum GNUNET_GenericReturnValue +postgres_create_tables (void *cls) { - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; + struct PostgresClosure *pc = cls; + struct GNUNET_PQ_Context *conn; - check_connection (pg); - postgres_preflight (pg); - pg->transaction_name = name; - if (GNUNET_OK != - GNUNET_PQ_exec_statements (pg->conn, - es)) - { - TALER_LOG_ERROR ("Failed to start transaction\n"); - GNUNET_break (0); + conn = GNUNET_PQ_connect_with_cfg (pc->cfg, + "stasis-postgres", + "stasis-", + NULL, + NULL); + if (NULL == conn) return GNUNET_SYSERR; - } + GNUNET_PQ_disconnect (conn); return GNUNET_OK; } /** -* Roll back the current transaction of a database connection. -* -* @param cls the `struct PostgresClosure` with the plugin-specific state -* @return #GNUNET_OK on success -*/ -static void -rollback (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("ROLLBACK"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - if (GNUNET_OK != - GNUNET_PQ_exec_statements (pg->conn, - es)) - { - TALER_LOG_ERROR ("Failed to rollback transaction\n"); - GNUNET_break (0); - } - pg->transaction_name = NULL; -} - - -/** - * Commit the current transaction of a database connection. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @return transaction status code - */ -static enum GNUNET_DB_QueryStatus -commit_transaction (void *cls) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_PQ_QueryParam no_params[] = { - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "do_commit", - no_params); - pg->transaction_name = NULL; - return qs; -} - - -/** - * Register callback to be invoked on events of type @a es. - * - * @param cls database context to use - * @param es specification of the event to listen for - * @param timeout how long to wait for the event - * @param cb function to call when the event happens, possibly - * multiple times (until cancel is invoked) - * @param cb_cls closure for @a cb - * @return handle useful to cancel the listener - */ -static struct GNUNET_DB_EventHandler * -postgres_event_listen (void *cls, - const struct GNUNET_DB_EventHeaderP *es, - struct GNUNET_TIME_Relative timeout, - GNUNET_DB_EventCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - - return GNUNET_PQ_event_listen (pg->conn, - es, - timeout, - cb, - cb_cls); -} - - -/** - * Stop notifications. - * - * @param eh handle to unregister. - */ -static void -postgres_event_listen_cancel (struct GNUNET_DB_EventHandler *eh) -{ - GNUNET_PQ_event_listen_cancel (eh); -} - - -/** - * Notify all that listen on @a es of an event. - * - * @param cls database context to use - * @param es specification of the event to generate - * @param extra additional event data provided - * @param extra_size number of bytes in @a extra - */ -static void -postgres_event_notify (void *cls, - const struct GNUNET_DB_EventHeaderP *es, - const void *extra, - size_t extra_size) -{ - struct PostgresClosure *pg = cls; - - return GNUNET_PQ_event_notify (pg->conn, - es, - extra, - extra_size); -} - - -/** - * Function called to perform "garbage collection" on the - * database, expiring records we no longer require. Deletes - * all user records that are not paid up (and by cascade deletes - * the associated recovery documents). Also deletes expired - * truth and financial records older than @a fin_expire. - * - * @param cls closure - * @param expire_backups backups older than the given time stamp should be garbage collected - * @param expire_pending_payments payments still pending from since before - * this value should be garbage collected - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_gc (void *cls, - struct GNUNET_TIME_Absolute expire_backups, - struct GNUNET_TIME_Absolute expire_pending_payments) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&expire_backups), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_QueryParam params2[] = { - GNUNET_PQ_query_param_absolute_time (&expire_pending_payments), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - postgres_preflight (pg); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "gc_accounts", - params); - if (qs < 0) - return qs; - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "gc_recdoc_pending_payments", - params2); -} - - -/** - * Store encrypted recovery document. + * Establish connection to the database. * - * @param cls closure - * @param account_pub public key of the user's account - * @param account_sig signature affirming storage request - * @param recovery_data_hash hash of @a data - * @param recovery_data contains encrypted_recovery_document - * @param recovery_data_size size of data blob - * @param payment_secret identifier for the payment, used to later charge on uploads - * @param[out] version set to the version assigned to the document by the database - * @return transaction status, 0 if upload could not be finished because @a payment_secret - * did not have enough upload left; HARD error if @a payment_secret is unknown, ... + * @param cls plugin context + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ -static enum ANASTASIS_DB_StoreStatus -postgres_store_recovery_document ( - void *cls, - const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, - const struct ANASTASIS_AccountSignatureP *account_sig, - const struct GNUNET_HashCode *recovery_data_hash, - const void *recovery_data, - size_t recovery_data_size, - const struct ANASTASIS_PaymentSecretP *payment_secret, - uint32_t *version) +static enum GNUNET_GenericReturnValue +postgres_connect (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_PreparedStatement ps[] = { + GNUNET_PQ_make_prepare ("user_insert", + "INSERT INTO anastasis_user " + "(user_id" + ",expiration_date" + ") VALUES " + "($1, $2);", + 2), + GNUNET_PQ_make_prepare ("do_commit", + "COMMIT", + 0), + GNUNET_PQ_make_prepare ("user_select", + "SELECT" + " expiration_date " + "FROM anastasis_user" + " WHERE user_id=$1" + " FOR UPDATE;", + 1), + GNUNET_PQ_make_prepare ("user_update", + "UPDATE anastasis_user" + " SET " + " expiration_date=$1" + " WHERE user_id=$2;", + 2), + GNUNET_PQ_make_prepare ("recdoc_payment_insert", + "INSERT INTO anastasis_recdoc_payment " + "(user_id" + ",post_counter" + ",amount_val" + ",amount_frac" + ",payment_identifier" + ",creation_date" + ") VALUES " + "($1, $2, $3, $4, $5, $6);", + 6), + GNUNET_PQ_make_prepare ("challenge_payment_insert", + "INSERT INTO anastasis_challenge_payment " + "(truth_uuid" + ",amount_val" + ",amount_frac" + ",payment_identifier" + ",creation_date" + ") VALUES " + "($1, $2, $3, $4, $5);", + 5), + GNUNET_PQ_make_prepare ("truth_payment_insert", + "INSERT INTO anastasis_truth_payment " + "(truth_uuid" + ",amount_val" + ",amount_frac" + ",expiration" + ") VALUES " + "($1, $2, $3, $4);", + 4), + GNUNET_PQ_make_prepare ("recdoc_payment_done", + "UPDATE anastasis_recdoc_payment " + "SET" + " paid=TRUE " + "WHERE" + " payment_identifier=$1" + " AND" + " user_id=$2" + " AND" + " paid=FALSE;", + 2), + GNUNET_PQ_make_prepare ("challenge_refund_update", + "UPDATE anastasis_challenge_payment " + "SET" + " refunded=TRUE " + "WHERE" + " payment_identifier=$1" + " AND" + " paid=TRUE" + " AND" + " truth_uuid=$2;", + 2), + GNUNET_PQ_make_prepare ("challenge_payment_done", + "UPDATE anastasis_challenge_payment " + "SET" + " paid=TRUE " + "WHERE" + " payment_identifier=$1" + " AND" + " refunded=FALSE" + " AND" + " truth_uuid=$2" + " AND" + " paid=FALSE;", + 2), + GNUNET_PQ_make_prepare ("recdoc_payment_select", + "SELECT" + " creation_date" + ",post_counter" + ",amount_val" + ",amount_frac" + ",paid" + " FROM anastasis_recdoc_payment" + " WHERE payment_identifier=$1;", + 1), + GNUNET_PQ_make_prepare ("truth_payment_select", + "SELECT" + " expiration" + " FROM anastasis_truth_payment" + " WHERE truth_uuid=$1" + " AND expiration>$2;", + 2), + GNUNET_PQ_make_prepare ("challenge_payment_select", + "SELECT" + " creation_date" + ",amount_val" + ",amount_frac" + ",paid" + " FROM anastasis_challenge_payment" + " WHERE payment_identifier=$1" + " AND truth_uuid=$2" + " AND refunded=FALSE" + " AND counter>0;", + 1), + GNUNET_PQ_make_prepare ("challenge_pending_payment_select", + "SELECT" + " creation_date" + ",payment_identifier" + ",amount_val" + ",amount_frac" + " FROM anastasis_challenge_payment" + " WHERE" + " paid=FALSE" + " AND" + " refunded=FALSE" + " AND" + " truth_uuid=$1" + " AND" + " creation_date > $2;", + 1), + GNUNET_PQ_make_prepare ("recdoc_payments_select", + "SELECT" + " user_id" + ",payment_identifier" + ",amount_val" + ",amount_frac" + " FROM anastasis_recdoc_payment" + " WHERE paid=FALSE;", + 0), + GNUNET_PQ_make_prepare ("gc_accounts", + "DELETE FROM anastasis_user " + "WHERE" + " expiration_date < $1;", + 1), + GNUNET_PQ_make_prepare ("gc_recdoc_pending_payments", + "DELETE FROM anastasis_recdoc_payment " + "WHERE" + " paid=FALSE" + " AND" + " creation_date < $1;", + 1), + GNUNET_PQ_make_prepare ("gc_challenge_pending_payments", + "DELETE FROM anastasis_challenge_payment " + "WHERE" + " (paid=FALSE" + " OR" + " refunded=TRUE)" + " AND" + " creation_date < $1;", + 1), + GNUNET_PQ_make_prepare ("truth_insert", + "INSERT INTO anastasis_truth " + "(truth_uuid" + ",key_share_data" + ",method_name" + ",encrypted_truth" + ",truth_mime" + ",expiration" + ") VALUES " + "($1, $2, $3, $4, $5, $6);", + 6), + + GNUNET_PQ_make_prepare ("test_auth_iban_payment", + "SELECT" + " credit_val" + ",credit_frac" + ",wire_subject" + " FROM anastasis_auth_iban_in" + " WHERE debit_account_details=$1" + " AND execution_date>=$2;", + 2), + GNUNET_PQ_make_prepare ("store_auth_iban_payment_details", + "INSERT INTO anastasis_auth_iban_in " + "(wire_reference" + ",wire_subject" + ",credit_val" + ",credit_frac" + ",debit_account_details" + ",credit_account_details" + ",execution_date" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7);", + 7), + + + GNUNET_PQ_make_prepare ("recovery_document_insert", + "INSERT INTO anastasis_recoverydocument " + "(user_id" + ",version" + ",account_sig" + ",recovery_data_hash" + ",recovery_data" + ") VALUES " + "($1, $2, $3, $4, $5);", + 5), + GNUNET_PQ_make_prepare ("truth_select", + "SELECT " + " method_name" + ",encrypted_truth" + ",truth_mime" + " FROM anastasis_truth" + " WHERE truth_uuid =$1;", + 1), + GNUNET_PQ_make_prepare ("latest_recoverydocument_select", + "SELECT " + " version" + ",account_sig" + ",recovery_data_hash" + ",recovery_data" + " FROM anastasis_recoverydocument" + " WHERE user_id =$1 " + " ORDER BY version DESC" + " LIMIT 1;", + 1), + GNUNET_PQ_make_prepare ("latest_recovery_version_select", + "SELECT" + " version" + ",recovery_data_hash" + ",expiration_date" + " FROM anastasis_recoverydocument" + " JOIN anastasis_user USING (user_id)" + " WHERE user_id=$1" + " ORDER BY version DESC" + " LIMIT 1;", + 1), + GNUNET_PQ_make_prepare ("recoverydocument_select", + "SELECT " + " account_sig" + ",recovery_data_hash" + ",recovery_data" + " FROM anastasis_recoverydocument" + " WHERE user_id=$1" + " AND version=$2;", + 2), + GNUNET_PQ_make_prepare ("postcounter_select", + "SELECT" + " post_counter" + " FROM anastasis_recdoc_payment" + " WHERE user_id=$1" + " AND payment_identifier=$2;", + 2), + GNUNET_PQ_make_prepare ("postcounter_update", + "UPDATE " + "anastasis_recdoc_payment " + "SET " + "post_counter=$1 " + "WHERE user_id =$2 " + "AND payment_identifier=$3;", + 3), + GNUNET_PQ_make_prepare ("key_share_select", + "SELECT " + "key_share_data " + "FROM " + "anastasis_truth " + "WHERE truth_uuid =$1;", + 1), + GNUNET_PQ_make_prepare ("challengecode_insert", + "INSERT INTO anastasis_challengecode " + "(truth_uuid" + ",code" + ",creation_date" + ",expiration_date" + ",retry_counter" + ") VALUES " + "($1, $2, $3, $4, $5);", + 5), + GNUNET_PQ_make_prepare ("challengecode_select", + "SELECT " + " code" + ",satisfied" + " FROM anastasis_challengecode" + " WHERE truth_uuid=$1" + " AND expiration_date > $2" + " AND retry_counter != 0;", + 2), + GNUNET_PQ_make_prepare ("challengecode_set_satisfied", + "UPDATE anastasis_challengecode" + " SET satisfied=TRUE" + " WHERE truth_uuid=$1" + " AND code=$2" + " AND creation_date IN" + " (SELECT creation_date" + " FROM anastasis_challengecode" + " WHERE truth_uuid=$1" + " AND code=$2" + " ORDER BY creation_date DESC" + " LIMIT 1);", + 2), + GNUNET_PQ_make_prepare ("challengecode_test_satisfied", + "SELECT 1 FROM anastasis_challengecode" + " WHERE truth_uuid=$1" + " AND satisfied=TRUE" + " AND code=$2" + " AND creation_date >= $3" + " LIMIT 1;", + 3), + GNUNET_PQ_make_prepare ("challengecode_select_meta", + "SELECT " + " code" + ",retry_counter" + ",retransmission_date" + " FROM anastasis_challengecode" + " WHERE truth_uuid=$1" + " AND expiration_date > $2" + " AND creation_date > $3" + " ORDER BY creation_date DESC" + " LIMIT 1;", + 2), + GNUNET_PQ_make_prepare ("challengecode_update_retry", + "UPDATE anastasis_challengecode" + " SET retry_counter=retry_counter - 1" + " WHERE truth_uuid=$1" + " AND code=$2" + " AND retry_counter != 0;", + 1), + GNUNET_PQ_make_prepare ("challengepayment_dec_counter", + "UPDATE anastasis_challenge_payment" + " SET counter=counter - 1" + " WHERE truth_uuid=$1" + " AND payment_identifier=$2" + " AND counter > 0;", + 2), + GNUNET_PQ_make_prepare ("challengecode_mark_sent", + "UPDATE anastasis_challengecode" + " SET retransmission_date=$3" + " WHERE truth_uuid=$1" + " AND code=$2" + " AND creation_date IN" + " (SELECT creation_date" + " FROM anastasis_challengecode" + " WHERE truth_uuid=$1" + " AND code=$2" + " ORDER BY creation_date DESC" + " LIMIT 1);", + 3), + GNUNET_PQ_make_prepare ("get_last_auth_iban_payment", + "SELECT " + " wire_reference" + " FROM anastasis_auth_iban_in" + " WHERE credit_account_details=$1" + " ORDER BY wire_reference DESC" + " LIMIT 1;", + 1), + GNUNET_PQ_make_prepare ("gc_challengecodes", + "DELETE FROM anastasis_challengecode " + "WHERE " + "expiration_date < $1;", + 1), + GNUNET_PQ_PREPARED_STATEMENT_END + }; + + pg->conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "stasis-postgres", + NULL, + NULL, + ps); + if (NULL == pg->conn) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Check that the database connection is still up. + * + * @param cls a `struct PostgresClosure` with connection to check + */ +static void +check_connection (void *cls) +{ + struct PostgresClosure *pg = cls; + + GNUNET_PQ_reconnect_if_down (pg->conn); +} + + +/** + * Do a pre-flight check that we are not in an uncommitted transaction. + * If we are, try to commit the previous transaction and output a warning. + * Does not return anything, as we will continue regardless of the outcome. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + */ +static void +postgres_preflight (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("COMMIT"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (NULL == pg->transaction_name) + return; /* all good */ + if (GNUNET_OK == + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check committed transaction `%s'!\n", + pg->transaction_name); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check failed to commit transaction `%s'!\n", + pg->transaction_name); + } + pg->transaction_name = NULL; +} + + +/** + * Start a transaction. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param name unique name identifying the transaction (for debugging), + * must point to a constant + * @return #GNUNET_OK on success + */ +static int +begin_transaction (void *cls, + const char *name) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + check_connection (pg); + postgres_preflight (pg); + pg->transaction_name = name; + if (GNUNET_OK != + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + TALER_LOG_ERROR ("Failed to start transaction\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** +* Roll back the current transaction of a database connection. +* +* @param cls the `struct PostgresClosure` with the plugin-specific state +* @return #GNUNET_OK on success +*/ +static void +rollback (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("ROLLBACK"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (GNUNET_OK != + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + TALER_LOG_ERROR ("Failed to rollback transaction\n"); + GNUNET_break (0); + } + pg->transaction_name = NULL; +} + + +/** + * Commit the current transaction of a database connection. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return transaction status code + */ +static enum GNUNET_DB_QueryStatus +commit_transaction (void *cls) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam no_params[] = { + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "do_commit", + no_params); + pg->transaction_name = NULL; + return qs; +} + + +/** + * Register callback to be invoked on events of type @a es. + * + * @param cls database context to use + * @param es specification of the event to listen for + * @param timeout how long to wait for the event + * @param cb function to call when the event happens, possibly + * multiple times (until cancel is invoked) + * @param cb_cls closure for @a cb + * @return handle useful to cancel the listener + */ +static struct GNUNET_DB_EventHandler * +postgres_event_listen (void *cls, + const struct GNUNET_DB_EventHeaderP *es, + struct GNUNET_TIME_Relative timeout, + GNUNET_DB_EventCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + + return GNUNET_PQ_event_listen (pg->conn, + es, + timeout, + cb, + cb_cls); +} + + +/** + * Stop notifications. + * + * @param eh handle to unregister. + */ +static void +postgres_event_listen_cancel (struct GNUNET_DB_EventHandler *eh) +{ + GNUNET_PQ_event_listen_cancel (eh); +} + + +/** + * Notify all that listen on @a es of an event. + * + * @param cls database context to use + * @param es specification of the event to generate + * @param extra additional event data provided + * @param extra_size number of bytes in @a extra + */ +static void +postgres_event_notify (void *cls, + const struct GNUNET_DB_EventHeaderP *es, + const void *extra, + size_t extra_size) +{ + struct PostgresClosure *pg = cls; + + return GNUNET_PQ_event_notify (pg->conn, + es, + extra, + extra_size); +} + + +/** + * Function called to perform "garbage collection" on the + * database, expiring records we no longer require. Deletes + * all user records that are not paid up (and by cascade deletes + * the associated recovery documents). Also deletes expired + * truth and financial records older than @a fin_expire. + * + * @param cls closure + * @param expire_backups backups older than the given time stamp should be garbage collected + * @param expire_pending_payments payments still pending from since before + * this value should be garbage collected + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_gc (void *cls, + struct GNUNET_TIME_Absolute expire_backups, + struct GNUNET_TIME_Absolute expire_pending_payments) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&expire_backups), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params2[] = { + GNUNET_PQ_query_param_absolute_time (&expire_pending_payments), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + postgres_preflight (pg); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_accounts", + params); + if (qs < 0) + return qs; + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_recdoc_pending_payments", + params2); +} + + +/** + * Store encrypted recovery document. + * + * @param cls closure + * @param account_pub public key of the user's account + * @param account_sig signature affirming storage request + * @param recovery_data_hash hash of @a data + * @param recovery_data contains encrypted_recovery_document + * @param recovery_data_size size of data blob + * @param payment_secret identifier for the payment, used to later charge on uploads + * @param[out] version set to the version assigned to the document by the database + * @return transaction status, 0 if upload could not be finished because @a payment_secret + * did not have enough upload left; HARD error if @a payment_secret is unknown, ... + */ +static enum ANASTASIS_DB_StoreStatus +postgres_store_recovery_document ( + void *cls, + const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, + const struct ANASTASIS_AccountSignatureP *account_sig, + const struct GNUNET_HashCode *recovery_data_hash, + const void *recovery_data, + size_t recovery_data_size, + const struct ANASTASIS_PaymentSecretP *payment_secret, + uint32_t *version) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs; @@ -2214,450 +2624,76 @@ postgres_mark_challenge_sent ( check_connection (pg); { struct GNUNET_TIME_Absolute now; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (truth_uuid), - GNUNET_PQ_query_param_uint64 (&code), - TALER_PQ_query_param_absolute_time (&now), - GNUNET_PQ_query_param_end - }; - - now = GNUNET_TIME_absolute_get (); - GNUNET_TIME_round_abs (&now); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "challengecode_mark_sent", - params); - if (qs <= 0) - return qs; - } - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (truth_uuid), - GNUNET_PQ_query_param_auto_from_type (payment_secret), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "challengepayment_dec_counter", - params); - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* probably was free */ - return qs; - } -} - - -/** - * Function called to remove all expired codes from the database. - * - * @return transaction status - */ -enum GNUNET_DB_QueryStatus -postgres_challenge_gc (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get (); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&time_now), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - postgres_preflight (pg); - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "gc_challengecodes", - params); -} - - -/** - * Initialize Postgres database subsystem. - * - * @param cls a configuration instance - * @return NULL on error, otherwise a `struct TALER_ANASTASISDB_Plugin` - */ -void * -libanastasis_plugin_db_postgres_init (void *cls) -{ - struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct PostgresClosure *pg; - struct ANASTASIS_DatabasePlugin *plugin; - struct GNUNET_PQ_PreparedStatement ps[] = { - GNUNET_PQ_make_prepare ("user_insert", - "INSERT INTO anastasis_user " - "(user_id" - ",expiration_date" - ") VALUES " - "($1, $2);", - 2), - GNUNET_PQ_make_prepare ("do_commit", - "COMMIT", - 0), - GNUNET_PQ_make_prepare ("user_select", - "SELECT" - " expiration_date " - "FROM anastasis_user" - " WHERE user_id=$1" - " FOR UPDATE;", - 1), - GNUNET_PQ_make_prepare ("user_update", - "UPDATE anastasis_user" - " SET " - " expiration_date=$1" - " WHERE user_id=$2;", - 2), - GNUNET_PQ_make_prepare ("recdoc_payment_insert", - "INSERT INTO anastasis_recdoc_payment " - "(user_id" - ",post_counter" - ",amount_val" - ",amount_frac" - ",payment_identifier" - ",creation_date" - ") VALUES " - "($1, $2, $3, $4, $5, $6);", - 6), - GNUNET_PQ_make_prepare ("challenge_payment_insert", - "INSERT INTO anastasis_challenge_payment " - "(truth_uuid" - ",amount_val" - ",amount_frac" - ",payment_identifier" - ",creation_date" - ") VALUES " - "($1, $2, $3, $4, $5);", - 5), - GNUNET_PQ_make_prepare ("truth_payment_insert", - "INSERT INTO anastasis_truth_payment " - "(truth_uuid" - ",amount_val" - ",amount_frac" - ",expiration" - ") VALUES " - "($1, $2, $3, $4);", - 4), - GNUNET_PQ_make_prepare ("recdoc_payment_done", - "UPDATE anastasis_recdoc_payment " - "SET" - " paid=TRUE " - "WHERE" - " payment_identifier=$1" - " AND" - " user_id=$2" - " AND" - " paid=FALSE;", - 2), - GNUNET_PQ_make_prepare ("challenge_refund_update", - "UPDATE anastasis_challenge_payment " - "SET" - " refunded=TRUE " - "WHERE" - " payment_identifier=$1" - " AND" - " paid=TRUE" - " AND" - " truth_uuid=$2;", - 2), - GNUNET_PQ_make_prepare ("challenge_payment_done", - "UPDATE anastasis_challenge_payment " - "SET" - " paid=TRUE " - "WHERE" - " payment_identifier=$1" - " AND" - " refunded=FALSE" - " AND" - " truth_uuid=$2" - " AND" - " paid=FALSE;", - 2), - GNUNET_PQ_make_prepare ("recdoc_payment_select", - "SELECT" - " creation_date" - ",post_counter" - ",amount_val" - ",amount_frac" - ",paid" - " FROM anastasis_recdoc_payment" - " WHERE payment_identifier=$1;", - 1), - GNUNET_PQ_make_prepare ("truth_payment_select", - "SELECT" - " expiration" - " FROM anastasis_truth_payment" - " WHERE truth_uuid=$1" - " AND expiration>$2;", - 2), - GNUNET_PQ_make_prepare ("challenge_payment_select", - "SELECT" - " creation_date" - ",amount_val" - ",amount_frac" - ",paid" - " FROM anastasis_challenge_payment" - " WHERE payment_identifier=$1" - " AND truth_uuid=$2" - " AND refunded=FALSE" - " AND counter>0;", - 1), - GNUNET_PQ_make_prepare ("challenge_pending_payment_select", - "SELECT" - " creation_date" - ",payment_identifier" - ",amount_val" - ",amount_frac" - " FROM anastasis_challenge_payment" - " WHERE" - " paid=FALSE" - " AND" - " refunded=FALSE" - " AND" - " truth_uuid=$1" - " AND" - " creation_date > $2;", - 1), - GNUNET_PQ_make_prepare ("recdoc_payments_select", - "SELECT" - " user_id" - ",payment_identifier" - ",amount_val" - ",amount_frac" - " FROM anastasis_recdoc_payment" - " WHERE paid=FALSE;", - 0), - GNUNET_PQ_make_prepare ("gc_accounts", - "DELETE FROM anastasis_user " - "WHERE" - " expiration_date < $1;", - 1), - GNUNET_PQ_make_prepare ("gc_recdoc_pending_payments", - "DELETE FROM anastasis_recdoc_payment " - "WHERE" - " paid=FALSE" - " AND" - " creation_date < $1;", - 1), - GNUNET_PQ_make_prepare ("gc_challenge_pending_payments", - "DELETE FROM anastasis_challenge_payment " - "WHERE" - " (paid=FALSE" - " OR" - " refunded=TRUE)" - " AND" - " creation_date < $1;", - 1), - GNUNET_PQ_make_prepare ("truth_insert", - "INSERT INTO anastasis_truth " - "(truth_uuid" - ",key_share_data" - ",method_name" - ",encrypted_truth" - ",truth_mime" - ",expiration" - ") VALUES " - "($1, $2, $3, $4, $5, $6);", - 6), + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_uint64 (&code), + TALER_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_end + }; - GNUNET_PQ_make_prepare ("test_auth_iban_payment", - "SELECT" - " credit_val" - ",credit_frac" - ",wire_subject" - " FROM anastasis_auth_iban_in" - " WHERE debit_account_details=$1" - " AND execution_date>=$2;", - 2), - GNUNET_PQ_make_prepare ("store_auth_iban_payment_details", - "INSERT INTO anastasis_auth_iban_in " - "(wire_reference" - ",wire_subject" - ",credit_val" - ",credit_frac" - ",debit_account_details" - ",credit_account_details" - ",execution_date" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7);", - 7), + now = GNUNET_TIME_absolute_get (); + GNUNET_TIME_round_abs (&now); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "challengecode_mark_sent", + params); + if (qs <= 0) + return qs; + } + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_auto_from_type (payment_secret), + GNUNET_PQ_query_param_end + }; + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "challengepayment_dec_counter", + params); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* probably was free */ + return qs; + } +} - GNUNET_PQ_make_prepare ("recovery_document_insert", - "INSERT INTO anastasis_recoverydocument " - "(user_id" - ",version" - ",account_sig" - ",recovery_data_hash" - ",recovery_data" - ") VALUES " - "($1, $2, $3, $4, $5);", - 5), - GNUNET_PQ_make_prepare ("truth_select", - "SELECT " - " method_name" - ",encrypted_truth" - ",truth_mime" - " FROM anastasis_truth" - " WHERE truth_uuid =$1;", - 1), - GNUNET_PQ_make_prepare ("latest_recoverydocument_select", - "SELECT " - " version" - ",account_sig" - ",recovery_data_hash" - ",recovery_data" - " FROM anastasis_recoverydocument" - " WHERE user_id =$1 " - " ORDER BY version DESC" - " LIMIT 1;", - 1), - GNUNET_PQ_make_prepare ("latest_recovery_version_select", - "SELECT" - " version" - ",recovery_data_hash" - ",expiration_date" - " FROM anastasis_recoverydocument" - " JOIN anastasis_user USING (user_id)" - " WHERE user_id=$1" - " ORDER BY version DESC" - " LIMIT 1;", - 1), - GNUNET_PQ_make_prepare ("recoverydocument_select", - "SELECT " - " account_sig" - ",recovery_data_hash" - ",recovery_data" - " FROM anastasis_recoverydocument" - " WHERE user_id=$1" - " AND version=$2;", - 2), - GNUNET_PQ_make_prepare ("postcounter_select", - "SELECT" - " post_counter" - " FROM anastasis_recdoc_payment" - " WHERE user_id=$1" - " AND payment_identifier=$2;", - 2), - GNUNET_PQ_make_prepare ("postcounter_update", - "UPDATE " - "anastasis_recdoc_payment " - "SET " - "post_counter=$1 " - "WHERE user_id =$2 " - "AND payment_identifier=$3;", - 3), - GNUNET_PQ_make_prepare ("key_share_select", - "SELECT " - "key_share_data " - "FROM " - "anastasis_truth " - "WHERE truth_uuid =$1;", - 1), - GNUNET_PQ_make_prepare ("challengecode_insert", - "INSERT INTO anastasis_challengecode " - "(truth_uuid" - ",code" - ",creation_date" - ",expiration_date" - ",retry_counter" - ") VALUES " - "($1, $2, $3, $4, $5);", - 5), - GNUNET_PQ_make_prepare ("challengecode_select", - "SELECT " - " code" - ",satisfied" - " FROM anastasis_challengecode" - " WHERE truth_uuid=$1" - " AND expiration_date > $2" - " AND retry_counter != 0;", - 2), - GNUNET_PQ_make_prepare ("challengecode_set_satisfied", - "UPDATE anastasis_challengecode" - " SET satisfied=TRUE" - " WHERE truth_uuid=$1" - " AND code=$2" - " AND creation_date IN" - " (SELECT creation_date" - " FROM anastasis_challengecode" - " WHERE truth_uuid=$1" - " AND code=$2" - " ORDER BY creation_date DESC" - " LIMIT 1);", - 2), - GNUNET_PQ_make_prepare ("challengecode_test_satisfied", - "SELECT 1 FROM anastasis_challengecode" - " WHERE truth_uuid=$1" - " AND satisfied=TRUE" - " AND code=$2" - " AND creation_date >= $3" - " LIMIT 1;", - 3), - GNUNET_PQ_make_prepare ("challengecode_select_meta", - "SELECT " - " code" - ",retry_counter" - ",retransmission_date" - " FROM anastasis_challengecode" - " WHERE truth_uuid=$1" - " AND expiration_date > $2" - " AND creation_date > $3" - " ORDER BY creation_date DESC" - " LIMIT 1;", - 2), - GNUNET_PQ_make_prepare ("challengecode_update_retry", - "UPDATE anastasis_challengecode" - " SET retry_counter=retry_counter - 1" - " WHERE truth_uuid=$1" - " AND code=$2" - " AND retry_counter != 0;", - 1), - GNUNET_PQ_make_prepare ("challengepayment_dec_counter", - "UPDATE anastasis_challenge_payment" - " SET counter=counter - 1" - " WHERE truth_uuid=$1" - " AND payment_identifier=$2" - " AND counter > 0;", - 2), - GNUNET_PQ_make_prepare ("challengecode_mark_sent", - "UPDATE anastasis_challengecode" - " SET retransmission_date=$3" - " WHERE truth_uuid=$1" - " AND code=$2" - " AND creation_date IN" - " (SELECT creation_date" - " FROM anastasis_challengecode" - " WHERE truth_uuid=$1" - " AND code=$2" - " ORDER BY creation_date DESC" - " LIMIT 1);", - 3), - GNUNET_PQ_make_prepare ("get_last_auth_iban_payment", - "SELECT " - " wire_reference" - " FROM anastasis_auth_iban_in" - " WHERE credit_account_details=$1" - " ORDER BY wire_reference DESC" - " LIMIT 1;", - 1), - GNUNET_PQ_make_prepare ("gc_challengecodes", - "DELETE FROM anastasis_challengecode " - "WHERE " - "expiration_date < $1;", - 1), - GNUNET_PQ_PREPARED_STATEMENT_END + +/** + * Function called to remove all expired codes from the database. + * + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +postgres_challenge_gc (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&time_now), + GNUNET_PQ_query_param_end }; + check_connection (pg); + postgres_preflight (pg); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_challengecodes", + params); +} + + +/** + * Initialize Postgres database subsystem. + * + * @param cls a configuration instance + * @return NULL on error, otherwise a `struct TALER_ANASTASISDB_Plugin` + */ +void * +libanastasis_plugin_db_postgres_init (void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct PostgresClosure *pg; + struct ANASTASIS_DatabasePlugin *plugin; + pg = GNUNET_new (struct PostgresClosure); pg->cfg = cfg; - pg->conn = GNUNET_PQ_connect_with_cfg (cfg, - "stasis-postgres", - "stasis-", - NULL, - ps); - if (NULL == pg->conn) - { - GNUNET_free (pg); - return NULL; - } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "taler", @@ -2673,6 +2709,8 @@ libanastasis_plugin_db_postgres_init (void *cls) } plugin = GNUNET_new (struct ANASTASIS_DatabasePlugin); plugin->cls = pg; + plugin->connect = &postgres_connect; + plugin->create_tables = &postgres_create_tables; plugin->drop_tables = &postgres_drop_tables; plugin->gc = &postgres_gc; plugin->preflight = &postgres_preflight; diff --git a/src/stasis/test_anastasis_db.c b/src/stasis/test_anastasis_db.c index 204307a..1ec9770 100644 --- a/src/stasis/test_anastasis_db.c +++ b/src/stasis/test_anastasis_db.c @@ -92,15 +92,15 @@ run (void *cls) result = 77; return; } - if (GNUNET_OK != plugin->drop_tables (plugin->cls)) + (void) plugin->drop_tables (plugin->cls); + if (GNUNET_OK != + plugin->create_tables (plugin->cls)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Dropping tables failed\n"); result = 77; return; } - ANASTASIS_DB_plugin_unload (plugin); - if (NULL == (plugin = ANASTASIS_DB_plugin_load (cfg))) + if (GNUNET_OK != + plugin->connect (plugin->cls)) { result = 77; return; -- cgit v1.2.3