properly handle GONE case on purse deposit

This commit is contained in:
Christian Grothoff 2022-12-09 13:33:57 +01:00
parent f9cc76ad3c
commit d1c160d1b9
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
8 changed files with 47 additions and 12 deletions

@ -1 +1 @@
Subproject commit 20f8eb7a72e2160409f0f78264ec5198e9caa193 Subproject commit 149aa0a08d787419e02277ef231d93c6a0154a47

View File

@ -201,6 +201,7 @@ create_transaction (void *cls,
struct TEH_PurseDepositedCoin *coin = &pcc->coins[i]; struct TEH_PurseDepositedCoin *coin = &pcc->coins[i];
bool balance_ok = false; bool balance_ok = false;
bool conflict = true; bool conflict = true;
bool too_late = true;
qs = TEH_make_coin_known (&coin->cpi, qs = TEH_make_coin_known (&coin->cpi,
connection, connection,
@ -215,6 +216,7 @@ create_transaction (void *cls,
&coin->coin_sig, &coin->coin_sig,
&coin->amount_minus_fee, &coin->amount_minus_fee,
&balance_ok, &balance_ok,
&too_late,
&conflict); &conflict);
if (qs <= 0) if (qs <= 0)
{ {
@ -243,6 +245,15 @@ create_transaction (void *cls,
&coin->cpi.coin_pub); &coin->cpi.coin_pub);
return GNUNET_DB_STATUS_HARD_ERROR; 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) if (conflict)
{ {
struct TALER_Amount amount; struct TALER_Amount amount;

View File

@ -166,6 +166,7 @@ deposit_transaction (void *cls,
struct TEH_PurseDepositedCoin *coin = &pcc->coins[i]; struct TEH_PurseDepositedCoin *coin = &pcc->coins[i];
bool balance_ok = false; bool balance_ok = false;
bool conflict = true; bool conflict = true;
bool too_late = true;
qs = TEH_make_coin_known (&coin->cpi, qs = TEH_make_coin_known (&coin->cpi,
connection, connection,
@ -180,6 +181,7 @@ deposit_transaction (void *cls,
&coin->coin_sig, &coin->coin_sig,
&coin->amount_minus_fee, &coin->amount_minus_fee,
&balance_ok, &balance_ok,
&too_late,
&conflict); &conflict);
if (qs <= 0) if (qs <= 0)
{ {
@ -204,9 +206,16 @@ deposit_transaction (void *cls,
&coin->cpi.coin_pub); &coin->cpi.coin_pub);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
// FIXME: there is also a 'conflict' case where the purse was already if (too_late)
// decided (fully paid up OR expired), we should probably distinguish {
// those better! 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) if (conflict)
{ {
struct TALER_Amount amount; struct TALER_Amount amount;

View File

@ -26,6 +26,7 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_deposit(
IN in_reserve_expiration INT8, IN in_reserve_expiration INT8,
IN in_now INT8, IN in_now INT8,
OUT out_balance_ok BOOLEAN, OUT out_balance_ok BOOLEAN,
OUT out_late BOOLEAN,
OUT out_conflict BOOLEAN) OUT out_conflict BOOLEAN)
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
@ -75,6 +76,7 @@ THEN
THEN THEN
-- Deposit exists, but with differences. Not allowed. -- Deposit exists, but with differences. Not allowed.
out_balance_ok=FALSE; out_balance_ok=FALSE;
out_late=FALSE;
out_conflict=TRUE; out_conflict=TRUE;
RETURN; RETURN;
END IF; END IF;
@ -106,6 +108,7 @@ IF NOT FOUND
THEN THEN
-- Insufficient balance. -- Insufficient balance.
out_balance_ok=FALSE; out_balance_ok=FALSE;
out_late=FALSE;
out_conflict=FALSE; out_conflict=FALSE;
RETURN; RETURN;
END IF; END IF;
@ -141,6 +144,8 @@ SELECT COALESCE(partner_serial_id,0)
IF NOT FOUND IF NOT FOUND
THEN THEN
-- Purse was not yet merged. We are done.
out_late=FALSE;
RETURN; RETURN;
END IF; END IF;
@ -159,6 +164,7 @@ SELECT
OR (amount_with_fee_val < balance_val) ) ); OR (amount_with_fee_val < balance_val) ) );
IF NOT FOUND IF NOT FOUND
THEN THEN
out_late=FALSE;
RETURN; RETURN;
END IF; END IF;
@ -175,10 +181,13 @@ ON CONFLICT DO NOTHING;
IF NOT FOUND IF NOT FOUND
THEN THEN
out_conflict=TRUE; -- Purse already decided, likely expired.
out_late=TRUE;
RETURN; RETURN;
END IF; END IF;
out_late=FALSE;
IF (my_in_reserve_quota) IF (my_in_reserve_quota)
THEN THEN
UPDATE reserves UPDATE reserves
@ -216,7 +225,7 @@ ELSE
IF NOT FOUND IF NOT FOUND
THEN THEN
-- Reserve existed, thus UPDATE instead of INSERT.
UPDATE reserves UPDATE reserves
SET SET
current_balance_frac=current_balance_frac+my_amount_frac current_balance_frac=current_balance_frac+my_amount_frac
@ -240,5 +249,3 @@ END IF;
END $$; END $$;

View File

@ -35,6 +35,7 @@ TEH_PG_do_purse_deposit (
const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *amount_minus_fee, const struct TALER_Amount *amount_minus_fee,
bool *balance_ok, bool *balance_ok,
bool *too_late,
bool *conflict) bool *conflict)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
@ -57,6 +58,8 @@ TEH_PG_do_purse_deposit (
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("balance_ok", GNUNET_PQ_result_spec_bool ("balance_ok",
balance_ok), balance_ok),
GNUNET_PQ_result_spec_bool ("too_late",
too_late),
GNUNET_PQ_result_spec_bool ("conflict", GNUNET_PQ_result_spec_bool ("conflict",
conflict), conflict),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
@ -72,6 +75,7 @@ TEH_PG_do_purse_deposit (
"SELECT " "SELECT "
" out_balance_ok AS balance_ok" " out_balance_ok AS balance_ok"
",out_conflict AS conflict" ",out_conflict AS conflict"
",out_late AS too_late"
" FROM exchange_do_purse_deposit" " FROM exchange_do_purse_deposit"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);"); " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");

View File

@ -43,6 +43,7 @@
* remaining balance is below @a amount; * remaining balance is below @a amount;
* in this case, the return value will be * in this case, the return value will be
* #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure * #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, * @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) * or deposited into this purse with a different amount)
* @return transaction status code * @return transaction status code
@ -56,6 +57,7 @@ TEH_PG_do_purse_deposit (
const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *amount_minus_fee, const struct TALER_Amount *amount_minus_fee,
bool *balance_ok, bool *balance_ok,
bool *too_late,
bool *conflict); bool *conflict);
#endif #endif

View File

@ -3465,9 +3465,10 @@ struct TALER_EXCHANGEDB_Plugin
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*batch2_reserves_in_insert)(void *cls, (*batch2_reserves_in_insert)(void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, const struct
unsigned int reserves_length, TALER_EXCHANGEDB_ReserveInInfo *reserves,
enum GNUNET_DB_QueryStatus *results); unsigned int reserves_length,
enum GNUNET_DB_QueryStatus *results);
/** /**
* Locate a nonce for use with a particular public key. * Locate a nonce for use with a particular public key.
@ -5911,6 +5912,7 @@ struct TALER_EXCHANGEDB_Plugin
* remaining balance is below @a amount; * remaining balance is below @a amount;
* in this case, the return value will be * in this case, the return value will be
* #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure * #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 * @param[out] conflict the same coin was deposited into
* this purse with a different amount already * this purse with a different amount already
* @return transaction status code * @return transaction status code
@ -5924,6 +5926,7 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_CoinSpendSignatureP *coin_sig,
const struct TALER_Amount *amount_minus_fee, const struct TALER_Amount *amount_minus_fee,
bool *balance_ok, bool *balance_ok,
bool *too_late,
bool *conflict); bool *conflict);

View File

@ -21,7 +21,6 @@
*/ */
#include "platform.h" #include "platform.h"
#include "taler_util.h" #include "taler_util.h"
#include "taler_crypto_lib.h"
extern uint8_t extern uint8_t
get_age_group ( get_age_group (