-add missing checkpointing logic

This commit is contained in:
Christian Grothoff 2022-06-19 14:04:41 +02:00
parent 8da74a6ca7
commit bad572a010
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 304 additions and 76 deletions

View File

@ -2350,6 +2350,11 @@ check_denomination (
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
* @param deposit deposit details
* @param reserve_pub which reserve is the purse merged into, NULL if unknown
* @param flags purse flags
* @param auditor_balance purse balance (according to the
* auditor during auditing)
* @param purse_total target amount the purse should reach
* @param denom_pub denomination public key of @a coin_pub
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@ -2358,6 +2363,10 @@ purse_deposit_cb (
void *cls,
uint64_t rowid,
const struct TALER_EXCHANGEDB_PurseDeposit *deposit,
const struct TALER_ReservePublicKeyP *reserve_pub,
enum TALER_WalletAccountMergeFlags flags,
const struct TALER_Amount *auditor_balance,
const struct TALER_Amount *purse_total,
const struct TALER_DenominationPublicKey *denom_pub)
{
struct CoinContext *cc = cls;
@ -2366,6 +2375,10 @@ purse_deposit_cb (
const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue;
struct DenominationSummary *ds;
(void) flags;
(void) auditor_balance;
(void) purse_total;
(void) reserve_pub;
GNUNET_assert (rowid >= ppc.last_purse_deposits_serial_id);
ppc.last_purse_deposits_serial_id = rowid + 1;
qs = TALER_ARL_get_denomination_info (denom_pub,

View File

@ -69,6 +69,11 @@ static json_t *denomination_key_validity_withdraw_inconsistencies;
*/
static json_t *report_reserve_balance_insufficient_inconsistencies;
/**
* Array of reports about purse balance insufficient inconsitencies.
*/
static json_t *report_purse_balance_insufficient_inconsistencies;
/**
* Total amount reserves were charged beyond their balance.
*/
@ -754,10 +759,11 @@ handle_recoup_by_reserve (
{
rev = "revoked";
}
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (rc->revoked,
&coin->denom_pub_hash.
hash,
GNUNET_assert (
GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (
rc->revoked,
&coin->denom_pub_hash.hash,
(void *) rev,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
@ -1255,6 +1261,12 @@ verify_reserve_balance (void *cls,
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
* @param deposit deposit details
* @param reserve_pub which reserve is the purse merged into, NULL if unknown
* @param auditor_balance balance of the purse calculated by auditor
* @param flags purse flags
* @param auditor_balance purse balance (according to the
* auditor during auditing)
* @param purse_total target amount the purse should reach
* @param denom_pub denomination public key of @a coin_pub
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@ -1263,12 +1275,25 @@ handle_purse_deposits (
void *cls,
uint64_t rowid,
const struct TALER_EXCHANGEDB_PurseDeposit *deposit,
const struct TALER_ReservePublicKeyP *reserve_pub,
enum TALER_WalletAccountMergeFlags flags,
const struct TALER_Amount *auditor_balance,
const struct TALER_Amount *purse_total,
const struct TALER_DenominationPublicKey *denom_pub)
{
struct ReserveContext *rc = cls;
const char *base_url
= (NULL == deposit->exchange_base_url)
? TALER_ARL_exchange_url
: deposit->exchange_base_url;
enum GNUNET_DB_QueryStatus qs;
struct TALER_Amount amount_minus_fee;
struct TALER_Amount new_balance;
struct ReserveSummary *rs;
/* should be monotonically increasing */
GNUNET_assert (rowid >= ppr.last_purse_deposits_serial_id);
ppr.last_purse_deposits_serial_id = rowid + 1;
if (GNUNET_OK !=
TALER_wallet_purse_deposit_verify (base_url,
@ -1293,11 +1318,88 @@ handle_purse_deposits (
return GNUNET_OK;
}
GNUNET_break (0); // FIXME
// FIXME: need flags + total deposited!
/* Credit purse value (if last op)! */
{
const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue;
enum GNUNET_DB_QueryStatus qs;
struct TALER_DenominationHashP h_denom_pub;
qs = TALER_ARL_get_denomination_info (denom_pub,
&issue,
&h_denom_pub);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Hard database error trying to get denomination %s from database!\n",
TALER_B2S (denom_pub));
rc->qs = qs;
return GNUNET_SYSERR;
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
report_row_inconsistency ("purse-deposit",
rowid,
"denomination key not found");
if (TALER_ARL_do_abort ())
return GNUNET_SYSERR;
return GNUNET_OK;
}
TALER_ARL_amount_subtract (&amount_minus_fee,
&deposit->amount,
&issue->fees.deposit);
}
TALER_ARL_amount_add (&new_balance,
auditor_balance,
&amount_minus_fee);
qs = TALER_ARL_edb->set_purse_balance (TALER_ARL_edb->cls,
&deposit->purse_pub,
&new_balance);
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs);
if (qs < 0)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
rc->qs = qs;
return GNUNET_SYSERR;
}
if (TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE !=
(flags & TALER_WAMF_MERGE_MODE_MASK))
{
/* This just created the purse, actual credit to
the reserve will be done in handle_account_merged() */
return GNUNET_OK;
}
if ( (NULL != deposit->exchange_base_url) &&
(0 != strcmp (deposit->exchange_base_url,
TALER_ARL_exchange_url)) )
{
/* credited reserve is at another exchange, do NOT credit here! */
return GNUNET_OK;
}
rs = setup_reserve (rc,
reserve_pub);
if (NULL == rs)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if ( (-1 != TALER_amount_cmp (&new_balance,
purse_total)) &&
(-1 == TALER_amount_cmp (auditor_balance,
purse_total)) )
{
/* new balance at or above purse_total
(and previous balance was below); thus
credit reserve with purse value! */
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
purse_total);
}
return GNUNET_OK;
}
/**
@ -1307,6 +1409,15 @@ handle_purse_deposits (
*
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
* @param partner_base_url where is the reserve, NULL for this exchange
* @param amount total amount expected in the purse
* @param balance current balance in the purse (according to the auditor)
* @param flags purse flags
* @param merge_pub merge capability key
* @param reserve_pub reserve the merge affects
* @param merge_sig signature affirming the merge
* @param purse_pub purse key
* @param merge_timestamp when did the merge happen
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
static enum GNUNET_GenericReturnValue
@ -1315,6 +1426,7 @@ handle_purse_merged (
uint64_t rowid,
const char *partner_base_url,
const struct TALER_Amount *amount,
const struct TALER_Amount *balance,
enum TALER_WalletAccountMergeFlags flags,
const struct TALER_PurseMergePublicKeyP *merge_pub,
const struct TALER_ReservePublicKeyP *reserve_pub,
@ -1326,6 +1438,9 @@ handle_purse_merged (
struct ReserveSummary *rs;
char *reserve_url;
/* should be monotonically increasing */
GNUNET_assert (rowid >= ppr.last_purse_merges_serial_id);
ppr.last_purse_merges_serial_id = rowid + 1;
reserve_url
= TALER_reserve_make_payto (NULL == partner_base_url
? TALER_ARL_exchange_url
@ -1376,10 +1491,34 @@ handle_purse_merged (
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (-1 == TALER_amount_cmp (balance,
amount))
{
struct TALER_Amount loss;
TALER_ARL_amount_subtract (&loss,
amount,
balance);
/* illegal merge, balance is still below total purse value */
TALER_ARL_report (report_purse_balance_insufficient_inconsistencies,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("operation",
"merge-purse"),
GNUNET_JSON_pack_uint64 ("row",
rowid),
TALER_JSON_pack_amount ("loss",
&loss),
GNUNET_JSON_pack_data_auto ("purse_pub",
purse_pub)));
TALER_ARL_amount_add (&total_balance_insufficient_loss,
&total_balance_insufficient_loss,
&loss);
return GNUNET_OK;
}
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
amount);
// rs->a_expiration_date = FIXME: set to what?;
// rs->a_expiration_date = FIXME: do we care? If so, set to what (so that the auditor no longer complains about the reserve not being closed)
return GNUNET_OK;
}
@ -1411,6 +1550,9 @@ handle_account_merged (
struct ReserveContext *rc = cls;
struct ReserveSummary *rs;
/* should be monotonically increasing */
GNUNET_assert (rowid >= ppr.last_account_merges_serial_id);
ppr.last_account_merges_serial_id = rowid + 1;
if (GNUNET_OK !=
TALER_wallet_account_merge_verify (merge_timestamp,
purse_pub,
@ -1476,6 +1618,9 @@ handle_history_request (
struct ReserveContext *rc = cls;
struct ReserveSummary *rs;
/* should be monotonically increasing */
GNUNET_assert (rowid >= ppr.last_history_requests_serial_id);
ppr.last_history_requests_serial_id = rowid + 1;
if (GNUNET_OK !=
TALER_wallet_reserve_history_verify (ts,
history_fee,
@ -1616,17 +1761,6 @@ analyze_reserves (void *cls)
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
/* Credit purse value (if last op)! */
qs = TALER_ARL_edb->select_purse_merges_above_serial_id (
TALER_ARL_edb->cls,
ppr.last_purse_merges_serial_id,
&handle_purse_merged,
&rc);
if (qs < 0)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
qs = TALER_ARL_edb->select_purse_deposits_above_serial_id (
TALER_ARL_edb->cls,
ppr.last_purse_deposits_serial_id,
@ -1648,6 +1782,17 @@ analyze_reserves (void *cls)
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
/* Credit purse value (if last op)! */
qs = TALER_ARL_edb->select_purse_merges_above_serial_id (
TALER_ARL_edb->cls,
ppr.last_purse_merges_serial_id,
&handle_purse_merged,
&rc);
if (qs < 0)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
/* Charge history fee! */
qs = TALER_ARL_edb->select_history_requests_above_serial_id (
TALER_ARL_edb->cls,
@ -1822,6 +1967,9 @@ run (void *cls,
GNUNET_assert (NULL !=
(report_reserve_balance_insufficient_inconsistencies
= json_array ()));
GNUNET_assert (NULL !=
(report_purse_balance_insufficient_inconsistencies
= json_array ()));
GNUNET_assert (NULL !=
(report_reserve_not_closed_inconsistencies
= json_array ()));
@ -1842,6 +1990,9 @@ run (void *cls,
GNUNET_JSON_pack_array_steal (
"reserve_balance_insufficient_inconsistencies",
report_reserve_balance_insufficient_inconsistencies),
GNUNET_JSON_pack_array_steal (
"purse_balance_insufficient_inconsistencies",
report_purse_balance_insufficient_inconsistencies),
/* Tested in test-auditor.sh #3 */
TALER_JSON_pack_amount ("total_loss_balance_insufficient",
&total_balance_insufficient_loss),

View File

@ -904,6 +904,14 @@ prepare_statements (struct PostgresClosure *pg)
" FROM exchange_do_purse_deposit"
" ($1,$2,$3,$4,$5,$6,$7,$8);",
8),
/* Used in #postgres_update_aggregation_transient() */
GNUNET_PQ_make_prepare (
"set_purse_balance",
"UPDATE purse_requests"
" SET balance_val=$2"
" ,balance_frac=$3"
" WHERE purse_pub=$1;",
3),
/* used in #postgres_expire_purse() */
GNUNET_PQ_make_prepare (
"call_expire_purse",
@ -1503,17 +1511,25 @@ prepare_statements (struct PostgresClosure *pg)
GNUNET_PQ_make_prepare (
"audit_get_purse_deposits_incr",
"SELECT"
" amount_with_fee_val"
",amount_with_fee_frac"
",purse_pub"
",coin_sig"
" pd.amount_with_fee_val"
",pd.amount_with_fee_frac"
",pr.amount_with_fee_val AS total_val"
",pr.amount_with_fee_frac AS total_frac"
",pr.balance_val"
",pr.balance_frac"
",pr.flags"
",pd.purse_pub"
",pd.coin_sig"
",partner_base_url"
",denom.denom_pub"
",pm.reserve_pub"
",kc.coin_pub"
",kc.age_commitment_hash"
",purse_deposit_serial_id"
" FROM purse_deposits"
",pd.purse_deposit_serial_id"
" FROM purse_deposits pd"
" LEFT JOIN partners USING (partner_serial_id)"
" LEFT JOIN purse_merges pm USING (purse_pub)"
" JOIN purse_requests pr USING (purse_pub)"
" JOIN known_coins kc USING (coin_pub)"
" JOIN denominations denom USING (denominations_serial)"
" WHERE ("
@ -1554,6 +1570,8 @@ prepare_statements (struct PostgresClosure *pg)
",partner_base_url"
",pr.amount_with_fee_val"
",pr.amount_with_fee_frac"
",pr.balance_val"
",pr.balance_frac"
",pr.flags"
",pr.merge_pub"
",pm.reserve_pub"
@ -10532,21 +10550,36 @@ purse_deposit_serial_helper_cb (void *cls,
};
struct TALER_DenominationPublicKey denom_pub;
uint64_t rowid;
uint32_t flags32;
struct TALER_ReservePublicKeyP reserve_pub;
bool not_merged = false;
struct TALER_Amount purse_balance;
struct TALER_Amount purse_total;
struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&deposit.amount),
TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
&purse_balance),
TALER_PQ_RESULT_SPEC_AMOUNT ("total",
&purse_total),
TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
&deposit.deposit_fee),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("partner_base_url",
&deposit.exchange_base_url),
NULL),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
&not_merged),
TALER_PQ_result_spec_denom_pub ("denom_pub",
&denom_pub),
GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
&deposit.purse_pub),
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
&deposit.coin_sig),
GNUNET_PQ_result_spec_uint32 ("flags",
&flags32),
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&deposit.coin_pub),
GNUNET_PQ_result_spec_allow_null (
@ -10574,6 +10607,10 @@ purse_deposit_serial_helper_cb (void *cls,
ret = dsc->cb (dsc->cb_cls,
rowid,
&deposit,
not_merged ? NULL : &reserve_pub,
(enum TALER_WalletAccountMergeFlags) flags32,
&purse_balance,
&purse_total,
&denom_pub);
GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret)
@ -10827,6 +10864,7 @@ purse_merges_serial_helper_cb (void *cls,
uint64_t rowid;
char *partner_base_url = NULL;
struct TALER_Amount amount;
struct TALER_Amount balance;
uint32_t flags32;
enum TALER_WalletAccountMergeFlags flags;
struct TALER_PurseMergePublicKeyP merge_pub;
@ -10837,6 +10875,8 @@ purse_merges_serial_helper_cb (void *cls,
struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&amount),
TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
&balance),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("partner_base_url",
&partner_base_url),
@ -10873,6 +10913,7 @@ purse_merges_serial_helper_cb (void *cls,
rowid,
partner_base_url,
&amount,
&balance,
flags,
&merge_pub,
&reserve_pub,
@ -15540,6 +15581,35 @@ postgres_do_purse_deposit (
}
/**
* Set the current @a balance in the purse
* identified by @a purse_pub. Used by the auditor
* to update the balance as calculated by the auditor.
*
* @param cls closure
* @param purse_pub public key of a purse
* @param balance new balance to store under the purse
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_set_purse_balance (
void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub,
const struct TALER_Amount *balance)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (purse_pub),
TALER_PQ_query_param_amount (balance),
GNUNET_PQ_query_param_end
};
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"set_purse_balance",
params);
}
/**
* Function called to obtain a coin deposit data from
* depositing the coin into a purse.
@ -16171,6 +16241,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_select_purse_by_merge_pub;
plugin->do_purse_deposit
= &postgres_do_purse_deposit;
plugin->set_purse_balance
= &postgres_set_purse_balance;
plugin->get_purse_deposit
= &postgres_get_purse_deposit;
plugin->do_purse_merge

View File

@ -1990,6 +1990,11 @@ typedef enum GNUNET_GenericReturnValue
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
* @param deposit deposit details
* @param reserve_pub which reserve is the purse merged into, NULL if unknown
* @param flags purse flags
* @param auditor_balance purse balance (according to the
* auditor during auditing)
* @param purse_total target amount the purse should reach
* @param denom_pub denomination public key of @a coin_pub
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@ -1998,6 +2003,10 @@ typedef enum GNUNET_GenericReturnValue
void *cls,
uint64_t rowid,
const struct TALER_EXCHANGEDB_PurseDeposit *deposit,
const struct TALER_ReservePublicKeyP *reserve_pub,
enum TALER_WalletAccountMergeFlags flags,
const struct TALER_Amount *auditor_balance,
const struct TALER_Amount *purse_total,
const struct TALER_DenominationPublicKey *denom_pub);
@ -2033,6 +2042,15 @@ typedef enum GNUNET_GenericReturnValue
*
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
* @param partner_base_url where is the reserve, NULL for this exchange
* @param amount total amount expected in the purse
* @param balance current balance in the purse (according to the auditor)
* @param flags purse flags
* @param merge_pub merge capability key
* @param reserve_pub reserve the merge affects
* @param merge_sig signature affirming the merge
* @param purse_pub purse key
* @param merge_timestamp when did the merge happen
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
typedef enum GNUNET_GenericReturnValue
@ -2041,6 +2059,7 @@ typedef enum GNUNET_GenericReturnValue
uint64_t rowid,
const char *partner_base_url,
const struct TALER_Amount *amount,
const struct TALER_Amount *balance,
enum TALER_WalletAccountMergeFlags flags,
const struct TALER_PurseMergePublicKeyP *merge_pub,
const struct TALER_ReservePublicKeyP *reserve_pub,
@ -5290,6 +5309,23 @@ struct TALER_EXCHANGEDB_Plugin
bool *conflict);
/**
* Set the current @a balance in the purse
* identified by @a purse_pub. Used by the auditor
* to update the balance as calculated by the auditor.
*
* @param cls closure
* @param purse_pub public key of a purse
* @param balance new balance to store under the purse
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*set_purse_balance)(
void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub,
const struct TALER_Amount *balance);
/**
* Function called to obtain a coin deposit data from
* depositing the coin into a purse.

View File

@ -119,50 +119,6 @@ struct TALER_EXCHANGE_AccountMergeHandle
};
static char *
make_payto (const char *exchange_url,
const struct TALER_ReservePublicKeyP *reserve_pub)
{
char pub_str[sizeof (*reserve_pub) * 2];
char *end;
bool is_http;
char *reserve_url;
end = GNUNET_STRINGS_data_to_string (
reserve_pub,
sizeof (*reserve_pub),
pub_str,
sizeof (pub_str));
*end = '\0';
if (0 == strncmp (exchange_url,
"http://",
strlen ("http://")))
{
is_http = true;
exchange_url = &exchange_url[strlen ("http://")];
}
else if (0 == strncmp (exchange_url,
"https://",
strlen ("https://")))
{
is_http = false;
exchange_url = &exchange_url[strlen ("https://")];
}
else
{
GNUNET_break (0);
return NULL;
}
/* exchange_url includes trailing '/' */
GNUNET_asprintf (&reserve_url,
"payto://%s/%s%s",
is_http ? "taler+http" : "taler",
exchange_url,
pub_str);
return reserve_url;
}
/**
* Function called when we're done processing the
* HTTP /purse/$PID/merge request.
@ -379,7 +335,7 @@ TALER_EXCHANGE_account_merge (
"/purses/%s/merge",
pub_str);
}
reserve_url = make_payto (pch->provider_url,
reserve_url = TALER_reserve_make_payto (pch->provider_url,
&pch->reserve_pub);
if (NULL == reserve_url)
{