From 2f993d3ee32ac614a8f0b405fc3177c3d33feba9 Mon Sep 17 00:00:00 2001 From: Joseph Date: Wed, 28 Dec 2022 09:37:33 -0500 Subject: populate denom-coin-dep --- src/exchangedb/Makefile.am | 27 +- src/exchangedb/test_exchangedb.c | 1 + src/exchangedb/test_exchangedb_populate_table.c | 431 ++++++++++++++++++++++++ 3 files changed, 457 insertions(+), 2 deletions(-) create mode 100644 src/exchangedb/test_exchangedb_populate_table.c (limited to 'src/exchangedb') diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 6955a0af9..694ac8089 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -283,13 +283,15 @@ check_PROGRAMS = \ bench-db-postgres\ perf-exchangedb-reserves-in-insert-postgres\ test-exchangedb-by-j-postgres\ - test-exchangedb-batch-reserves-in-insert-postgres + test-exchangedb-batch-reserves-in-insert-postgres\ + test-exchangedb-populate-table-postgres AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; TESTS = \ test-exchangedb-postgres\ test-exchangedb-by-j-postgres\ perf-exchangedb-reserves-in-insert-postgres\ - test-exchangedb-batch-reserves-in-insert-postgres + test-exchangedb-batch-reserves-in-insert-postgres\ + test-exchangedb-populate-table-postgres test_exchangedb_postgres_SOURCES = \ @@ -363,6 +365,27 @@ bench_db_postgres_LDADD = \ -lgnunetutil \ $(XLIB) +test_exchangedb_populate_table_postgres_SOURCES = \ + test_exchangedb_populate_table.c +test_exchangedb_populate_table_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + -ljansson \ + -lgnunetjson \ + -lgnunetutil \ + $(XLIB) + +bench_db_postgres_SOURCES = \ + bench_db.c +bench_db_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + -lgnunetpq \ + -lgnunetutil \ + $(XLIB) EXTRA_test_exchangedb_postgres_DEPENDENCIES = \ libtaler_plugin_exchangedb_postgres.la diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index eb258f002..68f94b6ea 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1351,6 +1351,7 @@ run (void *cls) RND_BLK (&age_hash); for (size_t i = 0; i < sizeof(p_ah) / sizeof(p_ah[0]); i++) { + RND_BLK (&coin_pub); GNUNET_assert (GNUNET_OK == TALER_denom_blind (&dkp->pub, diff --git a/src/exchangedb/test_exchangedb_populate_table.c b/src/exchangedb/test_exchangedb_populate_table.c new file mode 100644 index 000000000..ed30894b1 --- /dev/null +++ b/src/exchangedb/test_exchangedb_populate_table.c @@ -0,0 +1,431 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ +/** + * @file exchangedb/test_exchangedb_populate_table.c + * @brief test cases for DB interaction functions + * @author Joseph Xu + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + +/**o + * Global result from the testcase. + */ +static int result; + +/** + * Report line of error if @a cond is true, and jump to label "drop". + */ +#define FAILIF(cond) \ + do { \ + if (! (cond)) {break;} \ + GNUNET_break (0); \ + goto drop; \ + } while (0) + + +/** + * Initializes @a ptr with random data. + */ +#define RND_BLK(ptr) \ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) + +/** + * Initializes @a ptr with zeros. + */ +#define ZR_BLK(ptr) \ + memset (ptr, 0, sizeof (*ptr)) + + +/** + * Currency we use. Must match test-exchange-db-*.conf. + */ +#define CURRENCY "EUR" + + +/** + * Number of newly minted coins to use in the test. + */ +#define MELT_NEW_COINS 5 + + +/** + * How big do we make the RSA keys? + */ +#define RSA_KEY_SIZE 1024 + + +/** + * Database plugin under test. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; +static struct TALER_DenomFeeSet fees; + + +struct DenomKeyPair +{ + struct TALER_DenominationPrivateKey priv; + struct TALER_DenominationPublicKey pub; +}; + + +/** + * Destroy a denomination key pair. The key is not necessarily removed from the DB. + * + * @param dkp the key pair to destroy + */ +static void +destroy_denom_key_pair (struct DenomKeyPair *dkp) +{ + TALER_denom_pub_free (&dkp->pub); + TALER_denom_priv_free (&dkp->priv); + GNUNET_free (dkp); +} + + +/** + * Create a denomination key pair by registering the denomination in the DB. + * + * @param size the size of the denomination key + * @param now time to use for key generation, legal expiration will be 3h later. + * @param fees fees to use + * @return the denominaiton key pair; NULL upon error + */ +static struct DenomKeyPair * +create_denom_key_pair (unsigned int size, + struct GNUNET_TIME_Timestamp now, + const struct TALER_Amount *value, + const struct TALER_DenomFeeSet *fees) +{ + struct DenomKeyPair *dkp; + struct TALER_EXCHANGEDB_DenominationKey dki; + struct TALER_EXCHANGEDB_DenominationKeyInformation issue2; + + dkp = GNUNET_new (struct DenomKeyPair); + GNUNET_assert (GNUNET_OK == + TALER_denom_priv_create (&dkp->priv, + &dkp->pub, + TALER_DENOMINATION_RSA, + size)); + memset (&dki, + 0, + sizeof (struct TALER_EXCHANGEDB_DenominationKey)); + dki.denom_pub = dkp->pub; + dki.issue.start = now; + dki.issue.expire_withdraw + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_UNIT_HOURS)); + dki.issue.expire_deposit + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_HOURS, 2))); + dki.issue.expire_legal + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_HOURS, 3))); + dki.issue.value = *value; + dki.issue.fees = *fees; + TALER_denom_pub_hash (&dkp->pub, + &dki.issue.denom_hash); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_denomination_info (plugin->cls, + &dki.denom_pub, + &dki.issue)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + memset (&issue2, 0, sizeof (issue2)); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->get_denomination_info (plugin->cls, + &dki.issue.denom_hash, + &issue2)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + if (0 != GNUNET_memcmp (&dki.issue, + &issue2)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + return dkp; +} + + + + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure with config + */ + +static void +run (void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + const uint32_t num_partitions = 10; + struct DenomKeyPair *dkp = NULL; + struct GNUNET_TIME_Timestamp ts; + struct TALER_EXCHANGEDB_Deposit depos; + struct GNUNET_TIME_Timestamp ts_deadline; + struct TALER_Amount value; + union TALER_DenominationBlindingKeyP bks; + struct TALER_CoinPubHashP c_hash; + struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; + struct TALER_ExchangeWithdrawValues alg_values = { + .cipher = TALER_DENOMINATION_RSA + }; + struct TALER_PlanchetMasterSecretP ps; + struct TALER_ReservePublicKeyP reserve_pub; + + ZR_BLK (&cbc); + RND_BLK (&reserve_pub); + + memset (&depos, + 0, + sizeof (depos)); + + if (NULL == + (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + GNUNET_break (0); + result = 77; + return; + } + (void) plugin->drop_tables (plugin->cls); + if (GNUNET_OK != + plugin->create_tables (plugin->cls, + true, + num_partitions)) + { + GNUNET_break (0); + result = 77; + goto cleanup; + } + if (GNUNET_OK != + plugin->preflight (plugin->cls)) + { + GNUNET_break (0); + goto cleanup; + } + + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.withdraw)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.deposit)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.refresh)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.refund)); + + ts = GNUNET_TIME_timestamp_get (); + + dkp = create_denom_key_pair (RSA_KEY_SIZE, + ts, + &value, + &fees); + GNUNET_assert (NULL != dkp); + TALER_denom_pub_hash (&dkp->pub, + &cbc.denom_pub_hash); + RND_BLK (&cbc.reserve_sig); + RND_BLK (&ps); + TALER_planchet_blinding_secret_create (&ps, + &alg_values, + &bks); + + { + struct TALER_PlanchetDetail pd; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_AgeCommitmentHash age_hash; + struct TALER_AgeCommitmentHash *p_ah[2] = { + NULL, + &age_hash + }; + + + RND_BLK (&age_hash); + for (size_t i = 0; i < sizeof(p_ah) / sizeof(p_ah[0]); i++) + { + fprintf(stdout, "OPEN\n"); + RND_BLK (&coin_pub); + GNUNET_assert (GNUNET_OK == + TALER_denom_blind (&dkp->pub, + &bks, + p_ah[i], + &coin_pub, + &alg_values, + &c_hash, + &pd.blinded_planchet)); + GNUNET_assert (GNUNET_OK == + TALER_coin_ev_hash (&pd.blinded_planchet, + &cbc.denom_pub_hash, + &cbc.h_coin_envelope)); + if (i != 0) + TALER_blinded_denom_sig_free (&cbc.sig); + GNUNET_assert ( + GNUNET_OK == + TALER_denom_sign_blinded ( + &cbc.sig, + &dkp->priv, + false, + &pd.blinded_planchet)); + TALER_blinded_planchet_free (&pd.blinded_planchet); + } + } + + cbc.reserve_pub = reserve_pub; + cbc.amount_with_fee = value; + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (CURRENCY, + &cbc.withdraw_fee)); + + + + + ts_deadline = GNUNET_TIME_timestamp_get (); + + depos.deposit_fee = fees.deposit; + + RND_BLK (&depos.coin.coin_pub); + TALER_denom_pub_hash (&dkp->pub, + &depos.coin.denom_pub_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind (&depos.coin.denom_sig, + &cbc.sig, + &bks, + &c_hash, + &alg_values, + &dkp->pub)); + { + uint64_t known_coin_id; + struct TALER_DenominationHashP dph; + struct TALER_AgeCommitmentHash agh; + + FAILIF (TALER_EXCHANGEDB_CKS_ADDED != + plugin->ensure_coin_known (plugin->cls, + &depos.coin, + &known_coin_id, + &dph, + &agh)); + } + { + TALER_denom_sig_free (&depos.coin.denom_sig); + struct GNUNET_TIME_Timestamp now; + RND_BLK (&depos.merchant_pub); + RND_BLK (&depos.csig); + RND_BLK (&depos.h_contract_terms); + RND_BLK (&depos.wire_salt); + depos.amount_with_fee = value; + depos.refund_deadline = ts_deadline; + depos.wire_deadline = ts_deadline; + depos.receiver_wire_account = + "payto://iban/DE67830654080004822650?receiver-name=Test"; + depos.timestamp = ts; + + now = GNUNET_TIME_timestamp_get (); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_deposit (plugin->cls, + now, + &depos)); + } + + result = 0; + drop: + GNUNET_break (GNUNET_OK == + plugin->drop_tables (plugin->cls)); +cleanup: + if (NULL != dkp) + destroy_denom_key_pair (dkp); + TALER_denom_sig_free (&depos.coin.denom_sig); + TALER_blinded_denom_sig_free (&cbc.sig); + dkp = NULL; + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; +} + + +int +main (int argc, + char *const argv[]) +{ + const char *plugin_name; + char *config_filename; + char *testname; + struct GNUNET_CONFIGURATION_Handle *cfg; + + (void) argc; + result = -1; + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + GNUNET_log_setup (argv[0], + "WARNING", + NULL); + plugin_name++; + (void) GNUNET_asprintf (&testname, + "test-exchange-db-%s", + plugin_name); + (void) GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + fprintf (stdout, + "Using config: %s\n", + config_filename); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_free (config_filename); + GNUNET_free (testname); + return 2; + } + GNUNET_SCHEDULER_run (&run, + cfg); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config_filename); + GNUNET_free (testname); + return result; +} + + +/* end of test_exchangedb_by_j.c */ -- cgit v1.2.3 From 880c14909bfdaf1199ffc5da989eccb52f6cac12 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 28 Dec 2022 23:44:17 +0100 Subject: add notification logic on purse deletion --- src/exchangedb/pg_select_purse.c | 7 ++++++- src/exchangedb/pg_select_purse.h | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/exchangedb') diff --git a/src/exchangedb/pg_select_purse.c b/src/exchangedb/pg_select_purse.c index e2a36c33e..9143e8721 100644 --- a/src/exchangedb/pg_select_purse.c +++ b/src/exchangedb/pg_select_purse.c @@ -35,7 +35,8 @@ TEH_PG_select_purse ( struct TALER_Amount *amount, struct TALER_Amount *deposited, struct TALER_PrivateContractHashP *h_contract_terms, - struct GNUNET_TIME_Timestamp *merge_timestamp) + struct GNUNET_TIME_Timestamp *merge_timestamp, + bool *purse_deleted) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -57,6 +58,8 @@ TEH_PG_select_purse ( GNUNET_PQ_result_spec_timestamp ("merge_timestamp", merge_timestamp), NULL), + GNUNET_PQ_result_spec_bool ("purse_deleted", + purse_deleted), GNUNET_PQ_result_spec_end }; @@ -72,8 +75,10 @@ TEH_PG_select_purse ( ",balance_val" ",balance_frac" ",merge_timestamp" + ",purse_sig IS NOT NULL AS purse_deleted" " FROM purse_requests" " LEFT JOIN purse_merges USING (purse_pub)" + " LEFT JOIN purse_deletion USING (purse_pub)" " WHERE purse_pub=$1;"); *merge_timestamp = GNUNET_TIME_UNIT_FOREVER_TS; return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, diff --git a/src/exchangedb/pg_select_purse.h b/src/exchangedb/pg_select_purse.h index f522256df..db63f0c90 100644 --- a/src/exchangedb/pg_select_purse.h +++ b/src/exchangedb/pg_select_purse.h @@ -37,6 +37,7 @@ * @param[out] deposited set to actual amount put into the purse so far * @param[out] h_contract_terms set to hash of the contract for the purse * @param[out] merge_timestamp set to time when the purse was merged, or NEVER if not + * @param[out] purse_deleted set to true if purse was deleted * @return transaction status code */ enum GNUNET_DB_QueryStatus @@ -48,7 +49,8 @@ TEH_PG_select_purse ( struct TALER_Amount *amount, struct TALER_Amount *deposited, struct TALER_PrivateContractHashP *h_contract_terms, - struct GNUNET_TIME_Timestamp *merge_timestamp); + struct GNUNET_TIME_Timestamp *merge_timestamp, + bool *purse_deleted); #endif -- cgit v1.2.3 From 5df74558de6e725841c2f5a2ea6f90d0af264c89 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 29 Dec 2022 00:34:36 +0100 Subject: misc purse deletion fixes --- src/exchangedb/exchange_do_delete_purse.sql | 119 ---------------------------- src/exchangedb/exchange_do_purse_delete.sql | 119 ++++++++++++++++++++++++++++ src/exchangedb/procedures.sql.in | 2 +- 3 files changed, 120 insertions(+), 120 deletions(-) delete mode 100644 src/exchangedb/exchange_do_delete_purse.sql create mode 100644 src/exchangedb/exchange_do_purse_delete.sql (limited to 'src/exchangedb') diff --git a/src/exchangedb/exchange_do_delete_purse.sql b/src/exchangedb/exchange_do_delete_purse.sql deleted file mode 100644 index a57f25454..000000000 --- a/src/exchangedb/exchange_do_delete_purse.sql +++ /dev/null @@ -1,119 +0,0 @@ --- --- This file is part of TALER --- Copyright (C) 2014--2022 Taler Systems SA --- --- TALER is free software; you can redistribute it and/or modify it under the --- terms of the GNU General Public License as published by the Free Software --- Foundation; either version 3, or (at your option) any later version. --- --- TALER is distributed in the hope that it will be useful, but WITHOUT ANY --- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR --- A PARTICULAR PURPOSE. See the GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License along with --- TALER; see the file COPYING. If not, see --- - -CREATE OR REPLACE FUNCTION exchange_do_delete_purse( - IN in_purse_pub BYTEA, - IN in_purse_sig BYTEA, - IN in_now INT8, - OUT out_decided BOOLEAN, - OUT out_found BOOLEAN) -LANGUAGE plpgsql -AS $$ -DECLARE - my_deposit record; -DECLARE - my_in_reserve_quota BOOLEAN; -BEGIN - -SELECT COUNT(*) FROM purse_decision - WHERE purse_pub=in_purse_pub; -IF FOUND -THEN - out_found=TRUE; - out_decided=TRUE; - RETURN; -END IF; -out_decided=FALSE; - -SELECT in_reserve_quota - INTO my_in_reserve_quota - FROM exchange.purse_requests - WHERE purse_pub=in_purse_pub; -out_found=FOUND; -IF NOT FOUND -THEN - RETURN; -END IF; - --- store reserve deletion -INSERT INTO purse_deletion - (purse_pub - ,purse_sig) -VALUES - (in_purse_pub - ,in_purse_sig) -ON CONFLICT DO NOTHING; - -IF NOT FOUND -THEN - RETURN; -END IF; - --- Delete contract associated with purse, if it exists. -DELETE FROM contracts - WHERE purse_pub=in_purse_pub; - --- store purse decision -INSERT INTO purse_decision - (purse_pub - ,action_timestamp - ,refunded) -VALUES - (in_purse_pub - ,in_now - ,TRUE); - --- update purse quota at reserve -IF (my_in_reserve_quota) -THEN - UPDATE reserves - SET purses_active=purses_active-1 - WHERE reserve_pub IN - (SELECT reserve_pub - FROM exchange.purse_merges - WHERE purse_pub=in_purse_pub - LIMIT 1); -END IF; - --- restore balance to each coin deposited into the purse -FOR my_deposit IN - SELECT coin_pub - ,amount_with_fee_val - ,amount_with_fee_frac - FROM exchange.purse_deposits - WHERE purse_pub = in_purse_pub -LOOP - UPDATE exchange.known_coins SET - remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac - - CASE - WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 - THEN 100000000 - ELSE 0 - END, - remaining_val=remaining_val+my_deposit.amount_with_fee_val - + CASE - WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 - THEN 1 - ELSE 0 - END - WHERE coin_pub = my_deposit.coin_pub; -END LOOP; - - -END $$; - -COMMENT ON FUNCTION exchange_do_delete_purse(BYTEA,BYTEA,INT8) - IS 'Delete a previously undecided purse and refund the coins (if any).'; diff --git a/src/exchangedb/exchange_do_purse_delete.sql b/src/exchangedb/exchange_do_purse_delete.sql new file mode 100644 index 000000000..096475b43 --- /dev/null +++ b/src/exchangedb/exchange_do_purse_delete.sql @@ -0,0 +1,119 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2014--2022 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see +-- + +CREATE OR REPLACE FUNCTION exchange_do_purse_delete( + IN in_purse_pub BYTEA, + IN in_purse_sig BYTEA, + IN in_now INT8, + OUT out_decided BOOLEAN, + OUT out_found BOOLEAN) +LANGUAGE plpgsql +AS $$ +DECLARE + my_deposit record; +DECLARE + my_in_reserve_quota BOOLEAN; +BEGIN + +PERFORM refunded FROM purse_decision + WHERE purse_pub=in_purse_pub; +IF FOUND +THEN + out_found=TRUE; + out_decided=TRUE; + RETURN; +END IF; +out_decided=FALSE; + +SELECT in_reserve_quota + INTO my_in_reserve_quota + FROM exchange.purse_requests + WHERE purse_pub=in_purse_pub; +out_found=FOUND; +IF NOT FOUND +THEN + RETURN; +END IF; + +-- store reserve deletion +INSERT INTO exchange.purse_deletion + (purse_pub + ,purse_sig) +VALUES + (in_purse_pub + ,in_purse_sig) +ON CONFLICT DO NOTHING; + +IF NOT FOUND +THEN + RETURN; +END IF; + +-- Delete contract associated with purse, if it exists. +DELETE FROM contracts + WHERE purse_pub=in_purse_pub; + +-- store purse decision +INSERT INTO purse_decision + (purse_pub + ,action_timestamp + ,refunded) +VALUES + (in_purse_pub + ,in_now + ,TRUE); + +-- update purse quota at reserve +IF (my_in_reserve_quota) +THEN + UPDATE reserves + SET purses_active=purses_active-1 + WHERE reserve_pub IN + (SELECT reserve_pub + FROM exchange.purse_merges + WHERE purse_pub=in_purse_pub + LIMIT 1); +END IF; + +-- restore balance to each coin deposited into the purse +FOR my_deposit IN + SELECT coin_pub + ,amount_with_fee_val + ,amount_with_fee_frac + FROM exchange.purse_deposits + WHERE purse_pub = in_purse_pub +LOOP + UPDATE exchange.known_coins SET + remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac + - CASE + WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 + THEN 100000000 + ELSE 0 + END, + remaining_val=remaining_val+my_deposit.amount_with_fee_val + + CASE + WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 + THEN 1 + ELSE 0 + END + WHERE coin_pub = my_deposit.coin_pub; +END LOOP; + + +END $$; + +COMMENT ON FUNCTION exchange_do_purse_delete(BYTEA,BYTEA,INT8) + IS 'Delete a previously undecided purse and refund the coins (if any).'; diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in index af47bbf63..194830248 100644 --- a/src/exchangedb/procedures.sql.in +++ b/src/exchangedb/procedures.sql.in @@ -28,11 +28,11 @@ SET search_path TO exchange; #include "exchange_do_recoup_to_reserve.sql" #include "exchange_do_recoup_to_coin.sql" #include "exchange_do_gc.sql" +#include "exchange_do_purse_delete.sql" #include "exchange_do_purse_deposit.sql" #include "exchange_do_purse_merge.sql" #include "exchange_do_reserve_purse.sql" #include "exchange_do_expire_purse.sql" -#include "exchange_do_delete_purse.sql" #include "exchange_do_history_request.sql" #include "exchange_do_reserve_open_deposit.sql" #include "exchange_do_reserve_open.sql" -- cgit v1.2.3