make sure reserves are not gc'ed before legal expiration

This commit is contained in:
Christian Grothoff 2019-07-24 12:19:36 +02:00
parent 9e3f4bdd79
commit a654ceafba
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 100 additions and 54 deletions

View File

@ -21,3 +21,8 @@ WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/exchange/wirefees/
# it is only configurable for testing, and should be treated # it is only configurable for testing, and should be treated
# as constant in production. # as constant in production.
IDLE_RESERVE_EXPIRATION_TIME = 4 weeks IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
# After how long do we forget about reserves? Should be above
# the legal expiration timeframe of withdrawn coins.
LEGAL_RESERVE_EXPIRATION_TIME = 7 years

View File

@ -97,6 +97,12 @@ struct PostgresClosure
* After how long should idle reserves be closed? * After how long should idle reserves be closed?
*/ */
struct GNUNET_TIME_Relative idle_reserve_expiration_time; struct GNUNET_TIME_Relative idle_reserve_expiration_time;
/**
* After how long should reserves that have seen withdraw operations
* be garbage collected?
*/
struct GNUNET_TIME_Relative legal_reserve_expiration_time;
}; };
@ -210,6 +216,7 @@ postgres_create_tables (void *cls)
",current_balance_frac INT4 NOT NULL" ",current_balance_frac INT4 NOT NULL"
",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
",expiration_date INT8 NOT NULL" ",expiration_date INT8 NOT NULL"
",gc_date INT8 NOT NULL"
");"), ");"),
/* index on reserves table (TODO: useless due to primary key!?) */ /* index on reserves table (TODO: useless due to primary key!?) */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_reserve_pub_index ON " GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_reserve_pub_index ON "
@ -217,6 +224,9 @@ postgres_create_tables (void *cls)
/* index for get_expired_reserves */ /* index for get_expired_reserves */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_expiration_index" GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_expiration_index"
" ON reserves (expiration_date,current_balance_val,current_balance_frac);"), " ON reserves (expiration_date,current_balance_val,current_balance_frac);"),
/* index for reserve GC operations */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_gc_index"
" ON reserves (gc_date);"),
/* reserves_in table collects the transactions which transfer funds /* reserves_in table collects the transactions which transfer funds
into the reserve. The rows of this table correspond to each into the reserve. The rows of this table correspond to each
incoming transaction. */ incoming transaction. */
@ -649,6 +659,7 @@ postgres_prepare (PGconn *db_conn)
",current_balance_frac" ",current_balance_frac"
",current_balance_curr" ",current_balance_curr"
",expiration_date" ",expiration_date"
",gc_date"
" FROM reserves" " FROM reserves"
" WHERE reserve_pub=$1" " WHERE reserve_pub=$1"
" LIMIT 1" " LIMIT 1"
@ -663,9 +674,10 @@ postgres_prepare (PGconn *db_conn)
",current_balance_frac" ",current_balance_frac"
",current_balance_curr" ",current_balance_curr"
",expiration_date" ",expiration_date"
",gc_date"
") VALUES " ") VALUES "
"($1, $2, $3, $4, $5, $6);", "($1, $2, $3, $4, $5, $6, $7);",
6), 7),
/* Used in #postgres_insert_reserve_closed() */ /* Used in #postgres_insert_reserve_closed() */
GNUNET_PQ_make_prepare ("reserves_close_insert", GNUNET_PQ_make_prepare ("reserves_close_insert",
"INSERT INTO reserves_close " "INSERT INTO reserves_close "
@ -687,12 +699,13 @@ postgres_prepare (PGconn *db_conn)
"UPDATE reserves" "UPDATE reserves"
" SET" " SET"
" expiration_date=$1" " expiration_date=$1"
",current_balance_val=$2" ",gc_date=$2"
",current_balance_frac=$3" ",current_balance_val=$3"
",current_balance_curr=$4" ",current_balance_frac=$4"
",current_balance_curr=$5"
" WHERE" " WHERE"
" reserve_pub=$5;", " reserve_pub=$6;",
5), 6),
/* Used in #postgres_reserves_in_insert() to store transaction details */ /* Used in #postgres_reserves_in_insert() to store transaction details */
GNUNET_PQ_make_prepare ("reserves_in_add_transaction", GNUNET_PQ_make_prepare ("reserves_in_add_transaction",
"INSERT INTO reserves_in " "INSERT INTO reserves_in "
@ -1788,7 +1801,7 @@ postgres_prepare (PGconn *db_conn)
GNUNET_PQ_make_prepare ("gc_reserves", GNUNET_PQ_make_prepare ("gc_reserves",
"DELETE" "DELETE"
" FROM reserves" " FROM reserves"
" WHERE expiration_date < $1" " WHERE gc_date < $1"
" AND current_balance_val = 0" " AND current_balance_val = 0"
" AND current_balance_frac = 0;", " AND current_balance_frac = 0;",
1), 1),
@ -2277,6 +2290,7 @@ postgres_reserve_get (void *cls,
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_result_spec_amount("current_balance", &reserve->balance), TALER_PQ_result_spec_amount("current_balance", &reserve->balance),
TALER_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry), TALER_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry),
TALER_PQ_result_spec_absolute_time("gc_date", &reserve->gc),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
@ -2303,6 +2317,7 @@ reserves_update (void *cls,
{ {
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
TALER_PQ_query_param_absolute_time (&reserve->expiry), TALER_PQ_query_param_absolute_time (&reserve->expiry),
TALER_PQ_query_param_absolute_time (&reserve->gc),
TALER_PQ_query_param_amount (&reserve->balance), TALER_PQ_query_param_amount (&reserve->balance),
GNUNET_PQ_query_param_auto_from_type (&reserve->pub), GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
@ -2382,6 +2397,7 @@ postgres_reserves_in_insert (void *cls,
GNUNET_NO)); GNUNET_NO));
expiry = GNUNET_TIME_absolute_add (execution_time, expiry = GNUNET_TIME_absolute_add (execution_time,
pg->idle_reserve_expiration_time); pg->idle_reserve_expiration_time);
(void) GNUNET_TIME_round_abs (&expiry);
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == reserve_exists) if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == reserve_exists)
{ {
/* New reserve, create balance for the first time; we do this /* New reserve, create balance for the first time; we do this
@ -2394,6 +2410,7 @@ postgres_reserves_in_insert (void *cls,
GNUNET_PQ_query_param_string (sender_account_details), GNUNET_PQ_query_param_string (sender_account_details),
TALER_PQ_query_param_amount (balance), TALER_PQ_query_param_amount (balance),
TALER_PQ_query_param_absolute_time (&expiry), TALER_PQ_query_param_absolute_time (&expiry),
TALER_PQ_query_param_absolute_time (&expiry),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
@ -2461,6 +2478,10 @@ postgres_reserves_in_insert (void *cls,
} }
updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry,
reserve.expiry); reserve.expiry);
(void) GNUNET_TIME_round_abs (&updated_reserve.expiry);
updated_reserve.gc = GNUNET_TIME_absolute_max (updated_reserve.expiry,
reserve.gc);
(void) GNUNET_TIME_round_abs (&updated_reserve.gc);
return reserves_update (cls, return reserves_update (cls,
session, session,
&updated_reserve); &updated_reserve);
@ -2627,13 +2648,11 @@ postgres_insert_withdraw_info (void *cls,
TALER_B2S (&collectable->reserve_pub)); TALER_B2S (&collectable->reserve_pub));
return GNUNET_DB_STATUS_SOFT_ERROR; return GNUNET_DB_STATUS_SOFT_ERROR;
} }
/* FIXME: idle_reserve_expiration_time is not a good value here,
we should base this on the LEGAL expiration time of coins
as we need reserve data for payback! */
expiry = GNUNET_TIME_absolute_add (now, expiry = GNUNET_TIME_absolute_add (now,
pg->idle_reserve_expiration_time); pg->legal_reserve_expiration_time);
reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve.gc = GNUNET_TIME_absolute_max (expiry,
reserve.expiry); reserve.gc);
(void) GNUNET_TIME_round_abs (&reserve.gc);
qs = reserves_update (cls, qs = reserves_update (cls,
session, session,
&reserve); &reserve);
@ -7081,10 +7100,16 @@ postgres_insert_payback_request (void *cls,
GNUNET_break (0); GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
expiry = GNUNET_TIME_absolute_add (timestamp,
pg->legal_reserve_expiration_time);
reserve.gc = GNUNET_TIME_absolute_max (expiry,
reserve.gc);
(void) GNUNET_TIME_round_abs (&reserve.gc);
expiry = GNUNET_TIME_absolute_add (timestamp, expiry = GNUNET_TIME_absolute_add (timestamp,
pg->idle_reserve_expiration_time); pg->idle_reserve_expiration_time);
reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve.expiry = GNUNET_TIME_absolute_max (expiry,
reserve.expiry); reserve.expiry);
(void) GNUNET_TIME_round_abs (&reserve.expiry);
qs = reserves_update (cls, qs = reserves_update (cls,
session, session,
&reserve); &reserve);
@ -7725,15 +7750,20 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
} }
} }
if (GNUNET_OK != if ( (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (cfg, GNUNET_CONFIGURATION_get_value_time (cfg,
"exchangedb", "exchangedb",
"IDLE_RESERVE_EXPIRATION_TIME", "IDLE_RESERVE_EXPIRATION_TIME",
&pg->idle_reserve_expiration_time)) &pg->idle_reserve_expiration_time)) ||
(GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (cfg,
"exchangedb",
"LEGAL_RESERVE_EXPIRATION_TIME",
&pg->legal_reserve_expiration_time)) )
{ {
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchangedb", "exchangedb",
"IDLE_RESERVE_EXPIRATION_TIME"); "LEGAL/IDLE_RESERVE_EXPIRATION_TIME");
GNUNET_free (pg); GNUNET_free (pg);
return NULL; return NULL;
} }

View File

@ -17,3 +17,7 @@ CONFIG = postgres:///talercheck
# it is only configurable for testing, and should be treated # it is only configurable for testing, and should be treated
# as constant in production. # as constant in production.
IDLE_RESERVE_EXPIRATION_TIME = 4 weeks IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
# After how long do we forget about reserves? Should be above
# the legal expiration timeframe of withdrawn coins.
LEGAL_RESERVE_EXPIRATION_TIME = 7 years

View File

@ -127,9 +127,16 @@ struct TALER_EXCHANGEDB_Reserve
struct TALER_Amount balance; struct TALER_Amount balance;
/** /**
* The expiration date of this reserve * The expiration date of this reserve; funds will be wired back
* at this time.
*/ */
struct GNUNET_TIME_Absolute expiry; struct GNUNET_TIME_Absolute expiry;
/**
* The legal expiration date of this reserve; we will forget about
* it at this time.
*/
struct GNUNET_TIME_Absolute gc;
}; };