From d1c160d1b9bddfcd6f77148ae8a03944571fec25 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 9 Dec 2022 13:33:57 +0100 Subject: [PATCH] properly handle GONE case on purse deposit --- contrib/gana | 2 +- src/exchange/taler-exchange-httpd_purses_create.c | 11 +++++++++++ .../taler-exchange-httpd_purses_deposit.c | 15 ++++++++++++--- src/exchangedb/exchange_do_purse_deposit.sql | 15 +++++++++++---- src/exchangedb/pg_do_purse_deposit.c | 4 ++++ src/exchangedb/pg_do_purse_deposit.h | 2 ++ src/include/taler_exchangedb_plugin.h | 9 ++++++--- src/util/test_age_restriction.c | 1 - 8 files changed, 47 insertions(+), 12 deletions(-) diff --git a/contrib/gana b/contrib/gana index 20f8eb7a7..149aa0a08 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 20f8eb7a72e2160409f0f78264ec5198e9caa193 +Subproject commit 149aa0a08d787419e02277ef231d93c6a0154a47 diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index f3da2c85c..130f9faec 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -201,6 +201,7 @@ create_transaction (void *cls, struct TEH_PurseDepositedCoin *coin = &pcc->coins[i]; bool balance_ok = false; bool conflict = true; + bool too_late = true; qs = TEH_make_coin_known (&coin->cpi, connection, @@ -215,6 +216,7 @@ create_transaction (void *cls, &coin->coin_sig, &coin->amount_minus_fee, &balance_ok, + &too_late, &conflict); if (qs <= 0) { @@ -243,6 +245,15 @@ create_transaction (void *cls, &coin->cpi.coin_pub); return GNUNET_DB_STATUS_HARD_ERROR; } + if (too_late) + { + *mhd_ret + = TALER_MHD_reply_with_ec ( + connection, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "too late to deposit on purse creation"); + return GNUNET_DB_STATUS_HARD_ERROR; + } if (conflict) { struct TALER_Amount amount; diff --git a/src/exchange/taler-exchange-httpd_purses_deposit.c b/src/exchange/taler-exchange-httpd_purses_deposit.c index 0875ed2e6..4bebebf6f 100644 --- a/src/exchange/taler-exchange-httpd_purses_deposit.c +++ b/src/exchange/taler-exchange-httpd_purses_deposit.c @@ -166,6 +166,7 @@ deposit_transaction (void *cls, struct TEH_PurseDepositedCoin *coin = &pcc->coins[i]; bool balance_ok = false; bool conflict = true; + bool too_late = true; qs = TEH_make_coin_known (&coin->cpi, connection, @@ -180,6 +181,7 @@ deposit_transaction (void *cls, &coin->coin_sig, &coin->amount_minus_fee, &balance_ok, + &too_late, &conflict); if (qs <= 0) { @@ -204,9 +206,16 @@ deposit_transaction (void *cls, &coin->cpi.coin_pub); return GNUNET_DB_STATUS_HARD_ERROR; } - // FIXME: there is also a 'conflict' case where the purse was already - // decided (fully paid up OR expired), we should probably distinguish - // those better! + if (too_late) + { + TEH_plugin->rollback (TEH_plugin->cls); + *mhd_ret + = TALER_MHD_reply_with_ec ( + connection, + TALER_EC_EXCHANGE_PURSE_DEPOSIT_DECIDED_ALREADY, + NULL); + return GNUNET_DB_STATUS_HARD_ERROR; + } if (conflict) { struct TALER_Amount amount; diff --git a/src/exchangedb/exchange_do_purse_deposit.sql b/src/exchangedb/exchange_do_purse_deposit.sql index cddbd8d46..0ca4126af 100644 --- a/src/exchangedb/exchange_do_purse_deposit.sql +++ b/src/exchangedb/exchange_do_purse_deposit.sql @@ -26,6 +26,7 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_deposit( IN in_reserve_expiration INT8, IN in_now INT8, OUT out_balance_ok BOOLEAN, + OUT out_late BOOLEAN, OUT out_conflict BOOLEAN) LANGUAGE plpgsql AS $$ @@ -75,6 +76,7 @@ THEN THEN -- Deposit exists, but with differences. Not allowed. out_balance_ok=FALSE; + out_late=FALSE; out_conflict=TRUE; RETURN; END IF; @@ -106,6 +108,7 @@ IF NOT FOUND THEN -- Insufficient balance. out_balance_ok=FALSE; + out_late=FALSE; out_conflict=FALSE; RETURN; END IF; @@ -141,6 +144,8 @@ SELECT COALESCE(partner_serial_id,0) IF NOT FOUND THEN + -- Purse was not yet merged. We are done. + out_late=FALSE; RETURN; END IF; @@ -159,6 +164,7 @@ SELECT OR (amount_with_fee_val < balance_val) ) ); IF NOT FOUND THEN + out_late=FALSE; RETURN; END IF; @@ -175,10 +181,13 @@ ON CONFLICT DO NOTHING; IF NOT FOUND THEN - out_conflict=TRUE; + -- Purse already decided, likely expired. + out_late=TRUE; RETURN; END IF; +out_late=FALSE; + IF (my_in_reserve_quota) THEN UPDATE reserves @@ -216,7 +225,7 @@ ELSE IF NOT FOUND THEN - + -- Reserve existed, thus UPDATE instead of INSERT. UPDATE reserves SET current_balance_frac=current_balance_frac+my_amount_frac @@ -240,5 +249,3 @@ END IF; END $$; - - diff --git a/src/exchangedb/pg_do_purse_deposit.c b/src/exchangedb/pg_do_purse_deposit.c index 25496a262..ba6f03c11 100644 --- a/src/exchangedb/pg_do_purse_deposit.c +++ b/src/exchangedb/pg_do_purse_deposit.c @@ -35,6 +35,7 @@ TEH_PG_do_purse_deposit ( const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *amount_minus_fee, bool *balance_ok, + bool *too_late, bool *conflict) { struct PostgresClosure *pg = cls; @@ -57,6 +58,8 @@ TEH_PG_do_purse_deposit ( struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_bool ("balance_ok", balance_ok), + GNUNET_PQ_result_spec_bool ("too_late", + too_late), GNUNET_PQ_result_spec_bool ("conflict", conflict), GNUNET_PQ_result_spec_end @@ -72,6 +75,7 @@ TEH_PG_do_purse_deposit ( "SELECT " " out_balance_ok AS balance_ok" ",out_conflict AS conflict" + ",out_late AS too_late" " FROM exchange_do_purse_deposit" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);"); diff --git a/src/exchangedb/pg_do_purse_deposit.h b/src/exchangedb/pg_do_purse_deposit.h index b4b9c35c8..779b6c0c8 100644 --- a/src/exchangedb/pg_do_purse_deposit.h +++ b/src/exchangedb/pg_do_purse_deposit.h @@ -43,6 +43,7 @@ * remaining balance is below @a amount; * in this case, the return value will be * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure + * @param[out] too_late set to true if it is too late to deposit into the purse * @param[out] conflict set to true if the deposit failed due to a conflict (coin already spent, * or deposited into this purse with a different amount) * @return transaction status code @@ -56,6 +57,7 @@ TEH_PG_do_purse_deposit ( const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *amount_minus_fee, bool *balance_ok, + bool *too_late, bool *conflict); #endif diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 6951908ef..a14d31a3c 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -3465,9 +3465,10 @@ struct TALER_EXCHANGEDB_Plugin */ enum GNUNET_DB_QueryStatus (*batch2_reserves_in_insert)(void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - enum GNUNET_DB_QueryStatus *results); + const struct + TALER_EXCHANGEDB_ReserveInInfo *reserves, + unsigned int reserves_length, + enum GNUNET_DB_QueryStatus *results); /** * Locate a nonce for use with a particular public key. @@ -5911,6 +5912,7 @@ struct TALER_EXCHANGEDB_Plugin * remaining balance is below @a amount; * in this case, the return value will be * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure + * @param[out] too_late it is too late to deposit into this purse * @param[out] conflict the same coin was deposited into * this purse with a different amount already * @return transaction status code @@ -5924,6 +5926,7 @@ struct TALER_EXCHANGEDB_Plugin const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *amount_minus_fee, bool *balance_ok, + bool *too_late, bool *conflict); diff --git a/src/util/test_age_restriction.c b/src/util/test_age_restriction.c index 3c5d52629..77717616f 100644 --- a/src/util/test_age_restriction.c +++ b/src/util/test_age_restriction.c @@ -21,7 +21,6 @@ */ #include "platform.h" #include "taler_util.h" -#include "taler_crypto_lib.h" extern uint8_t get_age_group (