From cad64767d9fda2c18106f25ef101c2eb5fce15a1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 11 Jun 2017 01:59:09 +0200 Subject: match GNUnet API rename, work on #5010 --- src/exchange/taler-exchange-aggregator.c | 110 +- src/exchange/taler-exchange-httpd_db.c | 6 +- src/exchange/taler-exchange-httpd_keystate.c | 40 +- src/exchange/test_taler_exchange_aggregator.c | 4 +- src/exchangedb/perf_taler_exchangedb_interpreter.c | 9 +- src/exchangedb/plugin_exchangedb_postgres.c | 2670 ++++++++++---------- src/exchangedb/test_exchangedb.c | 6 +- src/include/taler_exchangedb_plugin.h | 3 +- 8 files changed, 1409 insertions(+), 1439 deletions(-) (limited to 'src') diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index f4573aaf8..d658398ae 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -732,6 +732,29 @@ static void run_aggregation (void *cls); +/** + * Perform a database commit. If it fails, print a warning. + * + * @param session session to perform the commit for. + * @return status of commit + */ +static enum GNUNET_DB_QueryStatus +commit_or_warn (struct TALER_EXCHANGEDB_Session *session) +{ + enum GNUNET_DB_QueryStatus qs; + + qs = db_plugin->commit (db_plugin->cls, + session); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + return qs; + GNUNET_log ((GNUNET_DB_STATUS_SOFT_ERROR == qs) + ? GNUNET_ERROR_TYPE_INFO + : GNUNET_ERROR_TYPE_ERROR, + "Failed to commit database transaction!\n"); + return qs; +} + + /** * Function to be called with the prepared transfer data * when closing a reserve. @@ -782,13 +805,7 @@ prepare_close_cb (void *cls, } /* finally commit */ - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - ctc->session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit database transaction!\n"); - } + (void) commit_or_warn (ctc->session); GNUNET_free (ctc->type); GNUNET_free (ctc); ctc = NULL; @@ -948,13 +965,7 @@ expired_reserve_cb (void *cls, return GNUNET_SYSERR; } /* Reserve balance was almost zero; just commit */ - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit database transaction!\n"); - } + (void) commit_or_warn (session); task = GNUNET_SCHEDULER_add_now (&run_reserve_closures, NULL); return GNUNET_SYSERR; @@ -1191,13 +1202,7 @@ run_aggregation (void *cls) au->additional_rows[i])) ret = GNUNET_SYSERR; /* commit */ - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit database transaction!\n"); - } + (void) commit_or_warn (session); GNUNET_free_non_null (au->additional_rows); if (NULL != au->wire) json_decref (au->wire); @@ -1336,6 +1341,8 @@ prepare_cb (void *cls, au = NULL; return; } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stored wire transfer out instructions\n"); if (NULL != au->wire) { json_decref (au->wire); @@ -1346,22 +1353,31 @@ prepare_cb (void *cls, /* Now we can finally commit the overall transaction, as we are again consistent if all of this passes. */ - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) + switch (commit_or_warn (session)) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to commit database transaction!\n"); + case GNUNET_DB_STATUS_SOFT_ERROR: /* try again */ task = GNUNET_SCHEDULER_add_now (&run_aggregation, NULL); return; + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + global_ret = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Preparation complete, switching to transfer mode\n"); + /* run alternative task: actually do wire transfer! */ + task = GNUNET_SCHEDULER_add_now (&run_transfers, + NULL); + return; + default: + GNUNET_break (0); + global_ret = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Preparation complete, switching to transfer mode\n"); - /* run alternative task: actually do wire transfer! */ - task = GNUNET_SCHEDULER_add_now (&run_transfers, - NULL); } @@ -1411,24 +1427,32 @@ wire_confirm_cb (void *cls, } GNUNET_free (wpd); wpd = NULL; - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) + switch (commit_or_warn (session)) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to commit database transaction!\n"); + case GNUNET_DB_STATUS_SOFT_ERROR: /* try again */ task = GNUNET_SCHEDULER_add_now (&run_aggregation, NULL); return; + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + global_ret = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Wire transfer complete\n"); + /* continue with #run_transfers(), just to guard + against the unlikely case that there are more. */ + task = GNUNET_SCHEDULER_add_now (&run_transfers, + NULL); + return; + default: + GNUNET_break (0); + global_ret = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Wire transfer complete\n"); - /* continue with #run_transfers(), just to guard - against the unlikely case that there are more. */ - task = GNUNET_SCHEDULER_add_now (&run_transfers, - NULL); - } diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index 51e1ef50e..71f82e9d5 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -46,7 +46,7 @@ #define START_TRANSACTION(session,connection) \ { /* start new scope, will be ended by COMMIT_TRANSACTION() */\ unsigned int transaction_retries = 0; \ - int transaction_commit_result; \ + enum GNUNET_DB_QueryStatus transaction_commit_result; \ transaction_start_label: /* we will use goto for retries */ \ if (GNUNET_OK != \ TEH_plugin->start (TEH_plugin->cls, \ @@ -71,13 +71,13 @@ transaction_start_label: /* we will use goto for retries */ \ transaction_commit_result = \ TEH_plugin->commit (TEH_plugin->cls, \ session); \ - if (GNUNET_SYSERR == transaction_commit_result) \ + if (GNUNET_DB_STATUS_HARD_ERROR == transaction_commit_result) \ { \ TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ return TEH_RESPONSE_reply_commit_error (connection, \ TALER_EC_DB_COMMIT_FAILED_HARD); \ } \ - if (GNUNET_NO == transaction_commit_result) \ + if (GNUNET_DB_STATUS_SOFT_ERROR == transaction_commit_result) \ { \ TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \ diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c index 3f81b2e33..6fc55a0b0 100644 --- a/src/exchange/taler-exchange-httpd_keystate.c +++ b/src/exchange/taler-exchange-httpd_keystate.c @@ -331,7 +331,9 @@ reload_keys_denom_iter (void *cls, struct GNUNET_TIME_Absolute expire_deposit; struct GNUNET_HashCode denom_key_hash; struct TALER_EXCHANGEDB_Session *session; + unsigned int thresh; int res; + enum GNUNET_DB_QueryStatus qs; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading denomination key `%s'\n", @@ -361,8 +363,6 @@ reload_keys_denom_iter (void *cls, if (NULL != revocation_master_sig) { - unsigned int thresh = 0; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Adding denomination key `%s' to revokation set\n", alias); @@ -373,11 +373,13 @@ reload_keys_denom_iter (void *cls, /* Try to insert DKI into DB until we succeed; note that if the DB failure is persistent, we need to die, as we cannot continue without the DKI being in the DB). */ - res = GNUNET_SYSERR; - while (GNUNET_OK != res) + thresh = 0; + qs = GNUNET_DB_STATUS_SOFT_ERROR; + while (0 > qs) { thresh++; - if (thresh > 16) + if ( (thresh > 16) || + (GNUNET_DB_STATUS_HARD_ERROR == qs) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Giving up, this is fatal. Committing suicide via SIGTERM.\n"); @@ -409,8 +411,8 @@ reload_keys_denom_iter (void *cls, session); break; /* already in is also OK! */ } - res = TEH_plugin->commit (TEH_plugin->cls, - session); + qs = TEH_plugin->commit (TEH_plugin->cls, + session); } GNUNET_assert (0 == json_array_append_new (ctx->payback_array, @@ -440,12 +442,22 @@ reload_keys_denom_iter (void *cls, if (NULL == session) return GNUNET_SYSERR; /* Try to insert DKI into DB until we succeed; note that if the DB - failure is persistent, this code may loop forever (as there is no - sane alternative, we cannot continue without the DKI being in the - DB). */ - res = GNUNET_SYSERR; - while (GNUNET_OK != res) + failure is persistent, we die, as we cannot continue without the + DKI being in the DB). */ + qs = GNUNET_DB_STATUS_SOFT_ERROR; + thresh = 0; + while (0 > qs) { + thresh++; + if ( (thresh > 16) || + (GNUNET_DB_STATUS_HARD_ERROR == qs) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Giving up, this is fatal. Committing suicide via SIGTERM.\n"); + handle_signal (SIGTERM); + return GNUNET_SYSERR; + } + res = TEH_plugin->start (TEH_plugin->cls, session); if (GNUNET_OK != res) @@ -485,8 +497,8 @@ reload_keys_denom_iter (void *cls, session); continue; } - res = TEH_plugin->commit (TEH_plugin->cls, - session); + qs = TEH_plugin->commit (TEH_plugin->cls, + session); /* If commit succeeded, we're done, otherwise we retry; this time without logging, as theroetically commits can fail in a transactional DB due to concurrent activities that diff --git a/src/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c index 57cb9d3c7..6eaa09320 100644 --- a/src/exchange/test_taler_exchange_aggregator.c +++ b/src/exchange/test_taler_exchange_aggregator.c @@ -450,7 +450,7 @@ do_deposit (struct Command *cmd) plugin->insert_deposit (plugin->cls, session, &deposit)) || - (GNUNET_OK != + (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->commit (plugin->cls, session)) ) ret = GNUNET_SYSERR; @@ -1148,7 +1148,7 @@ run (void *cls) session, &dpk, &issue)) || - (GNUNET_OK != + (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->commit (plugin->cls, session)) ) { diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c index 5e4155c38..0a8efbb5d 100644 --- a/src/exchangedb/perf_taler_exchangedb_interpreter.c +++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c @@ -1292,13 +1292,16 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) break; case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION: - state->plugin->start (state->plugin->cls, state->session); + GNUNET_break (GNUNET_OK == + state->plugin->start (state->plugin->cls, + state->session)); break; case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION: - state->plugin->commit (state->plugin->cls, state->session); + GNUNET_break (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == + state->plugin->commit (state->plugin->cls, + state->session)); break; - case PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION: state->plugin->rollback (state->plugin->cls, state->session); diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index e251722c9..2df4630b9 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -242,318 +242,298 @@ static int postgres_create_tables (void *cls) { struct PostgresClosure *pc = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + /* Denomination table for holding the publicly available information of + denominations keys. The denominations are to be referred to using + foreign keys. */ + GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS denominations" + "(denom_pub_hash BYTEA PRIMARY KEY CHECK (LENGTH(denom_pub_hash)=64)" + ",denom_pub BYTEA NOT NULL" + ",master_pub BYTEA NOT NULL CHECK (LENGTH(master_pub)=32)" + ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" + ",valid_from INT8 NOT NULL" + ",expire_withdraw INT8 NOT NULL" + ",expire_deposit INT8 NOT NULL" + ",expire_legal INT8 NOT NULL" + ",coin_val INT8 NOT NULL" /* value of this denom */ + ",coin_frac INT4 NOT NULL" /* fractional value of this denom */ + ",coin_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" /* assuming same currency for fees */ + ",fee_withdraw_val INT8 NOT NULL" + ",fee_withdraw_frac INT4 NOT NULL" + ",fee_withdraw_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",fee_deposit_val INT8 NOT NULL" + ",fee_deposit_frac INT4 NOT NULL" + ",fee_deposit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",fee_refresh_val INT8 NOT NULL" + ",fee_refresh_frac INT4 NOT NULL" + ",fee_refresh_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",fee_refund_val INT8 NOT NULL" + ",fee_refund_frac INT4 NOT NULL" + ",fee_refund_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ")"), + /* denomination_revocations table is for remembering which denomination keys have been revoked */ + GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS denomination_revocations" + "(denom_revocations_serial_id BIGSERIAL" + ",denom_pub_hash BYTEA PRIMARY KEY REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" + ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" + ");"), + /* reserves table is for summarization of a reserve. It is updated when new + funds are added and existing funds are withdrawn. The 'expiration_date' + can be used to eventually get rid of reserves that have not been used + for a very long time (either by refunding the owner or by greedily + grabbing the money, depending on the Exchange's terms of service) */ + GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS reserves" + "(reserve_pub BYTEA PRIMARY KEY CHECK(LENGTH(reserve_pub)=32)" + ",account_details TEXT NOT NULL " + ",current_balance_val INT8 NOT NULL" + ",current_balance_frac INT4 NOT NULL" + ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",expiration_date INT8 NOT NULL" + ");"), + /* index on reserves table */ + GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_reserve_pub_index ON " + "reserves (reserve_pub);"), + GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_expiration_index" + " ON reserves (expiration_date);"), + /* reserves_in table collects the transactions which transfer funds + into the reserve. The rows of this table correspond to each + incoming transaction. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS reserves_in" + "(reserve_in_serial_id BIGSERIAL" + ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",wire_reference BYTEA NOT NULL" + ",credit_val INT8 NOT NULL" + ",credit_frac INT4 NOT NULL" + ",credit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",sender_account_details TEXT NOT NULL" + ",execution_date INT8 NOT NULL" + ",PRIMARY KEY (reserve_pub, wire_reference)" + ");"), + /* Create indices on reserves_in */ + GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_in_execution_index" + " ON reserves_in (execution_date);"), + /* This table contains the data for wire transfers the exchange has + executed to close a reserve. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS reserves_close " + "(close_uuid BIGSERIAL PRIMARY KEY" + ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",execution_date INT8 NOT NULL" + ",wtid BYTEA NOT NULL CHECK (LENGTH(wtid)=32)" + ",receiver_account TEXT NOT NULL" + ",amount_val INT8 NOT NULL" + ",amount_frac INT4 NOT NULL" + ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",closing_fee_val INT8 NOT NULL" + ",closing_fee_frac INT4 NOT NULL" + ",closing_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ");"), + GNUNET_PQ_make_try_execute("CREATE INDEX reserves_close_by_reserve " + "ON reserves_close(reserve_pub)"), + /* Table with the withdraw operations that have been performed on a reserve. + The 'h_blind_ev' is the hash of the blinded coin. It serves as a primary + key, as (broken) clients that use a non-random coin and blinding factor + should fail to even withdraw, as otherwise the coins will fail to deposit + (as they really must be unique). */ + GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS reserves_out" + "(reserve_out_serial_id BIGSERIAL" + ",h_blind_ev BYTEA PRIMARY KEY" + ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" + ",denom_sig BYTEA NOT NULL" + ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)" + ",execution_date INT8 NOT NULL" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ");"), + /* Index blindcoins(reserve_pub) for get_reserves_out statement */ + GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_out_reserve_pub_index ON" + " reserves_out (reserve_pub)"), + GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_out_execution_date ON " + "reserves_out (execution_date)"), + /* Table with coins that have been (partially) spent, used to track + coin information only once. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS known_coins " + "(coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (LENGTH(coin_pub)=32)" + ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" + ",denom_sig BYTEA NOT NULL" + ");"), + /** + * The DB will show negative values for some values of the following fields as + * we use them as 16 bit unsigned integers + * @a num_newcoins + * @a noreveal_index + * Do not do arithmetic in SQL on these fields. + * NOTE: maybe we should instead forbid values >= 2^15 categorically? + */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS refresh_sessions " + "(melt_serial_id BIGSERIAL" + ",session_hash BYTEA PRIMARY KEY CHECK (LENGTH(session_hash)=64)" + ",old_coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" + ",old_coin_sig BYTEA NOT NULL CHECK(LENGTH(old_coin_sig)=64)" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",num_newcoins INT2 NOT NULL" + ",noreveal_index INT2 NOT NULL" + ");"), + /* Table with information about the desired denominations to be created + during a refresh operation; contains the denomination key for each + of the coins (for a given refresh session) */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS refresh_order " + "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" + ",newcoin_index INT2 NOT NULL " + ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" + ",PRIMARY KEY (session_hash, newcoin_index)" + ");"), + /* Table with the commitments for a refresh operation; includes + the session_hash for which this is the link information, the + oldcoin index and the cut-and-choose index (from 0 to #TALER_CNC_KAPPA-1), + as well as the actual link data (the transfer public key and the encrypted + link secret) */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS refresh_transfer_public_key " + "(session_hash BYTEA NOT NULL PRIMARY KEY REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" + ",transfer_pub BYTEA NOT NULL CHECK(LENGTH(transfer_pub)=32)" + ");"), + /* Table with the commitments for the new coins that are to be created + during a melting session. Includes the session, the cut-and-choose + index and the index of the new coin, and the envelope of the new + coin to be signed, as well as the encrypted information about the + private key and the blinding factor for the coin (for verification + in case this newcoin_index is chosen to be revealed) */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS refresh_commit_coin " + "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" + ",newcoin_index INT2 NOT NULL" + ",coin_ev BYTEA NOT NULL" + ",UNIQUE (session_hash, newcoin_index)" + ");"), + GNUNET_PQ_make_try_execute("CREATE INDEX refresh_commit_coin_session_hash_index " + "ON refresh_commit_coin(session_hash, newcoin_index)"), + /* Table with the signatures over coins generated during a refresh + operation. Needed to answer /refresh/link queries later. Stores + the coin signatures under the respective session hash and index. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS refresh_out " + "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" + ",newcoin_index INT2 NOT NULL" + ",ev_sig BYTEA NOT NULL" + ",UNIQUE (session_hash, newcoin_index)" + ");"), + GNUNET_PQ_make_try_execute("CREATE INDEX refresh_out_session_hash_index " + "ON refresh_out(session_hash, newcoin_index)"), + /* This table contains the wire transfers the exchange is supposed to + execute to transmit funds to the merchants (and manage refunds). */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS deposits " + "(deposit_serial_id BIGSERIAL PRIMARY KEY" + ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",timestamp INT8 NOT NULL" + ",refund_deadline INT8 NOT NULL" + ",wire_deadline INT8 NOT NULL" + ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)" + ",h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)" + ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)" + ",coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)" + ",wire TEXT NOT NULL" + ",tiny BOOLEAN NOT NULL DEFAULT false" + ",done BOOLEAN NOT NULL DEFAULT false" + ",UNIQUE (coin_pub, h_contract_terms, merchant_pub)" + ");"), + /* Index for get_deposit statement on coin_pub, h_contract_terms and merchant_pub */ + GNUNET_PQ_make_try_execute("CREATE INDEX deposits_coin_pub_index " + "ON deposits(coin_pub, h_contract_terms, merchant_pub)"), + /* Table with information about coins that have been refunded. (Technically + one of the deposit operations that a coin was involved with is refunded.)*/ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS refunds " + "(refund_serial_id BIGSERIAL" + ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" + ",merchant_pub BYTEA NOT NULL CHECK(LENGTH(merchant_pub)=32)" + ",merchant_sig BYTEA NOT NULL CHECK(LENGTH(merchant_sig)=64)" + ",h_contract_terms BYTEA NOT NULL CHECK(LENGTH(h_contract_terms)=64)" + ",rtransaction_id INT8 NOT NULL" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",PRIMARY KEY (coin_pub, merchant_pub, h_contract_terms, rtransaction_id)" /* this combo must be unique, and we usually select by coin_pub */ + ");"), + /* This table contains the data for + wire transfers the exchange has executed. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS wire_out " + "(wireout_uuid BIGSERIAL PRIMARY KEY" + ",execution_date INT8 NOT NULL" + ",wtid_raw BYTEA UNIQUE NOT NULL CHECK (LENGTH(wtid_raw)=" TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR ")" + ",wire_target TEXT NOT NULL" + ",amount_val INT8 NOT NULL" + ",amount_frac INT4 NOT NULL" + ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ");"), + /* Table for the tracking API, mapping from wire transfer identifiers + to transactions and back */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS aggregation_tracking " + "(aggregation_serial_id BIGSERIAL" + ",deposit_serial_id INT8 PRIMARY KEY REFERENCES deposits (deposit_serial_id) ON DELETE CASCADE" + ",wtid_raw BYTEA CONSTRAINT wire_out_ref REFERENCES wire_out(wtid_raw) ON DELETE CASCADE DEFERRABLE" + ");"), + /* Index for lookup_transactions statement on wtid */ + GNUNET_PQ_make_try_execute("CREATE INDEX aggregation_tracking_wtid_index " + "ON aggregation_tracking(wtid_raw)"), + /* Table for the wire fees. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS wire_fee " + "(wire_method VARCHAR NOT NULL" + ",start_date INT8 NOT NULL" + ",end_date INT8 NOT NULL" + ",wire_fee_val INT8 NOT NULL" + ",wire_fee_frac INT4 NOT NULL" + ",wire_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" + ",PRIMARY KEY (wire_method, start_date)" /* this combo must be unique */ + ");"), + /* Index for lookup_transactions statement on wtid */ + GNUNET_PQ_make_try_execute("CREATE INDEX aggregation_tracking_wtid_index " + "ON aggregation_tracking(wtid_raw);"), + /* Table for /payback information */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS payback " + "(payback_uuid BIGSERIAL" + ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" + ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)" + ",coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)" + ",amount_val INT8 NOT NULL" + ",amount_frac INT4 NOT NULL" + ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",timestamp INT8 NOT NULL" + ",h_blind_ev BYTEA NOT NULL REFERENCES reserves_out (h_blind_ev) ON DELETE CASCADE" + ");"), + GNUNET_PQ_make_try_execute("CREATE INDEX payback_by_coin_index " + "ON payback(coin_pub);"), + GNUNET_PQ_make_try_execute("CREATE INDEX payback_by_reserve_index " + "ON payback(reserve_pub);"), + + /* This table contains the pre-commit data for + wire transfers the exchange is about to execute. */ + GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS prewire " + "(prewire_uuid BIGSERIAL PRIMARY KEY" + ",type TEXT NOT NULL" + ",finished BOOLEAN NOT NULL DEFAULT false" + ",buf BYTEA NOT NULL" + ");"), + /* Index for prepare_data_iterate statement */ + GNUNET_PQ_make_try_execute("CREATE INDEX prepare_iteration_index " + "ON prewire(type,finished);"), + GNUNET_PQ_EXECUTE_STATEMENT_END + + }; PGconn *conn; + int ret; conn = GNUNET_PQ_connect (pc->connection_cfg_str); if (NULL == conn) return GNUNET_SYSERR; -#define SQLEXEC(sql) SQLEXEC_(conn, sql); -#define SQLEXEC_INDEX(sql) SQLEXEC_IGNORE_ERROR_(conn, sql); - /* Denomination table for holding the publicly available information of - denominations keys. The denominations are to be referred to using - foreign keys. */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS denominations" - "(denom_pub_hash BYTEA PRIMARY KEY CHECK (LENGTH(denom_pub_hash)=64)" - ",denom_pub BYTEA NOT NULL" - ",master_pub BYTEA NOT NULL CHECK (LENGTH(master_pub)=32)" - ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" - ",valid_from INT8 NOT NULL" - ",expire_withdraw INT8 NOT NULL" - ",expire_deposit INT8 NOT NULL" - ",expire_legal INT8 NOT NULL" - ",coin_val INT8 NOT NULL" /* value of this denom */ - ",coin_frac INT4 NOT NULL" /* fractional value of this denom */ - ",coin_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" /* assuming same currency for fees */ - ",fee_withdraw_val INT8 NOT NULL" - ",fee_withdraw_frac INT4 NOT NULL" - ",fee_withdraw_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",fee_deposit_val INT8 NOT NULL" - ",fee_deposit_frac INT4 NOT NULL" - ",fee_deposit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",fee_refresh_val INT8 NOT NULL" - ",fee_refresh_frac INT4 NOT NULL" - ",fee_refresh_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",fee_refund_val INT8 NOT NULL" - ",fee_refund_frac INT4 NOT NULL" - ",fee_refund_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ")"); - /* denomination_revocations table is for remembering which denomination keys have been revoked */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS denomination_revocations" - "(denom_revocations_serial_id BIGSERIAL" - ",denom_pub_hash BYTEA PRIMARY KEY REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" - ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" - ")"); - - /* reserves table is for summarization of a reserve. It is updated when new - funds are added and existing funds are withdrawn. The 'expiration_date' - can be used to eventually get rid of reserves that have not been used - for a very long time (either by refunding the owner or by greedily - grabbing the money, depending on the Exchange's terms of service) */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves" - "(reserve_pub BYTEA PRIMARY KEY CHECK(LENGTH(reserve_pub)=32)" - ",account_details TEXT NOT NULL " - ",current_balance_val INT8 NOT NULL" - ",current_balance_frac INT4 NOT NULL" - ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",expiration_date INT8 NOT NULL" - ")"); - /* index on reserves table */ - SQLEXEC_INDEX ("CREATE INDEX reserves_reserve_pub_index ON " - "reserves (reserve_pub)"); - SQLEXEC_INDEX ("CREATE INDEX reserves_expiration_index" - " ON reserves (expiration_date);"); - - /* reserves_in table collects the transactions which transfer funds - into the reserve. The rows of this table correspond to each - incoming transaction. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in" - "(reserve_in_serial_id BIGSERIAL" - ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",wire_reference BYTEA NOT NULL" - ",credit_val INT8 NOT NULL" - ",credit_frac INT4 NOT NULL" - ",credit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",sender_account_details TEXT NOT NULL" - ",execution_date INT8 NOT NULL" - ",PRIMARY KEY (reserve_pub, wire_reference)" - ");"); - /* Create indices on reserves_in */ - SQLEXEC_INDEX ("CREATE INDEX reserves_in_execution_index" - " ON reserves_in (execution_date);"); - - /* This table contains the data for wire transfers the exchange has - executed to close a reserve. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_close " - "(close_uuid BIGSERIAL PRIMARY KEY" - ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",execution_date INT8 NOT NULL" - ",wtid BYTEA NOT NULL CHECK (LENGTH(wtid)=32)" - ",receiver_account TEXT NOT NULL" - ",amount_val INT8 NOT NULL" - ",amount_frac INT4 NOT NULL" - ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",closing_fee_val INT8 NOT NULL" - ",closing_fee_frac INT4 NOT NULL" - ",closing_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ")"); - SQLEXEC_INDEX("CREATE INDEX reserves_close_by_reserve " - "ON reserves_close(reserve_pub)"); - - /* Table with the withdraw operations that have been performed on a reserve. - The 'h_blind_ev' is the hash of the blinded coin. It serves as a primary - key, as (broken) clients that use a non-random coin and blinding factor - should fail to even withdraw, as otherwise the coins will fail to deposit - (as they really must be unique). */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out" - "(reserve_out_serial_id BIGSERIAL" - ",h_blind_ev BYTEA PRIMARY KEY" - ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" - ",denom_sig BYTEA NOT NULL" - ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)" - ",execution_date INT8 NOT NULL" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ");"); - /* Index blindcoins(reserve_pub) for get_reserves_out statement */ - SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON" - " reserves_out (reserve_pub)"); - SQLEXEC_INDEX ("CREATE INDEX reserves_out_execution_date ON " - "reserves_out (execution_date)"); - /* Table with coins that have been (partially) spent, used to track - coin information only once. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins " - "(coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (LENGTH(coin_pub)=32)" - ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" - ",denom_sig BYTEA NOT NULL" - ")"); - /** - * The DB will show negative values for some values of the following fields as - * we use them as 16 bit unsigned integers - * @a num_newcoins - * @a noreveal_index - * Do not do arithmetic in SQL on these fields. - * NOTE: maybe we should instead forbid values >= 2^15 categorically? - */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions " - "(melt_serial_id BIGSERIAL" - ",session_hash BYTEA PRIMARY KEY CHECK (LENGTH(session_hash)=64)" - ",old_coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" - ",old_coin_sig BYTEA NOT NULL CHECK(LENGTH(old_coin_sig)=64)" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",num_newcoins INT2 NOT NULL" - ",noreveal_index INT2 NOT NULL" - ")"); - - /* Table with information about the desired denominations to be created - during a refresh operation; contains the denomination key for each - of the coins (for a given refresh session) */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order " - "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" - ",newcoin_index INT2 NOT NULL " - ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" - ",PRIMARY KEY (session_hash, newcoin_index)" - ")"); - - /* Table with the commitments for a refresh operation; includes - the session_hash for which this is the link information, the - oldcoin index and the cut-and-choose index (from 0 to #TALER_CNC_KAPPA-1), - as well as the actual link data (the transfer public key and the encrypted - link secret) */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_transfer_public_key " - "(session_hash BYTEA NOT NULL PRIMARY KEY REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" - ",transfer_pub BYTEA NOT NULL CHECK(LENGTH(transfer_pub)=32)" - ")"); - - /* Table with the commitments for the new coins that are to be created - during a melting session. Includes the session, the cut-and-choose - index and the index of the new coin, and the envelope of the new - coin to be signed, as well as the encrypted information about the - private key and the blinding factor for the coin (for verification - in case this newcoin_index is chosen to be revealed) */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin " - "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" - ",newcoin_index INT2 NOT NULL" - ",coin_ev BYTEA NOT NULL" - ",UNIQUE (session_hash, newcoin_index)" - ")"); - SQLEXEC_INDEX("CREATE INDEX refresh_commit_coin_session_hash_index " - "ON refresh_commit_coin(session_hash, newcoin_index)"); - - - /* Table with the signatures over coins generated during a refresh - operation. Needed to answer /refresh/link queries later. Stores - the coin signatures under the respective session hash and index. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_out " - "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) ON DELETE CASCADE" - ",newcoin_index INT2 NOT NULL" - ",ev_sig BYTEA NOT NULL" - ",UNIQUE (session_hash, newcoin_index)" - ")"); - SQLEXEC_INDEX("CREATE INDEX refresh_out_session_hash_index " - "ON refresh_out(session_hash, newcoin_index)"); - - /* This table contains the wire transfers the exchange is supposed to - execute to transmit funds to the merchants (and manage refunds). */ - SQLEXEC("CREATE TABLE IF NOT EXISTS deposits " - "(deposit_serial_id BIGSERIAL PRIMARY KEY" - ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",timestamp INT8 NOT NULL" - ",refund_deadline INT8 NOT NULL" - ",wire_deadline INT8 NOT NULL" - ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)" - ",h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)" - ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)" - ",coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)" - ",wire TEXT NOT NULL" - ",tiny BOOLEAN NOT NULL DEFAULT false" - ",done BOOLEAN NOT NULL DEFAULT false" - ",UNIQUE (coin_pub, h_contract_terms, merchant_pub)" - ")"); - /* Index for get_deposit statement on coin_pub, h_contract_terms and merchant_pub */ - SQLEXEC_INDEX("CREATE INDEX deposits_coin_pub_index " - "ON deposits(coin_pub, h_contract_terms, merchant_pub)"); - - /* Table with information about coins that have been refunded. (Technically - one of the deposit operations that a coin was involved with is refunded.)*/ - SQLEXEC("CREATE TABLE IF NOT EXISTS refunds " - "(refund_serial_id BIGSERIAL" - ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" - ",merchant_pub BYTEA NOT NULL CHECK(LENGTH(merchant_pub)=32)" - ",merchant_sig BYTEA NOT NULL CHECK(LENGTH(merchant_sig)=64)" - ",h_contract_terms BYTEA NOT NULL CHECK(LENGTH(h_contract_terms)=64)" - ",rtransaction_id INT8 NOT NULL" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",PRIMARY KEY (coin_pub, merchant_pub, h_contract_terms, rtransaction_id)" /* this combo must be unique, and we usually select by coin_pub */ - ") "); - - /* This table contains the data for - wire transfers the exchange has executed. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS wire_out " - "(wireout_uuid BIGSERIAL PRIMARY KEY" - ",execution_date INT8 NOT NULL" - ",wtid_raw BYTEA UNIQUE NOT NULL CHECK (LENGTH(wtid_raw)=" TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR ")" - ",wire_target TEXT NOT NULL" - ",amount_val INT8 NOT NULL" - ",amount_frac INT4 NOT NULL" - ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ")"); - - /* Table for the tracking API, mapping from wire transfer identifiers - to transactions and back */ - SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking " - "(aggregation_serial_id BIGSERIAL" - ",deposit_serial_id INT8 PRIMARY KEY REFERENCES deposits (deposit_serial_id) ON DELETE CASCADE" - ",wtid_raw BYTEA CONSTRAINT wire_out_ref REFERENCES wire_out(wtid_raw) ON DELETE CASCADE DEFERRABLE" - ")"); - /* Index for lookup_transactions statement on wtid */ - SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index " - "ON aggregation_tracking(wtid_raw)"); - - - /* Table for the wire fees. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS wire_fee " - "(wire_method VARCHAR NOT NULL" - ",start_date INT8 NOT NULL" - ",end_date INT8 NOT NULL" - ",wire_fee_val INT8 NOT NULL" - ",wire_fee_frac INT4 NOT NULL" - ",wire_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" - ",PRIMARY KEY (wire_method, start_date)" /* this combo must be unique */ - ")"); - /* Index for lookup_transactions statement on wtid */ - SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index " - "ON aggregation_tracking(wtid_raw)"); - - /* Table for /payback information */ - SQLEXEC("CREATE TABLE IF NOT EXISTS payback " - "(payback_uuid BIGSERIAL" - ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE" - ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)" - ",coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)" - ",amount_val INT8 NOT NULL" - ",amount_frac INT4 NOT NULL" - ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",timestamp INT8 NOT NULL" - ",h_blind_ev BYTEA NOT NULL REFERENCES reserves_out (h_blind_ev) ON DELETE CASCADE" - ")"); - SQLEXEC_INDEX("CREATE INDEX payback_by_coin_index " - "ON payback(coin_pub)"); - SQLEXEC_INDEX("CREATE INDEX payback_by_reserve_index " - "ON payback(reserve_pub)"); - - /* This table contains the pre-commit data for - wire transfers the exchange is about to execute. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS prewire " - "(prewire_uuid BIGSERIAL PRIMARY KEY" - ",type TEXT NOT NULL" - ",finished BOOLEAN NOT NULL DEFAULT false" - ",buf BYTEA NOT NULL" - ")"); - /* Index for prepare_data_iterate statement */ - SQLEXEC_INDEX("CREATE INDEX prepare_iteration_index " - "ON prewire(type,finished)"); - - -#undef SQLEXEC -#undef SQLEXEC_INDEX - - PQfinish (conn); - return GNUNET_OK; - - SQLEXEC_fail: + ret = GNUNET_PQ_exec_statements (conn, + es); PQfinish (conn); - return GNUNET_SYSERR; + return ret; } @@ -566,1050 +546,1012 @@ postgres_create_tables (void *cls) static int postgres_prepare (PGconn *db_conn) { - PGresult *result; - -#define PREPARE(name, sql, ...) \ - do { \ - result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ - if (PGRES_COMMAND_OK != PQresultStatus (result)) \ - { \ - BREAK_DB_ERR (result, db_conn); \ - PQclear (result); result = NULL; \ - return GNUNET_SYSERR; \ - } \ - PQclear (result); result = NULL; \ - } while (0); - - /* Used in #postgres_insert_denomination_info() */ - PREPARE ("denomination_insert", - "INSERT INTO denominations " - "(denom_pub_hash" - ",denom_pub" - ",master_pub" - ",master_sig" - ",valid_from" - ",expire_withdraw" - ",expire_deposit" - ",expire_legal" - ",coin_val" /* value of this denom */ - ",coin_frac" /* fractional value of this denom */ - ",coin_curr" /* assuming same currency for fees */ - ",fee_withdraw_val" - ",fee_withdraw_frac" - ",fee_withdraw_curr" /* must match coin_curr */ - ",fee_deposit_val" - ",fee_deposit_frac" - ",fee_deposit_curr" /* must match coin_curr */ - ",fee_refresh_val" - ",fee_refresh_frac" - ",fee_refresh_curr" /* must match coin_curr */ - ",fee_refund_val" - ",fee_refund_frac" - ",fee_refund_curr" /* must match coin_curr */ - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," - " $11, $12, $13, $14, $15, $16, $17, $18," - " $19, $20, $21, $22, $23);", - 23, NULL); - - /* Used in #postgres_get_denomination_info() */ - PREPARE ("denomination_get", - "SELECT" - " master_pub" - ",master_sig" - ",valid_from" - ",expire_withdraw" - ",expire_deposit" - ",expire_legal" - ",coin_val" /* value of this denom */ - ",coin_frac" /* fractional value of this denom */ - ",coin_curr" /* assuming same currency for fees */ - ",fee_withdraw_val" - ",fee_withdraw_frac" - ",fee_withdraw_curr" /* must match coin_curr */ - ",fee_deposit_val" - ",fee_deposit_frac" - ",fee_deposit_curr" /* must match coin_curr */ - ",fee_refresh_val" - ",fee_refresh_frac" - ",fee_refresh_curr" /* must match coin_curr */ - ",fee_refund_val" - ",fee_refund_frac" - ",fee_refund_curr" /* must match coin_curr */ - " FROM denominations" - " WHERE denom_pub=$1;", - 1, NULL); - - /* Used in #postgres_insert_denomination_revocation() */ - PREPARE ("denomination_revocation_insert", - "INSERT INTO denomination_revocations " - "(denom_pub_hash" - ",master_sig" - ") VALUES " - "($1, $2);", - 2, NULL); - - /* Used in #postgres_get_denomination_revocation() */ - PREPARE ("denomination_revocation_get", - "SELECT" - " master_sig" - ",denom_revocations_serial_id" - " FROM denomination_revocations" - " WHERE denom_pub_hash=$1;", - 1, NULL); - - - /* Used in #postgres_reserve_get() */ - PREPARE ("reserve_get", - "SELECT" - " current_balance_val" - ",current_balance_frac" - ",current_balance_curr" - ",expiration_date" - " FROM reserves" - " WHERE reserve_pub=$1" - " LIMIT 1;", - 1, NULL); - - /* Used in #postgres_reserves_in_insert() when the reserve is new */ - PREPARE ("reserve_create", - "INSERT INTO reserves " - "(reserve_pub" - ",account_details" - ",current_balance_val" - ",current_balance_frac" - ",current_balance_curr" - ",expiration_date" - ") VALUES " - "($1, $2, $3, $4, $5, $6);", - 6, NULL); - - /* Used in #postgres_insert_reserve_closed() */ - PREPARE ("reserves_close_insert", - "INSERT INTO reserves_close " - "(reserve_pub" - ",execution_date" - ",wtid" - ",receiver_account" - ",amount_val" - ",amount_frac" - ",amount_curr" - ",closing_fee_val" - ",closing_fee_frac" - ",closing_fee_curr" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);", - 10, NULL); - - /* Used in #postgres_reserves_update() when the reserve is updated */ - PREPARE ("reserve_update", - "UPDATE reserves" - " SET" - " expiration_date=$1 " - ",current_balance_val=$2 " - ",current_balance_frac=$3 " - "WHERE current_balance_curr=$4 AND reserve_pub=$5", - 5, NULL); - - /* Used in #postgres_reserves_in_insert() to store transaction details */ - PREPARE ("reserves_in_add_transaction", - "INSERT INTO reserves_in " - "(reserve_pub" - ",wire_reference" - ",credit_val" - ",credit_frac" - ",credit_curr" - ",sender_account_details" - ",execution_date" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7);", - 7, NULL); - - - /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound - transactions for reserves with serial id '\geq' the given parameter */ - PREPARE ("reserves_in_get_latest_wire_reference", - "SELECT" - " wire_reference" - " FROM reserves_in" - " ORDER BY reserve_in_serial_id DESC LIMIT 1", - 0, NULL); - - /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound - transactions for reserves with serial id '\geq' the given parameter */ - PREPARE ("audit_reserves_in_get_transactions_incr", - "SELECT" - " reserve_pub" - ",wire_reference" - ",credit_val" - ",credit_frac" - ",credit_curr" - ",execution_date" - ",sender_account_details" - ",reserve_in_serial_id" - " FROM reserves_in" - " WHERE reserve_in_serial_id>=$1" - " ORDER BY reserve_in_serial_id", - 1, NULL); - - /* Used in #postgres_get_reserve_history() to obtain inbound transactions - for a reserve */ - PREPARE ("reserves_in_get_transactions", - "SELECT" - " wire_reference" - ",credit_val" - ",credit_frac" - ",credit_curr" - ",execution_date" - ",sender_account_details" - " FROM reserves_in" - " WHERE reserve_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_withdraw_info() to store - the signature of a blinded coin with the blinded coin's - details before returning it during /reserve/withdraw. We store - the coin's denomination information (public key, signature) - and the blinded message as well as the reserve that the coin - is being withdrawn from and the signature of the message - authorizing the withdrawal. */ - PREPARE ("insert_withdraw_info", - "INSERT INTO reserves_out " - "(h_blind_ev" - ",denom_pub_hash" - ",denom_sig" - ",reserve_pub" - ",reserve_sig" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9);", - 9, NULL); - - /* Used in #postgres_get_withdraw_info() to - locate the response for a /reserve/withdraw request - using the hash of the blinded message. Used to - make sure /reserve/withdraw requests are idempotent. */ - PREPARE ("get_withdraw_info", - "SELECT" - " denom.denom_pub" - ",denom_sig" - ",reserve_sig" - ",reserve_pub" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_withdraw_val" - ",denom.fee_withdraw_frac" - ",denom.fee_withdraw_curr" - " FROM reserves_out" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE h_blind_ev=$1", - 1, NULL); - - /* Used during #postgres_get_reserve_history() to - obtain all of the /reserve/withdraw operations that - have been performed on a given reserve. (i.e. to - demonstrate double-spending) */ - PREPARE ("get_reserves_out", - "SELECT" - " h_blind_ev" - ",denom.denom_pub" - ",denom_sig" - ",reserve_sig" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_withdraw_val" - ",denom.fee_withdraw_frac" - ",denom.fee_withdraw_curr" - " FROM reserves_out" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE reserve_pub=$1;", - 1, NULL); - - /* Used in #postgres_select_reserves_out_above_serial_id() */ - PREPARE ("audit_get_reserves_out_incr", - "SELECT" - " h_blind_ev" - ",denom.denom_pub" - ",denom_sig" - ",reserve_sig" - ",reserve_pub" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",reserve_out_serial_id" - " FROM reserves_out" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE reserve_out_serial_id>=$1" - " ORDER BY reserve_out_serial_id ASC", - 1, NULL); - - /* Used in #postgres_get_refresh_session() to fetch - high-level information about a refresh session */ - PREPARE ("get_refresh_session", - "SELECT" - " old_coin_pub" - ",old_coin_sig" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_refresh_val " - ",denom.fee_refresh_frac " - ",denom.fee_refresh_curr " - ",num_newcoins" - ",noreveal_index" - " FROM refresh_sessions" - " JOIN known_coins ON (refresh_sessions.old_coin_pub = known_coins.coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE session_hash=$1 ", - 1, NULL); - - /* Used in #postgres_select_refreshs_above_serial_id() to fetch - refresh session with id '\geq' the given parameter */ - PREPARE ("audit_get_refresh_sessions_incr", - "SELECT" - " denom.denom_pub" - ",old_coin_pub" - ",old_coin_sig" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",num_newcoins" - ",noreveal_index" - ",melt_serial_id" - ",session_hash" - " FROM refresh_sessions" - " JOIN known_coins kc ON (refresh_sessions.old_coin_pub = kc.coin_pub)" - " JOIN denominations denom ON (kc.denom_pub_hash = denom.denom_pub_hash)" - " WHERE melt_serial_id>=$1" - " ORDER BY melt_serial_id ASC", - 1, NULL); - - /* Used in #postgres_create_refresh_session() to store - high-level information about a refresh session */ - PREPARE ("insert_refresh_session", - "INSERT INTO refresh_sessions " - "(session_hash " - ",old_coin_pub " - ",old_coin_sig " - ",amount_with_fee_val " - ",amount_with_fee_frac " - ",amount_with_fee_curr " - ",num_newcoins " - ",noreveal_index " - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8);", - 8, NULL); - - /* Used in #postgres_get_known_coin() to fetch - the denomination public key and signature for - a coin known to the exchange. */ - PREPARE ("get_known_coin", - "SELECT" - " denom.denom_pub" - ",denom_sig" - " FROM known_coins" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE coin_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_known_coin() to store - the denomination public key and signature for - a coin known to the exchange. */ - PREPARE ("insert_known_coin", - "INSERT INTO known_coins " - "(coin_pub" - ",denom_pub_hash" - ",denom_sig" - ") VALUES " - "($1,$2,$3);", - 3, NULL); - - /* Store information about the desired denominations for a - refresh operation, used in #postgres_insert_refresh_order() */ - PREPARE ("insert_refresh_order", - "INSERT INTO refresh_order " - "(newcoin_index " - ",session_hash " - ",denom_pub_hash " - ") VALUES " - "($1, $2, $3);", - 3, NULL); - - /* Obtain information about the desired denominations for a - refresh operation, used in #postgres_get_refresh_order() */ - PREPARE ("get_refresh_order", - "SELECT denom_pub" - " FROM refresh_order" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE session_hash=$1 AND newcoin_index=$2", - 2, NULL); - - /* Query the 'refresh_sessions' by coin public key */ - PREPARE ("get_refresh_session_by_coin", - "SELECT" - " session_hash" - ",old_coin_sig" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_refresh_val " - ",denom.fee_refresh_frac " - ",denom.fee_refresh_curr " - " FROM refresh_sessions" - " JOIN known_coins ON (refresh_sessions.old_coin_pub = known_coins.coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE old_coin_pub=$1", - 1, NULL); - - /* Fetch refunds with rowid '\geq' the given parameter */ - PREPARE ("audit_get_refunds_incr", - "SELECT" - " merchant_pub" - ",merchant_sig" - ",h_contract_terms" - ",rtransaction_id" - ",denom.denom_pub" - ",coin_pub" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",refund_serial_id" - " FROM refunds" - " JOIN known_coins kc USING (coin_pub)" - " JOIN denominations denom ON (kc.denom_pub_hash = denom.denom_pub_hash)" - " WHERE refund_serial_id>=$1" - " ORDER BY refund_serial_id ASC", - 1, NULL); - - /* Query the 'refunds' by coin public key */ - PREPARE ("get_refunds_by_coin", - "SELECT" - " merchant_pub" - ",merchant_sig" - ",h_contract_terms" - ",rtransaction_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_refund_val " - ",denom.fee_refund_frac " - ",denom.fee_refund_curr " - " FROM refunds" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE coin_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_transfer_public_key() to - store commitments */ - PREPARE ("insert_transfer_public_key", - "INSERT INTO refresh_transfer_public_key " - "(session_hash" - ",transfer_pub" - ") VALUES " - "($1, $2);", - 3, NULL); - - /* Used in #postgres_get_refresh_transfer_public_key() to - retrieve original commitments during /refresh/reveal */ - PREPARE ("get_refresh_transfer_public_key", - "SELECT" - " transfer_pub" - " FROM refresh_transfer_public_key" - " WHERE session_hash=$1", - 1, NULL); - - /* Used in #postgres_insert_refresh_commit_coins() to - store coin commitments. */ - PREPARE ("insert_refresh_commit_coin", - "INSERT INTO refresh_commit_coin " - "(session_hash" - ",newcoin_index" - ",coin_ev" - ") VALUES " - "($1, $2, $3);", - 3, NULL); - - /* Used in #postgres_get_refresh_commit_coins() to - retrieve the original coin envelopes, to either be - verified or signed. */ - PREPARE ("get_refresh_commit_coin", - "SELECT" - " coin_ev" - " FROM refresh_commit_coin" - " WHERE session_hash=$1 AND newcoin_index=$2", - 2, NULL); - - /* Store information about a /deposit the exchange is to execute. - Used in #postgres_insert_deposit(). */ - PREPARE ("insert_deposit", - "INSERT INTO deposits " - "(coin_pub" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",timestamp" - ",refund_deadline" - ",wire_deadline" - ",merchant_pub" - ",h_contract_terms" - ",h_wire" - ",coin_sig" - ",wire" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," - " $11, $12);", - 12, NULL); - - /* Used in #postgres_insert_refund() to store refund information */ - PREPARE ("insert_refund", - "INSERT INTO refunds " - "(coin_pub " - ",merchant_pub " - ",merchant_sig " - ",h_contract_terms " - ",rtransaction_id " - ",amount_with_fee_val " - ",amount_with_fee_frac " - ",amount_with_fee_curr " - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8);", - 8, NULL); - - /* Fetch an existing deposit request, used to ensure idempotency - during /deposit processing. Used in #postgres_have_deposit(). */ - PREPARE ("get_deposit", - "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",timestamp" - ",refund_deadline" - ",wire_deadline" - ",h_contract_terms" - ",h_wire" - " FROM deposits" - " WHERE (" - " (coin_pub=$1) AND" - " (h_contract_terms=$2) AND" - " (merchant_pub=$3)" - " )", - 3, NULL); - - /* Fetch deposits with rowid '\geq' the given parameter */ - PREPARE ("audit_get_deposits_incr", - "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",timestamp" - ",merchant_pub" - ",denom.denom_pub" - ",coin_pub" - ",coin_sig" - ",refund_deadline" - ",wire_deadline" - ",h_contract_terms" - ",wire" - ",done" - ",deposit_serial_id" - " FROM deposits" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE (" - " (deposit_serial_id>=$1)" - " )" - " ORDER BY deposit_serial_id ASC", - 1, NULL); - - /* Fetch an existing deposit request. - Used in #postgres_wire_lookup_deposit_wtid(). */ - PREPARE ("get_deposit_for_wtid", - "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",denom.fee_deposit_curr" - ",wire_deadline" - " FROM deposits" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE (" - " (coin_pub=$1) AND" - " (merchant_pub=$2) AND" - " (h_contract_terms=$3) AND" - " (h_wire=$4)" - " )", - 4, NULL); - - /* Used in #postgres_get_ready_deposit() */ - PREPARE ("deposits_get_ready", - "SELECT" - " deposit_serial_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",denom.fee_deposit_curr" - ",wire_deadline" - ",h_contract_terms" - ",wire" - ",merchant_pub" - ",coin_pub" - " FROM deposits" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE" - " tiny=false AND" - " done=false AND" - " wire_deadline<=$1 AND" - " refund_deadline<$1" - " ORDER BY wire_deadline ASC" - " LIMIT 1", - 1, NULL); - - /* Used in #postgres_iterate_matching_deposits() */ - PREPARE ("deposits_iterate_matching", - "SELECT" - " deposit_serial_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",denom.fee_deposit_curr" - ",wire_deadline" - ",h_contract_terms" - ",coin_pub" - " FROM deposits" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE" - " merchant_pub=$1 AND" - " h_wire=$2 AND" - " done=false" - " ORDER BY wire_deadline ASC" - " LIMIT " TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT_STR, - 2, NULL); - - /* Used in #postgres_mark_deposit_tiny() */ - PREPARE ("mark_deposit_tiny", - "UPDATE deposits" - " SET tiny=true" - " WHERE deposit_serial_id=$1", - 1, NULL); - - /* Used in #postgres_mark_deposit_done() */ - PREPARE ("mark_deposit_done", - "UPDATE deposits" - " SET done=true" - " WHERE deposit_serial_id=$1", - 1, NULL); - - /* Used in #postgres_test_deposit_done() */ - PREPARE ("test_deposit_done", - "SELECT done" - " FROM deposits" - " WHERE coin_pub=$1" - " AND merchant_pub=$2" - " AND h_contract_terms=$3" - " AND h_wire=$4", - 5, NULL); - - /* Used in #postgres_get_coin_transactions() to obtain information - about how a coin has been spend with /deposit requests. */ - PREPARE ("get_deposit_with_coin_pub", - "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",denom.fee_deposit_curr" - ",timestamp" - ",refund_deadline" - ",merchant_pub" - ",h_contract_terms" - ",h_wire" - ",wire" - ",coin_sig" - " FROM deposits" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " WHERE coin_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_refresh_out() to store the - generated signature(s) for future requests, i.e. /refresh/link */ - PREPARE ("insert_refresh_out", - "INSERT INTO refresh_out " - "(session_hash" - ",newcoin_index" - ",ev_sig" - ") VALUES " - "($1, $2, $3)", - 3, NULL); - - /* Used in #postgres_get_refresh_out() to test if the - generated signature(s) already exists */ - PREPARE ("get_refresh_out", - "SELECT ev_sig" - " FROM refresh_out" - " WHERE session_hash=$1" - " AND newcoin_index=$2", - 2, NULL); - - /* Used in #postgres_get_link_data_list(). We use the session_hash - to obtain the "noreveal_index" for that session, and then select the - corresponding signatures (ev_sig) and the denomination keys from - the respective tables (namely refresh_melts and refresh_order) - using the session_hash as the primary filter (on join) and the - 'noreveal_index' to constrain the selection on the commitment. - We also want to get the triplet for each of the newcoins, so we - have another constraint to ensure we get each triplet with - matching "newcoin_index" values. NOTE: This may return many - results, both for different sessions and for the different coins - being exchangeed in the refresh ops. NOTE: There may be more - efficient ways to express the same query. */ - PREPARE ("get_link", - "SELECT " - " ev_sig" - ",denoms.denom_pub" - " FROM refresh_sessions" - " JOIN refresh_order ro USING (session_hash)" - " JOIN refresh_commit_coin rcc USING (session_hash)" - " JOIN refresh_out rc USING (session_hash)" - " JOIN denominations denoms ON (ro.denom_pub_hash = denoms.denom_pub_hash)" - " WHERE ro.session_hash=$1" - " AND ro.newcoin_index=rcc.newcoin_index" - " AND ro.newcoin_index=rc.newcoin_index", - 1, NULL); - - /* Used in #postgres_get_transfer(). Given the public key of a - melted coin, we obtain the corresponding encrypted link secret - and the transfer public key. This is done by first finding - the session_hash(es) of all sessions the coin was melted into, - and then constraining the result to the selected "noreveal_index". - NOTE: This may (in theory) return multiple results, one per session - that the old coin was melted into. */ - PREPARE ("get_transfer", - "SELECT transfer_pub,session_hash" - " FROM refresh_sessions rs" - " JOIN refresh_transfer_public_key rcl USING (session_hash)" - " WHERE rs.old_coin_pub=$1", - 1, NULL); - - /* Used in #postgres_lookup_wire_transfer */ - PREPARE ("lookup_transactions", - "SELECT" - " aggregation_serial_id" - ",deposits.h_contract_terms" - ",deposits.wire" - ",deposits.h_wire" - ",deposits.coin_pub" - ",deposits.merchant_pub" - ",wire_out.execution_date" - ",deposits.amount_with_fee_val" - ",deposits.amount_with_fee_frac" - ",deposits.amount_with_fee_curr" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",denom.fee_deposit_curr" - " FROM aggregation_tracking" - " JOIN deposits USING (deposit_serial_id)" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " JOIN wire_out USING (wtid_raw)" - " WHERE wtid_raw=$1", - 1, NULL); - - /* Used in #postgres_wire_lookup_deposit_wtid */ - PREPARE ("lookup_deposit_wtid", - "SELECT" - " aggregation_tracking.wtid_raw" - ",wire_out.execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",denom.fee_deposit_curr" - " FROM deposits" - " JOIN aggregation_tracking USING (deposit_serial_id)" - " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" - " JOIN wire_out USING (wtid_raw)" - " WHERE coin_pub=$1" - " AND h_contract_terms=$2" - " AND h_wire=$3" - " AND merchant_pub=$4", - 4, NULL); - - /* Used in #postgres_insert_aggregation_tracking */ - PREPARE ("insert_aggregation_tracking", - "INSERT INTO aggregation_tracking " - "(deposit_serial_id" - ",wtid_raw" - ") VALUES " - "($1, $2)", - 2, NULL); - - /* Used in #postgres_get_wire_fee() */ - PREPARE ("get_wire_fee", - "SELECT " - " start_date" - ",end_date" - ",wire_fee_val" - ",wire_fee_frac" - ",wire_fee_curr" - ",master_sig" - " FROM wire_fee" - " WHERE wire_method=$1" - " AND start_date <= $2" - " AND end_date > $2", - 2, NULL); - - /* Used in #postgres_insert_wire_fee */ - PREPARE ("insert_wire_fee", - "INSERT INTO wire_fee " - "(wire_method" - ",start_date" - ",end_date" - ",wire_fee_val" - ",wire_fee_frac" - ",wire_fee_curr" - ",master_sig" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7)", - 7, NULL); - - /* Used in #postgres_store_wire_transfer_out */ - PREPARE ("insert_wire_out", - "INSERT INTO wire_out " - "(execution_date" - ",wtid_raw" - ",wire_target" - ",amount_val" - ",amount_frac" - ",amount_curr" - ") VALUES " - "($1, $2, $3, $4, $5, $6)", - 6, NULL); - - /* Used in #postgres_wire_prepare_data_insert() to store - wire transfer information before actually committing it with the bank */ - PREPARE ("wire_prepare_data_insert", - "INSERT INTO prewire " - "(type" - ",buf" - ") VALUES " - "($1, $2)", - 2, NULL); - - /* Used in #postgres_wire_prepare_data_mark_finished() */ - PREPARE ("wire_prepare_data_mark_done", - "UPDATE prewire" - " SET finished=true" - " WHERE prewire_uuid=$1", - 1, NULL); - - /* Used in #postgres_wire_prepare_data_get() */ - PREPARE ("wire_prepare_data_get", - "SELECT" - " prewire_uuid" - ",type" - ",buf" - " FROM prewire" - " WHERE finished=false" - " ORDER BY prewire_uuid ASC" - " LIMIT 1", - 0, NULL); - - /* Used in #postgres_gc() */ - PREPARE ("gc_prewire", - "DELETE" - " FROM prewire" - " WHERE finished=true", - 0, NULL); - - /* Used in #postgres_select_wire_out_above_serial_id() */ - PREPARE ("audit_get_wire_incr", - "SELECT" - " wireout_uuid" - ",execution_date" - ",wtid_raw" - ",wire_target" - ",amount_val" - ",amount_frac" - ",amount_curr" - " FROM wire_out" - " WHERE wireout_uuid>=$1" - " ORDER BY wireout_uuid ASC", - 1, NULL); - - /* Used in #postgres_insert_payback_request() to store payback - information */ - PREPARE ("payback_insert", - "INSERT INTO payback " - "(reserve_pub" - ",coin_pub" - ",coin_sig" - ",coin_blind" - ",amount_val" - ",amount_frac" - ",amount_curr" - ",timestamp" - ",h_blind_ev" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9)", - 9, NULL); - - /* Used in #postgres_select_payback_above_serial_id() to obtain payback transactions */ - PREPARE ("payback_get_incr", - "SELECT" - " payback_uuid" - ",timestamp" - ",reserve_pub" - ",coin_pub" - ",coin_sig" - ",coin_blind" - ",h_blind_ev" - ",denoms.denom_pub" - ",coins.denom_sig" - ",amount_val" - ",amount_frac" - ",amount_curr" - " FROM payback" - " JOIN known_coins coins USING (coin_pub)" - " JOIN denominations denoms USING (denom_pub_hash)" - " WHERE payback_uuid>=$1" - " ORDER BY payback_uuid ASC", - 1, NULL); - + struct GNUNET_PQ_PreparedStatement ps[] = { + /* Used in #postgres_insert_denomination_info() */ + GNUNET_PQ_make_prepare ("denomination_insert", + "INSERT INTO denominations " + "(denom_pub_hash" + ",denom_pub" + ",master_pub" + ",master_sig" + ",valid_from" + ",expire_withdraw" + ",expire_deposit" + ",expire_legal" + ",coin_val" /* value of this denom */ + ",coin_frac" /* fractional value of this denom */ + ",coin_curr" /* assuming same currency for fees */ + ",fee_withdraw_val" + ",fee_withdraw_frac" + ",fee_withdraw_curr" /* must match coin_curr */ + ",fee_deposit_val" + ",fee_deposit_frac" + ",fee_deposit_curr" /* must match coin_curr */ + ",fee_refresh_val" + ",fee_refresh_frac" + ",fee_refresh_curr" /* must match coin_curr */ + ",fee_refund_val" + ",fee_refund_frac" + ",fee_refund_curr" /* must match coin_curr */ + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," + " $11, $12, $13, $14, $15, $16, $17, $18," + " $19, $20, $21, $22, $23);", + 23), + /* Used in #postgres_get_denomination_info() */ + GNUNET_PQ_make_prepare ("denomination_get", + "SELECT" + " master_pub" + ",master_sig" + ",valid_from" + ",expire_withdraw" + ",expire_deposit" + ",expire_legal" + ",coin_val" /* value of this denom */ + ",coin_frac" /* fractional value of this denom */ + ",coin_curr" /* assuming same currency for fees */ + ",fee_withdraw_val" + ",fee_withdraw_frac" + ",fee_withdraw_curr" /* must match coin_curr */ + ",fee_deposit_val" + ",fee_deposit_frac" + ",fee_deposit_curr" /* must match coin_curr */ + ",fee_refresh_val" + ",fee_refresh_frac" + ",fee_refresh_curr" /* must match coin_curr */ + ",fee_refund_val" + ",fee_refund_frac" + ",fee_refund_curr" /* must match coin_curr */ + " FROM denominations" + " WHERE denom_pub=$1;", + 1), + /* Used in #postgres_insert_denomination_revocation() */ + GNUNET_PQ_make_prepare ("denomination_revocation_insert", + "INSERT INTO denomination_revocations " + "(denom_pub_hash" + ",master_sig" + ") VALUES " + "($1, $2);", + 2), + /* Used in #postgres_get_denomination_revocation() */ + GNUNET_PQ_make_prepare ("denomination_revocation_get", + "SELECT" + " master_sig" + ",denom_revocations_serial_id" + " FROM denomination_revocations" + " WHERE denom_pub_hash=$1;", + 1), + /* Used in #postgres_reserve_get() */ + GNUNET_PQ_make_prepare ("reserve_get", + "SELECT" + " current_balance_val" + ",current_balance_frac" + ",current_balance_curr" + ",expiration_date" + " FROM reserves" + " WHERE reserve_pub=$1" + " LIMIT 1;", + 1), + /* Used in #postgres_reserves_in_insert() when the reserve is new */ + GNUNET_PQ_make_prepare ("reserve_create", + "INSERT INTO reserves " + "(reserve_pub" + ",account_details" + ",current_balance_val" + ",current_balance_frac" + ",current_balance_curr" + ",expiration_date" + ") VALUES " + "($1, $2, $3, $4, $5, $6);", + 6), + /* Used in #postgres_insert_reserve_closed() */ + GNUNET_PQ_make_prepare ("reserves_close_insert", + "INSERT INTO reserves_close " + "(reserve_pub" + ",execution_date" + ",wtid" + ",receiver_account" + ",amount_val" + ",amount_frac" + ",amount_curr" + ",closing_fee_val" + ",closing_fee_frac" + ",closing_fee_curr" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);", + 10), + /* Used in #postgres_reserves_update() when the reserve is updated */ + GNUNET_PQ_make_prepare ("reserve_update", + "UPDATE reserves" + " SET" + " expiration_date=$1 " + ",current_balance_val=$2 " + ",current_balance_frac=$3" + " WHERE current_balance_curr=$4" + " AND reserve_pub=$5;", + 5), + /* Used in #postgres_reserves_in_insert() to store transaction details */ + GNUNET_PQ_make_prepare ("reserves_in_add_transaction", + "INSERT INTO reserves_in " + "(reserve_pub" + ",wire_reference" + ",credit_val" + ",credit_frac" + ",credit_curr" + ",sender_account_details" + ",execution_date" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7);", + 7), + /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound + transactions for reserves with serial id '\geq' the given parameter */ + GNUNET_PQ_make_prepare ("reserves_in_get_latest_wire_reference", + "SELECT" + " wire_reference" + " FROM reserves_in" + " ORDER BY reserve_in_serial_id DESC" + " LIMIT 1;", + 0), + /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound + transactions for reserves with serial id '\geq' the given parameter */ + GNUNET_PQ_make_prepare ("audit_reserves_in_get_transactions_incr", + "SELECT" + " reserve_pub" + ",wire_reference" + ",credit_val" + ",credit_frac" + ",credit_curr" + ",execution_date" + ",sender_account_details" + ",reserve_in_serial_id" + " FROM reserves_in" + " WHERE reserve_in_serial_id>=$1" + " ORDER BY reserve_in_serial_id;", + 1), + /* Used in #postgres_get_reserve_history() to obtain inbound transactions + for a reserve */ + GNUNET_PQ_make_prepare ("reserves_in_get_transactions", + "SELECT" + " wire_reference" + ",credit_val" + ",credit_frac" + ",credit_curr" + ",execution_date" + ",sender_account_details" + " FROM reserves_in" + " WHERE reserve_pub=$1;", + 1), + /* Used in #postgres_insert_withdraw_info() to store + the signature of a blinded coin with the blinded coin's + details before returning it during /reserve/withdraw. We store + the coin's denomination information (public key, signature) + and the blinded message as well as the reserve that the coin + is being withdrawn from and the signature of the message + authorizing the withdrawal. */ + GNUNET_PQ_make_prepare ("insert_withdraw_info", + "INSERT INTO reserves_out " + "(h_blind_ev" + ",denom_pub_hash" + ",denom_sig" + ",reserve_pub" + ",reserve_sig" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9);", + 9), + /* Used in #postgres_get_withdraw_info() to + locate the response for a /reserve/withdraw request + using the hash of the blinded message. Used to + make sure /reserve/withdraw requests are idempotent. */ + GNUNET_PQ_make_prepare ("get_withdraw_info", + "SELECT" + " denom.denom_pub" + ",denom_sig" + ",reserve_sig" + ",reserve_pub" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_withdraw_val" + ",denom.fee_withdraw_frac" + ",denom.fee_withdraw_curr" + " FROM reserves_out" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE h_blind_ev=$1;", + 1), + /* Used during #postgres_get_reserve_history() to + obtain all of the /reserve/withdraw operations that + have been performed on a given reserve. (i.e. to + demonstrate double-spending) */ + GNUNET_PQ_make_prepare ("get_reserves_out", + "SELECT" + " h_blind_ev" + ",denom.denom_pub" + ",denom_sig" + ",reserve_sig" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_withdraw_val" + ",denom.fee_withdraw_frac" + ",denom.fee_withdraw_curr" + " FROM reserves_out" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE reserve_pub=$1;", + 1), + /* Used in #postgres_select_reserves_out_above_serial_id() */ + GNUNET_PQ_make_prepare ("audit_get_reserves_out_incr", + "SELECT" + " h_blind_ev" + ",denom.denom_pub" + ",denom_sig" + ",reserve_sig" + ",reserve_pub" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",reserve_out_serial_id" + " FROM reserves_out" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE reserve_out_serial_id>=$1" + " ORDER BY reserve_out_serial_id ASC;", + 1), + /* Used in #postgres_get_refresh_session() to fetch + high-level information about a refresh session */ + GNUNET_PQ_make_prepare ("get_refresh_session", + "SELECT" + " old_coin_pub" + ",old_coin_sig" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_refresh_val " + ",denom.fee_refresh_frac " + ",denom.fee_refresh_curr " + ",num_newcoins" + ",noreveal_index" + " FROM refresh_sessions" + " JOIN known_coins" + " ON (refresh_sessions.old_coin_pub = known_coins.coin_pub)" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE session_hash=$1;", + 1), + /* Used in #postgres_select_refreshs_above_serial_id() to fetch + refresh session with id '\geq' the given parameter */ + GNUNET_PQ_make_prepare ("audit_get_refresh_sessions_incr", + "SELECT" + " denom.denom_pub" + ",old_coin_pub" + ",old_coin_sig" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",num_newcoins" + ",noreveal_index" + ",melt_serial_id" + ",session_hash" + " FROM refresh_sessions" + " JOIN known_coins kc" + " ON (refresh_sessions.old_coin_pub = kc.coin_pub)" + " JOIN denominations denom" + " ON (kc.denom_pub_hash = denom.denom_pub_hash)" + " WHERE melt_serial_id>=$1" + " ORDER BY melt_serial_id ASC;", + 1), + /* Used in #postgres_create_refresh_session() to store + high-level information about a refresh session */ + GNUNET_PQ_make_prepare ("insert_refresh_session", + "INSERT INTO refresh_sessions " + "(session_hash " + ",old_coin_pub " + ",old_coin_sig " + ",amount_with_fee_val " + ",amount_with_fee_frac " + ",amount_with_fee_curr " + ",num_newcoins " + ",noreveal_index " + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8);", + 8), + /* Used in #postgres_get_known_coin() to fetch + the denomination public key and signature for + a coin known to the exchange. */ + GNUNET_PQ_make_prepare ("get_known_coin", + "SELECT" + " denom.denom_pub" + ",denom_sig" + " FROM known_coins" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE coin_pub=$1;", + 1), + /* Used in #postgres_insert_known_coin() to store + the denomination public key and signature for + a coin known to the exchange. */ + GNUNET_PQ_make_prepare ("insert_known_coin", + "INSERT INTO known_coins " + "(coin_pub" + ",denom_pub_hash" + ",denom_sig" + ") VALUES " + "($1,$2,$3);", + 3), + /* Store information about the desired denominations for a + refresh operation, used in #postgres_insert_refresh_order() */ + GNUNET_PQ_make_prepare ("insert_refresh_order", + "INSERT INTO refresh_order " + "(newcoin_index " + ",session_hash " + ",denom_pub_hash " + ") VALUES " + "($1, $2, $3);", + 3), + /* Obtain information about the desired denominations for a + refresh operation, used in #postgres_get_refresh_order() */ + GNUNET_PQ_make_prepare ("get_refresh_order", + "SELECT denom_pub" + " FROM refresh_order" + " JOIN denominations denom " + " USING (denom_pub_hash)" + " WHERE session_hash=$1" + " AND newcoin_index=$2;", + 2), + /* Query the 'refresh_sessions' by coin public key */ + GNUNET_PQ_make_prepare ("get_refresh_session_by_coin", + "SELECT" + " session_hash" + ",old_coin_sig" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_refresh_val " + ",denom.fee_refresh_frac " + ",denom.fee_refresh_curr " + " FROM refresh_sessions" + " JOIN known_coins " + " ON (refresh_sessions.old_coin_pub = known_coins.coin_pub)" + " JOIN denominations denom USING (denom_pub_hash)" + " WHERE old_coin_pub=$1;", + 1), + /* Fetch refunds with rowid '\geq' the given parameter */ + GNUNET_PQ_make_prepare ("audit_get_refunds_incr", + "SELECT" + " merchant_pub" + ",merchant_sig" + ",h_contract_terms" + ",rtransaction_id" + ",denom.denom_pub" + ",coin_pub" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",refund_serial_id" + " FROM refunds" + " JOIN known_coins kc USING (coin_pub)" + " JOIN denominations denom ON (kc.denom_pub_hash = denom.denom_pub_hash)" + " WHERE refund_serial_id>=$1" + " ORDER BY refund_serial_id ASC;", + 1), + /* Query the 'refunds' by coin public key */ + GNUNET_PQ_make_prepare ("get_refunds_by_coin", + "SELECT" + " merchant_pub" + ",merchant_sig" + ",h_contract_terms" + ",rtransaction_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_refund_val " + ",denom.fee_refund_frac " + ",denom.fee_refund_curr " + " FROM refunds" + " JOIN known_coins USING (coin_pub)" + " JOIN denominations denom USING (denom_pub_hash)" + " WHERE coin_pub=$1;", + 1), + /* Used in #postgres_insert_transfer_public_key() to + store commitments */ + GNUNET_PQ_make_prepare ("insert_transfer_public_key", + "INSERT INTO refresh_transfer_public_key " + "(session_hash" + ",transfer_pub" + ") VALUES " + "($1, $2);", + 2), + /* Used in #postgres_get_refresh_transfer_public_key() to + retrieve original commitments during /refresh/reveal */ + GNUNET_PQ_make_prepare ("get_refresh_transfer_public_key", + "SELECT" + " transfer_pub" + " FROM refresh_transfer_public_key" + " WHERE session_hash=$1;", + 1), + /* Used in #postgres_insert_refresh_commit_coins() to + store coin commitments. */ + GNUNET_PQ_make_prepare ("insert_refresh_commit_coin", + "INSERT INTO refresh_commit_coin " + "(session_hash" + ",newcoin_index" + ",coin_ev" + ") VALUES " + "($1, $2, $3);", + 3), + /* Used in #postgres_get_refresh_commit_coins() to + retrieve the original coin envelopes, to either be + verified or signed. */ + GNUNET_PQ_make_prepare ("get_refresh_commit_coin", + "SELECT" + " coin_ev" + " FROM refresh_commit_coin" + " WHERE session_hash=$1 AND newcoin_index=$2;", + 2), + /* Store information about a /deposit the exchange is to execute. + Used in #postgres_insert_deposit(). */ + GNUNET_PQ_make_prepare ("insert_deposit", + "INSERT INTO deposits " + "(coin_pub" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",timestamp" + ",refund_deadline" + ",wire_deadline" + ",merchant_pub" + ",h_contract_terms" + ",h_wire" + ",coin_sig" + ",wire" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," + " $11, $12);", + 12), + /* Used in #postgres_insert_refund() to store refund information */ + GNUNET_PQ_make_prepare ("insert_refund", + "INSERT INTO refunds " + "(coin_pub " + ",merchant_pub " + ",merchant_sig " + ",h_contract_terms " + ",rtransaction_id " + ",amount_with_fee_val " + ",amount_with_fee_frac " + ",amount_with_fee_curr " + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8);", + 8), + /* Fetch an existing deposit request, used to ensure idempotency + during /deposit processing. Used in #postgres_have_deposit(). */ + GNUNET_PQ_make_prepare ("get_deposit", + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",timestamp" + ",refund_deadline" + ",wire_deadline" + ",h_contract_terms" + ",h_wire" + " FROM deposits" + " WHERE (" + " (coin_pub=$1)" + " AND (h_contract_terms=$2)" + " AND (merchant_pub=$3)" + " );", + 3), + /* Fetch deposits with rowid '\geq' the given parameter */ + GNUNET_PQ_make_prepare ("audit_get_deposits_incr", + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",timestamp" + ",merchant_pub" + ",denom.denom_pub" + ",coin_pub" + ",coin_sig" + ",refund_deadline" + ",wire_deadline" + ",h_contract_terms" + ",wire" + ",done" + ",deposit_serial_id" + " FROM deposits" + " JOIN known_coins USING (coin_pub)" + " JOIN denominations denom USING (denom_pub_hash)" + " WHERE (" + " (deposit_serial_id>=$1)" + " )" + " ORDER BY deposit_serial_id ASC;", + 1), + /* Fetch an existing deposit request. + Used in #postgres_wire_lookup_deposit_wtid(). */ + GNUNET_PQ_make_prepare ("get_deposit_for_wtid", + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_deposit_val" + ",denom.fee_deposit_frac" + ",denom.fee_deposit_curr" + ",wire_deadline" + " FROM deposits" + " JOIN known_coins USING (coin_pub)" + " JOIN denominations denom USING (denom_pub_hash)" + " WHERE (" + " (coin_pub=$1)" + " AND (merchant_pub=$2)" + " AND (h_contract_terms=$3)" + " AND (h_wire=$4)" + " );", + 4), + /* Used in #postgres_get_ready_deposit() */ + GNUNET_PQ_make_prepare ("deposits_get_ready", + "SELECT" + " deposit_serial_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_deposit_val" + ",denom.fee_deposit_frac" + ",denom.fee_deposit_curr" + ",wire_deadline" + ",h_contract_terms" + ",wire" + ",merchant_pub" + ",coin_pub" + " FROM deposits" + " JOIN known_coins USING (coin_pub)" + " JOIN denominations denom USING (denom_pub_hash)" + " WHERE tiny=false" + " AND done=false" + " AND wire_deadline<=$1" + " AND refund_deadline<$1" + " ORDER BY wire_deadline ASC" + " LIMIT 1;", + 1), + /* Used in #postgres_iterate_matching_deposits() */ + GNUNET_PQ_make_prepare ("deposits_iterate_matching", + "SELECT" + " deposit_serial_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_deposit_val" + ",denom.fee_deposit_frac" + ",denom.fee_deposit_curr" + ",wire_deadline" + ",h_contract_terms" + ",coin_pub" + " FROM deposits" + " JOIN known_coins" + " USING (coin_pub)" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE" + " merchant_pub=$1 AND" + " h_wire=$2 AND" + " done=false" + " ORDER BY wire_deadline ASC" + " LIMIT " TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT_STR ";", + 2), + /* Used in #postgres_mark_deposit_tiny() */ + GNUNET_PQ_make_prepare ("mark_deposit_tiny", + "UPDATE deposits" + " SET tiny=true" + " WHERE deposit_serial_id=$1", + 1), + /* Used in #postgres_mark_deposit_done() */ + GNUNET_PQ_make_prepare ("mark_deposit_done", + "UPDATE deposits" + " SET done=true" + " WHERE deposit_serial_id=$1;", + 1), + /* Used in #postgres_test_deposit_done() */ + GNUNET_PQ_make_prepare ("test_deposit_done", + "SELECT done" + " FROM deposits" + " WHERE coin_pub=$1" + " AND merchant_pub=$2" + " AND h_contract_terms=$3" + " AND h_wire=$4;", + 5), + /* Used in #postgres_get_coin_transactions() to obtain information + about how a coin has been spend with /deposit requests. */ + GNUNET_PQ_make_prepare ("get_deposit_with_coin_pub", + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_deposit_val" + ",denom.fee_deposit_frac" + ",denom.fee_deposit_curr" + ",timestamp" + ",refund_deadline" + ",merchant_pub" + ",h_contract_terms" + ",h_wire" + ",wire" + ",coin_sig" + " FROM deposits" + " JOIN known_coins" + " USING (coin_pub)" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " WHERE coin_pub=$1;", + 1), + /* Used in #postgres_insert_refresh_out() to store the + generated signature(s) for future requests, i.e. /refresh/link */ + GNUNET_PQ_make_prepare ("insert_refresh_out", + "INSERT INTO refresh_out " + "(session_hash" + ",newcoin_index" + ",ev_sig" + ") VALUES " + "($1, $2, $3);", + 3), + /* Used in #postgres_get_refresh_out() to test if the + generated signature(s) already exists */ + GNUNET_PQ_make_prepare ("get_refresh_out", + "SELECT ev_sig" + " FROM refresh_out" + " WHERE session_hash=$1" + " AND newcoin_index=$2;", + 2), + /* Used in #postgres_get_link_data_list(). We use the session_hash + to obtain the "noreveal_index" for that session, and then select the + corresponding signatures (ev_sig) and the denomination keys from + the respective tables (namely refresh_melts and refresh_order) + using the session_hash as the primary filter (on join) and the + 'noreveal_index' to constrain the selection on the commitment. + We also want to get the triplet for each of the newcoins, so we + have another constraint to ensure we get each triplet with + matching "newcoin_index" values. NOTE: This may return many + results, both for different sessions and for the different coins + being exchangeed in the refresh ops. NOTE: There may be more + efficient ways to express the same query. */ + GNUNET_PQ_make_prepare ("get_link", + "SELECT " + " ev_sig" + ",denoms.denom_pub" + " FROM refresh_sessions" + " JOIN refresh_order ro" + " USING (session_hash)" + " JOIN refresh_commit_coin rcc" + " USING (session_hash)" + " JOIN refresh_out rc" + " USING (session_hash)" + " JOIN denominations denoms" + " ON (ro.denom_pub_hash = denoms.denom_pub_hash)" + " WHERE ro.session_hash=$1" + " AND ro.newcoin_index=rcc.newcoin_index" + " AND ro.newcoin_index=rc.newcoin_index;", + 1), + /* Used in #postgres_get_transfer(). Given the public key of a + melted coin, we obtain the corresponding encrypted link secret + and the transfer public key. This is done by first finding + the session_hash(es) of all sessions the coin was melted into, + and then constraining the result to the selected "noreveal_index". + NOTE: This may (in theory) return multiple results, one per session + that the old coin was melted into. */ + GNUNET_PQ_make_prepare ("get_transfer", + "SELECT transfer_pub,session_hash" + " FROM refresh_sessions rs" + " JOIN refresh_transfer_public_key rcl" + " USING (session_hash)" + " WHERE rs.old_coin_pub=$1;", + 1), + /* Used in #postgres_lookup_wire_transfer */ + GNUNET_PQ_make_prepare ("lookup_transactions", + "SELECT" + " aggregation_serial_id" + ",deposits.h_contract_terms" + ",deposits.wire" + ",deposits.h_wire" + ",deposits.coin_pub" + ",deposits.merchant_pub" + ",wire_out.execution_date" + ",deposits.amount_with_fee_val" + ",deposits.amount_with_fee_frac" + ",deposits.amount_with_fee_curr" + ",denom.fee_deposit_val" + ",denom.fee_deposit_frac" + ",denom.fee_deposit_curr" + " FROM aggregation_tracking" + " JOIN deposits" + " USING (deposit_serial_id)" + " JOIN known_coins" + " USING (coin_pub)" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " JOIN wire_out" + " USING (wtid_raw)" + " WHERE wtid_raw=$1;", + 1), + /* Used in #postgres_wire_lookup_deposit_wtid */ + GNUNET_PQ_make_prepare ("lookup_deposit_wtid", + "SELECT" + " aggregation_tracking.wtid_raw" + ",wire_out.execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",denom.fee_deposit_val" + ",denom.fee_deposit_frac" + ",denom.fee_deposit_curr" + " FROM deposits" + " JOIN aggregation_tracking" + " USING (deposit_serial_id)" + " JOIN known_coins" + " USING (coin_pub)" + " JOIN denominations denom" + " USING (denom_pub_hash)" + " JOIN wire_out" + " USING (wtid_raw)" + " WHERE coin_pub=$1" + " AND h_contract_terms=$2" + " AND h_wire=$3" + " AND merchant_pub=$4;", + 4), + /* Used in #postgres_insert_aggregation_tracking */ + GNUNET_PQ_make_prepare ("insert_aggregation_tracking", + "INSERT INTO aggregation_tracking " + "(deposit_serial_id" + ",wtid_raw" + ") VALUES " + "($1, $2);", + 2), + /* Used in #postgres_get_wire_fee() */ + GNUNET_PQ_make_prepare ("get_wire_fee", + "SELECT " + " start_date" + ",end_date" + ",wire_fee_val" + ",wire_fee_frac" + ",wire_fee_curr" + ",master_sig" + " FROM wire_fee" + " WHERE wire_method=$1" + " AND start_date <= $2" + " AND end_date > $2;", + 2), + /* Used in #postgres_insert_wire_fee */ + GNUNET_PQ_make_prepare ("insert_wire_fee", + "INSERT INTO wire_fee " + "(wire_method" + ",start_date" + ",end_date" + ",wire_fee_val" + ",wire_fee_frac" + ",wire_fee_curr" + ",master_sig" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7);", + 7), + /* Used in #postgres_store_wire_transfer_out */ + GNUNET_PQ_make_prepare ("insert_wire_out", + "INSERT INTO wire_out " + "(execution_date" + ",wtid_raw" + ",wire_target" + ",amount_val" + ",amount_frac" + ",amount_curr" + ") VALUES " + "($1, $2, $3, $4, $5, $6);", + 6), + /* Used in #postgres_wire_prepare_data_insert() to store + wire transfer information before actually committing it with the bank */ + GNUNET_PQ_make_prepare ("wire_prepare_data_insert", + "INSERT INTO prewire " + "(type" + ",buf" + ") VALUES " + "($1, $2);", + 2), + /* Used in #postgres_wire_prepare_data_mark_finished() */ + GNUNET_PQ_make_prepare ("wire_prepare_data_mark_done", + "UPDATE prewire" + " SET finished=true" + " WHERE prewire_uuid=$1;", + 1), + /* Used in #postgres_wire_prepare_data_get() */ + GNUNET_PQ_make_prepare ("wire_prepare_data_get", + "SELECT" + " prewire_uuid" + ",type" + ",buf" + " FROM prewire" + " WHERE finished=false" + " ORDER BY prewire_uuid ASC" + " LIMIT 1;", + 0), + /* Used in #postgres_gc() */ + GNUNET_PQ_make_prepare ("gc_prewire", + "DELETE" + " FROM prewire" + " WHERE finished=true;", + 0), + /* Used in #postgres_select_wire_out_above_serial_id() */ + GNUNET_PQ_make_prepare ("audit_get_wire_incr", + "SELECT" + " wireout_uuid" + ",execution_date" + ",wtid_raw" + ",wire_target" + ",amount_val" + ",amount_frac" + ",amount_curr" + " FROM wire_out" + " WHERE wireout_uuid>=$1" + " ORDER BY wireout_uuid ASC;", + 1), + /* Used in #postgres_insert_payback_request() to store payback + information */ + GNUNET_PQ_make_prepare ("payback_insert", + "INSERT INTO payback " + "(reserve_pub" + ",coin_pub" + ",coin_sig" + ",coin_blind" + ",amount_val" + ",amount_frac" + ",amount_curr" + ",timestamp" + ",h_blind_ev" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9);", + 9), + /* Used in #postgres_select_payback_above_serial_id() to obtain payback transactions */ + GNUNET_PQ_make_prepare ("payback_get_incr", + "SELECT" + " payback_uuid" + ",timestamp" + ",reserve_pub" + ",coin_pub" + ",coin_sig" + ",coin_blind" + ",h_blind_ev" + ",denoms.denom_pub" + ",coins.denom_sig" + ",amount_val" + ",amount_frac" + ",amount_curr" + " FROM payback" + " JOIN known_coins coins" + " USING (coin_pub)" + " JOIN denominations denoms" + " USING (denom_pub_hash)" + " WHERE payback_uuid>=$1" + " ORDER BY payback_uuid ASC;", + 1), /* Used in #postgres_select_reserve_closed_above_serial_id() to obtain information about closed reserves */ - PREPARE ("reserves_close_get_incr", - "SELECT" - " close_uuid" - ",reserve_pub" - ",execution_date" - ",wtid" - ",receiver_account" - ",amount_val" - ",amount_frac" - ",amount_curr" - ",closing_fee_val" - ",closing_fee_frac" - ",closing_fee_curr" - " FROM reserves_close" - " WHERE close_uuid>=$1" - " ORDER BY close_uuid ASC", - 1, NULL); - - /* Used in #postgres_get_reserve_history() to obtain payback transactions - for a reserve */ - PREPARE ("payback_by_reserve", - "SELECT" - " coin_pub" - ",coin_sig" - ",coin_blind" - ",amount_val" - ",amount_frac" - ",amount_curr" - ",timestamp" - ",denoms.denom_pub" - ",coins.denom_sig" - " FROM payback" - " JOIN known_coins coins USING (coin_pub)" - " JOIN denominations denoms USING (denom_pub_hash)" - " WHERE payback.reserve_pub=$1", - 1, NULL); - - /* Used in #postgres_get_reserve_history() */ - PREPARE ("close_by_reserve", - "SELECT" - " amount_val" - ",amount_frac" - ",amount_curr" - ",closing_fee_val" - ",closing_fee_frac" - ",closing_fee_curr" - ",execution_date" - ",receiver_account" - ",wtid" - " FROM reserves_close" - " WHERE reserve_pub=$1;", - 1, NULL); - - /* Used in #postgres_get_expired_reserves() */ - PREPARE ("get_expired_reserves", - "SELECT" - " expiration_date" - ",account_details" - ",reserve_pub" - ",current_balance_val" - ",current_balance_frac" - ",current_balance_curr" - " FROM reserves" - " WHERE expiration_date<=$1" - " AND (current_balance_val != 0 " - " OR current_balance_frac != 0);", - 1, NULL); - - /* Used in #postgres_get_coin_transactions() to obtain payback transactions - for a coin */ - PREPARE ("payback_by_coin", - "SELECT" - " payback.reserve_pub" - ",coin_sig" - ",coin_blind" - ",amount_val" - ",amount_frac" - ",amount_curr" - ",timestamp" - ",denoms.denom_pub" - ",coins.denom_sig" - " FROM payback" - " JOIN known_coins coins USING (coin_pub)" - " JOIN denominations denoms USING (denom_pub_hash)" - " WHERE payback.coin_pub=$1", - 1, NULL); - - /* Used in #postgres_get_reserve_by_h_blind() */ - PREPARE ("reserve_by_h_blind", - "SELECT" - " reserve_pub" - " FROM reserves_out" - " WHERE h_blind_ev=$1" - " LIMIT 1;", - 1, NULL); - - PREPARE ("gc_denominations", - "DELETE" - " FROM denominations" - " WHERE expire_legal < $1", - 1, NULL); - PREPARE ("gc_reserves", - "DELETE" - " FROM reserves" - " WHERE expiration_date < $1" - " AND current_balance_val = 0" - " AND current_balance_frac = 0", - 1, NULL); + GNUNET_PQ_make_prepare ("reserves_close_get_incr", + "SELECT" + " close_uuid" + ",reserve_pub" + ",execution_date" + ",wtid" + ",receiver_account" + ",amount_val" + ",amount_frac" + ",amount_curr" + ",closing_fee_val" + ",closing_fee_frac" + ",closing_fee_curr" + " FROM reserves_close" + " WHERE close_uuid>=$1" + " ORDER BY close_uuid ASC;", + 1), + /* Used in #postgres_get_reserve_history() to obtain payback transactions + for a reserve */ + GNUNET_PQ_make_prepare ("payback_by_reserve", + "SELECT" + " coin_pub" + ",coin_sig" + ",coin_blind" + ",amount_val" + ",amount_frac" + ",amount_curr" + ",timestamp" + ",denoms.denom_pub" + ",coins.denom_sig" + " FROM payback" + " JOIN known_coins coins" + " USING (coin_pub)" + " JOIN denominations denoms" + " USING (denom_pub_hash)" + " WHERE payback.reserve_pub=$1;", + 1), + /* Used in #postgres_get_reserve_history() */ + GNUNET_PQ_make_prepare ("close_by_reserve", + "SELECT" + " amount_val" + ",amount_frac" + ",amount_curr" + ",closing_fee_val" + ",closing_fee_frac" + ",closing_fee_curr" + ",execution_date" + ",receiver_account" + ",wtid" + " FROM reserves_close" + " WHERE reserve_pub=$1;", + 1), + /* Used in #postgres_get_expired_reserves() */ + GNUNET_PQ_make_prepare ("get_expired_reserves", + "SELECT" + " expiration_date" + ",account_details" + ",reserve_pub" + ",current_balance_val" + ",current_balance_frac" + ",current_balance_curr" + " FROM reserves" + " WHERE expiration_date<=$1" + " AND (current_balance_val != 0 " + " OR current_balance_frac != 0);", + 1), + /* Used in #postgres_get_coin_transactions() to obtain payback transactions + for a coin */ + GNUNET_PQ_make_prepare ("payback_by_coin", + "SELECT" + " payback.reserve_pub" + ",coin_sig" + ",coin_blind" + ",amount_val" + ",amount_frac" + ",amount_curr" + ",timestamp" + ",denoms.denom_pub" + ",coins.denom_sig" + " FROM payback" + " JOIN known_coins coins" + " USING (coin_pub)" + " JOIN denominations denoms" + " USING (denom_pub_hash)" + " WHERE payback.coin_pub=$1;", + 1), + /* Used in #postgres_get_reserve_by_h_blind() */ + GNUNET_PQ_make_prepare ("reserve_by_h_blind", + "SELECT" + " reserve_pub" + " FROM reserves_out" + " WHERE h_blind_ev=$1" + " LIMIT 1;", + 1), + /* used in #postgres_commit */ + GNUNET_PQ_make_prepare ("do_commit", + "COMMIT", + 0), + GNUNET_PQ_make_prepare ("gc_denominations", + "DELETE" + " FROM denominations" + " WHERE expire_legal < $1;", + 1), + GNUNET_PQ_make_prepare ("gc_reserves", + "DELETE" + " FROM reserves" + " WHERE expiration_date < $1" + " AND current_balance_val = 0" + " AND current_balance_frac = 0;", + 1), + GNUNET_PQ_PREPARED_STATEMENT_END + }; - return GNUNET_OK; -#undef PREPARE + return GNUNET_PQ_prepare_statements (db_conn, + ps); } @@ -1775,32 +1717,19 @@ evaluate_pq_result (struct TALER_EXCHANGEDB_Session *session, * * @param cls the `struct PostgresClosure` with the plugin-specific state * @param session the database connection - * @return #GNUNET_SYSERR on hard error, - * #GNUNET_NO if commit failed but retry may work, - * #GNUNET_OK on success + * @return final transaction status */ -static int +static enum GNUNET_DB_QueryStatus postgres_commit (void *cls, struct TALER_EXCHANGEDB_Session *session) { - PGresult *result; - int ret; - int state; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_end + }; - state = session->state; - if (GNUNET_OK != state) - { - postgres_rollback (cls, - session); - return state; - } - result = PQexec (session->conn, - "COMMIT"); - ret = evaluate_pq_result (session, - result); - GNUNET_break (GNUNET_SYSERR != ret); - PQclear (result); - return ret; + return GNUNET_PQ_eval_prepared_non_select (session->conn, + "do_commit", + params); } @@ -2287,8 +2216,9 @@ postgres_reserves_in_insert (void *cls, &updated_reserve)) goto rollback; } - if (GNUNET_OK != postgres_commit (cls, - session)) + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + postgres_commit (cls, + session)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to commit transaction adding amount to reserve\n"); diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 232b58c6c..98a095b61 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1337,7 +1337,7 @@ test_wire_out (struct TALER_EXCHANGEDB_Session *session, wire_out_account, &wire_out_amount)); /* And now the commit should still succeed! */ - FAILIF (GNUNET_OK != + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->commit (plugin->cls, session)); @@ -1828,7 +1828,7 @@ run (void *cls) plugin->mark_deposit_done (plugin->cls, session, deposit_rowid)); - FAILIF (GNUNET_OK != + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->commit (plugin->cls, session)); FAILIF (GNUNET_YES != @@ -1873,7 +1873,7 @@ run (void *cls) session, &dkp_pub_hash, &master_sig)); - FAILIF (GNUNET_OK != + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->commit (plugin->cls, session)); FAILIF (GNUNET_OK != diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 5539d527d..810b66f06 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -24,6 +24,7 @@ #include #include +#include #include "taler_exchangedb_lib.h" @@ -1109,7 +1110,7 @@ struct TALER_EXCHANGEDB_Plugin * @return #GNUNET_OK on success, #GNUNET_NO if the transaction * can be retried, #GNUNET_SYSERR on hard failures */ - int + enum GNUNET_DB_QueryStatus (*commit) (void *cls, struct TALER_EXCHANGEDB_Session *session); -- cgit v1.2.3