summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/auditor/.gitignore1
-rw-r--r--src/auditor/taler-helper-auditor-purses.c676
-rw-r--r--src/exchange/taler-exchange-httpd_purses_create.c18
-rw-r--r--src/exchange/taler-exchange-httpd_purses_deposit.c2
-rw-r--r--src/exchange/taler-exchange-httpd_purses_get.c2
-rw-r--r--src/exchange/taler-exchange-httpd_purses_merge.c18
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_purse.c2
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c158
-rw-r--r--src/include/taler_auditordb_plugin.h55
-rw-r--r--src/include/taler_crypto_lib.h4
-rw-r--r--src/include/taler_exchangedb_plugin.h89
-rw-r--r--src/util/wallet_signatures.c4
12 files changed, 834 insertions, 195 deletions
diff --git a/src/auditor/.gitignore b/src/auditor/.gitignore
index 59088a1b3..963062c1e 100644
--- a/src/auditor/.gitignore
+++ b/src/auditor/.gitignore
@@ -23,3 +23,4 @@ auditor-basedb.sqlite3
taler-auditor-test.sqlite3
libeufin-nexus.pid
libeufin-sandbox.pid
+taler-helper-auditor-purses
diff --git a/src/auditor/taler-helper-auditor-purses.c b/src/auditor/taler-helper-auditor-purses.c
index cfc345ebe..6a101ee44 100644
--- a/src/auditor/taler-helper-auditor-purses.c
+++ b/src/auditor/taler-helper-auditor-purses.c
@@ -69,6 +69,11 @@ static json_t *report_purse_balance_insufficient_inconsistencies;
static struct TALER_Amount total_balance_insufficient_loss;
/**
+ * Total amount purse decisions are delayed past deadline.
+ */
+static struct TALER_Amount total_delayed_decisions;
+
+/**
* Array of reports about purses's not being closed inconsitencies.
*/
static json_t *report_purse_not_closed_inconsistencies;
@@ -199,6 +204,54 @@ report_row_inconsistency (const char *table,
}
+/**
+ * Obtain the purse fee for a purse created at @a time.
+ *
+ * @param atime when was the purse created
+ * @param[out] fee set to the purse fee
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+get_purse_fee (struct GNUNET_TIME_Timestamp atime,
+ struct TALER_Amount *fee)
+{
+ struct TALER_MasterSignatureP master_sig;
+ struct GNUNET_TIME_Timestamp start_date;
+ struct GNUNET_TIME_Timestamp end_date;
+ struct TALER_GlobalFeeSet fees;
+ struct GNUNET_TIME_Relative ptimeout;
+ struct GNUNET_TIME_Relative ktimeout;
+ struct GNUNET_TIME_Relative hexp;
+ uint32_t pacl;
+
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ TALER_ARL_edb->get_global_fee (TALER_ARL_edb->cls,
+ atime,
+ &start_date,
+ &end_date,
+ &fees,
+ &ptimeout,
+ &ktimeout,
+ &hexp,
+ &pacl,
+ &master_sig))
+ {
+ char *diag;
+
+ GNUNET_asprintf (&diag,
+ "purse fee unavailable at %s\n",
+ GNUNET_TIME_timestamp2s (atime));
+ report_row_inconsistency ("purse-fee",
+ atime.abs_time.abs_value_us,
+ diag);
+ GNUNET_free (diag);
+ return GNUNET_SYSERR;
+ }
+ *fee = fees.purse;
+ return GNUNET_OK;
+}
+
+
/* ***************************** Analyze purses ************************ */
/* This logic checks the purses_requests, purse_deposits,
purse_refunds, purse_merges and account_merges */
@@ -215,18 +268,38 @@ struct PurseSummary
struct TALER_PurseContractPublicKeyP purse_pub;
/**
- * Balance of the purse from deposits (excludes
- * deposit fees).
- * Updated only in #handle_purse_deposits().
+ * Balance of the purse from deposits (includes purse fee, excludes deposit
+ * fees), as calculated by auditor.
*/
struct TALER_Amount balance;
/**
- * Expected value of the purse.
+ * Expected value of the purse, excludes purse fee.
*/
struct TALER_Amount total_value;
/**
+ * Purse balance according to exchange DB.
+ */
+ struct TALER_Amount exchange_balance;
+
+ /**
+ * Contract terms of the purse.
+ */
+ struct TALER_PrivateContractHashP h_contract_terms;
+
+ /**
+ * Merge timestamp (as per exchange DB).
+ */
+ struct GNUNET_TIME_Timestamp merge_timestamp;
+
+ /**
+ * Purse creation date. This is when the merge
+ * fee is applied.
+ */
+ struct GNUNET_TIME_Timestamp creation_date;
+
+ /**
* Purse expiration date.
*/
struct GNUNET_TIME_Timestamp expiration_date;
@@ -328,6 +401,21 @@ setup_purse (struct PurseContext *pc,
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&ps->balance));
+ /* get purse meta-data from exchange DB */
+ qs = TALER_ARL_edb->select_purse (TALER_ARL_edb->cls,
+ purse_pub,
+ &ps->creation_date,
+ &ps->expiration_date,
+ &ps->total_value,
+ &ps->exchange_balance,
+ &ps->h_contract_terms,
+ &ps->merge_timestamp);
+ if (0 >= qs)
+ {
+ GNUNET_free (ps);
+ pc->qs = qs;
+ return NULL;
+ }
if (0 > (qs = load_auditor_purse_summary (ps)))
{
GNUNET_free (ps);
@@ -344,33 +432,76 @@ setup_purse (struct PurseContext *pc,
/**
- * Check that the purse summary matches what the exchange database
- * thinks about the purse, and update our own state of the purse.
- *
- * Remove all purses that we are happy with from the DB.
+ * Function called on purse requests.
*
- * @param cls our `struct PurseContext`
- * @param key hash of the purse public key
- * @param value a `struct PurseSummary`
- * @return #GNUNET_OK to process more entries
- */
+ * @param cls closure
+ * @param purse_pub public key of the purse
+ * @param merge_pub public key representing the merge capability
+ * @param purse_expiration when would an unmerged purse expire
+ * @param h_contract_terms contract associated with the purse
+ * @param age_limit the age limit for deposits into the purse
+ * @param target_amount amount to be put into the purse
+ * @param purse_sig signature of the purse over the initialization data
+ * @return #GNUNET_OK to continue to iterate
+ */
static enum GNUNET_GenericReturnValue
-verify_purse_balance (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
+handle_purse_requested (
+ void *cls,
+ uint64_t rowid,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_PurseMergePublicKeyP *merge_pub,
+ struct GNUNET_TIME_Timestamp purse_creation,
+ struct GNUNET_TIME_Timestamp purse_expiration,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ uint32_t age_limit,
+ const struct TALER_Amount *target_amount,
+ const struct TALER_PurseContractSignatureP *purse_sig)
{
struct PurseContext *pc = cls;
- struct PurseSummary *ps = value;
- enum GNUNET_GenericReturnValue ret;
+ struct PurseSummary *ps;
+ struct GNUNET_HashCode key;
- ret = GNUNET_OK;
- // FIXME: implement!
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (pc->purses,
- key,
- ps));
- GNUNET_free (ps);
- return ret;
+ if (GNUNET_OK !=
+ TALER_wallet_purse_create_verify (purse_expiration,
+ h_contract_terms,
+ merge_pub,
+ age_limit,
+ target_amount,
+ purse_pub,
+ purse_sig))
+ {
+ TALER_ARL_report (report_bad_sig_losses,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("operation",
+ "purse-reqeust"),
+ GNUNET_JSON_pack_uint64 ("row",
+ rowid),
+ TALER_JSON_pack_amount ("loss",
+ target_amount),
+ GNUNET_JSON_pack_data_auto ("key_pub",
+ purse_pub)));
+ TALER_ARL_amount_add (&total_bad_sig_loss,
+ &total_bad_sig_loss,
+ target_amount);
+ }
+ GNUNET_CRYPTO_hash (purse_pub,
+ sizeof (*purse_pub),
+ &key);
+ ps = GNUNET_new (struct PurseSummary);
+ ps->purse_pub = *purse_pub;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (TALER_ARL_currency,
+ &ps->balance));
+ ps->creation_date = purse_creation;
+ ps->expiration_date = purse_expiration;
+ ps->total_value = *target_amount;
+ ps->h_contract_terms = *h_contract_terms;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (pc->purses,
+ &key,
+ ps,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ return GNUNET_OK;
}
@@ -401,14 +532,12 @@ handle_purse_deposits (
const struct TALER_DenominationPublicKey *denom_pub)
{
struct PurseContext *pc = cls;
+ struct TALER_Amount amount_minus_fee;
+ struct PurseSummary *ps;
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 PurseSummary *rs;
struct TALER_DenominationHashP h_denom_pub;
/* should be monotonically increasing */
@@ -471,68 +600,42 @@ handle_purse_deposits (
return GNUNET_OK;
}
- 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);
- pc->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_purse (pc,
+ ps = setup_purse (pc,
&deposit->purse_pub);
- if (NULL == rs)
+ if (NULL == ps)
{
- GNUNET_break (0);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == pc->qs)
+ {
+ report_row_inconsistency ("purse-deposit",
+ rowid,
+ "purse not found");
+ }
+ else
+ {
+ /* Database trouble!? */
+ 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->balance,
- &rs->balance,
- purse_total);
- }
+ TALER_ARL_amount_add (&ps->balance,
+ &ps->balance,
+ &amount_minus_fee);
+ TALER_ARL_amount_add (&balance.balance,
+ &balance.balance,
+ &amount_minus_fee);
return GNUNET_OK;
}
/**
- * Function called with details about purse
- * merges that have been made, with
+ * Function called with details about purse merges that have been made, with
* the goal of auditing the purse merge execution.
*
* @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 balance current balance in the purse
* @param flags purse flags
* @param merge_pub merge capability key
* @param reserve_pub reserve the merge affects
@@ -557,97 +660,76 @@ handle_purse_merged (
{
struct PurseContext *pc = cls;
struct PurseSummary *ps;
- char *reserve_url;
/* should be monotonically increasing */
GNUNET_assert (rowid >= ppp.last_purse_merge_serial_id);
ppp.last_purse_merge_serial_id = rowid + 1;
- reserve_url
- = TALER_reserve_make_payto (NULL == partner_base_url
+
+ {
+ char *reserve_url;
+
+ reserve_url
+ = TALER_reserve_make_payto (NULL == partner_base_url
? TALER_ARL_exchange_url
: partner_base_url,
- reserve_pub);
- if (GNUNET_OK !=
- TALER_wallet_purse_merge_verify (reserve_url,
- merge_timestamp,
- purse_pub,
- merge_pub,
- merge_sig))
- {
+ reserve_pub);
+ if (GNUNET_OK !=
+ TALER_wallet_purse_merge_verify (reserve_url,
+ merge_timestamp,
+ purse_pub,
+ merge_pub,
+ merge_sig))
+ {
+ GNUNET_free (reserve_url);
+ TALER_ARL_report (report_bad_sig_losses,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("operation",
+ "merge-purse"),
+ GNUNET_JSON_pack_uint64 ("row",
+ rowid),
+ TALER_JSON_pack_amount ("loss",
+ amount),
+ GNUNET_JSON_pack_data_auto ("key_pub",
+ merge_pub)));
+ TALER_ARL_amount_add (&total_bad_sig_loss,
+ &total_bad_sig_loss,
+ amount);
+ return GNUNET_OK;
+ }
GNUNET_free (reserve_url);
- TALER_ARL_report (report_bad_sig_losses,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("operation",
- "merge-purse"),
- GNUNET_JSON_pack_uint64 ("row",
- rowid),
- TALER_JSON_pack_amount ("loss",
- amount),
- GNUNET_JSON_pack_data_auto ("key_pub",
- merge_pub)));
- TALER_ARL_amount_add (&total_bad_sig_loss,
- &total_bad_sig_loss,
- amount);
- return GNUNET_OK;
- }
- GNUNET_free (reserve_url);
- 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_purse_deposits() */
- return GNUNET_OK;
- }
- if ( (NULL != partner_base_url) &&
- (0 != strcmp (partner_base_url,
- TALER_ARL_exchange_url)) )
- {
- /* credited reserve is at another exchange, do NOT credit here! */
- return GNUNET_OK;
}
+
ps = setup_purse (pc,
purse_pub);
if (NULL == ps)
{
- GNUNET_break (0);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == pc->qs)
+ {
+ report_row_inconsistency ("purse-merge",
+ rowid,
+ "purse not found");
+ }
+ else
+ {
+ /* Database trouble!? */
+ 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;
- }
+ GNUNET_break (0 ==
+ GNUNET_TIME_timestamp_cmp (merge_timestamp,
+ ==,
+ ps->merge_timestamp));
TALER_ARL_amount_add (&ps->balance,
&ps->balance,
amount);
- // ps->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;
}
/**
- * Function called with details about
- * account merge requests that have been made, with
- * the goal of auditing the account merge execution.
+ * Function called with details about account merge requests that have been
+ * made, with the goal of auditing the account merge execution.
*
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
@@ -715,21 +797,266 @@ handle_account_merged (
purse_pub);
if (NULL == ps)
{
- GNUNET_break (0);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == pc->qs)
+ {
+ report_row_inconsistency ("account-merge",
+ rowid,
+ "purse not found");
+ }
+ else
+ {
+ /* Database trouble!? */
+ GNUNET_break (0);
+ }
return GNUNET_SYSERR;
}
-
TALER_ARL_amount_add (&balance.balance,
&balance.balance,
purse_fee);
TALER_ARL_amount_add (&ps->balance,
&ps->balance,
- amount);
+ purse_fee);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with details about purse decisions that have been made.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the deposit in our DB
+ * @param purse_pub which purse was the decision made on
+ * @param refunded true if decision was to refund
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static enum GNUNET_GenericReturnValue
+handle_purse_decision (
+ void *cls,
+ uint64_t rowid,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ bool refunded)
+{
+ struct PurseContext *pc = cls;
+ struct PurseSummary *ps;
+ struct GNUNET_HashCode key;
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_Amount purse_fee;
+ struct TALER_Amount balance_without_purse_fee;
+
+ ps = setup_purse (pc,
+ purse_pub);
+ if (NULL == ps)
+ {
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == pc->qs)
+ {
+ report_row_inconsistency ("purse-decision",
+ rowid,
+ "purse not found");
+ }
+ else
+ {
+ /* Database trouble!? */
+ GNUNET_break (0);
+ }
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ get_purse_fee (ps->creation_date,
+ &purse_fee))
+ {
+ report_row_inconsistency ("purse-request",
+ rowid,
+ "purse fee unavailable");
+ }
+ if (0 >
+ TALER_amount_subtract (&balance_without_purse_fee,
+ &ps->balance,
+ &purse_fee))
+ {
+ report_row_inconsistency ("purse-request",
+ rowid,
+ "purse fee higher than balance");
+ TALER_amount_set_zero (TALER_ARL_currency,
+ &balance_without_purse_fee);
+ }
+
+ if (refunded)
+ {
+ if (-1 != TALER_amount_cmp (&balance_without_purse_fee,
+ &ps->total_value))
+ {
+ report_amount_arithmetic_inconsistency ("purse-decision: refund",
+ rowid,
+ &balance_without_purse_fee,
+ &ps->total_value,
+ 0);
+ }
+ }
+ else
+ {
+ if (-1 == TALER_amount_cmp (&balance_without_purse_fee,
+ &ps->total_value))
+ {
+ report_amount_arithmetic_inconsistency ("purse-decision: merge",
+ rowid,
+ &ps->total_value,
+ &balance_without_purse_fee,
+ 0);
+ TALER_ARL_amount_add (&total_balance_insufficient_loss,
+ &total_balance_insufficient_loss,
+ &ps->total_value);
+ }
+ }
+
+ qs = TALER_ARL_adb->delete_purse_info (TALER_ARL_adb->cls,
+ purse_pub,
+ &TALER_ARL_master_pub);
+ 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);
+ pc->qs = qs;
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CRYPTO_hash (purse_pub,
+ sizeof (*purse_pub),
+ &key);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (pc->purses,
+ &key,
+ ps));
+ GNUNET_free (ps);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called on expired purses.
+ *
+ * @param cls closure
+ * @param purse_pub public key of the purse
+ * @param balance amount of money in the purse
+ * @param expiration_date when did the purse expire?
+ * @return #GNUNET_OK to continue to iterate
+ */
+static enum GNUNET_GenericReturnValue
+handle_purse_expired (
+ void *cls,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_Amount *balance,
+ struct GNUNET_TIME_Timestamp expiration_date)
+{
+ struct PurseContext *pc = cls;
+
+ (void) pc;
+ TALER_ARL_report (report_purse_not_closed_inconsistencies,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("purse_pub",
+ purse_pub),
+ TALER_JSON_pack_amount ("balance",
+ balance),
+ TALER_JSON_pack_time_abs_human ("expired",
+ expiration_date.abs_time)));
+ TALER_ARL_amount_add (&total_delayed_decisions,
+ &total_delayed_decisions,
+ balance);
return GNUNET_OK;
}
/**
+ * Check that the purse summary matches what the exchange database
+ * thinks about the purse, and update our own state of the purse.
+ *
+ * Remove all purses that we are happy with from the DB.
+ *
+ * @param cls our `struct PurseContext`
+ * @param key hash of the purse public key
+ * @param value a `struct PurseSummary`
+ * @return #GNUNET_OK to process more entries
+ */
+static enum GNUNET_GenericReturnValue
+verify_purse_balance (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct PurseContext *pc = cls;
+ struct PurseSummary *ps = value;
+ enum GNUNET_GenericReturnValue ret;
+ enum GNUNET_DB_QueryStatus qs;
+
+ ret = GNUNET_OK;
+ if (internal_checks)
+ {
+ struct TALER_Amount pf;
+ struct TALER_Amount balance_without_purse_fee;
+
+ /* subtract purse fee from ps->balance to get actual balance we expect, as
+ we track the balance including purse fee, while the exchange subtracts
+ the purse fee early on. */
+ if (GNUNET_OK !=
+ get_purse_fee (ps->creation_date,
+ &pf))
+ {
+ GNUNET_break (0);
+ report_row_inconsistency ("purse",
+ 0,
+ "purse fee unavailable");
+ }
+ if (0 >
+ TALER_amount_subtract (&balance_without_purse_fee,
+ &ps->balance,
+ &pf))
+ {
+ report_row_inconsistency ("purse",
+ 0,
+ "purse fee higher than balance");
+ TALER_amount_set_zero (TALER_ARL_currency,
+ &balance_without_purse_fee);
+ }
+
+ if (0 != TALER_amount_cmp (&ps->exchange_balance,
+ &balance_without_purse_fee))
+ {
+ report_amount_arithmetic_inconsistency ("purse-balance",
+ 0,
+ &ps->exchange_balance,
+ &balance_without_purse_fee,
+ 0);
+ }
+ }
+
+ if (ps->had_pi)
+ qs = TALER_ARL_adb->update_purse_info (TALER_ARL_adb->cls,
+ &ps->purse_pub,
+ &TALER_ARL_master_pub,
+ &ps->balance);
+ else
+ qs = TALER_ARL_adb->insert_purse_info (TALER_ARL_adb->cls,
+ &ps->purse_pub,
+ &TALER_ARL_master_pub,
+ &ps->balance,
+ ps->expiration_date);
+ 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);
+ pc->qs = qs;
+ return GNUNET_SYSERR;
+ }
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (pc->purses,
+ key,
+ ps));
+ GNUNET_free (ps);
+ return ret;
+}
+
+
+/**
* Analyze purses for being well-formed.
*
* @param cls NULL
@@ -762,9 +1089,10 @@ analyze_purses (void *cls)
else
{
ppp_start = ppp;
- // FIXME: add other values!
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Resuming purse audit at %llu/%llu/%llu\n",
+ "Resuming purse audit at %llu/%llu/%llu/%llu/%llu\n",
+ (unsigned long long) ppp.last_purse_request_serial_id,
+ (unsigned long long) ppp.last_purse_decision_serial_id,
(unsigned long long) ppp.last_purse_merge_serial_id,
(unsigned long long) ppp.last_purse_deposits_serial_id,
(unsigned long long) ppp.last_account_merge_serial_id);
@@ -780,6 +1108,18 @@ analyze_purses (void *cls)
}
pc.purses = GNUNET_CONTAINER_multihashmap_create (512,
GNUNET_NO);
+
+ qs = TALER_ARL_edb->select_purse_requests_above_serial_id (
+ TALER_ARL_edb->cls,
+ ppp.last_purse_request_serial_id,
+ &handle_purse_requested,
+ &pc);
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ return qs;
+ }
+
qs = TALER_ARL_edb->select_purse_merges_above_serial_id (
TALER_ARL_edb->cls,
ppp.last_purse_merge_serial_id,
@@ -812,6 +1152,28 @@ analyze_purses (void *cls)
return qs;
}
+ qs = TALER_ARL_edb->select_all_purse_decisions_above_serial_id (
+ TALER_ARL_edb->cls,
+ ppp.last_purse_decision_serial_id,
+ &handle_purse_decision,
+ &pc);
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ return qs;
+ }
+
+ qs = TALER_ARL_adb->select_purse_expired (
+ TALER_ARL_adb->cls,
+ &TALER_ARL_master_pub,
+ &handle_purse_expired,
+ &pc);
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ return qs;
+ }
+
GNUNET_CONTAINER_multihashmap_iterate (pc.purses,
&verify_purse_balance,
&pc);
@@ -853,7 +1215,9 @@ analyze_purses (void *cls)
return qs;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Concluded purse audit step at %llu/%llu/%llu\n",
+ "Concluded purse audit step at %llu/%llu/%llu/%llu/%llu\n",
+ (unsigned long long) ppp.last_purse_request_serial_id,
+ (unsigned long long) ppp.last_purse_decision_serial_id,
(unsigned long long) ppp.last_purse_merge_serial_id,
(unsigned long long) ppp.last_purse_deposits_serial_id,
(unsigned long long) ppp.last_account_merge_serial_id);
@@ -891,6 +1255,12 @@ run (void *cls,
&balance.balance));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
+ &total_balance_insufficient_loss));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (TALER_ARL_currency,
+ &total_delayed_decisions));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (TALER_ARL_currency,
&total_arithmetic_delta_plus));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
@@ -927,6 +1297,8 @@ run (void *cls,
/* Globals (REVIEW!) */
TALER_JSON_pack_amount ("total_balance_insufficient",
&total_balance_insufficient_loss),
+ TALER_JSON_pack_amount ("total_delayed_purse_decisions",
+ &total_delayed_decisions),
GNUNET_JSON_pack_array_steal (
"purse_balance_insufficient_inconsistencies",
report_purse_balance_insufficient_inconsistencies),
diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c
index 2bccd11f7..f3da2c85c 100644
--- a/src/exchange/taler-exchange-httpd_purses_create.c
+++ b/src/exchange/taler-exchange-httpd_purses_create.c
@@ -156,15 +156,15 @@ create_transaction (void *cls,
uint32_t min_age;
TEH_plugin->rollback (TEH_plugin->cls);
- qs = TEH_plugin->select_purse_request (TEH_plugin->cls,
- &pcc->pd.purse_pub,
- &merge_pub,
- &purse_expiration,
- &h_contract_terms,
- &min_age,
- &target_amount,
- &balance,
- &purse_sig);
+ qs = TEH_plugin->get_purse_request (TEH_plugin->cls,
+ &pcc->pd.purse_pub,
+ &merge_pub,
+ &purse_expiration,
+ &h_contract_terms,
+ &min_age,
+ &target_amount,
+ &balance,
+ &purse_sig);
if (qs < 0)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
diff --git a/src/exchange/taler-exchange-httpd_purses_deposit.c b/src/exchange/taler-exchange-httpd_purses_deposit.c
index 581abe90a..dc1a256d7 100644
--- a/src/exchange/taler-exchange-httpd_purses_deposit.c
+++ b/src/exchange/taler-exchange-httpd_purses_deposit.c
@@ -359,11 +359,13 @@ TEH_handler_purses_deposit (
{
enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_TIME_Timestamp create_timestamp;
struct GNUNET_TIME_Timestamp merge_timestamp;
qs = TEH_plugin->select_purse (
TEH_plugin->cls,
pcc.purse_pub,
+ &create_timestamp,
&pcc.purse_expiration,
&pcc.amount,
&pcc.deposit_total,
diff --git a/src/exchange/taler-exchange-httpd_purses_get.c b/src/exchange/taler-exchange-httpd_purses_get.c
index 3261ed34f..8384086b6 100644
--- a/src/exchange/taler-exchange-httpd_purses_get.c
+++ b/src/exchange/taler-exchange-httpd_purses_get.c
@@ -303,9 +303,11 @@ TEH_handler_purses_get (struct TEH_RequestContext *rc,
{
enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_TIME_Timestamp create_timestamp;
qs = TEH_plugin->select_purse (TEH_plugin->cls,
&gc->purse_pub,
+ &create_timestamp,
&gc->purse_expiration,
&gc->amount,
&gc->deposited,
diff --git a/src/exchange/taler-exchange-httpd_purses_merge.c b/src/exchange/taler-exchange-httpd_purses_merge.c
index c1582948b..0bb8a1867 100644
--- a/src/exchange/taler-exchange-httpd_purses_merge.c
+++ b/src/exchange/taler-exchange-httpd_purses_merge.c
@@ -426,15 +426,15 @@ TEH_handler_purses_merge (
}
/* Fetch purse details */
- qs = TEH_plugin->select_purse_request (TEH_plugin->cls,
- pcc.purse_pub,
- &pcc.merge_pub,
- &pcc.purse_expiration,
- &pcc.h_contract_terms,
- &pcc.min_age,
- &pcc.target_amount,
- &pcc.balance,
- &purse_sig);
+ qs = TEH_plugin->get_purse_request (TEH_plugin->cls,
+ pcc.purse_pub,
+ &pcc.merge_pub,
+ &pcc.purse_expiration,
+ &pcc.h_contract_terms,
+ &pcc.min_age,
+ &pcc.target_amount,
+ &pcc.balance,
+ &purse_sig);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.c b/src/exchange/taler-exchange-httpd_reserves_purse.c
index 79625a395..cc3ffeb15 100644
--- a/src/exchange/taler-exchange-httpd_reserves_purse.c
+++ b/src/exchange/taler-exchange-httpd_reserves_purse.c
@@ -252,7 +252,7 @@ purse_transaction (void *cls,
uint32_t min_age;
TEH_plugin->rollback (TEH_plugin->cls);
- qs = TEH_plugin->select_purse_request (
+ qs = TEH_plugin->get_purse_request (
TEH_plugin->cls,
&rpc->pd.purse_pub,
&merge_pub,
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index c4957c912..5ccb71127 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -2259,6 +2259,7 @@ prepare_statements (struct PostgresClosure *pg)
"select_purse",
"SELECT "
" merge_pub"
+ ",purse_creation"
",purse_expiration"
",h_contract_terms"
",amount_with_fee_val"
@@ -2269,9 +2270,9 @@ prepare_statements (struct PostgresClosure *pg)
" FROM purse_requests"
" LEFT JOIN purse_merges USING (purse_pub)"
" WHERE purse_pub=$1;"),
- /* Used in #postgres_select_purse_request */
+ /* Used in #postgres_get_purse_request */
GNUNET_PQ_make_prepare (
- "select_purse_request",
+ "get_purse_request",
"SELECT "
" merge_pub"
",purse_expiration"
@@ -8002,6 +8003,127 @@ postgres_select_purse_decisions_above_serial_id (
/**
+ * Closure for #all_purse_decision_serial_helper_cb().
+ */
+struct AllPurseDecisionSerialContext
+{
+
+ /**
+ * Callback to call.
+ */
+ TALER_EXCHANGEDB_AllPurseDecisionCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Status code, set to #GNUNET_SYSERR on hard errors.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Helper function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct PurseRefundSerialContext`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+all_purse_decision_serial_helper_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct AllPurseDecisionSerialContext *dsc = cls;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct TALER_PurseContractPublicKeyP purse_pub;
+ bool refunded;
+ uint64_t rowid;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
+ &purse_pub),
+ GNUNET_PQ_result_spec_bool ("refunded",
+ &refunded),
+ GNUNET_PQ_result_spec_uint64 ("purse_decision_serial_id",
+ &rowid),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_GenericReturnValue ret;
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ dsc->status = GNUNET_SYSERR;
+ return;
+ }
+ ret = dsc->cb (dsc->cb_cls,
+ rowid,
+ &purse_pub,
+ refunded);
+ GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
+ }
+}
+
+
+/**
+ * Select purse decisions above @a serial_id in monotonically increasing
+ * order.
+ *
+ * @param cls closure
+ * @param serial_id highest serial ID to exclude (select strictly larger)
+ * @param cb function to call on each result
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_select_all_purse_decisions_above_serial_id (
+ void *cls,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_AllPurseDecisionCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct AllPurseDecisionSerialContext dsc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .status = GNUNET_OK
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "audit_get_all_purse_decision_incr",
+ params,
+ &
+ all_purse_decision_serial_helper_cb,
+ &dsc);
+ if (GNUNET_OK != dsc.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
+
+
+/**
* Closure for #purse_refund_coin_helper_cb().
*/
struct PurseRefundCoinContext
@@ -11355,7 +11477,7 @@ postgres_insert_contract (
* @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
-postgres_select_purse_request (
+postgres_get_purse_request (
void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub,
struct TALER_PurseMergePublicKeyP *merge_pub,
@@ -11389,7 +11511,7 @@ postgres_select_purse_request (
GNUNET_PQ_result_spec_end
};
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "select_purse_request",
+ "get_purse_request",
params,
rs);
}
@@ -11464,15 +11586,15 @@ postgres_insert_purse_request (
struct TALER_Amount balance;
struct TALER_PurseContractSignatureP purse_sig2;
- qs = postgres_select_purse_request (pg,
- purse_pub,
- &merge_pub2,
- &purse_expiration2,
- &h_contract_terms2,
- &age_limit2,
- &amount2,
- &balance,
- &purse_sig2);
+ qs = postgres_get_purse_request (pg,
+ purse_pub,
+ &merge_pub2,
+ &purse_expiration2,
+ &h_contract_terms2,
+ &age_limit2,
+ &amount2,
+ &balance,
+ &purse_sig2);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
GNUNET_break (0);
@@ -11542,6 +11664,7 @@ postgres_expire_purse (
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param purse_pub public key of the new purse
+ * @param[out] purse_creation set to time when the purse was created
* @param[out] purse_expiration set to time when the purse will expire
* @param[out] amount set to target amount (with fees) to be put into the purse
* @param[out] deposited set to actual amount put into the purse so far
@@ -11553,6 +11676,7 @@ static enum GNUNET_DB_QueryStatus
postgres_select_purse (
void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub,
+ struct GNUNET_TIME_Timestamp *purse_creation,
struct GNUNET_TIME_Timestamp *purse_expiration,
struct TALER_Amount *amount,
struct TALER_Amount *deposited,
@@ -11567,6 +11691,8 @@ postgres_select_purse (
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_timestamp ("purse_expiration",
purse_expiration),
+ GNUNET_PQ_result_spec_timestamp ("purse_creation",
+ purse_creation),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
amount),
TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
@@ -13042,6 +13168,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_select_history_requests_above_serial_id;
plugin->select_purse_decisions_above_serial_id
= &postgres_select_purse_decisions_above_serial_id;
+ plugin->select_all_purse_decisions_above_serial_id
+ = &postgres_select_all_purse_decisions_above_serial_id;
plugin->select_purse_deposits_by_purse
= &postgres_select_purse_deposits_by_purse;
plugin->select_refreshes_above_serial_id
@@ -13136,8 +13264,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_select_contract_by_purse;
plugin->insert_purse_request
= &postgres_insert_purse_request;
- plugin->select_purse_request
- = &postgres_select_purse_request;
+ plugin->get_purse_request
+ = &postgres_get_purse_request;
plugin->expire_purse
= &postgres_expire_purse;
plugin->select_purse
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index 129b51714..709a956cb 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -605,6 +605,23 @@ typedef enum GNUNET_GenericReturnValue
/**
+ * Function called on expired purses.
+ *
+ * @param cls closure
+ * @param purse_pub public key of the purse
+ * @param balance amount of money in the purse
+ * @param expiration_date when did the purse expire?
+ * @return #GNUNET_OK to continue to iterate
+ */
+typedef enum GNUNET_GenericReturnValue
+(*TALER_AUDITORDB_ExpiredPurseCallback)(
+ void *cls,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_Amount *balance,
+ struct GNUNET_TIME_Timestamp expiration_date);
+
+
+/**
* @brief The plugin API, returned from the plugin's "init" function.
* The argument given to "init" is simply a configuration handle.
*
@@ -1220,7 +1237,7 @@ struct TALER_AUDITORDB_Plugin
* @param purse_pub public key of the purse
* @param master_pub master public key of the exchange
* @param balance balance of the purse
- * @param expiration_date expiration date of the reserve
+ * @param expiration_date expiration date of the purse
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@@ -1245,7 +1262,7 @@ struct TALER_AUDITORDB_Plugin
enum GNUNET_DB_QueryStatus
(*update_purse_info)(
void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *balance);
@@ -1254,7 +1271,7 @@ struct TALER_AUDITORDB_Plugin
* Get information about a purse.
*
* @param cls the @e cls of this struct with the plugin-specific state
- * @param reserve_pub public key of the reserve
+ * @param purse_pub public key of the purse
* @param master_pub master public key of the exchange
* @param[out] rowid which row did we get the information from
* @param[out] balance set to balance of the purse
@@ -1275,6 +1292,38 @@ struct TALER_AUDITORDB_Plugin
* Delete information about a purse.
*
* @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub public key of the reserve
+ * @param master_pub master public key of the exchange
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*delete_purse_info)(
+ void *cls,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_MasterPublicKeyP *master_pub);
+
+
+ /**
+ * Get information about expired purses.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param master_pub master public key of the exchange
+ * @param cb function to call on expired purses
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_purse_expired)(
+ void *cls,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ TALER_AUDITORDB_ExpiredPurseCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Delete information about a purse.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param purse_pub public key of the purse
* @param master_pub master public key of the exchange
* @return transaction status code
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index df992c6ee..2e85f6d91 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -2771,7 +2771,7 @@ TALER_CRYPTO_helper_esign_disconnect (
void
TALER_wallet_purse_create_sign (
struct GNUNET_TIME_Timestamp purse_expiration,
- struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_PurseMergePublicKeyP *merge_pub,
uint32_t min_age,
const struct TALER_Amount *amount,
@@ -2794,7 +2794,7 @@ TALER_wallet_purse_create_sign (
enum GNUNET_GenericReturnValue
TALER_wallet_purse_create_verify (
struct GNUNET_TIME_Timestamp purse_expiration,
- struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_PurseMergePublicKeyP *merge_pub,
uint32_t min_age,
const struct TALER_Amount *amount,
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 4965a27b1..de4babfd0 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -2356,7 +2356,7 @@ typedef enum GNUNET_GenericReturnValue
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
* @param purse_pub public key of the purse
- * @param reserve_pub public key of the target reserve, NULL if not known
+ * @param reserve_pub public key of the target reserve, NULL if not known / refunded
* @param purse_value what is the (target) value of the purse
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@@ -2370,6 +2370,24 @@ typedef enum GNUNET_GenericReturnValue
/**
+ * Function called with details about purse decisions that have been made, with
+ * the goal of auditing the purse's execution.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the deposit in our DB
+ * @param purse_pub public key of the purse
+ * @param refunded true if decision was to refund
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+typedef enum GNUNET_GenericReturnValue
+(*TALER_EXCHANGEDB_AllPurseDecisionCallback)(
+ void *cls,
+ uint64_t rowid,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ bool refunded);
+
+
+/**
* Function called with details about purse refunds that have been made, with
* the goal of auditing the purse refund's execution.
*
@@ -2994,6 +3012,34 @@ typedef void
/**
+ * Function called on purse requests.
+ *
+ * @param cls closure
+ * @param purse_pub public key of the purse
+ * @param merge_pub public key representing the merge capability
+ * @param purse_creation when was the purse created?
+ * @param purse_expiration when would an unmerged purse expire
+ * @param h_contract_terms contract associated with the purse
+ * @param age_limit the age limit for deposits into the purse
+ * @param target_amount amount to be put into the purse
+ * @param purse_sig signature of the purse over the initialization data
+ * @return #GNUNET_OK to continue to iterate
+ */
+typedef enum GNUNET_GenericReturnValue
+(*TALER_EXCHANGEDB_PurseRequestCallback)(
+ void *cls,
+ uint64_t rowid,
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const struct TALER_PurseMergePublicKeyP *merge_pub,
+ struct GNUNET_TIME_Timestamp purse_creation,
+ struct GNUNET_TIME_Timestamp purse_expiration,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ uint32_t age_limit,
+ const struct TALER_Amount *target_amount,
+ const struct TALER_PurseContractSignatureP *purse_sig);
+
+
+/**
* Function called with information about the exchange's denomination keys.
* Note that the 'master' field in @a issue will not yet be initialized when
* this function is called!
@@ -4594,6 +4640,25 @@ struct TALER_EXCHANGEDB_Plugin
TALER_EXCHANGEDB_DepositCallback cb,
void *cb_cls);
+
+ /**
+ * Function called to return meta data about a purses
+ * above a certain serial ID.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param serial_id number to select requests by
+ * @param cb function to call on each request
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_purse_requests_above_serial_id)(
+ void *cls,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_PurseRequestCallback cb,
+ void *cb_cls);
+
+
/**
* Select purse deposits above @a serial_id in monotonically increasing
* order.
@@ -4687,6 +4752,24 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * Select all purse refunds above @a serial_id in monotonically increasing
+ * order.
+ *
+ * @param cls closure
+ * @param serial_id highest serial ID to exclude (select strictly larger)
+ * @param cb function to call on each result
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_all_purse_decisions_above_serial_id)(
+ void *cls,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_AllPurseDecisionCallback cb,
+ void *cb_cls);
+
+
+ /**
* Select coins deposited into a purse.
*
* @param cls closure
@@ -5647,6 +5730,7 @@ struct TALER_EXCHANGEDB_Plugin
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param purse_pub public key of the new purse
+ * @param[out] purse_creation set to time when the purse was created
* @param[out] purse_expiration set to time when the purse will expire
* @param[out] amount set to target amount (with fees) to be put into the purse
* @param[out] deposited set to actual amount put into the purse so far
@@ -5658,6 +5742,7 @@ struct TALER_EXCHANGEDB_Plugin
(*select_purse)(
void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub,
+ struct GNUNET_TIME_Timestamp *purse_creation,
struct GNUNET_TIME_Timestamp *purse_expiration,
struct TALER_Amount *amount,
struct TALER_Amount *deposited,
@@ -5681,7 +5766,7 @@ struct TALER_EXCHANGEDB_Plugin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
- (*select_purse_request)(
+ (*get_purse_request)(
void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub,
struct TALER_PurseMergePublicKeyP *merge_pub,
diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c
index 192914394..6c8124d03 100644
--- a/src/util/wallet_signatures.c
+++ b/src/util/wallet_signatures.c
@@ -821,7 +821,7 @@ GNUNET_NETWORK_STRUCT_END
void
TALER_wallet_purse_create_sign (
struct GNUNET_TIME_Timestamp purse_expiration,
- struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_PurseMergePublicKeyP *merge_pub,
uint32_t min_age,
const struct TALER_Amount *amount,
@@ -848,7 +848,7 @@ TALER_wallet_purse_create_sign (
enum GNUNET_GenericReturnValue
TALER_wallet_purse_create_verify (
struct GNUNET_TIME_Timestamp purse_expiration,
- struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
const struct TALER_PurseMergePublicKeyP *merge_pub,
uint32_t min_age,
const struct TALER_Amount *amount,