[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [taler-merchant] branch master updated: fix #5733 by migrat
From: |
gnunet |
Subject: |
[GNUnet-SVN] [taler-merchant] branch master updated: fix #5733 by migrating to new GNUnet PQ API |
Date: |
Fri, 11 Oct 2019 23:36:20 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository merchant.
The following commit(s) were added to refs/heads/master by this push:
new 37bd689 fix #5733 by migrating to new GNUnet PQ API
37bd689 is described below
commit 37bd6899d24b234534926af5e40b112eb4565baa
Author: Christian Grothoff <address@hidden>
AuthorDate: Fri Oct 11 23:35:49 2019 +0200
fix #5733 by migrating to new GNUnet PQ API
---
src/backend/taler-merchant-httpd.c | 8 -
src/backenddb/plugin_merchantdb_postgres.c | 2000 ++++++++++++++--------------
src/backenddb/test_merchantdb.c | 4 +-
src/include/taler_merchantdb_plugin.h | 9 -
src/merchant-tools/taler-merchant-dbinit.c | 10 +-
5 files changed, 987 insertions(+), 1044 deletions(-)
diff --git a/src/backend/taler-merchant-httpd.c
b/src/backend/taler-merchant-httpd.c
index 47c3e34..bc784cd 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -1452,14 +1452,6 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- if (GNUNET_OK !=
- db->initialize (db->cls))
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
{
const char *choices[] = {"tcp",
diff --git a/src/backenddb/plugin_merchantdb_postgres.c
b/src/backenddb/plugin_merchantdb_postgres.c
index fc5e2d1..b2a4df6 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -54,6 +54,8 @@
#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \
amountp)
TALER_PQ_result_spec_amount_nbo ( \
field,pg->currency,amountp)
+
+
/**
* Wrapper macro to add the currency from the plugin's state
* when fetching amounts from the database.
@@ -75,7 +77,7 @@ struct PostgresClosure
/**
* Postgres connection handle.
*/
- PGconn *conn;
+ struct GNUNET_PQ_Context *conn;
/**
* Which currency do we deal in?
@@ -140,698 +142,83 @@ postgres_drop_tables (void *cls)
/**
- * Initialize merchant tables
+ * Check that the database connection is still up.
*
- * @param cls closure our `struct Plugin`
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ * @param pg connection to check
+ */
+static void
+check_connection (struct PostgresClosure *pg)
+{
+ 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
-postgres_initialize (void *cls)
+postgres_start (void *cls,
+ const char *name)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_ExecuteStatement es[] = {
- /* Orders created by the frontend, not signed or given a nonce yet.
- The contract terms will change (nonce will be added) when moved to the
- contract terms table */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_orders ("
- "order_id VARCHAR NOT NULL"
- ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
- ",contract_terms BYTEA NOT NULL"
- ",timestamp INT8 NOT NULL"
- ",PRIMARY KEY (order_id, merchant_pub)"
- ");"),
- /* Offers we made to customers */
- GNUNET_PQ_make_execute (
- "CREATE TABLE IF NOT EXISTS merchant_contract_terms ("
- "order_id VARCHAR NOT NULL"
- ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
- ",contract_terms BYTEA NOT NULL"
- ",h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)"
- ",timestamp INT8 NOT NULL"
- ",row_id BIGSERIAL UNIQUE"
- ",paid boolean DEFAULT FALSE NOT NULL"
- ",PRIMARY KEY (order_id, merchant_pub)"
- ",UNIQUE (h_contract_terms, merchant_pub)"
- ");"),
- /* Table with the proofs for each coin we deposited at the exchange */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_deposits ("
- " h_contract_terms BYTEA NOT NULL"
- ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
- ",coin_pub BYTEA NOT NULL CHECK
(LENGTH(coin_pub)=32)"
- ",exchange_url VARCHAR NOT NULL"
- ",amount_with_fee_val INT8 NOT NULL"
- ",amount_with_fee_frac INT4 NOT NULL"
- ",deposit_fee_val INT8 NOT NULL"
- ",deposit_fee_frac INT4 NOT NULL"
- ",refund_fee_val INT8 NOT NULL"
- ",refund_fee_frac INT4 NOT NULL"
- ",wire_fee_val INT8 NOT NULL"
- ",wire_fee_frac INT4 NOT NULL"
- ",signkey_pub BYTEA NOT NULL CHECK
(LENGTH(signkey_pub)=32)"
- ",exchange_proof BYTEA NOT NULL"
- ",PRIMARY KEY (h_contract_terms, coin_pub)"
- ",FOREIGN KEY (h_contract_terms, merchant_pub)
REFERENCES merchant_contract_terms (h_contract_terms, merchant_pub)"
- ");"),
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_proofs ("
- " exchange_url VARCHAR NOT NULL"
- ",wtid BYTEA CHECK (LENGTH(wtid)=32)"
- ",execution_time INT8 NOT NULL"
- ",signkey_pub BYTEA NOT NULL CHECK
(LENGTH(signkey_pub)=32)"
- ",proof BYTEA NOT NULL"
- ",PRIMARY KEY (wtid, exchange_url)"
- ");"),
- /* Note that h_contract_terms + coin_pub may actually be unknown to
- us, e.g. someone else deposits something for us at the exchange.
- Hence those cannot be foreign keys into deposits/transactions! */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_transfers ("
- " h_contract_terms BYTEA NOT NULL"
- ",coin_pub BYTEA NOT NULL CHECK
(LENGTH(coin_pub)=32)"
- ",wtid BYTEA NOT NULL CHECK (LENGTH(wtid)=32)"
- ",PRIMARY KEY (h_contract_terms, coin_pub)"
- ");"),
- GNUNET_PQ_make_try_execute (
- "CREATE INDEX IF NOT EXISTS merchant_transfers_by_coin"
- " ON merchant_transfers (h_contract_terms, coin_pub)"),
- GNUNET_PQ_make_try_execute (
- "CREATE INDEX IF NOT EXISTS merchant_transfers_by_wtid"
- " ON merchant_transfers (wtid)"),
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS exchange_wire_fees ("
- " exchange_pub BYTEA NOT NULL CHECK
(length(exchange_pub)=32)"
- ",h_wire_method BYTEA NOT NULL CHECK
(length(h_wire_method)=64)"
- ",wire_fee_val INT8 NOT NULL"
- ",wire_fee_frac INT4 NOT NULL"
- ",closing_fee_val INT8 NOT NULL"
- ",closing_fee_frac INT4 NOT NULL"
- ",start_date INT8 NOT NULL"
- ",end_date INT8 NOT NULL"
- ",exchange_sig BYTEA NOT NULL CHECK
(length(exchange_sig)=64)"
- ",PRIMARY KEY
(exchange_pub,h_wire_method,start_date,end_date)"
- ");"),
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_refunds ("
- " rtransaction_id BIGSERIAL UNIQUE"
- ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
- ",h_contract_terms BYTEA NOT NULL"
- ",coin_pub BYTEA NOT NULL CHECK
(LENGTH(coin_pub)=32)"
- ",reason VARCHAR NOT NULL"
- ",refund_amount_val INT8 NOT NULL"
- ",refund_amount_frac INT4 NOT NULL"
- ",refund_fee_val INT8 NOT NULL"
- ",refund_fee_frac INT4 NOT NULL"
- ");"),
- /* balances of the reserves available for tips */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tip_reserves
("
- " reserve_priv BYTEA NOT NULL CHECK
(LENGTH(reserve_priv)=32)"
- ",expiration INT8 NOT NULL"
- ",balance_val INT8 NOT NULL"
- ",balance_frac INT4 NOT NULL"
- ",PRIMARY KEY (reserve_priv)"
- ");"),
- /* table where we remember when tipping reserves where established /
enabled */
- GNUNET_PQ_make_execute (
- "CREATE TABLE IF NOT EXISTS merchant_tip_reserve_credits ("
- " reserve_priv BYTEA NOT NULL CHECK (LENGTH(reserve_priv)=32)"
- ",credit_uuid BYTEA UNIQUE NOT NULL CHECK (LENGTH(credit_uuid)=64)"
- ",timestamp INT8 NOT NULL"
- ",amount_val INT8 NOT NULL"
- ",amount_frac INT4 NOT NULL"
- ",PRIMARY KEY (credit_uuid)"
- ");"),
- /* tips that have been authorized */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tips ("
- " reserve_priv BYTEA NOT NULL CHECK
(LENGTH(reserve_priv)=32)"
- ",tip_id BYTEA NOT NULL CHECK (LENGTH(tip_id)=64)"
- ",exchange_url VARCHAR NOT NULL"
- ",justification VARCHAR NOT NULL"
- ",extra BYTEA NOT NULL"
- ",timestamp INT8 NOT NULL"
- ",amount_val INT8 NOT NULL" /* overall tip amount
*/
- ",amount_frac INT4 NOT NULL"
- ",left_val INT8 NOT NULL" /* tip amount not yet
picked up */
- ",left_frac INT4 NOT NULL"
- ",PRIMARY KEY (tip_id)"
- ");"),
- /* tips that have been picked up */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tip_pickups ("
- " tip_id BYTEA NOT NULL REFERENCES merchant_tips
(tip_id) ON DELETE CASCADE"
- ",pickup_id BYTEA NOT NULL CHECK
(LENGTH(pickup_id)=64)"
- ",amount_val INT8 NOT NULL"
- ",amount_frac INT4 NOT NULL"
- ",PRIMARY KEY (pickup_id)"
- ");"),
- /* sessions and their order_id/fulfillment_url mapping */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_session_info
("
- " session_id VARCHAR NOT NULL"
- ",fulfillment_url VARCHAR NOT NULL"
- ",order_id VARCHAR NOT NULL"
- ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
- ",timestamp INT8 NOT NULL"
- ",PRIMARY KEY (session_id, fulfillment_url,
merchant_pub)"
- ",UNIQUE (session_id, fulfillment_url, order_id,
merchant_pub)"
- ");"),
+ GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};
- struct GNUNET_PQ_PreparedStatement ps[] = {
- GNUNET_PQ_make_prepare ("insert_deposit",
- "INSERT INTO merchant_deposits"
- "(h_contract_terms"
- ",merchant_pub"
- ",coin_pub"
- ",exchange_url"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",signkey_pub"
- ",exchange_proof) VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
$12, $13, $14)",
- 14),
- GNUNET_PQ_make_prepare ("insert_transfer",
- "INSERT INTO merchant_transfers"
- "(h_contract_terms"
- ",coin_pub"
- ",wtid) VALUES "
- "($1, $2, $3)",
- 3),
- GNUNET_PQ_make_prepare ("insert_refund",
- "INSERT INTO merchant_refunds"
- "(merchant_pub"
- ",h_contract_terms"
- ",coin_pub"
- ",reason"
- ",refund_amount_val"
- ",refund_amount_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ") VALUES"
- "($1, $2, $3, $4, $5, $6, $7, $8)",
- 8),
- GNUNET_PQ_make_prepare ("insert_proof",
- "INSERT INTO merchant_proofs"
- "(exchange_url"
- ",wtid"
- ",execution_time"
- ",signkey_pub"
- ",proof) VALUES "
- "($1, $2, $3, $4, $5)",
- 5),
- GNUNET_PQ_make_prepare ("insert_contract_terms",
- "INSERT INTO merchant_contract_terms"
- "(order_id"
- ",merchant_pub"
- ",timestamp"
- ",contract_terms"
- ",h_contract_terms)"
- " VALUES "
- "($1, $2, $3, $4, $5)",
- 5),
- GNUNET_PQ_make_prepare ("insert_order",
- "INSERT INTO merchant_orders"
- "(order_id"
- ",merchant_pub"
- ",timestamp"
- ",contract_terms)"
- " VALUES "
- "($1, $2, $3, $4)",
- 4),
- GNUNET_PQ_make_prepare ("insert_session_info",
- "INSERT INTO merchant_session_info"
- "(session_id"
- ",fulfillment_url"
- ",order_id"
- ",merchant_pub"
- ",timestamp)"
- " VALUES "
- "($1, $2, $3, $4, $5)",
- 5),
- GNUNET_PQ_make_prepare ("mark_proposal_paid",
- "UPDATE merchant_contract_terms SET"
- " paid=TRUE"
- " WHERE h_contract_terms=$1"
- " AND merchant_pub=$2",
- 2),
- GNUNET_PQ_make_prepare ("insert_wire_fee",
- "INSERT INTO exchange_wire_fees"
- "(exchange_pub"
- ",h_wire_method"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",start_date"
- ",end_date"
- ",exchange_sig)"
- " VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9)",
- 9),
- GNUNET_PQ_make_prepare ("lookup_wire_fee",
- "SELECT"
- " wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",start_date"
- ",end_date"
- ",exchange_sig"
- " FROM exchange_wire_fees"
- " WHERE exchange_pub=$1"
- " AND h_wire_method=$2"
- " AND start_date <= $3"
- " AND end_date > $3",
- 1),
- GNUNET_PQ_make_prepare ("find_contract_terms_from_hash",
- "SELECT"
- " contract_terms"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$1"
- " AND merchant_pub=$2",
- 2),
- GNUNET_PQ_make_prepare ("find_paid_contract_terms_from_hash",
- "SELECT"
- " contract_terms"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$1"
- " AND merchant_pub=$2"
- " AND paid=TRUE",
- 2),
- GNUNET_PQ_make_prepare ("end_transaction",
- "COMMIT",
- 0),
-
- GNUNET_PQ_make_prepare ("find_refunds",
- "SELECT"
- " refund_amount_val"
- ",refund_amount_frac"
- " FROM merchant_refunds"
- " WHERE coin_pub=$1",
- 1),
- GNUNET_PQ_make_prepare ("find_contract_terms_history",
- "SELECT"
- " contract_terms"
- " FROM merchant_contract_terms"
- " WHERE"
- " order_id=$1"
- " AND merchant_pub=$2"
- " AND paid=TRUE",
- 2),
- GNUNET_PQ_make_prepare ("find_contract_terms",
- "SELECT"
- " contract_terms"
- " FROM merchant_contract_terms"
- " WHERE"
- " order_id=$1"
- " AND merchant_pub=$2",
- 2),
- GNUNET_PQ_make_prepare ("find_order",
- "SELECT"
- " contract_terms"
- " FROM merchant_orders"
- " WHERE"
- " order_id=$1"
- " AND merchant_pub=$2",
- 2),
- GNUNET_PQ_make_prepare ("find_session_info",
- "SELECT"
- " order_id"
- " FROM merchant_session_info"
- " WHERE"
- " fulfillment_url=$1"
- " AND session_id=$2"
- " AND merchant_pub=$3",
- 2),
- GNUNET_PQ_make_prepare ("find_contract_terms_by_date",
- "SELECT"
- " contract_terms"
- ",order_id"
- ",row_id"
- " FROM merchant_contract_terms"
- " WHERE"
- " timestamp<$1"
- " AND merchant_pub=$2"
- " AND paid=TRUE"
- " ORDER BY row_id DESC, timestamp DESC"
- " LIMIT $3",
- 3),
- GNUNET_PQ_make_prepare ("find_refunds_from_contract_terms_hash",
- "SELECT"
- " coin_pub"
- ",rtransaction_id"
- ",refund_amount_val"
- ",refund_amount_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",reason"
- " FROM merchant_refunds"
- " WHERE merchant_pub=$1"
- " AND h_contract_terms=$2",
- 2),
- GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_asc",
- "SELECT"
- " contract_terms"
- ",order_id"
- ",row_id"
- " FROM merchant_contract_terms"
- " WHERE"
- " timestamp>$1"
- " AND merchant_pub=$2"
- " AND row_id>$3"
- " AND paid=TRUE"
- " ORDER BY row_id ASC, timestamp ASC"
- " LIMIT $4",
- 4),
- GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range",
- "SELECT"
- " contract_terms"
- ",order_id"
- ",row_id"
- " FROM merchant_contract_terms"
- " WHERE"
- " timestamp>$1"
- " AND merchant_pub=$2"
- " AND row_id>$3"
- " AND paid=TRUE"
- " ORDER BY row_id DESC, timestamp DESC"
- " LIMIT $4",
- 4),
- GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_past_asc",
- "SELECT"
- " contract_terms"
- ",order_id"
- ",row_id"
- " FROM merchant_contract_terms"
- " WHERE"
- " timestamp<$1"
- " AND merchant_pub=$2"
- " AND row_id<$3"
- " AND paid=TRUE"
- " ORDER BY row_id ASC, timestamp ASC"
- " LIMIT $4",
- 4),
- GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_past",
- "SELECT"
- " contract_terms"
- ",order_id"
- ",row_id"
- " FROM merchant_contract_terms"
- " WHERE"
- " timestamp<$1"
- " AND merchant_pub=$2"
- " AND row_id<$3"
- " AND paid=TRUE"
- " ORDER BY row_id DESC, timestamp DESC"
- " LIMIT $4",
- 4),
- GNUNET_PQ_make_prepare ("find_deposits",
- "SELECT"
- " coin_pub"
- ",exchange_url"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",exchange_proof"
- " FROM merchant_deposits"
- " WHERE h_contract_terms=$1"
- " AND merchant_pub=$2",
- 2),
- GNUNET_PQ_make_prepare ("find_deposits_by_hash_and_coin",
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",exchange_url"
- ",exchange_proof"
- " FROM merchant_deposits"
- " WHERE h_contract_terms=$1"
- " AND merchant_pub=$2"
- " AND coin_pub=$3",
- 3),
- GNUNET_PQ_make_prepare ("find_transfers_by_hash",
- "SELECT"
- " coin_pub"
- ",wtid"
- ",merchant_proofs.execution_time"
- ",merchant_proofs.proof"
- " FROM merchant_transfers"
- " JOIN merchant_proofs USING (wtid)"
- " WHERE h_contract_terms=$1",
- 1),
- GNUNET_PQ_make_prepare ("find_deposits_by_wtid",
- "SELECT"
- " merchant_transfers.h_contract_terms"
- ",merchant_transfers.coin_pub"
- ",merchant_deposits.amount_with_fee_val"
- ",merchant_deposits.amount_with_fee_frac"
- ",merchant_deposits.deposit_fee_val"
- ",merchant_deposits.deposit_fee_frac"
- ",merchant_deposits.refund_fee_val"
- ",merchant_deposits.refund_fee_frac"
- ",merchant_deposits.wire_fee_val"
- ",merchant_deposits.wire_fee_frac"
- ",merchant_deposits.exchange_url"
- ",merchant_deposits.exchange_proof"
- " FROM merchant_transfers"
- " JOIN merchant_deposits"
- " ON (merchant_deposits.h_contract_terms =
merchant_transfers.h_contract_terms"
- " AND"
- " merchant_deposits.coin_pub =
merchant_transfers.coin_pub)"
- " WHERE wtid=$1",
- 1),
- GNUNET_PQ_make_prepare ("find_proof_by_wtid",
- "SELECT"
- " proof"
- " FROM merchant_proofs"
- " WHERE wtid=$1"
- " AND exchange_url=$2",
- 2),
- GNUNET_PQ_make_prepare ("lookup_tip_reserve_balance",
- "SELECT"
- " expiration"
- ",balance_val"
- ",balance_frac"
- " FROM merchant_tip_reserves"
- " WHERE reserve_priv=$1",
- 1),
- GNUNET_PQ_make_prepare ("find_tip_authorizations",
- "SELECT"
- " amount_val"
- ",amount_frac"
- ",justification"
- ",extra"
- ",tip_id"
- " FROM merchant_tips"
- " WHERE reserve_priv=$1",
- 1),
- GNUNET_PQ_make_prepare ("update_tip_reserve_balance",
- "UPDATE merchant_tip_reserves SET"
- " expiration=$2"
- ",balance_val=$3"
- ",balance_frac=$4"
- " WHERE reserve_priv=$1",
- 4),
- GNUNET_PQ_make_prepare ("insert_tip_reserve_balance",
- "INSERT INTO merchant_tip_reserves"
- "(reserve_priv"
- ",expiration"
- ",balance_val"
- ",balance_frac"
- ") VALUES "
- "($1, $2, $3, $4)",
- 4),
- GNUNET_PQ_make_prepare ("insert_tip_justification",
- "INSERT INTO merchant_tips"
- "(reserve_priv"
- ",tip_id"
- ",exchange_url"
- ",justification"
- ",extra"
- ",timestamp"
- ",amount_val"
- ",amount_frac"
- ",left_val"
- ",left_frac"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
- 10),
- GNUNET_PQ_make_prepare ("lookup_reserve_by_tip_id",
- "SELECT"
- " reserve_priv"
- ",left_val"
- ",left_frac"
- " FROM merchant_tips"
- " WHERE tip_id=$1",
- 1),
- GNUNET_PQ_make_prepare ("lookup_amount_by_pickup",
- "SELECT"
- " amount_val"
- ",amount_frac"
- " FROM merchant_tip_pickups"
- " WHERE pickup_id=$1"
- " AND tip_id=$2",
- 2),
- GNUNET_PQ_make_prepare ("find_tip_by_id",
- "SELECT"
- " exchange_url"
- ",extra"
- ",timestamp"
- ",amount_val"
- ",amount_frac"
- ",left_val"
- ",left_frac"
- " FROM merchant_tips"
- " WHERE tip_id=$1",
- 1),
- GNUNET_PQ_make_prepare ("update_tip_balance",
- "UPDATE merchant_tips SET"
- " left_val=$2"
- ",left_frac=$3"
- " WHERE tip_id=$1",
- 3),
- GNUNET_PQ_make_prepare ("insert_pickup_id",
- "INSERT INTO merchant_tip_pickups"
- "(tip_id"
- ",pickup_id"
- ",amount_val"
- ",amount_frac"
- ") VALUES "
- "($1, $2, $3, $4)",
- 4),
- GNUNET_PQ_make_prepare ("insert_tip_credit_uuid",
- "INSERT INTO merchant_tip_reserve_credits"
- "(reserve_priv"
- ",credit_uuid"
- ",timestamp"
- ",amount_val"
- ",amount_frac"
- ") VALUES "
- "($1, $2, $3, $4, $5)",
- 5),
- GNUNET_PQ_make_prepare ("lookup_tip_credit_uuid",
- "SELECT 1 "
- "FROM merchant_tip_reserve_credits "
- "WHERE credit_uuid=$1 AND reserve_priv=$2",
- 2),
- GNUNET_PQ_PREPARED_STATEMENT_END
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_exec_statements (pg->conn,
- es))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_PQ_prepare_statements (pg->conn,
- ps))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Check that the database connection is still up.
- *
- * @param pg connection to check
- */
-static void
-check_connection (struct PostgresClosure *pg)
-{
- if (CONNECTION_BAD != PQstatus (pg->conn))
- return;
- PQfinish (pg->conn);
- pg->conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
- "merchantdb-postgres");
- GNUNET_break (NULL != pg->conn);
- GNUNET_break (GNUNET_OK ==
- postgres_initialize (pg));
-}
-
-
-/**
- * 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;
- PGresult *result;
- ExecStatusType status;
-
- if (NULL == pg->transaction_name)
- return; /* all good */
- result = PQexec (pg->conn,
- "COMMIT");
- status = PQresultStatus (result);
- if (PGRES_COMMAND_OK == status)
- {
- 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;
- PQclear (result);
-}
-
-
-/**
- * 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
-postgres_start (void *cls,
- const char *name)
-{
- struct PostgresClosure *pg = cls;
- PGresult *result;
- ExecStatusType ex;
check_connection (pg);
postgres_preflight (pg);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Starting merchant DB transaction\n");
- result = PQexec (pg->conn,
- "START TRANSACTION ISOLATION LEVEL SERIALIZABLE");
- if (PGRES_COMMAND_OK !=
- (ex = PQresultStatus (result)))
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_statements (pg->conn,
+ es))
{
- TALER_LOG_ERROR ("Failed to start transaction (%s): %s\n",
- PQresStatus (ex),
- PQerrorMessage (pg->conn));
+ TALER_LOG_ERROR ("Failed to start transaction\n");
GNUNET_break (0);
- PQclear (result);
return GNUNET_SYSERR;
}
- PQclear (result);
pg->transaction_name = name;
return GNUNET_OK;
}
@@ -847,15 +234,16 @@ static void
postgres_rollback (void *cls)
{
struct PostgresClosure *pg = cls;
- PGresult *result;
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute ("ROLLBACK"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Rolling back merchant DB transaction\n");
- result = PQexec (pg->conn,
- "ROLLBACK");
- GNUNET_break (PGRES_COMMAND_OK ==
- PQresultStatus (result));
- PQclear (result);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_PQ_exec_statements (pg->conn,
+ es));
pg->transaction_name = NULL;
}
@@ -3282,393 +2670,969 @@ postgres_authorize_tip_TR (void *cls,
struct GNUNET_TIME_Absolute old_expiration;
struct TALER_Amount old_balance;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_absolute_time ("expiration",
- &old_expiration),
- TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
- &old_balance),
+ GNUNET_PQ_result_spec_absolute_time ("expiration",
+ &old_expiration),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
+ &old_balance),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_Amount new_balance;
+ unsigned int retries;
+
+ retries = 0;
+ check_connection (pg);
+RETRY:
+ if (MAX_RETRIES < ++retries)
+ return TALER_EC_TIP_AUTHORIZE_DB_SOFT_ERROR;
+ if (GNUNET_OK !=
+ postgres_start (pg,
+ "authorize tip"))
+ {
+ GNUNET_break (0);
+ return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ }
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_tip_reserve_balance",
+ params,
+ rs);
+ if (0 >= qs)
+ {
+ /* reserve unknown */
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ return TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS;
+ return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ }
+ if (0 == GNUNET_TIME_absolute_get_remaining (old_expiration).rel_value_us)
+ {
+ /* reserve expired, can't be used */
+ postgres_rollback (pg);
+ return TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED;
+ }
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&new_balance,
+ &old_balance,
+ amount))
+ {
+ /* insufficient funds left in reserve */
+ postgres_rollback (pg);
+ return TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS;
+ }
+ /* Update reserve balance */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_priv),
+ GNUNET_PQ_query_param_absolute_time (&old_expiration),
+ TALER_PQ_query_param_amount (&new_balance),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_tip_reserve_balance",
+ params);
+ if (0 > qs)
+ {
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ }
+ }
+ /* Generate and store tip ID */
+ *expiration = old_expiration;
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG,
+ tip_id);
+ {
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_priv),
+ GNUNET_PQ_query_param_auto_from_type (tip_id),
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_string (justification),
+ TALER_PQ_query_param_json (extra),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ TALER_PQ_query_param_amount (amount), /* overall amount */
+ TALER_PQ_query_param_amount (amount), /* amount left */
+ GNUNET_PQ_query_param_end
+ };
+
+ (void) GNUNET_TIME_round_abs (&now);
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_tip_justification",
+ params);
+ if (0 > qs)
+ {
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ }
+ }
+ qs = postgres_commit (pg);
+ if (0 <= qs)
+ return TALER_EC_NONE; /* success! */
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+}
+
+
+/**
+ * Find out tip authorization details associated with @a tip_id
+ *
+ * @param cls closure, typically a connection to the d
+ * @param tip_id the unique ID for the tip
+ * @param[out] exchange_url set to the URL of the exchange (unless NULL)
+ * @param[out] extra extra data to pass to the wallet (unless NULL)
+ * @param[out] amount set to the authorized amount (unless NULL)
+ * @param[out] amount_left set to the amount left (unless NULL)
+ * @param[out] timestamp set to the timestamp of the tip authorization (unless
NULL)
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_tip_by_id (void *cls,
+ const struct GNUNET_HashCode *tip_id,
+ char **exchange_url,
+ json_t **extra,
+ struct TALER_Amount *amount,
+ struct TALER_Amount *amount_left,
+ struct GNUNET_TIME_Absolute *timestamp)
+{
+ struct PostgresClosure *pg = cls;
+ char *res_exchange_url;
+ json_t *res_extra;
+ struct TALER_Amount res_amount;
+ struct TALER_Amount res_amount_left;
+ struct GNUNET_TIME_Absolute res_timestamp;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (tip_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &res_exchange_url),
+ GNUNET_PQ_result_spec_absolute_time ("timestamp",
+ &res_timestamp),
+ TALER_PQ_result_spec_json ("extra",
+ &res_extra),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+ &res_amount),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("left",
+ &res_amount_left),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "find_tip_by_id",
+ params,
+ rs);
+ if (0 >= qs)
+ {
+ if (NULL != exchange_url)
+ *exchange_url = NULL;
+ return qs;
+ }
+ if (NULL != exchange_url)
+ *exchange_url = strdup (res_exchange_url);
+ if (NULL != amount)
+ *amount = res_amount;
+ if (NULL != amount_left)
+ *amount_left = res_amount_left;
+ if (NULL != timestamp)
+ *timestamp = res_timestamp;
+ if (NULL != extra)
+ {
+ json_incref (res_extra);
+ *extra = res_extra;
+ }
+ GNUNET_PQ_cleanup_result (rs);
+ return qs;
+}
+
+
+/**
+ * Pickup a tip over @a amount using pickup id @a pickup_id.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param amount how high is the amount picked up (with fees)
+ * @param tip_id the unique ID from the tip authorization
+ * @param pickup_id the unique ID identifying the pick up operation
+ * (to allow replays, hash over the coin envelope and denomination key)
+ * @param[out] reserve_priv which reserve key to use to sign
+ * @return taler error code
+ * #TALER_EC_TIP_PICKUP_ID_UNKNOWN if @a tip_id is unknown
+ * #TALER_EC_TIP_PICKUP_NO_FUNDS if @a tip_id has insufficient funds left
+ * #TALER_EC_TIP_PICKUP_DB_ERROR_HARD on hard database errors
+ * #TALER_EC_TIP_PICKUP_AMOUNT_CHANGED if @a amount is different for
known @a pickup_id
+ * #TALER_EC_TIP_PICKUP_DB_ERROR_SOFT on soft database errors (client
should retry)
+ * #TALER_EC_NONE upon success (@a reserve_priv was set)
+ */
+static enum TALER_ErrorCode
+postgres_pickup_tip_TR (void *cls,
+ const struct TALER_Amount *amount,
+ const struct GNUNET_HashCode *tip_id,
+ const struct GNUNET_HashCode *pickup_id,
+ struct TALER_ReservePrivateKeyP *reserve_priv)
+{
+ struct PostgresClosure *pg = cls;
+ struct TALER_Amount left_amount;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (tip_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_priv",
+ reserve_priv),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("left",
+ &left_amount),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;
- struct TALER_Amount new_balance;
unsigned int retries;
retries = 0;
check_connection (pg);
RETRY:
if (MAX_RETRIES < ++retries)
- return TALER_EC_TIP_AUTHORIZE_DB_SOFT_ERROR;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_SOFT;
if (GNUNET_OK !=
postgres_start (pg,
- "authorize tip"))
+ "pickup tip"))
{
GNUNET_break (0);
- return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
}
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_tip_reserve_balance",
+ "lookup_reserve_by_tip_id",
params,
rs);
if (0 >= qs)
{
- /* reserve unknown */
+ /* tip ID unknown */
+ memset (reserve_priv,
+ 0,
+ sizeof (*reserve_priv));
postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ return TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN;
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
goto RETRY;
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS;
- return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
- }
- if (0 == GNUNET_TIME_absolute_get_remaining (old_expiration).rel_value_us)
- {
- /* reserve expired, can't be used */
- postgres_rollback (pg);
- return TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED;
- }
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (&new_balance,
- &old_balance,
- amount))
- {
- /* insufficient funds left in reserve */
- postgres_rollback (pg);
- return TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
}
- /* Update reserve balance */
+
+ /* Check if pickup_id already exists */
{
+ struct TALER_Amount existing_amount;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_priv),
- GNUNET_PQ_query_param_absolute_time (&old_expiration),
- TALER_PQ_query_param_amount (&new_balance),
+ GNUNET_PQ_query_param_auto_from_type (pickup_id),
+ GNUNET_PQ_query_param_auto_from_type (tip_id),
GNUNET_PQ_query_param_end
};
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+ &existing_amount),
+ GNUNET_PQ_result_spec_end
+ };
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_tip_reserve_balance",
- params);
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_amount_by_pickup",
+ params,
+ rs);
if (0 > qs)
{
+ /* DB error */
+ memset (reserve_priv,
+ 0,
+ sizeof (*reserve_priv));
postgres_rollback (pg);
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
goto RETRY;
- return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ if (0 !=
+ TALER_amount_cmp (&existing_amount,
+ amount))
+ {
+ GNUNET_break_op (0);
+ postgres_rollback (pg);
+ return TALER_EC_TIP_PICKUP_AMOUNT_CHANGED;
+ }
+ postgres_commit (pg);
+ return TALER_EC_NONE; /* we are done! */
}
}
- /* Generate and store tip ID */
- *expiration = old_expiration;
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG,
- tip_id);
+
+ /* Calculate new balance */
{
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_priv),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_string (justification),
- TALER_PQ_query_param_json (extra),
- GNUNET_PQ_query_param_absolute_time (&now),
- TALER_PQ_query_param_amount (amount), /* overall amount */
- TALER_PQ_query_param_amount (amount), /* amount left */
- GNUNET_PQ_query_param_end
- };
+ struct TALER_Amount new_left;
- (void) GNUNET_TIME_round_abs (&now);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_tip_justification",
- params);
- if (0 > qs)
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&new_left,
+ &left_amount,
+ amount))
{
+ /* attempt to take more tips than the tipping amount */
+ GNUNET_break_op (0);
+ memset (reserve_priv,
+ 0,
+ sizeof (*reserve_priv));
postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ return TALER_EC_TIP_PICKUP_NO_FUNDS;
+ }
+
+ /* Update DB: update balance */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (tip_id),
+ TALER_PQ_query_param_amount (&new_left),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_tip_balance",
+ params);
+ if (0 > qs)
+ {
+ postgres_rollback (pg);
+ memset (reserve_priv,
+ 0,
+ sizeof (*reserve_priv));
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
+ }
+ }
+
+ /* Update DB: remember pickup_id */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (tip_id),
+ GNUNET_PQ_query_param_auto_from_type (pickup_id),
+ TALER_PQ_query_param_amount (amount),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_pickup_id",
+ params);
+ if (0 > qs)
+ {
+ postgres_rollback (pg);
+ memset (reserve_priv,
+ 0,
+ sizeof (*reserve_priv));
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
+ }
}
}
qs = postgres_commit (pg);
if (0 <= qs)
- return TALER_EC_NONE; /* success! */
+ return TALER_EC_NONE; /* success */
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
goto RETRY;
- return TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR;
+ return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
}
/**
- * Find out tip authorization details associated with @a tip_id
+ * Initialize Postgres database subsystem.
*
- * @param cls closure, typically a connection to the d
- * @param tip_id the unique ID for the tip
- * @param[out] exchange_url set to the URL of the exchange (unless NULL)
- * @param[out] extra extra data to pass to the wallet (unless NULL)
- * @param[out] amount set to the authorized amount (unless NULL)
- * @param[out] amount_left set to the amount left (unless NULL)
- * @param[out] timestamp set to the timestamp of the tip authorization (unless
NULL)
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
+ * @param cls a configuration instance
+ * @return NULL on error, otherwise a `struct TALER_MERCHANTDB_Plugin`
*/
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_tip_by_id (void *cls,
- const struct GNUNET_HashCode *tip_id,
- char **exchange_url,
- json_t **extra,
- struct TALER_Amount *amount,
- struct TALER_Amount *amount_left,
- struct GNUNET_TIME_Absolute *timestamp)
+void *
+libtaler_plugin_merchantdb_postgres_init (void *cls)
{
- struct PostgresClosure *pg = cls;
- char *res_exchange_url;
- json_t *res_extra;
- struct TALER_Amount res_amount;
- struct TALER_Amount res_amount_left;
- struct GNUNET_TIME_Absolute res_timestamp;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("exchange_url",
- &res_exchange_url),
- GNUNET_PQ_result_spec_absolute_time ("timestamp",
- &res_timestamp),
- TALER_PQ_result_spec_json ("extra",
- &res_extra),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &res_amount),
- TALER_PQ_RESULT_SPEC_AMOUNT ("left",
- &res_amount_left),
- GNUNET_PQ_result_spec_end
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct PostgresClosure *pg;
+ struct TALER_MERCHANTDB_Plugin *plugin;
+ const char *ec;
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ /* Orders created by the frontend, not signed or given a nonce yet.
+ The contract terms will change (nonce will be added) when moved to the
+ contract terms table */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_orders ("
+ "order_id VARCHAR NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
+ ",contract_terms BYTEA NOT NULL"
+ ",timestamp INT8 NOT NULL"
+ ",PRIMARY KEY (order_id, merchant_pub)"
+ ");"),
+ /* Offers we made to customers */
+ GNUNET_PQ_make_execute (
+ "CREATE TABLE IF NOT EXISTS merchant_contract_terms ("
+ "order_id VARCHAR NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
+ ",contract_terms BYTEA NOT NULL"
+ ",h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)"
+ ",timestamp INT8 NOT NULL"
+ ",row_id BIGSERIAL UNIQUE"
+ ",paid boolean DEFAULT FALSE NOT NULL"
+ ",PRIMARY KEY (order_id, merchant_pub)"
+ ",UNIQUE (h_contract_terms, merchant_pub)"
+ ");"),
+ /* Table with the proofs for each coin we deposited at the exchange */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_deposits ("
+ " h_contract_terms BYTEA NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
+ ",coin_pub BYTEA NOT NULL CHECK
(LENGTH(coin_pub)=32)"
+ ",exchange_url VARCHAR NOT NULL"
+ ",amount_with_fee_val INT8 NOT NULL"
+ ",amount_with_fee_frac INT4 NOT NULL"
+ ",deposit_fee_val INT8 NOT NULL"
+ ",deposit_fee_frac INT4 NOT NULL"
+ ",refund_fee_val INT8 NOT NULL"
+ ",refund_fee_frac INT4 NOT NULL"
+ ",wire_fee_val INT8 NOT NULL"
+ ",wire_fee_frac INT4 NOT NULL"
+ ",signkey_pub BYTEA NOT NULL CHECK
(LENGTH(signkey_pub)=32)"
+ ",exchange_proof BYTEA NOT NULL"
+ ",PRIMARY KEY (h_contract_terms, coin_pub)"
+ ",FOREIGN KEY (h_contract_terms, merchant_pub)
REFERENCES merchant_contract_terms (h_contract_terms, merchant_pub)"
+ ");"),
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_proofs ("
+ " exchange_url VARCHAR NOT NULL"
+ ",wtid BYTEA CHECK (LENGTH(wtid)=32)"
+ ",execution_time INT8 NOT NULL"
+ ",signkey_pub BYTEA NOT NULL CHECK
(LENGTH(signkey_pub)=32)"
+ ",proof BYTEA NOT NULL"
+ ",PRIMARY KEY (wtid, exchange_url)"
+ ");"),
+ /* Note that h_contract_terms + coin_pub may actually be unknown to
+ us, e.g. someone else deposits something for us at the exchange.
+ Hence those cannot be foreign keys into deposits/transactions! */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_transfers ("
+ " h_contract_terms BYTEA NOT NULL"
+ ",coin_pub BYTEA NOT NULL CHECK
(LENGTH(coin_pub)=32)"
+ ",wtid BYTEA NOT NULL CHECK (LENGTH(wtid)=32)"
+ ",PRIMARY KEY (h_contract_terms, coin_pub)"
+ ");"),
+ GNUNET_PQ_make_try_execute (
+ "CREATE INDEX IF NOT EXISTS merchant_transfers_by_coin"
+ " ON merchant_transfers (h_contract_terms, coin_pub)"),
+ GNUNET_PQ_make_try_execute (
+ "CREATE INDEX IF NOT EXISTS merchant_transfers_by_wtid"
+ " ON merchant_transfers (wtid)"),
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS exchange_wire_fees ("
+ " exchange_pub BYTEA NOT NULL CHECK
(length(exchange_pub)=32)"
+ ",h_wire_method BYTEA NOT NULL CHECK
(length(h_wire_method)=64)"
+ ",wire_fee_val INT8 NOT NULL"
+ ",wire_fee_frac INT4 NOT NULL"
+ ",closing_fee_val INT8 NOT NULL"
+ ",closing_fee_frac INT4 NOT NULL"
+ ",start_date INT8 NOT NULL"
+ ",end_date INT8 NOT NULL"
+ ",exchange_sig BYTEA NOT NULL CHECK
(length(exchange_sig)=64)"
+ ",PRIMARY KEY
(exchange_pub,h_wire_method,start_date,end_date)"
+ ");"),
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_refunds ("
+ " rtransaction_id BIGSERIAL UNIQUE"
+ ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
+ ",h_contract_terms BYTEA NOT NULL"
+ ",coin_pub BYTEA NOT NULL CHECK
(LENGTH(coin_pub)=32)"
+ ",reason VARCHAR NOT NULL"
+ ",refund_amount_val INT8 NOT NULL"
+ ",refund_amount_frac INT4 NOT NULL"
+ ",refund_fee_val INT8 NOT NULL"
+ ",refund_fee_frac INT4 NOT NULL"
+ ");"),
+ /* balances of the reserves available for tips */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tip_reserves
("
+ " reserve_priv BYTEA NOT NULL CHECK
(LENGTH(reserve_priv)=32)"
+ ",expiration INT8 NOT NULL"
+ ",balance_val INT8 NOT NULL"
+ ",balance_frac INT4 NOT NULL"
+ ",PRIMARY KEY (reserve_priv)"
+ ");"),
+ /* table where we remember when tipping reserves where established /
enabled */
+ GNUNET_PQ_make_execute (
+ "CREATE TABLE IF NOT EXISTS merchant_tip_reserve_credits ("
+ " reserve_priv BYTEA NOT NULL CHECK (LENGTH(reserve_priv)=32)"
+ ",credit_uuid BYTEA UNIQUE NOT NULL CHECK (LENGTH(credit_uuid)=64)"
+ ",timestamp INT8 NOT NULL"
+ ",amount_val INT8 NOT NULL"
+ ",amount_frac INT4 NOT NULL"
+ ",PRIMARY KEY (credit_uuid)"
+ ");"),
+ /* tips that have been authorized */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tips ("
+ " reserve_priv BYTEA NOT NULL CHECK
(LENGTH(reserve_priv)=32)"
+ ",tip_id BYTEA NOT NULL CHECK (LENGTH(tip_id)=64)"
+ ",exchange_url VARCHAR NOT NULL"
+ ",justification VARCHAR NOT NULL"
+ ",extra BYTEA NOT NULL"
+ ",timestamp INT8 NOT NULL"
+ ",amount_val INT8 NOT NULL" /* overall tip amount
*/
+ ",amount_frac INT4 NOT NULL"
+ ",left_val INT8 NOT NULL" /* tip amount not yet
picked up */
+ ",left_frac INT4 NOT NULL"
+ ",PRIMARY KEY (tip_id)"
+ ");"),
+ /* tips that have been picked up */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tip_pickups ("
+ " tip_id BYTEA NOT NULL REFERENCES merchant_tips
(tip_id) ON DELETE CASCADE"
+ ",pickup_id BYTEA NOT NULL CHECK
(LENGTH(pickup_id)=64)"
+ ",amount_val INT8 NOT NULL"
+ ",amount_frac INT4 NOT NULL"
+ ",PRIMARY KEY (pickup_id)"
+ ");"),
+ /* sessions and their order_id/fulfillment_url mapping */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_session_info
("
+ " session_id VARCHAR NOT NULL"
+ ",fulfillment_url VARCHAR NOT NULL"
+ ",order_id VARCHAR NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK
(LENGTH(merchant_pub)=32)"
+ ",timestamp INT8 NOT NULL"
+ ",PRIMARY KEY (session_id, fulfillment_url,
merchant_pub)"
+ ",UNIQUE (session_id, fulfillment_url, order_id,
merchant_pub)"
+ ");"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
};
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "find_tip_by_id",
- params,
- rs);
- if (0 >= qs)
- {
- if (NULL != exchange_url)
- *exchange_url = NULL;
- return qs;
- }
- if (NULL != exchange_url)
- *exchange_url = strdup (res_exchange_url);
- if (NULL != amount)
- *amount = res_amount;
- if (NULL != amount_left)
- *amount_left = res_amount_left;
- if (NULL != timestamp)
- *timestamp = res_timestamp;
- if (NULL != extra)
- {
- json_incref (res_extra);
- *extra = res_extra;
- }
- GNUNET_PQ_cleanup_result (rs);
- return qs;
-}
-
+ struct GNUNET_PQ_PreparedStatement ps[] = {
+ GNUNET_PQ_make_prepare ("insert_deposit",
+ "INSERT INTO merchant_deposits"
+ "(h_contract_terms"
+ ",merchant_pub"
+ ",coin_pub"
+ ",exchange_url"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",refund_fee_val"
+ ",refund_fee_frac"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",signkey_pub"
+ ",exchange_proof) VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
$12, $13, $14)",
+ 14),
+ GNUNET_PQ_make_prepare ("insert_transfer",
+ "INSERT INTO merchant_transfers"
+ "(h_contract_terms"
+ ",coin_pub"
+ ",wtid) VALUES "
+ "($1, $2, $3)",
+ 3),
+ GNUNET_PQ_make_prepare ("insert_refund",
+ "INSERT INTO merchant_refunds"
+ "(merchant_pub"
+ ",h_contract_terms"
+ ",coin_pub"
+ ",reason"
+ ",refund_amount_val"
+ ",refund_amount_frac"
+ ",refund_fee_val"
+ ",refund_fee_frac"
+ ") VALUES"
+ "($1, $2, $3, $4, $5, $6, $7, $8)",
+ 8),
+ GNUNET_PQ_make_prepare ("insert_proof",
+ "INSERT INTO merchant_proofs"
+ "(exchange_url"
+ ",wtid"
+ ",execution_time"
+ ",signkey_pub"
+ ",proof) VALUES "
+ "($1, $2, $3, $4, $5)",
+ 5),
+ GNUNET_PQ_make_prepare ("insert_contract_terms",
+ "INSERT INTO merchant_contract_terms"
+ "(order_id"
+ ",merchant_pub"
+ ",timestamp"
+ ",contract_terms"
+ ",h_contract_terms)"
+ " VALUES "
+ "($1, $2, $3, $4, $5)",
+ 5),
+ GNUNET_PQ_make_prepare ("insert_order",
+ "INSERT INTO merchant_orders"
+ "(order_id"
+ ",merchant_pub"
+ ",timestamp"
+ ",contract_terms)"
+ " VALUES "
+ "($1, $2, $3, $4)",
+ 4),
+ GNUNET_PQ_make_prepare ("insert_session_info",
+ "INSERT INTO merchant_session_info"
+ "(session_id"
+ ",fulfillment_url"
+ ",order_id"
+ ",merchant_pub"
+ ",timestamp)"
+ " VALUES "
+ "($1, $2, $3, $4, $5)",
+ 5),
+ GNUNET_PQ_make_prepare ("mark_proposal_paid",
+ "UPDATE merchant_contract_terms SET"
+ " paid=TRUE"
+ " WHERE h_contract_terms=$1"
+ " AND merchant_pub=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("insert_wire_fee",
+ "INSERT INTO exchange_wire_fees"
+ "(exchange_pub"
+ ",h_wire_method"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",closing_fee_val"
+ ",closing_fee_frac"
+ ",start_date"
+ ",end_date"
+ ",exchange_sig)"
+ " VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9)",
+ 9),
+ GNUNET_PQ_make_prepare ("lookup_wire_fee",
+ "SELECT"
+ " wire_fee_val"
+ ",wire_fee_frac"
+ ",closing_fee_val"
+ ",closing_fee_frac"
+ ",start_date"
+ ",end_date"
+ ",exchange_sig"
+ " FROM exchange_wire_fees"
+ " WHERE exchange_pub=$1"
+ " AND h_wire_method=$2"
+ " AND start_date <= $3"
+ " AND end_date > $3",
+ 1),
+ GNUNET_PQ_make_prepare ("find_contract_terms_from_hash",
+ "SELECT"
+ " contract_terms"
+ " FROM merchant_contract_terms"
+ " WHERE h_contract_terms=$1"
+ " AND merchant_pub=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("find_paid_contract_terms_from_hash",
+ "SELECT"
+ " contract_terms"
+ " FROM merchant_contract_terms"
+ " WHERE h_contract_terms=$1"
+ " AND merchant_pub=$2"
+ " AND paid=TRUE",
+ 2),
+ GNUNET_PQ_make_prepare ("end_transaction",
+ "COMMIT",
+ 0),
-/**
- * Pickup a tip over @a amount using pickup id @a pickup_id.
- *
- * @param cls closure, typically a connection to the db
- * @param amount how high is the amount picked up (with fees)
- * @param tip_id the unique ID from the tip authorization
- * @param pickup_id the unique ID identifying the pick up operation
- * (to allow replays, hash over the coin envelope and denomination key)
- * @param[out] reserve_priv which reserve key to use to sign
- * @return taler error code
- * #TALER_EC_TIP_PICKUP_ID_UNKNOWN if @a tip_id is unknown
- * #TALER_EC_TIP_PICKUP_NO_FUNDS if @a tip_id has insufficient funds left
- * #TALER_EC_TIP_PICKUP_DB_ERROR_HARD on hard database errors
- * #TALER_EC_TIP_PICKUP_AMOUNT_CHANGED if @a amount is different for
known @a pickup_id
- * #TALER_EC_TIP_PICKUP_DB_ERROR_SOFT on soft database errors (client
should retry)
- * #TALER_EC_NONE upon success (@a reserve_priv was set)
- */
-static enum TALER_ErrorCode
-postgres_pickup_tip_TR (void *cls,
- const struct TALER_Amount *amount,
- const struct GNUNET_HashCode *tip_id,
- const struct GNUNET_HashCode *pickup_id,
- struct TALER_ReservePrivateKeyP *reserve_priv)
-{
- struct PostgresClosure *pg = cls;
- struct TALER_Amount left_amount;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("reserve_priv",
- reserve_priv),
- TALER_PQ_RESULT_SPEC_AMOUNT ("left",
- &left_amount),
- GNUNET_PQ_result_spec_end
+ GNUNET_PQ_make_prepare ("find_refunds",
+ "SELECT"
+ " refund_amount_val"
+ ",refund_amount_frac"
+ " FROM merchant_refunds"
+ " WHERE coin_pub=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("find_contract_terms_history",
+ "SELECT"
+ " contract_terms"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " order_id=$1"
+ " AND merchant_pub=$2"
+ " AND paid=TRUE",
+ 2),
+ GNUNET_PQ_make_prepare ("find_contract_terms",
+ "SELECT"
+ " contract_terms"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " order_id=$1"
+ " AND merchant_pub=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("find_order",
+ "SELECT"
+ " contract_terms"
+ " FROM merchant_orders"
+ " WHERE"
+ " order_id=$1"
+ " AND merchant_pub=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("find_session_info",
+ "SELECT"
+ " order_id"
+ " FROM merchant_session_info"
+ " WHERE"
+ " fulfillment_url=$1"
+ " AND session_id=$2"
+ " AND merchant_pub=$3",
+ 2),
+ GNUNET_PQ_make_prepare ("find_contract_terms_by_date",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp<$1"
+ " AND merchant_pub=$2"
+ " AND paid=TRUE"
+ " ORDER BY row_id DESC, timestamp DESC"
+ " LIMIT $3",
+ 3),
+ GNUNET_PQ_make_prepare ("find_refunds_from_contract_terms_hash",
+ "SELECT"
+ " coin_pub"
+ ",rtransaction_id"
+ ",refund_amount_val"
+ ",refund_amount_frac"
+ ",refund_fee_val"
+ ",refund_fee_frac"
+ ",reason"
+ " FROM merchant_refunds"
+ " WHERE merchant_pub=$1"
+ " AND h_contract_terms=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_asc",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp>$1"
+ " AND merchant_pub=$2"
+ " AND row_id>$3"
+ " AND paid=TRUE"
+ " ORDER BY row_id ASC, timestamp ASC"
+ " LIMIT $4",
+ 4),
+ GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp>$1"
+ " AND merchant_pub=$2"
+ " AND row_id>$3"
+ " AND paid=TRUE"
+ " ORDER BY row_id DESC, timestamp DESC"
+ " LIMIT $4",
+ 4),
+ GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_past_asc",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp<$1"
+ " AND merchant_pub=$2"
+ " AND row_id<$3"
+ " AND paid=TRUE"
+ " ORDER BY row_id ASC, timestamp ASC"
+ " LIMIT $4",
+ 4),
+ GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_past",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp<$1"
+ " AND merchant_pub=$2"
+ " AND row_id<$3"
+ " AND paid=TRUE"
+ " ORDER BY row_id DESC, timestamp DESC"
+ " LIMIT $4",
+ 4),
+ GNUNET_PQ_make_prepare ("find_deposits",
+ "SELECT"
+ " coin_pub"
+ ",exchange_url"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",refund_fee_val"
+ ",refund_fee_frac"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",exchange_proof"
+ " FROM merchant_deposits"
+ " WHERE h_contract_terms=$1"
+ " AND merchant_pub=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("find_deposits_by_hash_and_coin",
+ "SELECT"
+ " amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",refund_fee_val"
+ ",refund_fee_frac"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",exchange_url"
+ ",exchange_proof"
+ " FROM merchant_deposits"
+ " WHERE h_contract_terms=$1"
+ " AND merchant_pub=$2"
+ " AND coin_pub=$3",
+ 3),
+ GNUNET_PQ_make_prepare ("find_transfers_by_hash",
+ "SELECT"
+ " coin_pub"
+ ",wtid"
+ ",merchant_proofs.execution_time"
+ ",merchant_proofs.proof"
+ " FROM merchant_transfers"
+ " JOIN merchant_proofs USING (wtid)"
+ " WHERE h_contract_terms=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("find_deposits_by_wtid",
+ "SELECT"
+ " merchant_transfers.h_contract_terms"
+ ",merchant_transfers.coin_pub"
+ ",merchant_deposits.amount_with_fee_val"
+ ",merchant_deposits.amount_with_fee_frac"
+ ",merchant_deposits.deposit_fee_val"
+ ",merchant_deposits.deposit_fee_frac"
+ ",merchant_deposits.refund_fee_val"
+ ",merchant_deposits.refund_fee_frac"
+ ",merchant_deposits.wire_fee_val"
+ ",merchant_deposits.wire_fee_frac"
+ ",merchant_deposits.exchange_url"
+ ",merchant_deposits.exchange_proof"
+ " FROM merchant_transfers"
+ " JOIN merchant_deposits"
+ " ON (merchant_deposits.h_contract_terms =
merchant_transfers.h_contract_terms"
+ " AND"
+ " merchant_deposits.coin_pub =
merchant_transfers.coin_pub)"
+ " WHERE wtid=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("find_proof_by_wtid",
+ "SELECT"
+ " proof"
+ " FROM merchant_proofs"
+ " WHERE wtid=$1"
+ " AND exchange_url=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("lookup_tip_reserve_balance",
+ "SELECT"
+ " expiration"
+ ",balance_val"
+ ",balance_frac"
+ " FROM merchant_tip_reserves"
+ " WHERE reserve_priv=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("find_tip_authorizations",
+ "SELECT"
+ " amount_val"
+ ",amount_frac"
+ ",justification"
+ ",extra"
+ ",tip_id"
+ " FROM merchant_tips"
+ " WHERE reserve_priv=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("update_tip_reserve_balance",
+ "UPDATE merchant_tip_reserves SET"
+ " expiration=$2"
+ ",balance_val=$3"
+ ",balance_frac=$4"
+ " WHERE reserve_priv=$1",
+ 4),
+ GNUNET_PQ_make_prepare ("insert_tip_reserve_balance",
+ "INSERT INTO merchant_tip_reserves"
+ "(reserve_priv"
+ ",expiration"
+ ",balance_val"
+ ",balance_frac"
+ ") VALUES "
+ "($1, $2, $3, $4)",
+ 4),
+ GNUNET_PQ_make_prepare ("insert_tip_justification",
+ "INSERT INTO merchant_tips"
+ "(reserve_priv"
+ ",tip_id"
+ ",exchange_url"
+ ",justification"
+ ",extra"
+ ",timestamp"
+ ",amount_val"
+ ",amount_frac"
+ ",left_val"
+ ",left_frac"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ 10),
+ GNUNET_PQ_make_prepare ("lookup_reserve_by_tip_id",
+ "SELECT"
+ " reserve_priv"
+ ",left_val"
+ ",left_frac"
+ " FROM merchant_tips"
+ " WHERE tip_id=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("lookup_amount_by_pickup",
+ "SELECT"
+ " amount_val"
+ ",amount_frac"
+ " FROM merchant_tip_pickups"
+ " WHERE pickup_id=$1"
+ " AND tip_id=$2",
+ 2),
+ GNUNET_PQ_make_prepare ("find_tip_by_id",
+ "SELECT"
+ " exchange_url"
+ ",extra"
+ ",timestamp"
+ ",amount_val"
+ ",amount_frac"
+ ",left_val"
+ ",left_frac"
+ " FROM merchant_tips"
+ " WHERE tip_id=$1",
+ 1),
+ GNUNET_PQ_make_prepare ("update_tip_balance",
+ "UPDATE merchant_tips SET"
+ " left_val=$2"
+ ",left_frac=$3"
+ " WHERE tip_id=$1",
+ 3),
+ GNUNET_PQ_make_prepare ("insert_pickup_id",
+ "INSERT INTO merchant_tip_pickups"
+ "(tip_id"
+ ",pickup_id"
+ ",amount_val"
+ ",amount_frac"
+ ") VALUES "
+ "($1, $2, $3, $4)",
+ 4),
+ GNUNET_PQ_make_prepare ("insert_tip_credit_uuid",
+ "INSERT INTO merchant_tip_reserve_credits"
+ "(reserve_priv"
+ ",credit_uuid"
+ ",timestamp"
+ ",amount_val"
+ ",amount_frac"
+ ") VALUES "
+ "($1, $2, $3, $4, $5)",
+ 5),
+ GNUNET_PQ_make_prepare ("lookup_tip_credit_uuid",
+ "SELECT 1 "
+ "FROM merchant_tip_reserve_credits "
+ "WHERE credit_uuid=$1 AND reserve_priv=$2",
+ 2),
+ GNUNET_PQ_PREPARED_STATEMENT_END
};
- enum GNUNET_DB_QueryStatus qs;
- unsigned int retries;
-
- retries = 0;
- check_connection (pg);
-RETRY:
- if (MAX_RETRIES < ++retries)
- return TALER_EC_TIP_PICKUP_DB_ERROR_SOFT;
- if (GNUNET_OK !=
- postgres_start (pg,
- "pickup tip"))
- {
- GNUNET_break (0);
- return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
- }
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_reserve_by_tip_id",
- params,
- rs);
- if (0 >= qs)
- {
- /* tip ID unknown */
- memset (reserve_priv,
- 0,
- sizeof (*reserve_priv));
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN;
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
- }
-
- /* Check if pickup_id already exists */
- {
- struct TALER_Amount existing_amount;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (pickup_id),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &existing_amount),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_amount_by_pickup",
- params,
- rs);
- if (0 > qs)
- {
- /* DB error */
- memset (reserve_priv,
- 0,
- sizeof (*reserve_priv));
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
- }
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- if (0 !=
- TALER_amount_cmp (&existing_amount,
- amount))
- {
- GNUNET_break_op (0);
- postgres_rollback (pg);
- return TALER_EC_TIP_PICKUP_AMOUNT_CHANGED;
- }
- postgres_commit (pg);
- return TALER_EC_NONE; /* we are done! */
- }
- }
-
- /* Calculate new balance */
- {
- struct TALER_Amount new_left;
-
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (&new_left,
- &left_amount,
- amount))
- {
- /* attempt to take more tips than the tipping amount */
- GNUNET_break_op (0);
- memset (reserve_priv,
- 0,
- sizeof (*reserve_priv));
- postgres_rollback (pg);
- return TALER_EC_TIP_PICKUP_NO_FUNDS;
- }
-
- /* Update DB: update balance */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- TALER_PQ_query_param_amount (&new_left),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_tip_balance",
- params);
- if (0 > qs)
- {
- postgres_rollback (pg);
- memset (reserve_priv,
- 0,
- sizeof (*reserve_priv));
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
- }
- }
-
- /* Update DB: remember pickup_id */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_auto_from_type (pickup_id),
- TALER_PQ_query_param_amount (amount),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_pickup_id",
- params);
- if (0 > qs)
- {
- postgres_rollback (pg);
- memset (reserve_priv,
- 0,
- sizeof (*reserve_priv));
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
- }
- }
- }
- qs = postgres_commit (pg);
- if (0 <= qs)
- return TALER_EC_NONE; /* success */
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
-}
-
-
-/**
- * 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)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct PostgresClosure *pg;
- struct TALER_MERCHANTDB_Plugin *plugin;
- const char *ec;
pg = GNUNET_new (struct PostgresClosure);
ec = getenv ("TALER_MERCHANTDB_POSTGRES_CONFIG");
@@ -3694,7 +3658,9 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
}
pg->cfg = cfg;
pg->conn = GNUNET_PQ_connect_with_cfg (cfg,
- "merchantdb-postgres");
+ "merchantdb-postgres",
+ es,
+ ps);
if (NULL == pg->conn)
{
GNUNET_free (pg);
@@ -3709,13 +3675,13 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler",
"CURRENCY");
+ GNUNET_PQ_disconnect (pg->conn);
GNUNET_free (pg);
return NULL;
}
plugin = GNUNET_new (struct TALER_MERCHANTDB_Plugin);
plugin->cls = pg;
plugin->drop_tables = &postgres_drop_tables;
- plugin->initialize = &postgres_initialize;
plugin->store_deposit = &postgres_store_deposit;
plugin->store_coin_to_transfer = &postgres_store_coin_to_transfer;
plugin->store_transfer_to_proof = &postgres_store_transfer_to_proof;
@@ -3772,7 +3738,7 @@ libtaler_plugin_merchantdb_postgres_done (void *cls)
struct TALER_MERCHANTDB_Plugin *plugin = cls;
struct PostgresClosure *pg = plugin->cls;
- PQfinish (pg->conn);
+ GNUNET_PQ_disconnect (pg->conn);
GNUNET_free (pg->currency);
GNUNET_free (pg);
GNUNET_free (plugin);
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 5756bbb..1a569b1 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -749,7 +749,6 @@ run (void *cls)
result = 77;
return;
}
-
if (GNUNET_OK != plugin->drop_tables (plugin->cls))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -757,7 +756,8 @@ run (void *cls)
result = 77;
return;
}
- if (GNUNET_OK != plugin->initialize (plugin->cls))
+ TALER_MERCHANTDB_plugin_unload (plugin);
+ if (NULL == (plugin = TALER_MERCHANTDB_plugin_load (cfg)))
{
result = 77;
return;
diff --git a/src/include/taler_merchantdb_plugin.h
b/src/include/taler_merchantdb_plugin.h
index 59cd2db..e8a91b5 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -191,15 +191,6 @@ struct TALER_MERCHANTDB_Plugin
int
(*drop_tables) (void *cls);
- /**
- * Initialize merchant tables
- *
- * @param cls closure
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- int
- (*initialize) (void *cls);
-
/**
* Insert order into db.
*
diff --git a/src/merchant-tools/taler-merchant-dbinit.c
b/src/merchant-tools/taler-merchant-dbinit.c
index 2da6cd5..b5e85ee 100644
--- a/src/merchant-tools/taler-merchant-dbinit.c
+++ b/src/merchant-tools/taler-merchant-dbinit.c
@@ -60,17 +60,11 @@ run (void *cls,
return;
}
if (reset_db)
- (void) plugin->drop_tables (plugin->cls);
- if (GNUNET_OK !=
- plugin->initialize (plugin->cls))
{
- fprintf (stderr,
- "Failed to initialize database.\n");
+ (void) plugin->drop_tables (plugin->cls);
TALER_MERCHANTDB_plugin_unload (plugin);
- global_ret = 1;
- return;
+ plugin = TALER_MERCHANTDB_plugin_load (cfg);
}
-
TALER_MERCHANTDB_plugin_unload (plugin);
}
--
To stop receiving notification emails like this one, please contact
address@hidden.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] [taler-merchant] branch master updated: fix #5733 by migrating to new GNUnet PQ API,
gnunet <=