add support for reserve open/close operations to auditor, begin to split off purse auditing logic

This commit is contained in:
Christian Grothoff 2022-10-30 17:36:57 +01:00
parent 38a078d543
commit 2d55647f2a
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
42 changed files with 4327 additions and 2508 deletions

View File

@ -140,9 +140,9 @@ In that time, the wire auditor processed the following table ranges:
\end{center} \end{center}
The total credits to the exchange processed in The total credits to the exchange processed in
this audit run was {\bf {{ wire.total_wire_in }}. this audit run was {\bf {{ wire.total_wire_in }}}.
The total debits initiated by the exchange processed in The total debits initiated by the exchange processed in
this audit run was {\bf {{ wire.total_wire_out }}. this audit run was {\bf {{ wire.total_wire_out }}}.
\section{Operations} \section{Operations}
@ -169,9 +169,8 @@ Loss (actualized risk from recoups) is
{\bf {{ coins.total_recoup_loss }}}. {\bf {{ coins.total_recoup_loss }}}.
\noindent \noindent
Recoups of non-revoked coins are at Losses from irregular reserve operations are at
{\bf {{ coins.total_irregular_recoups }}} (coins) {\bf {{ reserves.total_irregular_loss }}} (reserves).
plus {\bf {{ reserves.total_irregular_recoups }}} (reserves).
\section{Income} \section{Income}
@ -613,7 +612,7 @@ compromise resulting in proportional financial losses to the exchange.
\endfoot \endfoot
\hline \hline
{\bf Total loss} & {\bf Total loss} &
{{ reserves.total_loss_balance_insufficient }} \\ {{ reserves.total_irregular_loss }} \\
\caption{Reserves with withdrawals higher than reserve funding.} \caption{Reserves with withdrawals higher than reserve funding.}
\label{table:reserve:balance_insufficient} \label{table:reserve:balance_insufficient}
\endlastfoot \endlastfoot
@ -782,7 +781,7 @@ invalid and the amount involved should be considered lost.
\endfoot \endfoot
\hline \hline
\multicolumn{2}{l}{ {\bf Total losses} } & \multicolumn{2}{l}{ {\bf Total losses} } &
{\bf {{ coins.total_bad_sig_loss}} } \\ {\bf {{ coins.irregular_loss}} } \\
\caption{Losses from operations performed on coins without proper signatures.} \caption{Losses from operations performed on coins without proper signatures.}
\label{table:bad_signature_losses} \label{table:bad_signature_losses}
\endlastfoot \endlastfoot

@ -1 +1 @@
Subproject commit 3a2899981056f1d349730464b7f7172ffcc9671f Subproject commit 9657bf77de05c0ac17ff39629306a604066b21de

View File

@ -65,21 +65,6 @@ taler_auditor_dbinit_CPPFLAGS = \
-I$(top_srcdir)/src/pq/ \ -I$(top_srcdir)/src/pq/ \
$(POSTGRESQL_CPPFLAGS) $(POSTGRESQL_CPPFLAGS)
taler_helper_auditor_reserves_SOURCES = \
taler-helper-auditor-reserves.c
taler_helper_auditor_reserves_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/auditordb/libtalerauditordb.la \
libauditorreport.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
$(XLIB)
taler_helper_auditor_coins_SOURCES = \ taler_helper_auditor_coins_SOURCES = \
taler-helper-auditor-coins.c taler-helper-auditor-coins.c
taler_helper_auditor_coins_LDADD = \ taler_helper_auditor_coins_LDADD = \
@ -125,6 +110,38 @@ taler_helper_auditor_deposits_LDADD = \
-lgnunetutil \ -lgnunetutil \
$(XLIB) $(XLIB)
taler_helper_auditor_purses_SOURCES = \
taler-helper-auditor-purses.c
taler_helper_auditor_purses_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/auditordb/libtalerauditordb.la \
libauditorreport.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
$(XLIB)
taler_helper_auditor_reserves_SOURCES = \
taler-helper-auditor-reserves.c
taler_helper_auditor_reserves_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/auditordb/libtalerauditordb.la \
libauditorreport.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
$(XLIB)
taler_helper_auditor_wire_SOURCES = \ taler_helper_auditor_wire_SOURCES = \
taler-helper-auditor-wire.c taler-helper-auditor-wire.c
taler_helper_auditor_wire_LDADD = \ taler_helper_auditor_wire_LDADD = \

View File

@ -119,7 +119,7 @@ static struct Table tables[] = {
{ .rt = TALER_EXCHANGEDB_RT_EXTENSIONS}, { .rt = TALER_EXCHANGEDB_RT_EXTENSIONS},
{ .rt = TALER_EXCHANGEDB_RT_EXTENSION_DETAILS }, { .rt = TALER_EXCHANGEDB_RT_EXTENSION_DETAILS },
{ .rt = TALER_EXCHANGEDB_RT_PURSE_REQUESTS}, { .rt = TALER_EXCHANGEDB_RT_PURSE_REQUESTS},
{ .rt = TALER_EXCHANGEDB_RT_PURSE_REFUNDS}, { .rt = TALER_EXCHANGEDB_RT_PURSE_DECISION},
{ .rt = TALER_EXCHANGEDB_RT_PURSE_MERGES}, { .rt = TALER_EXCHANGEDB_RT_PURSE_MERGES},
{ .rt = TALER_EXCHANGEDB_RT_PURSE_DEPOSITS}, { .rt = TALER_EXCHANGEDB_RT_PURSE_DEPOSITS},
{ .rt = TALER_EXCHANGEDB_RT_ACCOUNT_MERGES}, { .rt = TALER_EXCHANGEDB_RT_ACCOUNT_MERGES},

View File

@ -91,6 +91,7 @@ done
taler-helper-auditor-wire $INF ${ARGS[*]} > ${DIR}/wire.json taler-helper-auditor-wire $INF ${ARGS[*]} > ${DIR}/wire.json
echo "Generating auditor report in ${DIR}."
taler-helper-auditor-render.py \ taler-helper-auditor-render.py \
${DIR}/aggregation.json \ ${DIR}/aggregation.json \
${DIR}/coins.json \ ${DIR}/coins.json \

View File

@ -113,50 +113,15 @@ static struct TALER_Amount reported_emergency_loss;
static struct TALER_Amount reported_emergency_loss_by_count; static struct TALER_Amount reported_emergency_loss_by_count;
/** /**
* Expected balance in the escrow account. * Global coin balance sheet (for coins).
*/ */
static struct TALER_Amount total_escrow_balance; static struct TALER_AUDITORDB_GlobalCoinBalance balance;
/**
* Active risk exposure.
*/
static struct TALER_Amount total_risk;
/**
* Actualized risk (= loss) from recoups.
*/
static struct TALER_Amount total_recoup_loss;
/**
* Recoups we made on denominations that were not revoked (!?).
*/
static struct TALER_Amount total_irregular_recoups;
/**
* Total deposit fees earned.
*/
static struct TALER_Amount total_deposit_fee_income;
/**
* Total melt fees earned.
*/
static struct TALER_Amount total_melt_fee_income;
/**
* Total refund fees earned.
*/
static struct TALER_Amount total_refund_fee_income;
/** /**
* Array of reports about coin operations with bad signatures. * Array of reports about coin operations with bad signatures.
*/ */
static json_t *report_bad_sig_losses; static json_t *report_bad_sig_losses;
/**
* Total amount lost by operations for which signatures were invalid.
*/
static struct TALER_Amount total_bad_sig_loss;
/** /**
* Array of refresh transactions where the /refresh/reveal has not yet * Array of refresh transactions where the /refresh/reveal has not yet
* happened (and may of course never happen). * happened (and may of course never happen).
@ -605,33 +570,9 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
struct DenominationSummary struct DenominationSummary
{ {
/** /**
* Total value of outstanding (not deposited) coins issued with this * Information about the circulation.
* denomination key.
*/ */
struct TALER_Amount denom_balance; struct TALER_AUDITORDB_DenominationCirculationData dcd;
/**
* Total losses made (once coins deposited exceed
* coins withdrawn and thus the @e denom_balance is
* effectively negative).
*/
struct TALER_Amount denom_loss;
/**
* Total value of coins issued with this denomination key.
*/
struct TALER_Amount denom_risk;
/**
* Total value of coins subjected to recoup with this denomination key.
*/
struct TALER_Amount denom_recoup;
/**
* How many coins (not their amount!) of this denomination
* did the exchange issue overall?
*/
uint64_t num_issued;
/** /**
* Denomination key information for this denomination. * Denomination key information for this denomination.
@ -694,11 +635,7 @@ init_denomination (const struct TALER_DenominationHashP *denom_hash,
qs = TALER_ARL_adb->get_denomination_balance (TALER_ARL_adb->cls, qs = TALER_ARL_adb->get_denomination_balance (TALER_ARL_adb->cls,
denom_hash, denom_hash,
&ds->denom_balance, &ds->dcd);
&ds->denom_loss,
&ds->denom_risk,
&ds->denom_recoup,
&ds->num_issued);
if (0 > qs) if (0 > qs)
{ {
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@ -712,22 +649,22 @@ init_denomination (const struct TALER_DenominationHashP *denom_hash,
{ {
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&ds->denom_balance)); &ds->dcd.denom_balance));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&ds->denom_loss)); &ds->dcd.denom_loss));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&ds->denom_risk)); &ds->dcd.denom_risk));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&ds->denom_recoup)); &ds->dcd.recoup_loss));
} }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Starting balance for denomination `%s' is %s (%llu)\n", "Starting balance for denomination `%s' is %s (%llu)\n",
GNUNET_h2s (&denom_hash->hash), GNUNET_h2s (&denom_hash->hash),
TALER_amount2s (&ds->denom_balance), TALER_amount2s (&ds->dcd.denom_balance),
(unsigned long long) ds->num_issued); (unsigned long long) ds->dcd.num_issued);
qs = TALER_ARL_edb->get_denomination_revocation (TALER_ARL_edb->cls, qs = TALER_ARL_edb->get_denomination_revocation (TALER_ARL_edb->cls,
denom_hash, denom_hash,
&msig, &msig,
@ -842,15 +779,14 @@ sync_denomination (void *cls,
else else
qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
( (0 != ds->denom_risk.value) || (! TALER_amount_is_zero (&ds->dcd.denom_risk)) )
(0 != ds->denom_risk.fraction) ) )
{ {
/* The denomination expired and carried a balance; we can now /* The denomination expired and carried a balance; we can now
book the remaining balance as profit, and reduce our risk book the remaining balance as profit, and reduce our risk
exposure by the accumulated risk of the denomination. */ exposure by the accumulated risk of the denomination. */
TALER_ARL_amount_subtract (&total_risk, TALER_ARL_amount_subtract (&balance.risk,
&total_risk, &balance.risk,
&ds->denom_risk); &ds->dcd.denom_risk);
/* If the above fails, our risk assessment is inconsistent! /* If the above fails, our risk assessment is inconsistent!
This is really, really bad (auditor-internal invariant This is really, really bad (auditor-internal invariant
would be violated). Hence we can "safely" assert. If would be violated). Hence we can "safely" assert. If
@ -858,22 +794,21 @@ sync_denomination (void *cls,
in the auditor _or_ the auditor's database is corrupt. */ in the auditor _or_ the auditor's database is corrupt. */
} }
if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
( (0 != ds->denom_balance.value) || (! TALER_amount_is_zero (&ds->dcd.denom_balance)) )
(0 != ds->denom_balance.fraction) ) )
{ {
/* book denom_balance coin expiration profits! */ /* book denom_balance coin expiration profits! */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Denomination `%s' expired, booking %s in expiration profits\n", "Denomination `%s' expired, booking %s in expiration profits\n",
GNUNET_h2s (denom_hash), GNUNET_h2s (denom_hash),
TALER_amount2s (&ds->denom_balance)); TALER_amount2s (&ds->dcd.denom_balance));
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
(qs = TALER_ARL_adb->insert_historic_denom_revenue ( (qs = TALER_ARL_adb->insert_historic_denom_revenue (
TALER_ARL_adb->cls, TALER_ARL_adb->cls,
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
&denom_h, &denom_h,
expire_deposit, expire_deposit,
&ds->denom_balance, &ds->dcd.denom_balance,
&ds->denom_recoup))) &ds->dcd.recoup_loss)))
{ {
/* Failed to store profits? Bad database */ /* Failed to store profits? Bad database */
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@ -890,8 +825,8 @@ sync_denomination (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Final balance for denomination `%s' is %s (%llu)\n", "Final balance for denomination `%s' is %s (%llu)\n",
GNUNET_h2s (denom_hash), GNUNET_h2s (denom_hash),
TALER_amount2s (&ds->denom_balance), TALER_amount2s (&ds->dcd.denom_balance),
(unsigned long long) ds->num_issued); (unsigned long long) ds->dcd.num_issued);
cnt = TALER_ARL_edb->count_known_coins (TALER_ARL_edb->cls, cnt = TALER_ARL_edb->count_known_coins (TALER_ARL_edb->cls,
&denom_h); &denom_h);
if (0 > cnt) if (0 > cnt)
@ -903,39 +838,31 @@ sync_denomination (void *cls,
} }
else else
{ {
if (ds->num_issued < (uint64_t) cnt) if (ds->dcd.num_issued < (uint64_t) cnt)
{ {
/* more coins deposited than issued! very bad */ /* more coins deposited than issued! very bad */
report_emergency_by_count (issue, report_emergency_by_count (issue,
ds->num_issued, ds->dcd.num_issued,
cnt, cnt,
&ds->denom_risk); &ds->dcd.denom_risk);
} }
if (ds->report_emergency) if (ds->report_emergency)
{ {
/* Value of coins deposited exceed value of coins /* Value of coins deposited exceed value of coins
issued! Also very bad! */ issued! Also very bad! */
report_emergency_by_amount (issue, report_emergency_by_amount (issue,
&ds->denom_risk, &ds->dcd.denom_risk,
&ds->denom_loss); &ds->dcd.denom_loss);
} }
if (ds->in_db) if (ds->in_db)
qs = TALER_ARL_adb->update_denomination_balance (TALER_ARL_adb->cls, qs = TALER_ARL_adb->update_denomination_balance (TALER_ARL_adb->cls,
&denom_h, &denom_h,
&ds->denom_balance, &ds->dcd);
&ds->denom_loss,
&ds->denom_risk,
&ds->denom_recoup,
ds->num_issued);
else else
qs = TALER_ARL_adb->insert_denomination_balance (TALER_ARL_adb->cls, qs = TALER_ARL_adb->insert_denomination_balance (TALER_ARL_adb->cls,
&denom_h, &denom_h,
&ds->denom_balance, &ds->dcd);
&ds->denom_loss,
&ds->denom_risk,
&ds->denom_recoup,
ds->num_issued);
} }
} }
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
@ -1032,22 +959,22 @@ withdraw_cb (void *cls,
"Issued coin in denomination `%s' of total value %s\n", "Issued coin in denomination `%s' of total value %s\n",
GNUNET_h2s (&dh.hash), GNUNET_h2s (&dh.hash),
TALER_amount2s (&issue->value)); TALER_amount2s (&issue->value));
ds->num_issued++;
TALER_ARL_amount_add (&ds->denom_balance,
&ds->denom_balance,
&issue->value);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' is %s\n", "New balance of denomination `%s' is %s\n",
GNUNET_h2s (&dh.hash), GNUNET_h2s (&dh.hash),
TALER_amount2s (&ds->denom_balance)); TALER_amount2s (&ds->dcd.denom_balance));
TALER_ARL_amount_add (&total_escrow_balance, TALER_ARL_amount_add (&balance.total_escrowed,
&total_escrow_balance, &balance.total_escrowed,
&issue->value); &issue->value);
TALER_ARL_amount_add (&total_risk, TALER_ARL_amount_add (&balance.risk,
&total_risk, &balance.risk,
&issue->value); &issue->value);
TALER_ARL_amount_add (&ds->denom_risk, ds->dcd.num_issued++;
&ds->denom_risk, TALER_ARL_amount_add (&ds->dcd.denom_balance,
&ds->dcd.denom_balance,
&issue->value);
TALER_ARL_amount_add (&ds->dcd.denom_risk,
&ds->dcd.denom_risk,
&issue->value); &issue->value);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -1201,8 +1128,8 @@ check_known_coin (
loss_potential), loss_potential),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
coin_pub))); coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
loss_potential); loss_potential);
} }
TALER_denom_sig_free (&ci.denom_sig); TALER_denom_sig_free (&ci.denom_sig);
@ -1228,19 +1155,19 @@ reduce_denom_balance (struct DenominationSummary *dso,
if (TALER_ARL_SR_INVALID_NEGATIVE == if (TALER_ARL_SR_INVALID_NEGATIVE ==
TALER_ARL_amount_subtract_neg (&tmp, TALER_ARL_amount_subtract_neg (&tmp,
&dso->denom_balance, &dso->dcd.denom_balance,
amount_with_fee)) amount_with_fee))
{ {
TALER_ARL_amount_add (&dso->denom_loss, TALER_ARL_amount_add (&dso->dcd.denom_loss,
&dso->denom_loss, &dso->dcd.denom_loss,
amount_with_fee); amount_with_fee);
dso->report_emergency = true; dso->report_emergency = true;
} }
else else
{ {
dso->denom_balance = tmp; dso->dcd.denom_balance = tmp;
} }
if (-1 == TALER_amount_cmp (&total_escrow_balance, if (-1 == TALER_amount_cmp (&balance.total_escrowed,
amount_with_fee)) amount_with_fee))
{ {
/* This can theoretically happen if for example the exchange /* This can theoretically happen if for example the exchange
@ -1252,20 +1179,20 @@ reduce_denom_balance (struct DenominationSummary *dso,
report_amount_arithmetic_inconsistency ( report_amount_arithmetic_inconsistency (
"subtracting amount from escrow balance", "subtracting amount from escrow balance",
rowid, rowid,
&total_escrow_balance, &balance.total_escrowed,
amount_with_fee, amount_with_fee,
0); 0);
} }
else else
{ {
TALER_ARL_amount_subtract (&total_escrow_balance, TALER_ARL_amount_subtract (&balance.total_escrowed,
&total_escrow_balance, &balance.total_escrowed,
amount_with_fee); amount_with_fee);
} }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' is %s\n", "New balance of denomination `%s' is %s\n",
GNUNET_h2s (&dso->issue->denom_hash.hash), GNUNET_h2s (&dso->issue->denom_hash.hash),
TALER_amount2s (&dso->denom_balance)); TALER_amount2s (&dso->dcd.denom_balance));
} }
@ -1365,8 +1292,8 @@ refresh_session_cb (void *cls,
amount_with_fee), amount_with_fee),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
coin_pub))); coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
amount_with_fee); amount_with_fee);
} }
} }
@ -1501,22 +1428,22 @@ refresh_session_cb (void *cls,
"Created fresh coin in denomination `%s' of value %s\n", "Created fresh coin in denomination `%s' of value %s\n",
GNUNET_h2s (&ni->denom_hash.hash), GNUNET_h2s (&ni->denom_hash.hash),
TALER_amount2s (&ni->value)); TALER_amount2s (&ni->value));
dsi->num_issued++; dsi->dcd.num_issued++;
TALER_ARL_amount_add (&dsi->denom_balance, TALER_ARL_amount_add (&dsi->dcd.denom_balance,
&dsi->denom_balance, &dsi->dcd.denom_balance,
&ni->value); &ni->value);
TALER_ARL_amount_add (&dsi->denom_risk, TALER_ARL_amount_add (&dsi->dcd.denom_risk,
&dsi->denom_risk, &dsi->dcd.denom_risk,
&ni->value); &ni->value);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' is %s\n", "New balance of denomination `%s' is %s\n",
GNUNET_h2s (&ni->denom_hash.hash), GNUNET_h2s (&ni->denom_hash.hash),
TALER_amount2s (&dsi->denom_balance)); TALER_amount2s (&dsi->dcd.denom_balance));
TALER_ARL_amount_add (&total_escrow_balance, TALER_ARL_amount_add (&balance.total_escrowed,
&total_escrow_balance, &balance.total_escrowed,
&ni->value); &ni->value);
TALER_ARL_amount_add (&total_risk, TALER_ARL_amount_add (&balance.risk,
&total_risk, &balance.risk,
&ni->value); &ni->value);
} }
} }
@ -1541,8 +1468,8 @@ refresh_session_cb (void *cls,
} }
/* update global melt fees */ /* update global melt fees */
TALER_ARL_amount_add (&total_melt_fee_income, TALER_ARL_amount_add (&balance.melt_fee_balance,
&total_melt_fee_income, &balance.melt_fee_balance,
&issue->fees.refresh); &issue->fees.refresh);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -1657,8 +1584,8 @@ deposit_cb (void *cls,
&deposit->amount_with_fee), &deposit->amount_with_fee),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
&deposit->coin.coin_pub))); &deposit->coin.coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
&deposit->amount_with_fee); &deposit->amount_with_fee);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -1689,8 +1616,8 @@ deposit_cb (void *cls,
} }
/* update global deposit fees */ /* update global deposit fees */
TALER_ARL_amount_add (&total_deposit_fee_income, TALER_ARL_amount_add (&balance.deposit_fee_balance,
&total_deposit_fee_income, &balance.deposit_fee_balance,
&issue->fees.deposit); &issue->fees.deposit);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -1774,8 +1701,8 @@ refund_cb (void *cls,
amount_with_fee), amount_with_fee),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
coin_pub))); coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
amount_with_fee); amount_with_fee);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -1815,31 +1742,31 @@ refund_cb (void *cls,
} }
else else
{ {
TALER_ARL_amount_add (&ds->denom_balance, TALER_ARL_amount_add (&ds->dcd.denom_balance,
&ds->denom_balance, &ds->dcd.denom_balance,
&amount_without_fee); &amount_without_fee);
TALER_ARL_amount_add (&ds->denom_risk, TALER_ARL_amount_add (&ds->dcd.denom_risk,
&ds->denom_risk, &ds->dcd.denom_risk,
&amount_without_fee); &amount_without_fee);
TALER_ARL_amount_add (&total_escrow_balance, TALER_ARL_amount_add (&balance.total_escrowed,
&total_escrow_balance, &balance.total_escrowed,
&amount_without_fee); &amount_without_fee);
TALER_ARL_amount_add (&total_risk, TALER_ARL_amount_add (&balance.risk,
&total_risk, &balance.risk,
&amount_without_fee); &amount_without_fee);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' after refund is %s\n", "New balance of denomination `%s' after refund is %s\n",
GNUNET_h2s (&issue->denom_hash.hash), GNUNET_h2s (&issue->denom_hash.hash),
TALER_amount2s (&ds->denom_balance)); TALER_amount2s (&ds->dcd.denom_balance));
} }
/* update total refund fee balance */ /* update total refund fee balance */
TALER_ARL_amount_add (&total_refund_fee_income, TALER_ARL_amount_add (&balance.refund_fee_balance,
&total_refund_fee_income, &balance.refund_fee_balance,
&issue->fees.refund); &issue->fees.refund);
if (full_refund) if (full_refund)
{ {
TALER_ARL_amount_subtract (&total_deposit_fee_income, TALER_ARL_amount_subtract (&balance.deposit_fee_balance,
&total_deposit_fee_income, &balance.deposit_fee_balance,
&issue->fees.deposit); &issue->fees.deposit);
} }
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
@ -1907,26 +1834,26 @@ purse_refund_coin_cb (
} }
else else
{ {
TALER_ARL_amount_add (&ds->denom_balance, TALER_ARL_amount_add (&ds->dcd.denom_balance,
&ds->denom_balance, &ds->dcd.denom_balance,
amount_with_fee); amount_with_fee);
TALER_ARL_amount_add (&ds->denom_risk, TALER_ARL_amount_add (&ds->dcd.denom_risk,
&ds->denom_risk, &ds->dcd.denom_risk,
amount_with_fee); amount_with_fee);
TALER_ARL_amount_add (&total_escrow_balance, TALER_ARL_amount_add (&balance.total_escrowed,
&total_escrow_balance, &balance.total_escrowed,
amount_with_fee); amount_with_fee);
TALER_ARL_amount_add (&total_risk, TALER_ARL_amount_add (&balance.risk,
&total_risk, &balance.risk,
amount_with_fee); amount_with_fee);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' after purse-refund is %s\n", "New balance of denomination `%s' after purse-refund is %s\n",
GNUNET_h2s (&issue->denom_hash.hash), GNUNET_h2s (&issue->denom_hash.hash),
TALER_amount2s (&ds->denom_balance)); TALER_amount2s (&ds->dcd.denom_balance));
} }
/* update total deposit fee balance */ /* update total deposit fee balance */
TALER_ARL_amount_subtract (&total_deposit_fee_income, TALER_ARL_amount_subtract (&balance.deposit_fee_balance,
&total_deposit_fee_income, &balance.deposit_fee_balance,
&issue->fees.deposit); &issue->fees.deposit);
return GNUNET_OK; return GNUNET_OK;
@ -1941,16 +1868,22 @@ purse_refund_coin_cb (
* @param cls closure * @param cls closure
* @param rowid unique serial ID for the refund in our DB * @param rowid unique serial ID for the refund in our DB
* @param purse_pub public key of the purse * @param purse_pub public key of the purse
* @param reserve_pub public key of the targeted reserve (ignored)
* @param val targeted amount to be in the reserve (ignored)
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/ */
static enum GNUNET_GenericReturnValue static enum GNUNET_GenericReturnValue
purse_refund_cb (void *cls, purse_refund_cb (void *cls,
uint64_t rowid, uint64_t rowid,
const struct TALER_PurseContractPublicKeyP *purse_pub) const struct TALER_PurseContractPublicKeyP *purse_pub,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *val)
{ {
struct CoinContext *cc = cls; struct CoinContext *cc = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
(void) val; /* irrelevant on refund */
(void) reserve_pub; /* irrelevant, may even be NULL */
GNUNET_assert (rowid >= ppc.last_purse_refunds_serial_id); /* should be monotonically increasing */ GNUNET_assert (rowid >= ppc.last_purse_refunds_serial_id); /* should be monotonically increasing */
ppc.last_purse_refunds_serial_id = rowid + 1; ppc.last_purse_refunds_serial_id = rowid + 1;
qs = TALER_ARL_edb->select_purse_deposits_by_purse (TALER_ARL_edb->cls, qs = TALER_ARL_edb->select_purse_deposits_by_purse (TALER_ARL_edb->cls,
@ -2020,8 +1953,8 @@ check_recoup (struct CoinContext *cc,
amount), amount),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
&coin->denom_pub_hash))); &coin->denom_pub_hash)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
amount); amount);
} }
qs = TALER_ARL_get_denomination_info_by_hash (&coin->denom_pub_hash, qs = TALER_ARL_get_denomination_info_by_hash (&coin->denom_pub_hash,
@ -2081,15 +2014,15 @@ check_recoup (struct CoinContext *cc,
amount), amount),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
&coin->coin_pub))); &coin->coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
amount); amount);
} }
TALER_ARL_amount_add (&ds->denom_recoup, TALER_ARL_amount_add (&ds->dcd.recoup_loss,
&ds->denom_recoup, &ds->dcd.recoup_loss,
amount); amount);
TALER_ARL_amount_add (&total_recoup_loss, TALER_ARL_amount_add (&balance.loss,
&total_recoup_loss, &balance.loss,
amount); amount);
} }
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
@ -2145,8 +2078,8 @@ recoup_cb (void *cls,
amount), amount),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
&coin->coin_pub))); &coin->coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
amount); amount);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -2233,13 +2166,13 @@ recoup_refresh_cb (void *cls,
} }
else else
{ {
TALER_ARL_amount_add (&dso->denom_balance, TALER_ARL_amount_add (&dso->dcd.denom_balance,
&dso->denom_balance, &dso->dcd.denom_balance,
amount); amount);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"New balance of denomination `%s' after refresh-recoup is %s\n", "New balance of denomination `%s' after refresh-recoup is %s\n",
GNUNET_h2s (&issue->denom_hash.hash), GNUNET_h2s (&issue->denom_hash.hash),
TALER_amount2s (&dso->denom_balance)); TALER_amount2s (&dso->dcd.denom_balance));
} }
} }
@ -2259,8 +2192,8 @@ recoup_refresh_cb (void *cls,
amount), amount),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
&coin->coin_pub))); &coin->coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
amount); amount);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -2432,8 +2365,8 @@ purse_deposit_cb (
&deposit->amount), &deposit->amount),
GNUNET_JSON_pack_data_auto ("coin_pub", GNUNET_JSON_pack_data_auto ("coin_pub",
&deposit->coin_pub))); &deposit->coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss, TALER_ARL_amount_add (&balance.irregular_loss,
&total_bad_sig_loss, &balance.irregular_loss,
&deposit->amount); &deposit->amount);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -2458,8 +2391,8 @@ purse_deposit_cb (
} }
/* update global deposit fees */ /* update global deposit fees */
TALER_ARL_amount_add (&total_deposit_fee_income, TALER_ARL_amount_add (&balance.deposit_fee_balance,
&total_deposit_fee_income, &balance.deposit_fee_balance,
&issue->fees.deposit); &issue->fees.deposit);
if (TALER_ARL_do_abort ()) if (TALER_ARL_do_abort ())
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -2511,13 +2444,15 @@ analyze_coins (void *cls)
{ {
ppc_start = ppc; ppc_start = ppc;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Resuming coin audit at %llu/%llu/%llu/%llu/%llu/%llu\n", "Resuming coin audit at %llu/%llu/%llu/%llu/%llu/%llu/%llu/%llu\n",
(unsigned long long) ppc.last_deposit_serial_id, (unsigned long long) ppc.last_deposit_serial_id,
(unsigned long long) ppc.last_melt_serial_id, (unsigned long long) ppc.last_melt_serial_id,
(unsigned long long) ppc.last_refund_serial_id, (unsigned long long) ppc.last_refund_serial_id,
(unsigned long long) ppc.last_withdraw_serial_id, (unsigned long long) ppc.last_withdraw_serial_id,
(unsigned long long) ppc.last_recoup_refresh_serial_id, (unsigned long long) ppc.last_recoup_refresh_serial_id,
(unsigned long long) ppc.last_purse_deposits_serial_id); (unsigned long long) ppc.last_open_deposits_serial_id,
(unsigned long long) ppc.last_purse_deposits_serial_id,
(unsigned long long) ppc.last_purse_refunds_serial_id);
} }
/* setup 'cc' */ /* setup 'cc' */
@ -2526,13 +2461,7 @@ analyze_coins (void *cls)
GNUNET_NO); GNUNET_NO);
qsx = TALER_ARL_adb->get_balance_summary (TALER_ARL_adb->cls, qsx = TALER_ARL_adb->get_balance_summary (TALER_ARL_adb->cls,
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
&total_escrow_balance, &balance);
&total_deposit_fee_income,
&total_melt_fee_income,
&total_refund_fee_income,
&total_risk,
&total_recoup_loss,
&total_irregular_recoups);
if (0 > qsx) if (0 > qsx)
{ {
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
@ -2569,9 +2498,10 @@ analyze_coins (void *cls)
/* process purse_refunds */ /* process purse_refunds */
if (0 > if (0 >
(qs = TALER_ARL_edb->select_purse_refunds_above_serial_id ( (qs = TALER_ARL_edb->select_purse_decisions_above_serial_id (
TALER_ARL_edb->cls, TALER_ARL_edb->cls,
ppc.last_purse_refunds_serial_id, ppc.last_purse_refunds_serial_id,
true, /* only go for refunds! */
&purse_refund_cb, &purse_refund_cb,
&cc))) &cc)))
{ {
@ -2663,23 +2593,11 @@ analyze_coins (void *cls)
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx) if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx)
qs = TALER_ARL_adb->update_balance_summary (TALER_ARL_adb->cls, qs = TALER_ARL_adb->update_balance_summary (TALER_ARL_adb->cls,
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
&total_escrow_balance, &balance);
&total_deposit_fee_income,
&total_melt_fee_income,
&total_refund_fee_income,
&total_risk,
&total_recoup_loss,
&total_irregular_recoups);
else else
qs = TALER_ARL_adb->insert_balance_summary (TALER_ARL_adb->cls, qs = TALER_ARL_adb->insert_balance_summary (TALER_ARL_adb->cls,
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
&total_escrow_balance, &balance);
&total_deposit_fee_income,
&total_melt_fee_income,
&total_refund_fee_income,
&total_risk,
&total_recoup_loss,
&total_irregular_recoups);
if (0 >= qs) if (0 >= qs)
{ {
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@ -2702,13 +2620,15 @@ analyze_coins (void *cls)
return qs; return qs;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Concluded coin audit step at %llu/%llu/%llu/%llu/%llu/%llu\n", "Concluded coin audit step at %llu/%llu/%llu/%llu/%llu/%llu/%llu/%llu\n",
(unsigned long long) ppc.last_deposit_serial_id, (unsigned long long) ppc.last_deposit_serial_id,
(unsigned long long) ppc.last_melt_serial_id, (unsigned long long) ppc.last_melt_serial_id,
(unsigned long long) ppc.last_refund_serial_id, (unsigned long long) ppc.last_refund_serial_id,
(unsigned long long) ppc.last_withdraw_serial_id, (unsigned long long) ppc.last_withdraw_serial_id,
(unsigned long long) ppc.last_recoup_refresh_serial_id, (unsigned long long) ppc.last_recoup_refresh_serial_id,
(unsigned long long) ppc.last_purse_deposits_serial_id); (unsigned long long) ppc.last_open_deposits_serial_id,
(unsigned long long) ppc.last_purse_deposits_serial_id,
(unsigned long long) ppc.last_purse_refunds_serial_id);
return qs; return qs;
} }
@ -2754,34 +2674,37 @@ run (void *cls,
&reported_emergency_loss_by_count)); &reported_emergency_loss_by_count));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_escrow_balance)); &balance.total_escrowed));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_risk)); &balance.deposit_fee_balance));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_recoup_loss)); &balance.melt_fee_balance));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_irregular_recoups)); &balance.refund_fee_balance));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_deposit_fee_income)); &balance.purse_fee_balance));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_melt_fee_income)); &balance.open_deposit_fee_balance));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_refund_fee_income)); &balance.risk));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&balance.loss));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&balance.irregular_loss));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_arithmetic_delta_plus)); &total_arithmetic_delta_plus));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_arithmetic_delta_minus)); &total_arithmetic_delta_minus));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&total_bad_sig_loss));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency, TALER_amount_set_zero (TALER_ARL_currency,
&total_refresh_hanging)); &total_refresh_hanging));
@ -2812,27 +2735,30 @@ run (void *cls,
TALER_ARL_done ( TALER_ARL_done (
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
TALER_JSON_pack_amount ("total_escrow_balance", TALER_JSON_pack_amount ("total_escrow_balance",
&total_escrow_balance), &balance.total_escrowed),
TALER_JSON_pack_amount ("total_active_risk",
&total_risk),
TALER_JSON_pack_amount ("total_deposit_fee_income", TALER_JSON_pack_amount ("total_deposit_fee_income",
&total_deposit_fee_income), &balance.deposit_fee_balance),
TALER_JSON_pack_amount ("total_melt_fee_income", TALER_JSON_pack_amount ("total_melt_fee_income",
&total_melt_fee_income), &balance.melt_fee_balance),
TALER_JSON_pack_amount ("total_refund_fee_income", TALER_JSON_pack_amount ("total_refund_fee_income",
&total_refund_fee_income), &balance.refund_fee_balance),
TALER_JSON_pack_amount ("total_purse_fee_income",
&balance.purse_fee_balance),
TALER_JSON_pack_amount ("total_open_deposit_fee_income",
&balance.open_deposit_fee_balance),
TALER_JSON_pack_amount ("total_active_risk",
&balance.risk),
TALER_JSON_pack_amount ("total_recoup_loss",
&balance.loss),
/* Tested in test-auditor.sh #4/#5/#6/#13/#26 */
TALER_JSON_pack_amount ("irregular_loss",
&balance.irregular_loss),
/* Tested in test-auditor.sh #18 */ /* Tested in test-auditor.sh #18 */
GNUNET_JSON_pack_array_steal ("emergencies", GNUNET_JSON_pack_array_steal ("emergencies",
report_emergencies), report_emergencies),
/* Tested in test-auditor.sh #18 */ /* Tested in test-auditor.sh #18 */
TALER_JSON_pack_amount ("emergencies_risk_by_amount", TALER_JSON_pack_amount ("emergencies_risk_by_amount",
&reported_emergency_risk_by_amount), &reported_emergency_risk_by_amount),
/* Tested in test-auditor.sh #4/#5/#6/#13/#26 */
GNUNET_JSON_pack_array_steal ("bad_sig_losses",
report_bad_sig_losses),
/* Tested in test-auditor.sh #4/#5/#6/#13/#26 */
TALER_JSON_pack_amount ("total_bad_sig_loss",
&total_bad_sig_loss),
/* Tested in test-auditor.sh #31 */ /* Tested in test-auditor.sh #31 */
GNUNET_JSON_pack_array_steal ("row_inconsistencies", GNUNET_JSON_pack_array_steal ("row_inconsistencies",
report_row_inconsistencies), report_row_inconsistencies),
@ -2845,11 +2771,11 @@ run (void *cls,
&total_arithmetic_delta_minus), &total_arithmetic_delta_minus),
TALER_JSON_pack_amount ("total_refresh_hanging", TALER_JSON_pack_amount ("total_refresh_hanging",
&total_refresh_hanging), &total_refresh_hanging),
GNUNET_JSON_pack_array_steal ("bad_sig_losses",
report_bad_sig_losses),
/* Tested in test-auditor.sh #12 */ /* Tested in test-auditor.sh #12 */
GNUNET_JSON_pack_array_steal ("refresh_hanging", GNUNET_JSON_pack_array_steal ("refresh_hanging",
report_refreshs_hanging), report_refreshs_hanging),
TALER_JSON_pack_amount ("total_recoup_loss",
&total_recoup_loss),
/* Tested in test-auditor.sh #18 */ /* Tested in test-auditor.sh #18 */
GNUNET_JSON_pack_array_steal ("emergencies_by_count", GNUNET_JSON_pack_array_steal ("emergencies_by_count",
report_emergencies_by_count), report_emergencies_by_count),
@ -2898,8 +2824,6 @@ run (void *cls,
start_time), start_time),
TALER_JSON_pack_time_abs_human ("auditor_end_time", TALER_JSON_pack_time_abs_human ("auditor_end_time",
GNUNET_TIME_absolute_get ()), GNUNET_TIME_absolute_get ()),
TALER_JSON_pack_amount ("total_irregular_recoups",
&total_irregular_recoups),
GNUNET_JSON_pack_array_steal ("unsigned_denominations", GNUNET_JSON_pack_array_steal ("unsigned_denominations",
report_denominations_without_sigs))); report_denominations_without_sigs)));
} }

File diff suppressed because it is too large Load Diff

View File

@ -53,4 +53,14 @@ jinjaEnv = jinja2.Environment(loader=StdinLoader(),
autoescape=False) autoescape=False)
tmpl = jinjaEnv.get_template('stdin'); tmpl = jinjaEnv.get_template('stdin');
print(tmpl.render(aggregation = jsonData1, coins = jsonData2, deposits = jsonData3, reserves = jsonData4, wire = jsonData5)) try:
print(tmpl.render(aggregation = jsonData1, coins = jsonData2, deposits = jsonData3, reserves = jsonData4, wire = jsonData5))
except jinja2.TemplateSyntaxError as error:
print("Template syntax error: {error.message} on line {error.lineno}.".format(error=error))
exit(1)
except jinja2.UndefinedError as error:
print("Template undefined error: {error.message}.".format(error=error))
exit(1)
except TypeError as error:
print("Template type error: {0}.".format(error.args[0]))
exit(1)

File diff suppressed because it is too large Load Diff

View File

@ -93,14 +93,9 @@ struct WireAccount
struct TALER_AUDITORDB_WireAccountProgressPoint start_pp; struct TALER_AUDITORDB_WireAccountProgressPoint start_pp;
/** /**
* Where we are in the inbound (CREDIT) transaction history. * Where we are in the transaction history.
*/ */
uint64_t in_wire_off; struct TALER_AUDITORDB_BankAccountProgressPoint wire_off;
/**
* Where we are in the inbound (DEBIT) transaction history.
*/
uint64_t out_wire_off;
/** /**
* Return value when we got this account's progress point. * Return value when we got this account's progress point.
@ -772,16 +767,14 @@ commit (enum GNUNET_DB_QueryStatus qs)
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
wa->ai->section_name, wa->ai->section_name,
&wa->pp, &wa->pp,
wa->in_wire_off, &wa->wire_off);
wa->out_wire_off);
else else
qs = TALER_ARL_adb->insert_wire_auditor_account_progress ( qs = TALER_ARL_adb->insert_wire_auditor_account_progress (
TALER_ARL_adb->cls, TALER_ARL_adb->cls,
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
wa->ai->section_name, wa->ai->section_name,
&wa->pp, &wa->pp,
wa->in_wire_off, &wa->wire_off);
wa->out_wire_off);
if (0 >= qs) if (0 >= qs)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -1520,7 +1513,7 @@ history_debit_cb (void *cls,
TALER_amount2s (&details->amount), TALER_amount2s (&details->amount),
TALER_B2S (&details->wtid)); TALER_B2S (&details->wtid));
/* Update offset */ /* Update offset */
wa->out_wire_off = row_off; wa->wire_off.out_wire_off = row_off;
slen = strlen (details->credit_account_uri) + 1; slen = strlen (details->credit_account_uri) + 1;
roi = GNUNET_malloc (sizeof (struct ReserveOutInfo) roi = GNUNET_malloc (sizeof (struct ReserveOutInfo)
+ slen); + slen);
@ -1594,7 +1587,7 @@ process_debits (void *cls)
// (CG: used to be INT64_MAX, changed by MS to INT32_MAX, why? To be discussed with him!) // (CG: used to be INT64_MAX, changed by MS to INT32_MAX, why? To be discussed with him!)
wa->dhh = TALER_BANK_debit_history (ctx, wa->dhh = TALER_BANK_debit_history (ctx,
wa->ai->auth, wa->ai->auth,
wa->out_wire_off, wa->wire_off.out_wire_off,
INT32_MAX, INT32_MAX,
GNUNET_TIME_UNIT_ZERO, GNUNET_TIME_UNIT_ZERO,
&history_debit_cb, &history_debit_cb,
@ -1846,7 +1839,7 @@ history_credit_cb (void *cls,
} }
/* Update offset */ /* Update offset */
wa->in_wire_off = row_off; wa->wire_off.in_wire_off = row_off;
/* compare records with expected data */ /* compare records with expected data */
if (0 != GNUNET_memcmp (&details->reserve_pub, if (0 != GNUNET_memcmp (&details->reserve_pub,
&rii->details.reserve_pub)) &rii->details.reserve_pub))
@ -2032,7 +2025,7 @@ process_credits (void *cls)
// (CG: used to be INT64_MAX, changed by MS to INT32_MAX, why? To be discussed with him!) // (CG: used to be INT64_MAX, changed by MS to INT32_MAX, why? To be discussed with him!)
wa->chh = TALER_BANK_credit_history (ctx, wa->chh = TALER_BANK_credit_history (ctx,
wa->ai->auth, wa->ai->auth,
wa->in_wire_off, wa->wire_off.in_wire_off,
INT32_MAX, INT32_MAX,
GNUNET_TIME_UNIT_ZERO, GNUNET_TIME_UNIT_ZERO,
&history_credit_cb, &history_credit_cb,
@ -2084,12 +2077,14 @@ reserve_closed_cb (void *cls,
const struct TALER_Amount *closing_fee, const struct TALER_Amount *closing_fee,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const char *receiver_account, const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid) const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t close_request_row)
{ {
struct ReserveClosure *rc; struct ReserveClosure *rc;
struct GNUNET_HashCode key; struct GNUNET_HashCode key;
(void) cls; (void) cls;
(void) close_request_row;
rc = GNUNET_new (struct ReserveClosure); rc = GNUNET_new (struct ReserveClosure);
if (TALER_ARL_SR_INVALID_NEGATIVE == if (TALER_ARL_SR_INVALID_NEGATIVE ==
TALER_ARL_amount_subtract_neg (&rc->amount, TALER_ARL_amount_subtract_neg (&rc->amount,
@ -2210,8 +2205,7 @@ begin_transaction (void)
&TALER_ARL_master_pub, &TALER_ARL_master_pub,
wa->ai->section_name, wa->ai->section_name,
&wa->pp, &wa->pp,
&wa->in_wire_off, &wa->wire_off);
&wa->out_wire_off);
if (0 > wa->qsx) if (0 > wa->qsx)
{ {
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == wa->qsx); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == wa->qsx);

View File

@ -388,7 +388,7 @@ function test_0() {
then then
exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS" exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS != "TESTKUDOS:0" if test $LOSS != "TESTKUDOS:0"
then then
exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS" exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS"
@ -613,7 +613,7 @@ function test_3() {
exit_fail "Expected reserve balance summary amount wrong, got $EXPECTED (exchange)" exit_fail "Expected reserve balance summary amount wrong, got $EXPECTED (exchange)"
fi fi
WIRED=`jq -r .total_loss_balance_insufficient < test-audit-reserves.json` WIRED=`jq -r .total_irregular_loss < test-audit-reserves.json`
if test $WIRED != "TESTKUDOS:0" if test $WIRED != "TESTKUDOS:0"
then then
exit_fail "Wrong total loss from insufficient balance, got $WIRED" exit_fail "Wrong total loss from insufficient balance, got $WIRED"
@ -690,7 +690,7 @@ function test_4() {
exit_fail "Wrong operation, got $OP" exit_fail "Wrong operation, got $OP"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS != "TESTKUDOS:3" if test $LOSS != "TESTKUDOS:3"
then then
exit_fail "Wrong total bad sig loss, got $LOSS" exit_fail "Wrong total bad sig loss, got $LOSS"
@ -734,7 +734,7 @@ function test_5() {
exit_fail "Wrong operation, got $OP" exit_fail "Wrong operation, got $OP"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS != "TESTKUDOS:3" if test $LOSS != "TESTKUDOS:3"
then then
exit_fail "Wrong total bad sig loss, got $LOSS" exit_fail "Wrong total bad sig loss, got $LOSS"
@ -776,7 +776,7 @@ function test_6() {
exit_fail "Wrong operation, got $OP" exit_fail "Wrong operation, got $OP"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS == "TESTKUDOS:0" if test $LOSS == "TESTKUDOS:0"
then then
exit_fail "Wrong total bad sig loss, got $LOSS" exit_fail "Wrong total bad sig loss, got $LOSS"
@ -1093,7 +1093,7 @@ function test_13() {
fi fi
LOSS=`jq -er .bad_sig_losses[0].loss < test-audit-coins.json` LOSS=`jq -er .bad_sig_losses[0].loss < test-audit-coins.json`
TOTAL_LOSS=`jq -er .total_bad_sig_loss < test-audit-coins.json` TOTAL_LOSS=`jq -er .irregular_loss < test-audit-coins.json`
if test x$LOSS != x$TOTAL_LOSS if test x$LOSS != x$TOTAL_LOSS
then then
exit_fail "Loss inconsistent, got $LOSS and $TOTAL_LOSS" exit_fail "Loss inconsistent, got $LOSS and $TOTAL_LOSS"
@ -1644,7 +1644,7 @@ function test_26() {
exit_fail "Wrong operation, got $OP" exit_fail "Wrong operation, got $OP"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS != "TESTKUDOS:3" if test $LOSS != "TESTKUDOS:3"
then then
exit_fail "Wrong total bad sig loss, got $LOSS" exit_fail "Wrong total bad sig loss, got $LOSS"
@ -1805,7 +1805,7 @@ function test_31() {
run_audit aggregator run_audit aggregator
echo -n "Testing inconsistency detection... " echo -n "Testing inconsistency detection... "
AMOUNT=`jq -r .total_bad_sig_loss < test-audit-coins.json` AMOUNT=`jq -r .irregular_loss < test-audit-coins.json`
if test "x$AMOUNT" == "xTESTKUDOS:0" if test "x$AMOUNT" == "xTESTKUDOS:0"
then then
exit_fail "Reported total amount wrong: $AMOUNT" exit_fail "Reported total amount wrong: $AMOUNT"
@ -1892,7 +1892,7 @@ function test_33() {
then then
exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS" exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS != "TESTKUDOS:0" if test $LOSS != "TESTKUDOS:0"
then then
exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS" exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS"

View File

@ -337,7 +337,7 @@ function test_0() {
then then
exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS" exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS"
fi fi
LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json` LOSS=`jq -r .irregular_loss < test-audit-coins.json`
if test $LOSS != "TESTKUDOS:0" if test $LOSS != "TESTKUDOS:0"
then then
exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS" exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS"
@ -561,7 +561,7 @@ function test_4() {
echo -n "Testing inconsistency detection... " echo -n "Testing inconsistency detection... "
# Coin spent exceeded coin's value # Coin spent exceeded coin's value
jq -e .bad_sig_losses[0] < test-audit-coins.json > /dev/null || exit_fail "Bad recoup not detected" jq -e .bad_sig_losses[0] < test-audit-coins.json > /dev/null || exit_fail "Bad recoup not detected"
AMOUNT=`jq -r .total_bad_sig_losses < test-audit-coins.json` AMOUNT=`jq -r .irregular_loss < test-audit-coins.json`
if test $AMOUNT == "TESTKUDOS:0" if test $AMOUNT == "TESTKUDOS:0"
then then
exit_fail "Total bad sig losses are wrong" exit_fail "Total bad sig losses are wrong"

View File

@ -1,53 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2020 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 3, or (at your option) any later version.
--
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
-- Everything in one big transaction
BEGIN;
NOTE: This code is not yet ready / in use. It was archived here
as we might want this kind of table in the future. It is NOT
to be installed in a production system (hence in EXTRA_DIST and
not in the SQL target!)
-- Check patch versioning is in place.
SELECT _v.register_patch('auditor-9999', NULL, NULL);
-- Table with historic business ledger; basically, when the exchange
-- operator decides to use operating costs for anything but wire
-- transfers to merchants, it goes in here. This happens when the
-- operator users transaction fees for business expenses. purpose
-- is free-form but should be a human-readable wire transfer
-- identifier. This is NOT yet used and outside of the scope of
-- the core auditing logic. However, once we do take fees to use
-- operating costs, and if we still want auditor_predicted_result to match
-- the tables overall, we'll need a command-line tool to insert rows
-- into this table and update auditor_predicted_result accordingly.
-- (So this table for now just exists as a reminder of what we'll
-- need in the long term.)
CREATE TABLE IF NOT EXISTS auditor_historic_ledger
(master_pub BYTEA CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
,purpose VARCHAR NOT NULL
,timestamp INT8 NOT NULL
,balance_val INT8 NOT NULL
,balance_frac INT4 NOT NULL
);
CREATE INDEX history_ledger_by_master_pub_and_time
ON auditor_historic_ledger
(master_pub
,timestamp);
COMMIT;

View File

@ -1,6 +1,6 @@
-- --
-- This file is part of TALER -- This file is part of TALER
-- Copyright (C) 2014--2020 Taler Systems SA -- Copyright (C) 2014--2022 Taler Systems SA
-- --
-- TALER is free software; you can redistribute it and/or modify it under the -- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software -- terms of the GNU General Public License as published by the Free Software
@ -52,16 +52,29 @@ CREATE TABLE IF NOT EXISTS auditor_progress_reserve
,last_reserve_in_serial_id INT8 NOT NULL DEFAULT 0 ,last_reserve_in_serial_id INT8 NOT NULL DEFAULT 0
,last_reserve_out_serial_id INT8 NOT NULL DEFAULT 0 ,last_reserve_out_serial_id INT8 NOT NULL DEFAULT 0
,last_reserve_recoup_serial_id INT8 NOT NULL DEFAULT 0 ,last_reserve_recoup_serial_id INT8 NOT NULL DEFAULT 0
,last_reserve_open_serial_id INT8 NOT NULL DEFAULT 0
,last_reserve_close_serial_id INT8 NOT NULL DEFAULT 0 ,last_reserve_close_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_merges_serial_id INT8 NOT NULL DEFAULT 0 ,last_purse_decision_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_deposits_serial_id INT8 NOT NULL DEFAULT 0
,last_account_merges_serial_id INT8 NOT NULL DEFAULT 0 ,last_account_merges_serial_id INT8 NOT NULL DEFAULT 0
,last_history_requests_serial_id INT8 NOT NULL DEFAULT 0 ,last_history_requests_serial_id INT8 NOT NULL DEFAULT 0
,last_close_requests_serial_id INT8 NOT NULL DEFAULT 0
,PRIMARY KEY (master_pub) ,PRIMARY KEY (master_pub)
); );
COMMENT ON TABLE auditor_progress_reserve COMMENT ON TABLE auditor_progress_reserve
IS 'information as to which transactions the auditor has processed in the exchange database. Used for SELECTing the IS 'information as to which transactions the reserve auditor has processed in the exchange database. Used for SELECTing the
statements to process. The indices include the last serial ID from the respective tables that we have processed. Thus, we need to select those table entries that are strictly larger (and process in monotonically increasing order).';
CREATE TABLE IF NOT EXISTS auditor_progress_purse
(master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
,last_purse_request_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_decision_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_merges_serial_id INT8 NOT NULL DEFAULT 0
,last_account_merges_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_deposits_serial_id INT8 NOT NULL DEFAULT 0
,PRIMARY KEY (master_pub)
);
COMMENT ON TABLE auditor_progress_purse
IS 'information as to which purses the purse auditor has processed in the exchange database. Used for SELECTing the
statements to process. The indices include the last serial ID from the respective tables that we have processed. Thus, we need to select those table entries that are strictly larger (and process in monotonically increasing order).'; statements to process. The indices include the last serial ID from the respective tables that we have processed. Thus, we need to select those table entries that are strictly larger (and process in monotonically increasing order).';
@ -93,8 +106,9 @@ CREATE TABLE IF NOT EXISTS auditor_progress_coin
,last_refund_serial_id INT8 NOT NULL DEFAULT 0 ,last_refund_serial_id INT8 NOT NULL DEFAULT 0
,last_recoup_serial_id INT8 NOT NULL DEFAULT 0 ,last_recoup_serial_id INT8 NOT NULL DEFAULT 0
,last_recoup_refresh_serial_id INT8 NOT NULL DEFAULT 0 ,last_recoup_refresh_serial_id INT8 NOT NULL DEFAULT 0
,last_open_deposits_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_deposits_serial_id INT8 NOT NULL DEFAULT 0 ,last_purse_deposits_serial_id INT8 NOT NULL DEFAULT 0
,last_purse_refunds_serial_id INT8 NOT NULL DEFAULT 0 ,last_purse_decision_serial_id INT8 NOT NULL DEFAULT 0
,PRIMARY KEY (master_pub) ,PRIMARY KEY (master_pub)
); );
COMMENT ON TABLE auditor_progress_coin COMMENT ON TABLE auditor_progress_coin
@ -129,10 +143,20 @@ CREATE TABLE IF NOT EXISTS auditor_reserves
,master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE ,master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
,reserve_balance_val INT8 NOT NULL ,reserve_balance_val INT8 NOT NULL
,reserve_balance_frac INT4 NOT NULL ,reserve_balance_frac INT4 NOT NULL
,reserve_loss_val INT8 NOT NULL
,reserve_loss_frac INT4 NOT NULL
,withdraw_fee_balance_val INT8 NOT NULL ,withdraw_fee_balance_val INT8 NOT NULL
,withdraw_fee_balance_frac INT4 NOT NULL ,withdraw_fee_balance_frac INT4 NOT NULL
,close_fee_balance_val INT8 NOT NULL
,close_fee_balance_frac INT4 NOT NULL
,purse_fee_balance_val INT8 NOT NULL
,purse_fee_balance_frac INT4 NOT NULL
,open_fee_balance_val INT8 NOT NULL
,open_fee_balance_frac INT4 NOT NULL
,history_fee_balance_val INT8 NOT NULL
,history_fee_balance_frac INT4 NOT NULL
,expiration_date INT8 NOT NULL ,expiration_date INT8 NOT NULL
,auditor_reserves_rowid BIGSERIAL UNIQUE ,auditor_reserves_rowid BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,origin_account TEXT ,origin_account TEXT
); );
COMMENT ON TABLE auditor_reserves COMMENT ON TABLE auditor_reserves
@ -143,14 +167,38 @@ CREATE INDEX IF NOT EXISTS auditor_reserves_by_reserve_pub
(reserve_pub); (reserve_pub);
CREATE TABLE IF NOT EXISTS auditor_purses
(purse_pub BYTEA NOT NULL CHECK(LENGTH(purse_pub)=32)
,master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
,balance_val INT8 NOT NULL
,balance_frac INT4 NOT NULL
,target_val INT8 NOT NULL
,target_frac INT4 NOT NULL
,expiration_date INT8 NOT NULL
,auditor_purses_rowid BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
);
COMMENT ON TABLE auditor_purses
IS 'all of the purses and their respective balances that the auditor is aware of';
CREATE INDEX IF NOT EXISTS auditor_purses_by_purse_pub
ON auditor_purses
(purse_pub);
CREATE TABLE IF NOT EXISTS auditor_reserve_balance CREATE TABLE IF NOT EXISTS auditor_reserve_balance
(master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE (master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
,reserve_balance_val INT8 NOT NULL ,reserve_balance_val INT8 NOT NULL
,reserve_balance_frac INT4 NOT NULL ,reserve_balance_frac INT4 NOT NULL
,reserve_loss_val INT8 NOT NULL
,reserve_loss_frac INT4 NOT NULL
,withdraw_fee_balance_val INT8 NOT NULL ,withdraw_fee_balance_val INT8 NOT NULL
,withdraw_fee_balance_frac INT4 NOT NULL ,withdraw_fee_balance_frac INT4 NOT NULL
,close_fee_balance_val INT8 NOT NULL
,close_fee_balance_frac INT4 NOT NULL
,purse_fee_balance_val INT8 NOT NULL ,purse_fee_balance_val INT8 NOT NULL
,purse_fee_balance_frac INT4 NOT NULL ,purse_fee_balance_frac INT4 NOT NULL
,open_fee_balance_val INT8 NOT NULL
,open_fee_balance_frac INT4 NOT NULL
,history_fee_balance_val INT8 NOT NULL ,history_fee_balance_val INT8 NOT NULL
,history_fee_balance_frac INT4 NOT NULL ,history_fee_balance_frac INT4 NOT NULL
); );
@ -185,8 +233,10 @@ COMMENT ON COLUMN auditor_denomination_pending.num_issued
IS 'counts the number of coins issued (withdraw, refresh) of this denomination'; IS 'counts the number of coins issued (withdraw, refresh) of this denomination';
COMMENT ON COLUMN auditor_denomination_pending.denom_risk_val COMMENT ON COLUMN auditor_denomination_pending.denom_risk_val
IS 'amount that could theoretically be lost in the future due to recoup operations'; IS 'amount that could theoretically be lost in the future due to recoup operations';
COMMENT ON COLUMN auditor_denomination_pending.denom_loss_val
IS 'amount that was lost due to failures by the exchange';
COMMENT ON COLUMN auditor_denomination_pending.recoup_loss_val COMMENT ON COLUMN auditor_denomination_pending.recoup_loss_val
IS 'amount actually lost due to recoup operations past revocation'; IS 'amount actually lost due to recoup operations after a revocation';
CREATE TABLE IF NOT EXISTS auditor_balance_summary CREATE TABLE IF NOT EXISTS auditor_balance_summary
@ -199,15 +249,21 @@ CREATE TABLE IF NOT EXISTS auditor_balance_summary
,melt_fee_balance_frac INT4 NOT NULL ,melt_fee_balance_frac INT4 NOT NULL
,refund_fee_balance_val INT8 NOT NULL ,refund_fee_balance_val INT8 NOT NULL
,refund_fee_balance_frac INT4 NOT NULL ,refund_fee_balance_frac INT4 NOT NULL
,purse_fee_balance_val INT8 NOT NULL
,purse_fee_balance_frac INT4 NOT NULL
,open_deposit_fee_balance_val INT8 NOT NULL
,open_deposit_fee_balance_frac INT4 NOT NULL
,risk_val INT8 NOT NULL ,risk_val INT8 NOT NULL
,risk_frac INT4 NOT NULL ,risk_frac INT4 NOT NULL
,loss_val INT8 NOT NULL ,loss_val INT8 NOT NULL
,loss_frac INT4 NOT NULL ,loss_frac INT4 NOT NULL
,irregular_recoup_val INT8 NOT NULL ,irregular_loss_val INT8 NOT NULL
,irregular_recoup_frac INT4 NOT NULL ,irregular_loss_frac INT4 NOT NULL
); );
COMMENT ON TABLE auditor_balance_summary COMMENT ON TABLE auditor_balance_summary
IS 'the sum of the outstanding coins from auditor_denomination_pending (denom_pubs must belong to the respectives exchange master public key); it represents the auditor_balance_summary of the exchange at this point (modulo unexpected historic_loss-style events where denomination keys are compromised)'; IS 'the sum of the outstanding coins from auditor_denomination_pending (denom_pubs must belong to the respectives exchange master public key); it represents the auditor_balance_summary of the exchange at this point (modulo unexpected historic_loss-style events where denomination keys are compromised)';
COMMENT ON COLUMN auditor_balance_summary.denom_balance_frac
IS 'total amount we should have in escrow for all denominations';
CREATE TABLE IF NOT EXISTS auditor_historic_denomination_revenue CREATE TABLE IF NOT EXISTS auditor_historic_denomination_revenue
@ -243,7 +299,7 @@ CREATE INDEX IF NOT EXISTS auditor_historic_reserve_summary_by_master_pub_start_
CREATE TABLE IF NOT EXISTS deposit_confirmations CREATE TABLE IF NOT EXISTS deposit_confirmations
(master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE (master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
,serial_id BIGSERIAL NOT NULL UNIQUE ,serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64) ,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)
,h_extensions BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64) ,h_extensions BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)
,h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64) ,h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2016 Taler Systems SA Copyright (C) 2016--2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -17,17 +17,17 @@
* @file auditordb/test_auditordb.c * @file auditordb/test_auditordb.c
* @brief test cases for DB interaction functions * @brief test cases for DB interaction functions
* @author Gabor X Toth * @author Gabor X Toth
* @author Christian Grothoff
*/ */
#include "platform.h" #include "platform.h"
#include <gnunet/gnunet_db_lib.h> #include <gnunet/gnunet_db_lib.h>
#include "taler_auditordb_lib.h" #include "taler_auditordb_lib.h"
#include "taler_auditordb_plugin.h" #include "taler_auditordb_plugin.h"
/** /**
* Global result from the testcase. * Currency we use, must match CURRENCY in "test-auditor-db-postgres.conf".
*/ */
static int result = -1; #define CURRENCY "EUR"
/** /**
* Report line of error if @a cond is true, and jump to label "drop". * Report line of error if @a cond is true, and jump to label "drop".
@ -39,7 +39,6 @@ static int result = -1;
goto drop; \ goto drop; \
} while (0) } while (0)
/** /**
* Initializes @a ptr with random data. * Initializes @a ptr with random data.
*/ */
@ -54,15 +53,124 @@ static int result = -1;
/** /**
* Currency we use, must match CURRENCY in "test-auditor-db-postgres.conf". * Global result from the testcase.
*/ */
#define CURRENCY "EUR" static int result = -1;
/**
* Hash of denomination public key.
*/
static struct TALER_DenominationHashP denom_pub_hash;
/**
* Another hash of a denomination public key.
*/
static struct TALER_DenominationHashP rnd_hash;
/**
* Current time.
*/
static struct GNUNET_TIME_Timestamp now;
/**
* Timestamp in the past.
*/
static struct GNUNET_TIME_Timestamp past;
/**
* Timestamp in the future.
*/
static struct GNUNET_TIME_Timestamp future;
/** /**
* Database plugin under test. * Database plugin under test.
*/ */
static struct TALER_AUDITORDB_Plugin *plugin; static struct TALER_AUDITORDB_Plugin *plugin;
/**
* Historic denomination revenue value.
*/
static struct TALER_Amount rbalance;
/**
* Historic denomination loss value.
*/
static struct TALER_Amount rloss;
/**
* Reserve profit value we are using.
*/
static struct TALER_Amount reserve_profits;
static enum GNUNET_GenericReturnValue
select_historic_denom_revenue_result (
void *cls,
const struct TALER_DenominationHashP *denom_pub_hash2,
struct GNUNET_TIME_Timestamp revenue_timestamp2,
const struct TALER_Amount *revenue_balance2,
const struct TALER_Amount *loss2)
{
static int n = 0;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"select_historic_denom_revenue_result: row %u\n", n);
if ( (2 <= n++)
|| (cls != NULL)
|| ((0 != GNUNET_memcmp (&revenue_timestamp2,
&past))
&& (0 != GNUNET_memcmp (&revenue_timestamp2,
&now)))
|| ((0 != GNUNET_memcmp (denom_pub_hash2,
&denom_pub_hash))
&& (0 != GNUNET_memcmp (denom_pub_hash2,
&rnd_hash)))
|| (0 != TALER_amount_cmp (revenue_balance2,
&rbalance))
|| (0 != TALER_amount_cmp (loss2,
&rloss)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"select_historic_denom_revenue_result: result does not match\n");
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
static enum GNUNET_GenericReturnValue
select_historic_reserve_revenue_result (
void *cls,
struct GNUNET_TIME_Timestamp start_time2,
struct GNUNET_TIME_Timestamp end_time2,
const struct TALER_Amount *reserve_profits2)
{
static int n = 0;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"select_historic_reserve_revenue_result: row %u\n", n);
if ((2 <= n++)
|| (cls != NULL)
|| ((0 != GNUNET_memcmp (&start_time2,
&past))
&& (0 != GNUNET_memcmp (&start_time2,
&now)))
|| (0 != GNUNET_memcmp (&end_time2,
&future))
|| (0 != TALER_amount_cmp (reserve_profits2,
&reserve_profits)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"select_historic_reserve_revenue_result: result does not match\n");
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/** /**
* Main function that will be run by the scheduler. * Main function that will be run by the scheduler.
@ -130,13 +238,8 @@ run (void *cls)
struct TALER_MasterPublicKeyP master_pub; struct TALER_MasterPublicKeyP master_pub;
struct TALER_ReservePublicKeyP reserve_pub; struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_DenominationHashP rnd_hash;
struct TALER_DenominationPrivateKey denom_priv; struct TALER_DenominationPrivateKey denom_priv;
struct TALER_DenominationPublicKey denom_pub; struct TALER_DenominationPublicKey denom_pub;
struct TALER_DenominationHashP denom_pub_hash;
struct GNUNET_TIME_Timestamp now;
struct GNUNET_TIME_Timestamp past;
struct GNUNET_TIME_Timestamp future;
struct GNUNET_TIME_Timestamp date; struct GNUNET_TIME_Timestamp date;
RND_BLK (&master_pub); RND_BLK (&master_pub);
@ -217,472 +320,364 @@ run (void *cls)
(ppc.last_refund_serial_id != ppc2.last_refund_serial_id) || (ppc.last_refund_serial_id != ppc2.last_refund_serial_id) ||
(ppc.last_withdraw_serial_id != ppc2.last_withdraw_serial_id) ); (ppc.last_withdraw_serial_id != ppc2.last_withdraw_serial_id) );
GNUNET_log (GNUNET_ERROR_TYPE_INFO, {
"Test: insert_reserve_info\n"); struct TALER_AUDITORDB_ReserveFeeBalance rfb;
struct TALER_AUDITORDB_ReserveFeeBalance rfb2;
struct TALER_Amount reserve_balance; GNUNET_log (GNUNET_ERROR_TYPE_INFO,
struct TALER_Amount withdraw_fee_balance; "Test: insert_reserve_info\n");
struct TALER_Amount purse_fee_balance; GNUNET_assert (GNUNET_OK ==
struct TALER_Amount history_fee_balance; TALER_string_to_amount (CURRENCY ":12.345678",
struct TALER_Amount reserve_balance2 = {}; &rfb.reserve_balance));
struct TALER_Amount withdraw_fee_balance2 = {}; GNUNET_assert (GNUNET_OK ==
struct TALER_Amount purse_fee_balance2 = {}; TALER_string_to_amount (CURRENCY ":11.245678",
struct TALER_Amount history_fee_balance2 = {}; &rfb.reserve_loss));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":23.456789",
&rfb.withdraw_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":23.456719",
&rfb.close_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":33.456789",
&rfb.purse_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":43.456789",
&rfb.open_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":53.456789",
&rfb.history_fee_balance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_reserve_info (plugin->cls,
&reserve_pub,
&master_pub,
&rfb,
past,
"payto://bla/blub"));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_reserve_info\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_reserve_info (plugin->cls,
&reserve_pub,
&master_pub,
&rfb,
future));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_reserve_info\n");
{
char *payto;
GNUNET_assert (GNUNET_OK == FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
TALER_string_to_amount (CURRENCY ":12.345678", plugin->get_reserve_info (plugin->cls,
&reserve_balance)); &reserve_pub,
GNUNET_assert (GNUNET_OK == &master_pub,
TALER_string_to_amount (CURRENCY ":23.456789", &rowid,
&withdraw_fee_balance)); &rfb2,
GNUNET_assert (GNUNET_OK == &date,
TALER_string_to_amount (CURRENCY ":23.456789", &payto));
&purse_fee_balance)); FAILIF (0 != strcmp (payto,
GNUNET_assert (GNUNET_OK == "payto://bla/blub"));
TALER_string_to_amount (CURRENCY ":23.456789", GNUNET_free (payto);
&history_fee_balance)); }
FAILIF ( (0 != GNUNET_memcmp (&date,
&future))
|| (0 != TALER_amount_cmp (&rfb2.reserve_balance,
&rfb.reserve_balance))
|| (0 != TALER_amount_cmp (&rfb2.withdraw_fee_balance,
&rfb.withdraw_fee_balance))
|| (0 != TALER_amount_cmp (&rfb2.close_fee_balance,
&rfb.close_fee_balance))
|| (0 != TALER_amount_cmp (&rfb2.purse_fee_balance,
&rfb.purse_fee_balance))
|| (0 != TALER_amount_cmp (&rfb2.open_fee_balance,
&rfb.open_fee_balance))
|| (0 != TALER_amount_cmp (&rfb2.history_fee_balance,
&rfb.history_fee_balance))
);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_reserve_summary\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_reserve_info (plugin->cls, plugin->insert_reserve_summary (plugin->cls,
&reserve_pub, &master_pub,
&master_pub, &rfb));
&reserve_balance, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
&withdraw_fee_balance, "Test: update_reserve_summary\n");
past, FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
"payto://bla/blub")); plugin->update_reserve_summary (plugin->cls,
&master_pub,
&rfb));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_reserve_summary\n");
ZR_BLK (&rfb2);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_reserve_summary (plugin->cls,
&master_pub,
&rfb2));
FAILIF ( (0 != TALER_amount_cmp (&rfb2.reserve_balance,
&rfb.reserve_balance) ||
(0 != TALER_amount_cmp (&rfb2.withdraw_fee_balance,
&rfb.withdraw_fee_balance)) ||
(0 != TALER_amount_cmp (&rfb2.close_fee_balance,
&rfb.close_fee_balance)) ||
(0 != TALER_amount_cmp (&rfb2.purse_fee_balance,
&rfb.purse_fee_balance)) ||
(0 != TALER_amount_cmp (&rfb2.open_fee_balance,
&rfb.open_fee_balance)) ||
(0 != TALER_amount_cmp (&rfb2.history_fee_balance,
&rfb.history_fee_balance))));
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO, {
"Test: update_reserve_info\n"); GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_denomination_balance\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != struct TALER_AUDITORDB_DenominationCirculationData dcd;
plugin->update_reserve_info (plugin->cls, struct TALER_AUDITORDB_DenominationCirculationData dcd2;
&reserve_pub,
&master_pub,
&reserve_balance,
&withdraw_fee_balance,
future));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_assert (GNUNET_OK ==
"Test: get_reserve_info\n"); TALER_string_to_amount (CURRENCY ":12.345678",
&dcd.denom_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.1",
&dcd.denom_loss));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":13.57986",
&dcd.denom_risk));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":12.57986",
&dcd.recoup_loss));
dcd.num_issued = 62;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_denomination_balance (plugin->cls,
&denom_pub_hash,
&dcd));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_denomination_balance\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_denomination_balance (plugin->cls,
&denom_pub_hash,
&dcd));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_denomination_balance\n");
char *payto; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_denomination_balance (plugin->cls,
&denom_pub_hash,
&dcd2));
FAILIF (0 != TALER_amount_cmp (&dcd2.denom_balance,
&dcd.denom_balance));
FAILIF (0 != TALER_amount_cmp (&dcd2.denom_loss,
&dcd.denom_loss));
FAILIF (0 != TALER_amount_cmp (&dcd2.denom_risk,
&dcd.denom_risk));
FAILIF (0 != TALER_amount_cmp (&dcd2.recoup_loss,
&dcd.recoup_loss));
FAILIF (dcd2.num_issued != dcd.num_issued);
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != {
plugin->get_reserve_info (plugin->cls, struct TALER_AUDITORDB_GlobalCoinBalance gcb;
&reserve_pub, struct TALER_AUDITORDB_GlobalCoinBalance gcb2;
&master_pub,
&rowid,
&reserve_balance2,
&withdraw_fee_balance2,
&date,
&payto));
FAILIF (0 != strcmp (payto,
"payto://bla/blub"));
GNUNET_free (payto);
FAILIF (0 != GNUNET_memcmp (&date,
&future)
|| 0 != TALER_amount_cmp (&reserve_balance2,
&reserve_balance)
|| 0 != TALER_amount_cmp (&withdraw_fee_balance2,
&withdraw_fee_balance));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_assert (GNUNET_OK ==
"Test: insert_reserve_summary\n"); TALER_string_to_amount (CURRENCY ":12.345678",
&gcb.total_escrowed));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != GNUNET_assert (GNUNET_OK ==
plugin->insert_reserve_summary (plugin->cls, TALER_string_to_amount (CURRENCY ":23.456789",
&master_pub, &gcb.deposit_fee_balance));
&reserve_balance, GNUNET_assert (GNUNET_OK ==
&withdraw_fee_balance, TALER_string_to_amount (CURRENCY ":34.567890",
&purse_fee_balance, &gcb.melt_fee_balance));
&history_fee_balance)); GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":45.678901",
GNUNET_log (GNUNET_ERROR_TYPE_INFO, &gcb.refund_fee_balance));
"Test: update_reserve_summary\n"); GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":55.678901",
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != &gcb.purse_fee_balance));
plugin->update_reserve_summary (plugin->cls, GNUNET_assert (GNUNET_OK ==
&master_pub, TALER_string_to_amount (CURRENCY ":65.678901",
&reserve_balance, &gcb.open_deposit_fee_balance));
&withdraw_fee_balance, GNUNET_assert (GNUNET_OK ==
&purse_fee_balance, TALER_string_to_amount (CURRENCY ":13.57986",
&history_fee_balance)); &gcb.risk));
GNUNET_assert (GNUNET_OK ==
GNUNET_log (GNUNET_ERROR_TYPE_INFO, TALER_string_to_amount (CURRENCY ":0.1",
"Test: get_reserve_summary\n"); &gcb.loss));
GNUNET_assert (GNUNET_OK ==
ZR_BLK (&reserve_balance2); TALER_string_to_amount (CURRENCY ":1.1",
ZR_BLK (&withdraw_fee_balance2); &gcb.irregular_loss));
ZR_BLK (&purse_fee_balance2); GNUNET_log (GNUNET_ERROR_TYPE_INFO,
ZR_BLK (&history_fee_balance2); "Test: insert_balance_summary\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_reserve_summary (plugin->cls,
&master_pub,
&reserve_balance2,
&withdraw_fee_balance2,
&purse_fee_balance2,
&history_fee_balance2));
FAILIF ( (0 != TALER_amount_cmp (&reserve_balance2,
&reserve_balance) ||
(0 != TALER_amount_cmp (&withdraw_fee_balance2,
&withdraw_fee_balance)) ||
(0 != TALER_amount_cmp (&purse_fee_balance2,
&purse_fee_balance)) ||
(0 != TALER_amount_cmp (&history_fee_balance2,
&history_fee_balance))));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_denomination_balance\n");
struct TALER_Amount denom_balance;
struct TALER_Amount denom_loss;
struct TALER_Amount denom_loss2;
struct TALER_Amount deposit_fee_balance;
struct TALER_Amount melt_fee_balance;
struct TALER_Amount refund_fee_balance;
struct TALER_Amount denom_balance2;
struct TALER_Amount deposit_fee_balance2;
struct TALER_Amount melt_fee_balance2;
struct TALER_Amount refund_fee_balance2;
struct TALER_Amount rbalance;
struct TALER_Amount dbalance;
struct TALER_Amount rbalance2;
struct TALER_Amount dbalance2;
struct TALER_Amount loss;
struct TALER_Amount loss2;
struct TALER_Amount iirp;
struct TALER_Amount iirp2;
uint64_t nissued;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":12.345678",
&denom_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.1",
&denom_loss));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":23.456789",
&deposit_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":34.567890",
&melt_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":45.678901",
&refund_fee_balance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":13.57986",
&rbalance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":12.57986",
&dbalance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.6",
&loss));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.1",
&iirp));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_denomination_balance (plugin->cls,
&denom_pub_hash,
&denom_balance,
&denom_loss,
&rbalance,
&loss,
42));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_denomination_balance\n");
ppc.last_withdraw_serial_id++;
ppc.last_deposit_serial_id++;
ppc.last_melt_serial_id++;
ppc.last_refund_serial_id++;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_denomination_balance (plugin->cls,
&denom_pub_hash,
&denom_balance,
&denom_loss,
&rbalance,
&loss,
62));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_denomination_balance\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_denomination_balance (plugin->cls,
&denom_pub_hash,
&denom_balance2,
&denom_loss2,
&rbalance2,
&loss2,
&nissued));
FAILIF (0 != GNUNET_memcmp (&denom_balance2, &denom_balance));
FAILIF (0 != GNUNET_memcmp (&denom_loss2, &denom_loss));
FAILIF (0 != GNUNET_memcmp (&rbalance2, &rbalance));
FAILIF (62 != nissued);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_balance_summary\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_balance_summary (plugin->cls,
&master_pub,
&refund_fee_balance,
&melt_fee_balance,
&deposit_fee_balance,
&denom_balance,
&rbalance,
&loss,
&iirp));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_balance_summary\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_balance_summary (plugin->cls,
&master_pub,
&denom_balance,
&deposit_fee_balance,
&melt_fee_balance,
&refund_fee_balance,
&rbalance,
&loss,
&iirp));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_balance_summary\n");
ZR_BLK (&denom_balance2);
ZR_BLK (&deposit_fee_balance2);
ZR_BLK (&melt_fee_balance2);
ZR_BLK (&refund_fee_balance2);
ZR_BLK (&rbalance2);
ZR_BLK (&loss2);
ZR_BLK (&iirp2);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_balance_summary (plugin->cls,
&master_pub,
&denom_balance2,
&deposit_fee_balance2,
&melt_fee_balance2,
&refund_fee_balance2,
&rbalance2,
&loss2,
&iirp2));
FAILIF ( (0 != GNUNET_memcmp (&denom_balance2,
&denom_balance) ) ||
(0 != GNUNET_memcmp (&deposit_fee_balance2,
&deposit_fee_balance) ) ||
(0 != GNUNET_memcmp (&melt_fee_balance2,
&melt_fee_balance) ) ||
(0 != GNUNET_memcmp (&refund_fee_balance2,
&refund_fee_balance)) );
FAILIF (0 != GNUNET_memcmp (&rbalance2,
&rbalance));
FAILIF (0 != GNUNET_memcmp (&loss2,
&loss));
FAILIF (0 != GNUNET_memcmp (&iirp2,
&iirp));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_balance_summary (plugin->cls,
&master_pub,
&gcb));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_balance_summary\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_balance_summary (plugin->cls,
&master_pub,
&gcb));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_balance_summary\n");
ZR_BLK (&gcb2);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_balance_summary (plugin->cls,
&master_pub,
&gcb2));
FAILIF (0 != TALER_amount_cmp (&gcb2.total_escrowed,
&gcb.total_escrowed));
FAILIF (0 != TALER_amount_cmp (&gcb2.deposit_fee_balance,
&gcb.deposit_fee_balance) );
FAILIF (0 != TALER_amount_cmp (&gcb2.melt_fee_balance,
&gcb.melt_fee_balance) );
FAILIF (0 != TALER_amount_cmp (&gcb2.refund_fee_balance,
&gcb.refund_fee_balance));
FAILIF (0 != TALER_amount_cmp (&gcb2.purse_fee_balance,
&gcb.purse_fee_balance));
FAILIF (0 != TALER_amount_cmp (&gcb2.open_deposit_fee_balance,
&gcb.open_deposit_fee_balance));
FAILIF (0 != TALER_amount_cmp (&gcb2.risk,
&gcb.risk));
FAILIF (0 != TALER_amount_cmp (&gcb2.loss,
&gcb.loss));
FAILIF (0 != TALER_amount_cmp (&gcb2.irregular_loss,
&gcb.irregular_loss));
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_historic_denom_revenue\n"); "Test: insert_historic_denom_revenue\n");
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":12.345678",
&rbalance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":23.456789",
&rloss));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_historic_denom_revenue (plugin->cls, plugin->insert_historic_denom_revenue (plugin->cls,
&master_pub, &master_pub,
&denom_pub_hash, &denom_pub_hash,
past, past,
&rbalance, &rbalance,
&loss)); &rloss));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_historic_denom_revenue (plugin->cls, plugin->insert_historic_denom_revenue (plugin->cls,
&master_pub, &master_pub,
&rnd_hash, &rnd_hash,
now, now,
&rbalance, &rbalance,
&loss)); &rloss));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: select_historic_denom_revenue\n"); "Test: select_historic_denom_revenue\n");
int
select_historic_denom_revenue_result (
void *cls,
const struct TALER_DenominationHashP *denom_pub_hash2,
struct GNUNET_TIME_Timestamp revenue_timestamp2,
const struct TALER_Amount *revenue_balance2,
const struct TALER_Amount *loss2)
{
static int n = 0;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"select_historic_denom_revenue_result: row %u\n", n);
if ((2 <= n++)
|| (cls != NULL)
|| ((0 != GNUNET_memcmp (&revenue_timestamp2, &past))
&& (0 != GNUNET_memcmp (&revenue_timestamp2, &now)))
|| ((0 != GNUNET_memcmp (denom_pub_hash2, &denom_pub_hash))
&& (0 != GNUNET_memcmp (denom_pub_hash2, &rnd_hash)))
|| (0 != GNUNET_memcmp (revenue_balance2, &rbalance))
|| (0 != GNUNET_memcmp (loss2, &loss)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"select_historic_denom_revenue_result: result does not match\n");
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
FAILIF (0 >= FAILIF (0 >=
plugin->select_historic_denom_revenue (plugin->cls, plugin->select_historic_denom_revenue (
&master_pub, plugin->cls,
& &master_pub,
select_historic_denom_revenue_result, &select_historic_denom_revenue_result,
NULL)); NULL));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_historic_reserve_revenue\n"); "Test: insert_historic_reserve_revenue\n");
struct TALER_Amount reserve_profits;
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":56.789012", TALER_string_to_amount (CURRENCY ":56.789012",
&reserve_profits)); &reserve_profits));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_historic_reserve_revenue (plugin->cls, plugin->insert_historic_reserve_revenue (plugin->cls,
&master_pub, &master_pub,
past, past,
future, future,
&reserve_profits)); &reserve_profits));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_historic_reserve_revenue (plugin->cls, plugin->insert_historic_reserve_revenue (plugin->cls,
&master_pub, &master_pub,
now, now,
future, future,
&reserve_profits)); &reserve_profits));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: select_historic_reserve_revenue\n"); "Test: select_historic_reserve_revenue\n");
int
select_historic_reserve_revenue_result (
void *cls,
struct GNUNET_TIME_Timestamp start_time2,
struct GNUNET_TIME_Timestamp end_time2,
const struct TALER_Amount *reserve_profits2)
{
static int n = 0;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"select_historic_reserve_revenue_result: row %u\n", n);
if ((2 <= n++)
|| (cls != NULL)
|| ((0 != GNUNET_memcmp (&start_time2, &past))
&& (0 != GNUNET_memcmp (&start_time2, &now)))
|| (0 != GNUNET_memcmp (&end_time2, &future))
|| (0 != GNUNET_memcmp (reserve_profits2, &reserve_profits)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"select_historic_reserve_revenue_result: result does not match\n");
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
FAILIF (0 >= FAILIF (0 >=
plugin->select_historic_reserve_revenue (plugin->cls, plugin->select_historic_reserve_revenue (plugin->cls,
&master_pub, &master_pub,
select_historic_reserve_revenue_result, select_historic_reserve_revenue_result,
NULL)); NULL));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_predicted_result\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_predicted_result (plugin->cls,
&master_pub,
&rbalance,
&dbalance));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_predicted_result\n");
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":78.901234",
&rbalance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":73.901234",
&dbalance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_predicted_result (plugin->cls,
&master_pub,
&rbalance,
&dbalance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_wire_fee_summary (plugin->cls,
&master_pub,
&rbalance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_wire_fee_summary (plugin->cls,
&master_pub,
&reserve_profits));
{ {
struct TALER_Amount rprof; struct TALER_Amount dbalance;
struct TALER_Amount dbalance2;
struct TALER_Amount rbalance2;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":2.535678",
&dbalance));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: insert_predicted_result\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_predicted_result (plugin->cls,
&master_pub,
&rbalance,
&dbalance));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: update_predicted_result\n");
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":78.901234",
&rbalance));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":73.901234",
&dbalance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_predicted_result (plugin->cls,
&master_pub,
&rbalance,
&dbalance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_wire_fee_summary (plugin->cls,
&master_pub,
&rbalance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->update_wire_fee_summary (plugin->cls,
&master_pub,
&reserve_profits));
{
struct TALER_Amount rprof;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_wire_fee_summary (plugin->cls,
&master_pub,
&rprof));
FAILIF (0 !=
TALER_amount_cmp (&rprof,
&reserve_profits));
}
FAILIF (0 >
plugin->commit (plugin->cls));
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_predicted_balance\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_wire_fee_summary (plugin->cls, plugin->get_predicted_balance (plugin->cls,
&master_pub, &master_pub,
&rprof)); &rbalance2,
FAILIF (0 != &dbalance2));
TALER_amount_cmp (&rprof,
&reserve_profits)); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->del_reserve_info (plugin->cls,
&reserve_pub,
&master_pub));
FAILIF (0 != TALER_amount_cmp (&rbalance2,
&rbalance));
FAILIF (0 != TALER_amount_cmp (&dbalance2,
&dbalance));
plugin->rollback (plugin->cls);
} }
FAILIF (0 >
plugin->commit (plugin->cls));
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Test: get_predicted_balance\n");
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_predicted_balance (plugin->cls,
&master_pub,
&rbalance2,
&dbalance2));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->del_reserve_info (plugin->cls,
&reserve_pub,
&master_pub));
FAILIF (0 != TALER_amount_cmp (&rbalance2,
&rbalance));
FAILIF (0 != TALER_amount_cmp (&dbalance2,
&dbalance));
plugin->rollback (plugin->cls);
#if GC_IMPLEMENTED #if GC_IMPLEMENTED
FAILIF (GNUNET_OK != FAILIF (GNUNET_OK !=

View File

@ -204,6 +204,8 @@ commit_or_warn (void)
* @param account_payto_uri information about the bank account that initially * @param account_payto_uri information about the bank account that initially
* caused the reserve to be created * caused the reserve to be created
* @param expiration_date when did the reserve expire * @param expiration_date when did the reserve expire
* @param close_request_row row of request asking for
* closure, 0 for expired reserves
* @return #GNUNET_OK on success (continue) * @return #GNUNET_OK on success (continue)
* #GNUNET_NO on non-fatal errors (try again) * #GNUNET_NO on non-fatal errors (try again)
* #GNUNET_SYSERR on fatal errors (abort) * #GNUNET_SYSERR on fatal errors (abort)
@ -213,7 +215,8 @@ expired_reserve_cb (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *left, const struct TALER_Amount *left,
const char *account_payto_uri, const char *account_payto_uri,
struct GNUNET_TIME_Timestamp expiration_date) struct GNUNET_TIME_Timestamp expiration_date,
uint64_t close_request_row)
{ {
struct GNUNET_TIME_Timestamp now; struct GNUNET_TIME_Timestamp now;
struct TALER_WireTransferIdentifierRawP wtid; struct TALER_WireTransferIdentifierRawP wtid;
@ -319,7 +322,8 @@ expired_reserve_cb (void *cls,
account_payto_uri, account_payto_uri,
&wtid, &wtid,
left, left,
&closing_fee); &closing_fee,
close_request_row);
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Closing reserve %s over %s (%d, %d)\n", "Closing reserve %s over %s (%d, %d)\n",
TALER_B2S (reserve_pub), TALER_B2S (reserve_pub),

View File

@ -231,6 +231,10 @@ create_transaction (void *cls,
} }
if (! balance_ok) if (! balance_ok)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Coin %s has insufficient balance for purse deposit of amount %s\n",
TALER_B2S (&coin->cpi.coin_pub),
TALER_amount2s (&coin->amount));
*mhd_ret *mhd_ret
= TEH_RESPONSE_reply_coin_insufficient_funds ( = TEH_RESPONSE_reply_coin_insufficient_funds (
connection, connection,

View File

@ -79,7 +79,9 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_iterate_reserve_close_info.c pg_iterate_reserve_close_info.h \ pg_iterate_reserve_close_info.c pg_iterate_reserve_close_info.h \
pg_lookup_records_by_table.c pg_lookup_records_by_table.h \ pg_lookup_records_by_table.c pg_lookup_records_by_table.h \
pg_lookup_serial_by_table.c pg_lookup_serial_by_table.h \ pg_lookup_serial_by_table.c pg_lookup_serial_by_table.h \
pg_select_reserve_close_info.c pg_select_reserve_close_info.h pg_select_reserve_close_info.c pg_select_reserve_close_info.h \
pg_select_reserve_closed_above_serial_id.c pg_select_reserve_closed_above_serial_id.h \
pg_select_reserve_open_above_serial_id.c pg_select_reserve_open_above_serial_id.h
libtaler_plugin_exchangedb_postgres_la_LIBADD = \ libtaler_plugin_exchangedb_postgres_la_LIBADD = \
$(LTLIBINTL) $(LTLIBINTL)
libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \ libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \

View File

@ -8,3 +8,7 @@ CONFIG = postgres:///talercheck
# Where are the SQL files to setup our tables? # Where are the SQL files to setup our tables?
# Important: this MUST end with a "/"! # Important: this MUST end with a "/"!
SQL_DIR = $DATADIR/sql/exchange/ SQL_DIR = $DATADIR/sql/exchange/
[exchangedb]
# Number of purses per account by default.
DEFAULT_PURSE_LIMIT = 1

View File

@ -346,6 +346,7 @@ BEGIN
',amount_frac INT4 NOT NULL' ',amount_frac INT4 NOT NULL'
',closing_fee_val INT8 NOT NULL' ',closing_fee_val INT8 NOT NULL'
',closing_fee_frac INT4 NOT NULL' ',closing_fee_frac INT4 NOT NULL'
',close_request_row INT8 NOT NULL DEFAULT(0)'
') %s ;' ') %s ;'
,table_name ,table_name
,'PARTITION BY HASH (reserve_pub)' ,'PARTITION BY HASH (reserve_pub)'
@ -383,6 +384,79 @@ END
$$; $$;
--------------------------- close_requests ---------------------------
CREATE OR REPLACE FUNCTION create_table_close_requests(
IN shard_suffix VARCHAR DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'close_requests';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I '
'(close_request_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' --UNIQUE'
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)' -- REFERENCES reserves(reserve_pub) ON DELETE CASCADE
',close_timestamp INT8 NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
',close_val INT8 NOT NULL'
',close_frac INT4 NOT NULL'
',close_fee_val INT8 NOT NULL'
',close_fee_frac INT4 NOT NULL'
',payto_uri VARCHAR NOT NULL'
',done BOOL NOT NULL DEFAULT(FALSE)'
',PRIMARY KEY (reserve_pub,close_timestamp)'
') %s ;'
,table_name
,'PARTITION BY HASH (reserve_pub)'
,shard_suffix
);
END
$$;
CREATE OR REPLACE FUNCTION add_constraints_to_close_requests(
IN partition_suffix VARCHAR
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'close_requests';
BEGIN
EXECUTE FORMAT (
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_uuid_index '
'ON ' || table_name || ' '
'(close_request_serial_id);'
);
EXECUTE FORMAT (
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_done_index '
'ON ' || table_name || ' '
'(done);'
);
END
$$;
CREATE OR REPLACE FUNCTION add_constraints_to_close_requests_partition(
IN partition_suffix VARCHAR
)
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE FORMAT (
'ALTER TABLE close_requests_' || partition_suffix || ' '
'ADD CONSTRAINT close_requests_' || partition_suffix || '_close_request_uuid_pkey '
'UNIQUE (close_request_serial_id)'
);
END
$$;
--------------------------- reserves_open_requests ------------------------------- --------------------------- reserves_open_requests -------------------------------
CREATE OR REPLACE FUNCTION create_table_reserves_open_requests( CREATE OR REPLACE FUNCTION create_table_reserves_open_requests(
@ -1391,8 +1465,6 @@ BEGIN
',h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)' ',h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)'
',age_limit INT4 NOT NULL' ',age_limit INT4 NOT NULL'
',flags INT4 NOT NULL' ',flags INT4 NOT NULL'
',refunded BOOLEAN NOT NULL DEFAULT(FALSE)'
',finished BOOLEAN NOT NULL DEFAULT(FALSE)'
',in_reserve_quota BOOLEAN NOT NULL DEFAULT(FALSE)' ',in_reserve_quota BOOLEAN NOT NULL DEFAULT(FALSE)'
',amount_with_fee_val INT8 NOT NULL' ',amount_with_fee_val INT8 NOT NULL'
',amount_with_fee_frac INT4 NOT NULL' ',amount_with_fee_frac INT4 NOT NULL'
@ -1444,53 +1516,6 @@ END
$$; $$;
------------------------------- purse_refunds ----------------------------------------
CREATE OR REPLACE FUNCTION create_table_purse_refunds(
IN shard_suffix VARCHAR DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'purse_refunds';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I '
'(purse_refunds_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' --UNIQUE
',purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32)'
',PRIMARY KEY (purse_pub)'
') %s ;'
,table_name
,'PARTITION BY HASH (purse_pub)'
,shard_suffix
);
table_name = concat_ws('_', table_name, shard_suffix);
END
$$;
CREATE OR REPLACE FUNCTION add_constraints_to_purse_refunds_partition(
IN partition_suffix VARCHAR
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE FORMAT (
'ALTER TABLE purse_refunds_' || partition_suffix || ' '
'ADD CONSTRAINT purse_refunds_' || partition_suffix || '_purse_refunds_serial_id_key '
'UNIQUE (purse_refunds_serial_id) '
);
END
$$;
---------------------------- purse_merges ----------------------------- ---------------------------- purse_merges -----------------------------
CREATE OR REPLACE FUNCTION create_table_purse_merges( CREATE OR REPLACE FUNCTION create_table_purse_merges(
@ -1602,6 +1627,53 @@ BEGIN
END END
$$; $$;
------------------------------- purse_decision ----------------------------------------
CREATE OR REPLACE FUNCTION create_table_purse_decision(
IN shard_suffix VARCHAR DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'purse_decision';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I '
'(purse_decision_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' --UNIQUE
',purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32)'
',action_timestamp INT8 NOT NULL'
',refunded BOOL NOT NULL'
',PRIMARY KEY (purse_pub)'
') %s ;'
,table_name
,'PARTITION BY HASH (purse_pub)'
,shard_suffix
);
table_name = concat_ws('_', table_name, shard_suffix);
END
$$;
CREATE OR REPLACE FUNCTION add_constraints_to_purse_decision_partition(
IN partition_suffix VARCHAR
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE FORMAT (
'ALTER TABLE purse_decision_' || partition_suffix || ' '
'ADD CONSTRAINT purse_decision_' || partition_suffix || '_purse_action_serial_id_key '
'UNIQUE (purse_decision_serial_id) '
);
END
$$;
------------------------- contracts ------------------------------- ------------------------- contracts -------------------------------
CREATE OR REPLACE FUNCTION create_table_contracts( CREATE OR REPLACE FUNCTION create_table_contracts(
@ -1678,80 +1750,6 @@ BEGIN
END END
$$; $$;
--------------------------- close_requests ---------------------------
CREATE OR REPLACE FUNCTION create_table_close_requests(
IN shard_suffix VARCHAR DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'close_requests';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I '
'(close_request_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' --UNIQUE'
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)' -- REFERENCES reserves(reserve_pub) ON DELETE CASCADE
',close_timestamp INT8 NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
',close_val INT8 NOT NULL'
',close_frac INT4 NOT NULL'
',close_fee_val INT8 NOT NULL'
',close_fee_frac INT4 NOT NULL'
',payto_uri VARCHAR NOT NULL'
',done BOOL NOT NULL DEFAULT(FALSE)'
',PRIMARY KEY (reserve_pub,close_timestamp)'
') %s ;'
,table_name
,'PARTITION BY HASH (reserve_pub)'
,shard_suffix
);
END
$$;
CREATE OR REPLACE FUNCTION add_constraints_to_close_requests(
IN partition_suffix VARCHAR
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'close_requests';
BEGIN
EXECUTE FORMAT (
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_uuid_index '
'ON ' || table_name || ' '
'(close_request_serial_id);'
);
EXECUTE FORMAT (
'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_close_request_done_index '
'ON ' || table_name || ' '
'(done);'
);
END
$$;
CREATE OR REPLACE FUNCTION add_constraints_to_close_requests_partition(
IN partition_suffix VARCHAR
)
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE FORMAT (
'ALTER TABLE close_requests_' || partition_suffix || ' '
'ADD CONSTRAINT close_requests_' || partition_suffix || '_close_request_uuid_pkey '
'UNIQUE (close_request_serial_id)'
);
END
$$;
------------------------------- purse_deposits ------------------------------- ------------------------------- purse_deposits -------------------------------
CREATE OR REPLACE FUNCTION create_table_purse_deposits( CREATE OR REPLACE FUNCTION create_table_purse_deposits(
@ -2087,6 +2085,15 @@ BEGIN
ALTER TABLE IF EXISTS reserves_close ALTER TABLE IF EXISTS reserves_close
DETACH PARTITION reserves_close_default; DETACH PARTITION reserves_close_default;
ALTER TABLE IF EXISTS history_requests
DETACH partition history_requests_default;
ALTER TABLE IF EXISTS close_requests
DETACH partition close_requests_default;
ALTER TABLE IF EXISTS reserves_open_requests
DETACH partition reserves_open_requests_default;
ALTER TABLE IF EXISTS reserves_out ALTER TABLE IF EXISTS reserves_out
DETACH PARTITION reserves_out_default; DETACH PARTITION reserves_out_default;
@ -2145,8 +2152,8 @@ BEGIN
ALTER TABLE IF EXISTS purse_requests ALTER TABLE IF EXISTS purse_requests
DETACH partition purse_requests_default; DETACH partition purse_requests_default;
ALTER TABLE IF EXISTS purse_refunds ALTER TABLE IF EXISTS purse_decision
DETACH partition purse_refunds_default; DETACH partition purse_decision_default;
ALTER TABLE IF EXISTS purse_merges ALTER TABLE IF EXISTS purse_merges
DETACH partition purse_merges_default; DETACH partition purse_merges_default;
@ -2157,12 +2164,6 @@ BEGIN
ALTER TABLE IF EXISTS contracts ALTER TABLE IF EXISTS contracts
DETACH partition contracts_default; DETACH partition contracts_default;
ALTER TABLE IF EXISTS history_requests
DETACH partition history_requests_default;
ALTER TABLE IF EXISTS close_requests
DETACH partition close_requests_default;
ALTER TABLE IF EXISTS purse_deposits ALTER TABLE IF EXISTS purse_deposits
DETACH partition purse_deposits_default; DETACH partition purse_deposits_default;
@ -2194,6 +2195,10 @@ BEGIN
DROP TABLE IF EXISTS reserves_default; DROP TABLE IF EXISTS reserves_default;
DROP TABLE IF EXISTS reserves_in_default; DROP TABLE IF EXISTS reserves_in_default;
DROP TABLE IF EXISTS reserves_close_default; DROP TABLE IF EXISTS reserves_close_default;
DROP TABLE IF EXISTS reserves_open_requests_default;
DROP TABLE IF EXISTS history_requests_default;
DROP TABLE IF EXISTS close_requests_default;
DROP TABLE IF EXISTS reserves_out_default; DROP TABLE IF EXISTS reserves_out_default;
DROP TABLE IF EXISTS reserves_out_by_reserve_default; DROP TABLE IF EXISTS reserves_out_by_reserve_default;
DROP TABLE IF EXISTS known_coins_default; DROP TABLE IF EXISTS known_coins_default;
@ -2214,13 +2219,12 @@ BEGIN
DROP TABLE IF EXISTS cs_nonce_locks_default; DROP TABLE IF EXISTS cs_nonce_locks_default;
DROP TABLE IF EXISTS purse_requests_default; DROP TABLE IF EXISTS purse_requests_default;
DROP TABLE IF EXISTS purse_refunds_default; DROP TABLE IF EXISTS purse_decision_default;
DROP TABLE IF EXISTS purse_merges_default; DROP TABLE IF EXISTS purse_merges_default;
DROP TABLE IF EXISTS account_merges_default; DROP TABLE IF EXISTS account_merges_default;
DROP TABLE IF EXISTS contracts_default;
DROP TABLE IF EXISTS history_requests_default;
DROP TABLE IF EXISTS close_requests_default;
DROP TABLE IF EXISTS purse_deposits_default; DROP TABLE IF EXISTS purse_deposits_default;
DROP TABLE IF EXISTS contracts_default;
DROP TABLE IF EXISTS wad_out_entries_default; DROP TABLE IF EXISTS wad_out_entries_default;
DROP TABLE IF EXISTS wads_in_default; DROP TABLE IF EXISTS wads_in_default;
DROP TABLE IF EXISTS wad_in_entries_default; DROP TABLE IF EXISTS wad_in_entries_default;
@ -2417,6 +2421,27 @@ BEGIN
); );
PERFORM add_constraints_to_cs_nonce_locks_partition(num_partitions::varchar); PERFORM add_constraints_to_cs_nonce_locks_partition(num_partitions::varchar);
PERFORM create_hash_partition(
'close_requests'
,modulus
,num_partitions
);
PERFORM create_hash_partition(
'reserves_open_requests'
,modulus
,num_partitions
);
PERFORM add_constraints_to_reserves_open_request_partition(num_partitions::varchar);
PERFORM create_hash_partition(
'history_requests'
,modulus
,num_partitions
);
---------------- P2P ---------------------- ---------------- P2P ----------------------
PERFORM create_hash_partition( PERFORM create_hash_partition(
@ -2427,11 +2452,11 @@ BEGIN
PERFORM add_constraints_to_purse_requests_partition(num_partitions::varchar); PERFORM add_constraints_to_purse_requests_partition(num_partitions::varchar);
PERFORM create_hash_partition( PERFORM create_hash_partition(
'purse_refunds' 'purse_decision'
,modulus ,modulus
,num_partitions ,num_partitions
); );
PERFORM add_constraints_to_purse_refunds_partition(num_partitions::varchar); PERFORM add_constraints_to_purse_decision_partition(num_partitions::varchar);
PERFORM create_hash_partition( PERFORM create_hash_partition(
'purse_merges' 'purse_merges'
@ -2454,18 +2479,6 @@ BEGIN
); );
PERFORM add_constraints_to_contracts_partition(num_partitions::varchar); PERFORM add_constraints_to_contracts_partition(num_partitions::varchar);
PERFORM create_hash_partition(
'history_requests'
,modulus
,num_partitions
);
PERFORM create_hash_partition(
'close_requests'
,modulus
,num_partitions
);
PERFORM create_hash_partition( PERFORM create_hash_partition(
'purse_deposits' 'purse_deposits'
,modulus ,modulus
@ -2644,8 +2657,8 @@ BEGIN
DROP CONSTRAINT IF EXISTS purse_requests_pkey CASCADE DROP CONSTRAINT IF EXISTS purse_requests_pkey CASCADE
; ;
ALTER TABLE IF EXISTS purse_refunds ALTER TABLE IF EXISTS purse_decision
DROP CONSTRAINT IF EXISTS purse_refunds_pkey CASCADE DROP CONSTRAINT IF EXISTS purse_decision_pkey CASCADE
; ;
ALTER TABLE IF EXISTS purse_merges ALTER TABLE IF EXISTS purse_merges
@ -2781,6 +2794,27 @@ BEGIN
,current_shard_num ,current_shard_num
,local_user ,local_user
); );
PERFORM create_foreign_hash_partition(
'history_requests'
,total_num_shards
,shard_suffix
,current_shard_num
,local_user
);
PERFORM create_foreign_hash_partition(
'close_requests'
,total_num_shards
,shard_suffix
,current_shard_num
,local_user
);
PERFORM create_foreign_hash_partition(
'open_requests'
,total_num_shards
,shard_suffix
,current_shard_num
,local_user
);
PERFORM create_foreign_hash_partition( PERFORM create_foreign_hash_partition(
'known_coins' 'known_coins'
,total_num_shards ,total_num_shards
@ -2904,7 +2938,7 @@ BEGIN
,local_user ,local_user
); );
PERFORM create_foreign_hash_partition( PERFORM create_foreign_hash_partition(
'purse_refunds' 'purse_decision'
,total_num_shards ,total_num_shards
,shard_suffix ,shard_suffix
,current_shard_num ,current_shard_num
@ -2931,20 +2965,7 @@ BEGIN
,current_shard_num ,current_shard_num
,local_user ,local_user
); );
PERFORM create_foreign_hash_partition(
'history_requests'
,total_num_shards
,shard_suffix
,current_shard_num
,local_user
);
PERFORM create_foreign_hash_partition(
'close_requests'
,total_num_shards
,shard_suffix
,current_shard_num
,local_user
);
PERFORM create_foreign_hash_partition( PERFORM create_foreign_hash_partition(
'purse_deposits' 'purse_deposits'
,total_num_shards ,total_num_shards

View File

@ -1135,10 +1135,6 @@ COMMENT ON COLUMN purse_requests.h_contract_terms
IS 'Hash of the contract the parties are to agree to'; IS 'Hash of the contract the parties are to agree to';
COMMENT ON COLUMN purse_requests.flags COMMENT ON COLUMN purse_requests.flags
IS 'see the enum TALER_WalletAccountMergeFlags'; IS 'see the enum TALER_WalletAccountMergeFlags';
COMMENT ON COLUMN purse_requests.finished
IS 'set to TRUE once the purse has been merged (into reserve or wad) or the coins were refunded (transfer aborted)';
COMMENT ON COLUMN purse_requests.refunded
IS 'set to TRUE if the purse could not be merged and thus all deposited coins were refunded';
COMMENT ON COLUMN purse_requests.in_reserve_quota COMMENT ON COLUMN purse_requests.in_reserve_quota
IS 'set to TRUE if this purse currently counts against the number of free purses in the respective reserve'; IS 'set to TRUE if this purse currently counts against the number of free purses in the respective reserve';
COMMENT ON COLUMN purse_requests.amount_with_fee_val COMMENT ON COLUMN purse_requests.amount_with_fee_val
@ -1157,20 +1153,20 @@ CREATE TABLE IF NOT EXISTS purse_requests_default
SELECT add_constraints_to_purse_requests_partition('default'); SELECT add_constraints_to_purse_requests_partition('default');
-- ------------------------------ purse_refunds ---------------------------------------- -- ------------------------------ purse_decisions ----------------------------------------
SELECT create_table_purse_refunds(); SELECT create_table_purse_decision();
COMMENT ON TABLE purse_refunds COMMENT ON TABLE purse_decision
IS 'Purses that were refunded due to expiration'; IS 'Purses that were decided upon (refund or merge)';
COMMENT ON COLUMN purse_refunds.purse_pub COMMENT ON COLUMN purse_decision.purse_pub
IS 'Public key of the purse'; IS 'Public key of the purse';
CREATE TABLE IF NOT EXISTS purse_refunds_default CREATE TABLE IF NOT EXISTS purse_decision_default
PARTITION OF purse_refunds PARTITION OF purse_decision
FOR VALUES WITH (MODULUS 1, REMAINDER 0); FOR VALUES WITH (MODULUS 1, REMAINDER 0);
SELECT add_constraints_to_purse_refunds_partition('default'); SELECT add_constraints_to_purse_decision_partition('default');
-- ------------------------------ purse_merges ---------------------------------------- -- ------------------------------ purse_merges ----------------------------------------
@ -1462,7 +1458,6 @@ CREATE OR REPLACE FUNCTION purse_requests_insert_trigger()
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
BEGIN BEGIN
ASSERT NOT NEW.finished,'Internal invariant violated';
INSERT INTO INSERT INTO
purse_actions purse_actions
(purse_pub (purse_pub
@ -1482,45 +1477,3 @@ CREATE TRIGGER purse_requests_on_insert
COMMENT ON TRIGGER purse_requests_on_insert COMMENT ON TRIGGER purse_requests_on_insert
ON purse_requests ON purse_requests
IS 'Here we install an entry for the purse expiration.'; IS 'Here we install an entry for the purse expiration.';
CREATE OR REPLACE FUNCTION purse_requests_on_update_trigger()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF (NEW.finished AND NOT OLD.finished)
THEN
-- If this purse counted against the reserve's
-- quota of purses, decrement the reserve accounting.
IF (NEW.in_reserve_quota)
THEN
UPDATE reserves
SET purses_active=purses_active-1
WHERE reserve_pub IN
(SELECT reserve_pub
FROM exchange.purse_merges
WHERE purse_pub=NEW.purse_pub
LIMIT 1);
NEW.in_reserve_quota=FALSE;
END IF;
-- Delete from the purse_actions table, we are done
-- with this purse for good.
DELETE FROM exchange.purse_actions
WHERE purse_pub=NEW.purse_pub;
RETURN NEW;
END IF;
RETURN NEW;
END $$;
COMMENT ON FUNCTION purse_requests_on_update_trigger()
IS 'Trigger the router if the purse is ready. Also removes the entry from the router watchlist once the purse is finished.';
CREATE TRIGGER purse_requests_on_update
BEFORE UPDATE
ON purse_requests
FOR EACH ROW EXECUTE FUNCTION purse_requests_on_update_trigger();
COMMENT ON TRIGGER purse_requests_on_update
ON purse_requests
IS 'This covers the case where a deposit is made into a purse, which inherently then changes the purse balance via an UPDATE. If the merge is already present and the balance matches the total, we trigger the router. Once the router sets the purse to finished, the trigger will remove the purse from the watchlist of the router.';

View File

@ -4,3 +4,6 @@ CONFIG = "postgres:///taler"
# Where are the SQL files to setup our tables? # Where are the SQL files to setup our tables?
# Important: this MUST end with a "/"! # Important: this MUST end with a "/"!
SQL_DIR = $DATADIR/sql/exchange/ SQL_DIR = $DATADIR/sql/exchange/
# Number of purses per account by default.
DEFAULT_PURSE_LIMIT = 1

View File

@ -169,6 +169,7 @@ add_coin_purse_deposit (void *cls,
chc->have_deposit_or_melt = true; chc->have_deposit_or_melt = true;
deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry); deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry);
{ {
bool not_finished;
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&deposit->amount), &deposit->amount),
@ -186,8 +187,10 @@ add_coin_purse_deposit (void *cls,
&deposit->coin_sig), &deposit->coin_sig),
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash", GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
&deposit->h_age_commitment), &deposit->h_age_commitment),
GNUNET_PQ_result_spec_bool ("refunded", GNUNET_PQ_result_spec_allow_null (
&deposit->refunded), GNUNET_PQ_result_spec_bool ("refunded",
&deposit->refunded),
&not_finished),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
@ -201,6 +204,8 @@ add_coin_purse_deposit (void *cls,
chc->failed = true; chc->failed = true;
return; return;
} }
if (not_finished)
deposit->refunded = false;
deposit->no_age_commitment = GNUNET_is_zero (&deposit->h_age_commitment); deposit->no_age_commitment = GNUNET_is_zero (&deposit->h_age_commitment);
} }
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
@ -352,9 +357,9 @@ add_coin_refund (void *cls,
* @param num_results the number of results in @a result * @param num_results the number of results in @a result
*/ */
static void static void
add_coin_purse_refund (void *cls, add_coin_purse_decision (void *cls,
PGresult *result, PGresult *result,
unsigned int num_results) unsigned int num_results)
{ {
struct CoinHistoryContext *chc = cls; struct CoinHistoryContext *chc = cls;
struct PostgresClosure *pg = chc->pg; struct PostgresClosure *pg = chc->pg;
@ -374,7 +379,7 @@ add_coin_purse_refund (void *cls,
&prefund->refund_amount), &prefund->refund_amount),
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund", TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
&prefund->refund_fee), &prefund->refund_fee),
GNUNET_PQ_result_spec_uint64 ("purse_refunds_serial_id", GNUNET_PQ_result_spec_uint64 ("purse_decision_serial_id",
&serial_id), &serial_id),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
@ -687,8 +692,8 @@ TEH_PG_get_coin_transactions (
{ "get_purse_deposit_by_coin_pub", { "get_purse_deposit_by_coin_pub",
&add_coin_purse_deposit }, &add_coin_purse_deposit },
/** #TALER_EXCHANGEDB_TT_PURSE_REFUND */ /** #TALER_EXCHANGEDB_TT_PURSE_REFUND */
{ "get_purse_refund_by_coin_pub", { "get_purse_decision_by_coin_pub",
&add_coin_purse_refund }, &add_coin_purse_decision },
/** #TALER_EXCHANGEDB_TT_REFUND */ /** #TALER_EXCHANGEDB_TT_REFUND */
{ "get_refunds_by_coin", { "get_refunds_by_coin",
&add_coin_refund }, &add_coin_refund },
@ -775,12 +780,14 @@ TEH_PG_get_coin_transactions (
",kc.age_commitment_hash" ",kc.age_commitment_hash"
",pd.coin_sig" ",pd.coin_sig"
",pd.purse_deposit_serial_id" ",pd.purse_deposit_serial_id"
",pr.refunded" ",pdes.refunded"
" FROM purse_deposits pd" " FROM purse_deposits pd"
" LEFT JOIN partners" " LEFT JOIN partners"
" USING (partner_serial_id)" " USING (partner_serial_id)"
" JOIN purse_requests pr" " JOIN purse_requests pr"
" USING (purse_pub)" " USING (purse_pub)"
" LEFT JOIN purse_decision pdes"
" USING (purse_pub)"
" JOIN known_coins kc" " JOIN known_coins kc"
" ON (pd.coin_pub = kc.coin_pub)" " ON (pd.coin_pub = kc.coin_pub)"
" JOIN denominations denoms" " JOIN denominations denoms"
@ -809,22 +816,23 @@ TEH_PG_get_coin_transactions (
" USING (denominations_serial)" " USING (denominations_serial)"
" WHERE ref.coin_pub=$1;"); " WHERE ref.coin_pub=$1;");
PREPARE (pg, PREPARE (pg,
"get_purse_refund_by_coin_pub", "get_purse_decision_by_coin_pub",
"SELECT" "SELECT"
" pr.purse_pub" " pdes.purse_pub"
",pd.amount_with_fee_val" ",pd.amount_with_fee_val"
",pd.amount_with_fee_frac" ",pd.amount_with_fee_frac"
",denom.fee_refund_val " ",denom.fee_refund_val "
",denom.fee_refund_frac " ",denom.fee_refund_frac "
",pr.purse_refunds_serial_id" ",pdes.purse_decision_serial_id"
" FROM purse_deposits pd" " FROM purse_deposits pd"
" JOIN purse_refunds pr" " JOIN purse_decision pdes"
" USING (purse_pub)" " USING (purse_pub)"
" JOIN known_coins kc" " JOIN known_coins kc"
" ON (pd.coin_pub = kc.coin_pub)" " ON (pd.coin_pub = kc.coin_pub)"
" JOIN denominations denom" " JOIN denominations denom"
" USING (denominations_serial)" " USING (denominations_serial)"
" WHERE pd.coin_pub=$1;"); " WHERE pd.coin_pub=$1"
" AND pdes.refunded;");
PREPARE (pg, PREPARE (pg,
"recoup_by_old_coin", "recoup_by_old_coin",
"SELECT" "SELECT"

View File

@ -102,7 +102,8 @@ reserve_expired_cb (void *cls,
&reserve_pub, &reserve_pub,
&remaining_balance, &remaining_balance,
account_details, account_details,
exp_date); exp_date,
0);
GNUNET_PQ_cleanup_result (rs); GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret) if (GNUNET_OK != ret)
break; break;

View File

@ -797,13 +797,14 @@ TEH_PG_get_reserve_history (void *cls,
" FROM purse_merges pm" " FROM purse_merges pm"
" JOIN purse_requests pr" " JOIN purse_requests pr"
" USING (purse_pub)" " USING (purse_pub)"
" JOIN purse_decision pdes"
" USING (purse_pub)"
" JOIN account_merges am" " JOIN account_merges am"
" ON (am.purse_pub = pm.purse_pub AND" " ON (am.purse_pub = pm.purse_pub AND"
" am.reserve_pub = pm.reserve_pub)" " am.reserve_pub = pm.reserve_pub)"
" WHERE pm.reserve_pub=$1" " WHERE pm.reserve_pub=$1"
" AND pm.partner_serial_id=0" /* must be local! */ " AND pm.partner_serial_id=0" /* must be local! */
" AND pr.finished" " AND NOT pdes.refunded;");
" AND NOT pr.refunded;");
PREPARE (pg, PREPARE (pg,
"history_by_reserve", "history_by_reserve",
"SELECT" "SELECT"
@ -1089,14 +1090,15 @@ TEH_PG_get_reserve_status (void *cls,
" FROM purse_merges pm" " FROM purse_merges pm"
" JOIN purse_requests pr" " JOIN purse_requests pr"
" USING (purse_pub)" " USING (purse_pub)"
" JOIN purse_decision pdes"
" USING (purse_pub)"
" JOIN account_merges am" " JOIN account_merges am"
" ON (am.purse_pub = pm.purse_pub AND" " ON (am.purse_pub = pm.purse_pub AND"
" am.reserve_pub = pm.reserve_pub)" " am.reserve_pub = pm.reserve_pub)"
" WHERE pm.reserve_pub=$1" " WHERE pm.reserve_pub=$1"
" AND pm.merge_timestamp >= $2" " AND pm.merge_timestamp >= $2"
" AND pm.partner_serial_id=0" /* must be local! */ " AND pm.partner_serial_id=0" /* must be local! */
" AND pr.finished" " AND NOT pdes.refunded;");
" AND NOT pr.refunded;");
PREPARE (pg, PREPARE (pg,
"history_by_reserve_truncated", "history_by_reserve_truncated",
"SELECT" "SELECT"

View File

@ -77,6 +77,7 @@ reserve_cb (void *cls,
char *account_details; char *account_details;
struct TALER_ReservePublicKeyP reserve_pub; struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_Amount remaining_balance; struct TALER_Amount remaining_balance;
uint64_t close_request_row;
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_timestamp ("expiration_date", GNUNET_PQ_result_spec_timestamp ("expiration_date",
&exp_date), &exp_date),
@ -86,6 +87,8 @@ reserve_cb (void *cls,
&reserve_pub), &reserve_pub),
TALER_PQ_RESULT_SPEC_AMOUNT ("close", TALER_PQ_RESULT_SPEC_AMOUNT ("close",
&remaining_balance), &remaining_balance),
GNUNET_PQ_result_spec_uint64 ("close_request_serial_id",
&close_request_row),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
@ -102,7 +105,8 @@ reserve_cb (void *cls,
&reserve_pub, &reserve_pub,
&remaining_balance, &remaining_balance,
account_details, account_details,
exp_date); exp_date,
close_request_row);
GNUNET_PQ_cleanup_result (rs); GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret) if (GNUNET_OK != ret)
break; break;
@ -136,6 +140,7 @@ TEH_PG_get_unfinished_close_requests (
" WHERE done=FALSE" " WHERE done=FALSE"
" RETURNING" " RETURNING"
" reserve_pub" " reserve_pub"
" ,close_request_serial_id"
" ,close_timestamp AS expiration_date" " ,close_timestamp AS expiration_date"
" ,close_val" " ,close_val"
" ,close_frac" " ,close_frac"

View File

@ -1336,19 +1336,23 @@ irbt_cb_table_purse_requests (struct PostgresClosure *pg,
/** /**
* Function called with purse_refunds records to insert into table. * Function called with purse_decision records to insert into table.
* *
* @param pg plugin context * @param pg plugin context
* @param td record to insert * @param td record to insert
*/ */
static enum GNUNET_DB_QueryStatus static enum GNUNET_DB_QueryStatus
irbt_cb_table_purse_refunds (struct PostgresClosure *pg, irbt_cb_table_purse_decision (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_TableData *td) const struct TALER_EXCHANGEDB_TableData *td)
{ {
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial), GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type ( GNUNET_PQ_query_param_auto_from_type (
&td->details.purse_refunds.purse_pub), &td->details.purse_decision.purse_pub),
GNUNET_PQ_query_param_timestamp (
&td->details.purse_decision.action_timestamp),
GNUNET_PQ_query_param_bool (
&td->details.purse_decision.refunded),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
@ -1357,10 +1361,12 @@ irbt_cb_table_purse_refunds (struct PostgresClosure *pg,
"INSERT INTO purse_refunds" "INSERT INTO purse_refunds"
"(purse_refunds_serial_id" "(purse_refunds_serial_id"
",purse_pub" ",purse_pub"
",action_timestamp"
",refunded"
") VALUES " ") VALUES "
"($1, $2);"); "($1, $2, $3, $4);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn, return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_purse_refunds", "insert_into_table_purse_decision",
params); params);
} }
@ -1910,8 +1916,8 @@ TEH_PG_insert_records_by_table (void *cls,
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS: case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
rh = &irbt_cb_table_purse_requests; rh = &irbt_cb_table_purse_requests;
break; break;
case TALER_EXCHANGEDB_RT_PURSE_REFUNDS: case TALER_EXCHANGEDB_RT_PURSE_DECISION:
rh = &irbt_cb_table_purse_refunds; rh = &irbt_cb_table_purse_decision;
break; break;
case TALER_EXCHANGEDB_RT_PURSE_MERGES: case TALER_EXCHANGEDB_RT_PURSE_MERGES:
rh = &irbt_cb_table_purse_merges; rh = &irbt_cb_table_purse_merges;

View File

@ -1575,20 +1575,20 @@ lrbt_cb_table_purse_requests (void *cls,
/** /**
* Function called with purse_refunds table entries. * Function called with purse_decision table entries.
* *
* @param cls closure * @param cls closure
* @param result the postgres result * @param result the postgres result
* @param num_results the number of results in @a result * @param num_results the number of results in @a result
*/ */
static void static void
lrbt_cb_table_purse_refunds (void *cls, lrbt_cb_table_purse_decision (void *cls,
PGresult *result, PGresult *result,
unsigned int num_results) unsigned int num_results)
{ {
struct LookupRecordsByTableContext *ctx = cls; struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = { struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_PURSE_REFUNDS .table = TALER_EXCHANGEDB_RT_PURSE_DECISION
}; };
for (unsigned int i = 0; i<num_results; i++) for (unsigned int i = 0; i<num_results; i++)
@ -1599,7 +1599,13 @@ lrbt_cb_table_purse_refunds (void *cls,
&td.serial), &td.serial),
GNUNET_PQ_result_spec_auto_from_type ( GNUNET_PQ_result_spec_auto_from_type (
"purse_pub", "purse_pub",
&td.details.purse_refunds.purse_pub), &td.details.purse_decision.purse_pub),
GNUNET_PQ_result_spec_timestamp (
"action_timestamp",
&td.details.purse_decision.action_timestamp),
GNUNET_PQ_result_spec_bool (
"refunded",
&td.details.purse_decision.refunded),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
@ -2639,15 +2645,17 @@ TEH_PG_lookup_records_by_table (void *cls,
" ORDER BY purse_requests_serial_id ASC;"); " ORDER BY purse_requests_serial_id ASC;");
rh = &lrbt_cb_table_purse_requests; rh = &lrbt_cb_table_purse_requests;
break; break;
case TALER_EXCHANGEDB_RT_PURSE_REFUNDS: case TALER_EXCHANGEDB_RT_PURSE_DECISION:
XPREPARE ("select_above_serial_by_table_purse_refunds", XPREPARE ("select_above_serial_by_table_purse_decision",
"SELECT" "SELECT"
" purse_refunds_serial_id" " purse_decision_serial_id"
",action_timestamp"
",refunded"
",purse_pub" ",purse_pub"
" FROM purse_refunds" " FROM purse_decision"
" WHERE purse_refunds_serial_id > $1" " WHERE purse_decision_serial_id > $1"
" ORDER BY purse_refunds_serial_id ASC;"); " ORDER BY purse_decision_serial_id ASC;");
rh = &lrbt_cb_table_purse_refunds; rh = &lrbt_cb_table_purse_decision;
break; break;
case TALER_EXCHANGEDB_RT_PURSE_MERGES: case TALER_EXCHANGEDB_RT_PURSE_MERGES:
XPREPARE ("select_above_serial_by_table_purse_merges", XPREPARE ("select_above_serial_by_table_purse_merges",

View File

@ -293,12 +293,12 @@ TEH_PG_lookup_serial_by_table (void *cls,
" ORDER BY purse_requests_serial_id DESC" " ORDER BY purse_requests_serial_id DESC"
" LIMIT 1;") " LIMIT 1;")
break; break;
case TALER_EXCHANGEDB_RT_PURSE_REFUNDS: case TALER_EXCHANGEDB_RT_PURSE_DECISION:
XPREPARE ("select_serial_by_table_purse_refunds", XPREPARE ("select_serial_by_table_purse_decision",
"SELECT" "SELECT"
" purse_refunds_serial_id AS serial" " purse_decision_serial_id AS serial"
" FROM purse_refunds" " FROM purse_decision"
" ORDER BY purse_refunds_serial_id DESC" " ORDER BY purse_decision_serial_id DESC"
" LIMIT 1;"); " LIMIT 1;");
break; break;
case TALER_EXCHANGEDB_RT_PURSE_MERGES: case TALER_EXCHANGEDB_RT_PURSE_MERGES:

View File

@ -0,0 +1,180 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pg_select_reserve_closed_above_serial_id.c
* @brief Low-level (statement-level) Postgres database access for the exchange
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_get_reserve_history.h"
#include "plugin_exchangedb_common.h"
#include "pg_helper.h"
/**
* Closure for #reserve_closed_serial_helper_cb().
*/
struct ReserveClosedSerialContext
{
/**
* Callback to call.
*/
TALER_EXCHANGEDB_ReserveClosedCallback cb;
/**
* Closure for @e cb.
*/
void *cb_cls;
/**
* Plugin's 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 ReserveClosedSerialContext`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
reserve_closed_serial_helper_cb (void *cls,
PGresult *result,
unsigned int num_results)
{
struct ReserveClosedSerialContext *rcsc = cls;
struct PostgresClosure *pg = rcsc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
uint64_t rowid;
struct TALER_ReservePublicKeyP reserve_pub;
char *receiver_account;
struct TALER_WireTransferIdentifierRawP wtid;
struct TALER_Amount amount_with_fee;
struct TALER_Amount closing_fee;
struct GNUNET_TIME_Timestamp execution_date;
uint64_t close_request_row;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("close_uuid",
&rowid),
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
GNUNET_PQ_result_spec_timestamp ("execution_date",
&execution_date),
GNUNET_PQ_result_spec_auto_from_type ("wtid",
&wtid),
GNUNET_PQ_result_spec_string ("receiver_account",
&receiver_account),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
&amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
&closing_fee),
GNUNET_PQ_result_spec_uint64 ("close_request_row",
&close_request_row),
GNUNET_PQ_result_spec_end
};
enum GNUNET_GenericReturnValue ret;
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
rcsc->status = GNUNET_SYSERR;
return;
}
ret = rcsc->cb (rcsc->cb_cls,
rowid,
execution_date,
&amount_with_fee,
&closing_fee,
&reserve_pub,
receiver_account,
&wtid,
close_request_row);
GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret)
break;
}
}
enum GNUNET_DB_QueryStatus
TEH_PG_select_reserve_closed_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_ReserveClosedCallback 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 ReserveClosedSerialContext rcsc = {
.cb = cb,
.cb_cls = cb_cls,
.pg = pg,
.status = GNUNET_OK
};
enum GNUNET_DB_QueryStatus qs;
/* Used in #postgres_select_reserve_closed_above_serial_id() to
obtain information about closed reserves */
PREPARE (
pg,
"reserves_close_get_incr",
"SELECT"
" close_uuid"
",reserves.reserve_pub"
",execution_date"
",wtid"
",payto_uri AS receiver_account"
",amount_val"
",amount_frac"
",closing_fee_val"
",closing_fee_frac"
",close_request_row"
" FROM reserves_close"
" JOIN wire_targets"
" USING (wire_target_h_payto)"
" JOIN reserves"
" USING (reserve_pub)"
" WHERE close_uuid>=$1"
" ORDER BY close_uuid ASC;");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"reserves_close_get_incr",
params,
&reserve_closed_serial_helper_cb,
&rcsc);
if (GNUNET_OK != rcsc.status)
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
}

View File

@ -0,0 +1,47 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pg_select_reserve_closed_above_serial_id.h
* @brief implementation of the select_reserve_closed_above_serial_id function
* @author Christian Grothoff
*/
#ifndef PG_SELECT_RESERVE_CLOSED_ABOVE_SERIAL_ID_H
#define PG_SELECT_RESERVE_CLOSED_ABOVE_SERIAL_ID_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
* Function called to select reserve close operations the aggregator
* triggered, ordered by serial ID (monotonically increasing).
*
* @param cls closure
* @param serial_id lowest serial ID to include (select larger or equal)
* @param cb function to call for ONE unfinished item
* @param cb_cls closure for @a cb
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
TEH_PG_select_reserve_closed_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_ReserveClosedCallback cb,
void *cb_cls);
#endif

View File

@ -0,0 +1,169 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pg_select_reserve_open_above_serial_id.c
* @brief Low-level (statement-level) Postgres database access for the exchange
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_select_reserve_open_above_serial_id.h"
#include "plugin_exchangedb_common.h"
#include "pg_helper.h"
/**
* Closure for #reserve_open_serial_helper_cb().
*/
struct ReserveOpenSerialContext
{
/**
* Callback to call.
*/
TALER_EXCHANGEDB_ReserveOpenCallback cb;
/**
* Closure for @e cb.
*/
void *cb_cls;
/**
* Plugin's 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 ReserveOpenSerialContext`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
reserve_open_serial_helper_cb (void *cls,
PGresult *result,
unsigned int num_results)
{
struct ReserveOpenSerialContext *rcsc = cls;
struct PostgresClosure *pg = rcsc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
uint64_t rowid;
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_ReserveSignatureP reserve_sig;
uint32_t requested_purse_limit;
struct GNUNET_TIME_Timestamp request_timestamp;
struct GNUNET_TIME_Timestamp reserve_expiration;
struct TALER_Amount reserve_payment;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("open_request_uuid",
&rowid),
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
&reserve_sig),
GNUNET_PQ_result_spec_timestamp ("request_timestamp",
&request_timestamp),
GNUNET_PQ_result_spec_timestamp ("expiration_date",
&reserve_expiration),
GNUNET_PQ_result_spec_uint32 ("requested_purse_limit",
&requested_purse_limit),
TALER_PQ_RESULT_SPEC_AMOUNT ("reserve_payment",
&reserve_payment),
GNUNET_PQ_result_spec_end
};
enum GNUNET_GenericReturnValue ret;
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
rcsc->status = GNUNET_SYSERR;
return;
}
ret = rcsc->cb (rcsc->cb_cls,
rowid,
&reserve_payment,
request_timestamp,
reserve_expiration,
requested_purse_limit,
&reserve_pub,
&reserve_sig);
GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret)
break;
}
}
enum GNUNET_DB_QueryStatus
TEH_PG_select_reserve_open_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_ReserveOpenCallback 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 ReserveOpenSerialContext rcsc = {
.cb = cb,
.cb_cls = cb_cls,
.pg = pg,
.status = GNUNET_OK
};
enum GNUNET_DB_QueryStatus qs;
PREPARE (
pg,
"reserves_open_get_incr",
"SELECT"
" open_request_uuid"
",reserve_pub"
",request_timestamp"
",expiration_date"
",reserve_sig"
",reserve_payment_val"
",reserve_payment_frac"
",requested_purse_limit"
" FROM reserves_open_requests"
" WHERE open_request_uuid>=$1"
" ORDER BY open_request_uuid ASC;");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"reserves_open_get_incr",
params,
&reserve_open_serial_helper_cb,
&rcsc);
if (GNUNET_OK != rcsc.status)
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
}

View File

@ -0,0 +1,47 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pg_select_reserve_open_above_serial_id.h
* @brief implementation of the select_reserve_open_above_serial_id function
* @author Christian Grothoff
*/
#ifndef PG_SELECT_RESERVE_OPEN_ABOVE_SERIAL_ID_H
#define PG_SELECT_RESERVE_OPEN_ABOVE_SERIAL_ID_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
* Function called to select reserve open operations, ordered by serial ID
* (monotonically increasing).
*
* @param cls closure
* @param serial_id lowest serial ID to include (select larger or equal)
* @param cb function to call for ONE unfinished item
* @param cb_cls closure for @a cb
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
TEH_PG_select_reserve_open_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_ReserveOpenCallback cb,
void *cb_cls);
#endif

View File

@ -44,6 +44,8 @@
#include "pg_lookup_records_by_table.h" #include "pg_lookup_records_by_table.h"
#include "pg_lookup_serial_by_table.h" #include "pg_lookup_serial_by_table.h"
#include "pg_select_reserve_close_info.h" #include "pg_select_reserve_close_info.h"
#include "pg_select_reserve_closed_above_serial_id.h"
#include "pg_select_reserve_open_above_serial_id.h"
#include <poll.h> #include <poll.h>
#include <pthread.h> #include <pthread.h>
#include <libpq-fe.h> #include <libpq-fe.h>
@ -574,7 +576,8 @@ prepare_statements (struct PostgresClosure *pg)
",amount_frac" ",amount_frac"
",closing_fee_val" ",closing_fee_val"
",closing_fee_frac" ",closing_fee_frac"
") VALUES ($1, $2, $3, $4, $5, $6, $7, $8);"), ",close_request_row"
") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);"),
/* Used in #postgres_insert_drain_profit() */ /* Used in #postgres_insert_drain_profit() */
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
"drain_profit_insert", "drain_profit_insert",
@ -741,7 +744,7 @@ prepare_statements (struct PostgresClosure *pg)
" out_balance_ok AS balance_ok" " out_balance_ok AS balance_ok"
",out_conflict AS conflict" ",out_conflict AS conflict"
" FROM exchange_do_purse_deposit" " FROM exchange_do_purse_deposit"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9);"), " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);"),
/* Used in #postgres_update_aggregation_transient() */ /* Used in #postgres_update_aggregation_transient() */
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
"set_purse_balance", "set_purse_balance",
@ -755,7 +758,7 @@ prepare_statements (struct PostgresClosure *pg)
"SELECT " "SELECT "
" out_found AS found" " out_found AS found"
" FROM exchange_do_expire_purse" " FROM exchange_do_expire_purse"
" ($1,$2);"), " ($1,$2,$3);"),
/* Used in #postgres_do_melt() to melt a coin. */ /* Used in #postgres_do_melt() to melt a coin. */
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
"call_melt", "call_melt",
@ -1304,15 +1307,21 @@ prepare_statements (struct PostgresClosure *pg)
" JOIN denominations denom USING (denominations_serial)" " JOIN denominations denom USING (denominations_serial)"
" WHERE purse_pub=$1;"), " WHERE purse_pub=$1;"),
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
"audit_get_purse_refunds_incr", "audit_get_purse_decisions_incr",
"SELECT" "SELECT"
" purse_pub" " pd.purse_pub"
",purse_refunds_serial_id" ",pm.reserve_pub"
" FROM purse_refunds" ",pd.purse_decision_serial_id"
",pr.amount_with_fee_val"
",pr.amount_with_fee_frac"
" FROM purse_decision pd"
" JOIN purse_requests pr ON (pd.purse_pub = pr.purse_pub)"
" LEFT JOIN purse_merges pm ON (pm.purse_pub = pd.purse_pub)"
" WHERE (" " WHERE ("
" (purse_refunds_serial_id>=$1)" " (purse_decision_serial_id>=$1) AND "
" (refunded=$2)"
" )" " )"
" ORDER BY purse_refunds_serial_id ASC;"), " ORDER BY purse_decision_serial_id ASC;"),
/* Fetch an existing deposit request. /* Fetch an existing deposit request.
Used in #postgres_lookup_transfer_by_deposit(). */ Used in #postgres_lookup_transfer_by_deposit(). */
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
@ -1845,27 +1854,6 @@ prepare_statements (struct PostgresClosure *pg)
" ON (old_coins.denominations_serial = old_denoms.denominations_serial)" " ON (old_coins.denominations_serial = old_denoms.denominations_serial)"
" WHERE recoup_refresh_uuid>=$1" " WHERE recoup_refresh_uuid>=$1"
" ORDER BY recoup_refresh_uuid ASC;"), " ORDER BY recoup_refresh_uuid ASC;"),
/* Used in #postgres_select_reserve_closed_above_serial_id() to
obtain information about closed reserves */
GNUNET_PQ_make_prepare (
"reserves_close_get_incr",
"SELECT"
" close_uuid"
",reserves.reserve_pub"
",execution_date"
",wtid"
",payto_uri AS receiver_account"
",amount_val"
",amount_frac"
",closing_fee_val"
",closing_fee_frac"
" FROM reserves_close"
" JOIN wire_targets"
" USING (wire_target_h_payto)"
" JOIN reserves"
" USING (reserve_pub)"
" WHERE close_uuid>=$1"
" ORDER BY close_uuid ASC;"),
/* Used in #postgres_get_reserve_by_h_blind() */ /* Used in #postgres_get_reserve_by_h_blind() */
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
"reserve_by_h_blind", "reserve_by_h_blind",
@ -2491,9 +2479,10 @@ prepare_statements (struct PostgresClosure *pg)
" FROM account_merges" " FROM account_merges"
" JOIN purse_merges USING (purse_pub)" " JOIN purse_merges USING (purse_pub)"
" JOIN purse_requests USING (purse_pub)" " JOIN purse_requests USING (purse_pub)"
" JOIN purse_decision USING (purse_pub)"
" WHERE wallet_h_payto=$1" " WHERE wallet_h_payto=$1"
" AND merge_timestamp >= $2" " AND merge_timestamp >= $2"
" AND finished" " AND NOT refunded"
" ORDER BY merge_timestamp DESC"), " ORDER BY merge_timestamp DESC"),
GNUNET_PQ_PREPARED_STATEMENT_END GNUNET_PQ_PREPARED_STATEMENT_END
@ -6725,6 +6714,7 @@ postgres_insert_global_fee (void *cls,
* @param wtid wire transfer details * @param wtid wire transfer details
* @param amount_with_fee amount we charged to the reserve * @param amount_with_fee amount we charged to the reserve
* @param closing_fee how high is the closing fee * @param closing_fee how high is the closing fee
* @param close_request_row identifies explicit close request, 0 for none
* @return transaction status code * @return transaction status code
*/ */
static enum GNUNET_DB_QueryStatus static enum GNUNET_DB_QueryStatus
@ -6735,7 +6725,8 @@ postgres_insert_reserve_closed (
const char *receiver_account, const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *closing_fee) const struct TALER_Amount *closing_fee,
uint64_t close_request_row)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct TALER_EXCHANGEDB_Reserve reserve; struct TALER_EXCHANGEDB_Reserve reserve;
@ -6752,6 +6743,7 @@ postgres_insert_reserve_closed (
GNUNET_PQ_query_param_auto_from_type (&h_payto), GNUNET_PQ_query_param_auto_from_type (&h_payto),
TALER_PQ_query_param_amount (amount_with_fee), TALER_PQ_query_param_amount (amount_with_fee),
TALER_PQ_query_param_amount (closing_fee), TALER_PQ_query_param_amount (closing_fee),
GNUNET_PQ_query_param_uint64 (&close_request_row),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
@ -7879,15 +7871,15 @@ postgres_select_history_requests_above_serial_id (
/** /**
* Closure for #purse_refund_serial_helper_cb(). * Closure for #purse_decision_serial_helper_cb().
*/ */
struct PurseRefundSerialContext struct PurseDecisionSerialContext
{ {
/** /**
* Callback to call. * Callback to call.
*/ */
TALER_EXCHANGEDB_PurseRefundCallback cb; TALER_EXCHANGEDB_PurseDecisionCallback cb;
/** /**
* Closure for @e cb. * Closure for @e cb.
@ -7915,19 +7907,29 @@ struct PurseRefundSerialContext
* @param num_results the number of results in @a result * @param num_results the number of results in @a result
*/ */
static void static void
purse_refund_serial_helper_cb (void *cls, purse_decision_serial_helper_cb (void *cls,
PGresult *result, PGresult *result,
unsigned int num_results) unsigned int num_results)
{ {
struct PurseRefundSerialContext *dsc = cls; struct PurseDecisionSerialContext *dsc = cls;
struct PostgresClosure *pg = dsc->pg;
for (unsigned int i = 0; i<num_results; i++) for (unsigned int i = 0; i<num_results; i++)
{ {
struct TALER_PurseContractPublicKeyP purse_pub; struct TALER_PurseContractPublicKeyP purse_pub;
struct TALER_ReservePublicKeyP reserve_pub;
bool no_reserve = true;
uint64_t rowid; uint64_t rowid;
struct TALER_Amount val;
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("purse_pub", GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
&purse_pub), &purse_pub),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
&no_reserve),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&val),
GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id", GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
&rowid), &rowid),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
@ -7945,7 +7947,9 @@ purse_refund_serial_helper_cb (void *cls,
} }
ret = dsc->cb (dsc->cb_cls, ret = dsc->cb (dsc->cb_cls,
rowid, rowid,
&purse_pub); &purse_pub,
no_reserve ? NULL : &reserve_pub,
&val);
GNUNET_PQ_cleanup_result (rs); GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret) if (GNUNET_OK != ret)
break; break;
@ -7954,28 +7958,31 @@ purse_refund_serial_helper_cb (void *cls,
/** /**
* Select purse refunds above @a serial_id in monotonically increasing * Select purse decisions above @a serial_id in monotonically increasing
* order. * order.
* *
* @param cls closure * @param cls closure
* @param serial_id highest serial ID to exclude (select strictly larger) * @param serial_id highest serial ID to exclude (select strictly larger)
* @param refunded which refund status to select for
* @param cb function to call on each result * @param cb function to call on each result
* @param cb_cls closure for @a cb * @param cb_cls closure for @a cb
* @return transaction status code * @return transaction status code
*/ */
static enum GNUNET_DB_QueryStatus static enum GNUNET_DB_QueryStatus
postgres_select_purse_refunds_above_serial_id ( postgres_select_purse_decisions_above_serial_id (
void *cls, void *cls,
uint64_t serial_id, uint64_t serial_id,
TALER_EXCHANGEDB_PurseRefundCallback cb, bool refunded,
TALER_EXCHANGEDB_PurseDecisionCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&serial_id), GNUNET_PQ_query_param_uint64 (&serial_id),
GNUNET_PQ_query_param_bool (refunded),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
struct PurseRefundSerialContext dsc = { struct PurseDecisionSerialContext dsc = {
.cb = cb, .cb = cb,
.cb_cls = cb_cls, .cb_cls = cb_cls,
.pg = pg, .pg = pg,
@ -7984,9 +7991,9 @@ postgres_select_purse_refunds_above_serial_id (
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"audit_get_purse_refunds_incr", "audit_get_purse_decisions_incr",
params, params,
&purse_refund_serial_helper_cb, &purse_decision_serial_helper_cb,
&dsc); &dsc);
if (GNUNET_OK != dsc.status) if (GNUNET_OK != dsc.status)
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
@ -9232,143 +9239,6 @@ postgres_select_recoup_refresh_above_serial_id (
} }
/**
* Closure for #reserve_closed_serial_helper_cb().
*/
struct ReserveClosedSerialContext
{
/**
* Callback to call.
*/
TALER_EXCHANGEDB_ReserveClosedCallback cb;
/**
* Closure for @e cb.
*/
void *cb_cls;
/**
* Plugin's 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 ReserveClosedSerialContext`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
reserve_closed_serial_helper_cb (void *cls,
PGresult *result,
unsigned int num_results)
{
struct ReserveClosedSerialContext *rcsc = cls;
struct PostgresClosure *pg = rcsc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
uint64_t rowid;
struct TALER_ReservePublicKeyP reserve_pub;
char *receiver_account;
struct TALER_WireTransferIdentifierRawP wtid;
struct TALER_Amount amount_with_fee;
struct TALER_Amount closing_fee;
struct GNUNET_TIME_Timestamp execution_date;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("close_uuid",
&rowid),
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
GNUNET_PQ_result_spec_timestamp ("execution_date",
&execution_date),
GNUNET_PQ_result_spec_auto_from_type ("wtid",
&wtid),
GNUNET_PQ_result_spec_string ("receiver_account",
&receiver_account),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
&amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
&closing_fee),
GNUNET_PQ_result_spec_end
};
enum GNUNET_GenericReturnValue ret;
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
rcsc->status = GNUNET_SYSERR;
return;
}
ret = rcsc->cb (rcsc->cb_cls,
rowid,
execution_date,
&amount_with_fee,
&closing_fee,
&reserve_pub,
receiver_account,
&wtid);
GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret)
break;
}
}
/**
* Function called to select reserve close operations the aggregator
* triggered, ordered by serial ID (monotonically increasing).
*
* @param cls closure
* @param serial_id lowest serial ID to include (select larger or equal)
* @param cb function to call for ONE unfinished item
* @param cb_cls closure for @a cb
* @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
postgres_select_reserve_closed_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_ReserveClosedCallback 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 ReserveClosedSerialContext rcsc = {
.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,
"reserves_close_get_incr",
params,
&reserve_closed_serial_helper_cb,
&rcsc);
if (GNUNET_OK != rcsc.status)
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
}
/** /**
* Obtain information about which reserve a coin was generated * Obtain information about which reserve a coin was generated
* from given the hash of the blinded coin. * from given the hash of the blinded coin.
@ -11639,9 +11509,11 @@ postgres_expire_purse (
struct GNUNET_TIME_Absolute end_time) struct GNUNET_TIME_Absolute end_time)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_absolute_time (&start_time), GNUNET_PQ_query_param_absolute_time (&start_time),
GNUNET_PQ_query_param_absolute_time (&end_time), GNUNET_PQ_query_param_absolute_time (&end_time),
GNUNET_PQ_query_param_absolute_time (&now),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
bool found = false; bool found = false;
@ -11806,6 +11678,7 @@ postgres_do_purse_deposit (
bool *conflict) bool *conflict)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
struct GNUNET_TIME_Timestamp reserve_expiration; struct GNUNET_TIME_Timestamp reserve_expiration;
uint64_t partner_id = 0; /* FIXME #7271: WAD support... */ uint64_t partner_id = 0; /* FIXME #7271: WAD support... */
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -11816,6 +11689,7 @@ postgres_do_purse_deposit (
GNUNET_PQ_query_param_auto_from_type (coin_sig), GNUNET_PQ_query_param_auto_from_type (coin_sig),
TALER_PQ_query_param_amount (amount_minus_fee), TALER_PQ_query_param_amount (amount_minus_fee),
GNUNET_PQ_query_param_timestamp (&reserve_expiration), GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_timestamp (&now),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
@ -13166,8 +13040,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_select_purse_merges_above_serial_id; = &postgres_select_purse_merges_above_serial_id;
plugin->select_history_requests_above_serial_id plugin->select_history_requests_above_serial_id
= &postgres_select_history_requests_above_serial_id; = &postgres_select_history_requests_above_serial_id;
plugin->select_purse_refunds_above_serial_id plugin->select_purse_decisions_above_serial_id
= &postgres_select_purse_refunds_above_serial_id; = &postgres_select_purse_decisions_above_serial_id;
plugin->select_purse_deposits_by_purse plugin->select_purse_deposits_by_purse
= &postgres_select_purse_deposits_by_purse; = &postgres_select_purse_deposits_by_purse;
plugin->select_refreshes_above_serial_id plugin->select_refreshes_above_serial_id
@ -13188,8 +13062,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_select_recoup_above_serial_id; = &postgres_select_recoup_above_serial_id;
plugin->select_recoup_refresh_above_serial_id plugin->select_recoup_refresh_above_serial_id
= &postgres_select_recoup_refresh_above_serial_id; = &postgres_select_recoup_refresh_above_serial_id;
plugin->select_reserve_closed_above_serial_id
= &postgres_select_reserve_closed_above_serial_id;
plugin->get_reserve_by_h_blind plugin->get_reserve_by_h_blind
= &postgres_get_reserve_by_h_blind; = &postgres_get_reserve_by_h_blind;
plugin->get_old_coin_by_h_blind plugin->get_old_coin_by_h_blind
@ -13347,6 +13219,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_lookup_serial_by_table; = &TEH_PG_lookup_serial_by_table;
plugin->select_reserve_close_info plugin->select_reserve_close_info
= &TEH_PG_select_reserve_close_info; = &TEH_PG_select_reserve_close_info;
plugin->select_reserve_closed_above_serial_id
= &TEH_PG_select_reserve_closed_above_serial_id;
plugin->select_reserve_open_above_serial_id
= &TEH_PG_select_reserve_open_above_serial_id;
return plugin; return plugin;
} }

View File

@ -1428,6 +1428,7 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_deposit(
IN in_amount_without_fee_val INT8, IN in_amount_without_fee_val INT8,
IN in_amount_without_fee_frac INT4, IN in_amount_without_fee_frac INT4,
IN in_reserve_expiration INT8, IN in_reserve_expiration INT8,
IN in_now INT8,
OUT out_balance_ok BOOLEAN, OUT out_balance_ok BOOLEAN,
OUT out_conflict BOOLEAN) OUT out_conflict BOOLEAN)
LANGUAGE plpgsql LANGUAGE plpgsql
@ -1442,6 +1443,8 @@ DECLARE
my_amount_frac INT4; -- total in purse my_amount_frac INT4; -- total in purse
DECLARE DECLARE
was_paid BOOLEAN; was_paid BOOLEAN;
DECLARE
my_in_reserve_quota BOOLEAN;
DECLARE DECLARE
my_reserve_pub BYTEA; my_reserve_pub BYTEA;
BEGIN BEGIN
@ -1548,9 +1551,11 @@ END IF;
SELECT SELECT
amount_with_fee_val amount_with_fee_val
,amount_with_fee_frac ,amount_with_fee_frac
,in_reserve_quota
INTO INTO
my_amount_val my_amount_val
,my_amount_frac ,my_amount_frac
,my_in_reserve_quota
FROM exchange.purse_requests FROM exchange.purse_requests
WHERE (purse_pub=in_purse_pub) WHERE (purse_pub=in_purse_pub)
AND ( ( ( (amount_with_fee_val <= balance_val) AND ( ( ( (amount_with_fee_val <= balance_val)
@ -1561,6 +1566,28 @@ THEN
RETURN; RETURN;
END IF; END IF;
-- Remember how this purse was finished.
INSERT INTO purse_decision
(purse_pub
,action_timestamp
,refunded)
VALUES
(in_purse_pub
,in_now
,FALSE);
IF (my_in_reserve_quota)
THEN
UPDATE reserves
SET purses_active=purses_active-1
WHERE reserve_pub IN
(SELECT reserve_pub
FROM exchange.purse_merges
WHERE purse_pub=my_purse_pub
LIMIT 1);
END IF;
IF (0 != psi) IF (0 != psi)
THEN THEN
-- The taler-exchange-router will take care of this. -- The taler-exchange-router will take care of this.
@ -1606,11 +1633,6 @@ ELSE
WHERE reserve_pub=my_reserve_pub; WHERE reserve_pub=my_reserve_pub;
END IF; END IF;
-- ... and mark purse as finished.
-- FIXME: combine with UPDATE above?
UPDATE purse_requests
SET finished=true
WHERE purse_pub=in_purse_pub;
END IF; END IF;
@ -1644,7 +1666,7 @@ DECLARE
DECLARE DECLARE
my_partner_serial_id INT8; my_partner_serial_id INT8;
DECLARE DECLARE
my_finished BOOLEAN; my_in_reserve_quota BOOLEAN;
BEGIN BEGIN
IF in_partner_url IS NULL IF in_partner_url IS NULL
@ -1675,12 +1697,12 @@ SELECT amount_with_fee_val
,amount_with_fee_frac ,amount_with_fee_frac
,purse_fee_val ,purse_fee_val
,purse_fee_frac ,purse_fee_frac
,finished ,in_reserve_quota
INTO my_amount_val INTO my_amount_val
,my_amount_frac ,my_amount_frac
,my_purse_fee_val ,my_purse_fee_val
,my_purse_fee_frac ,my_purse_fee_frac
,my_finished ,my_in_reserve_quota
FROM exchange.purse_requests FROM exchange.purse_requests
WHERE purse_pub=in_purse_pub WHERE purse_pub=in_purse_pub
AND balance_val >= amount_with_fee_val AND balance_val >= amount_with_fee_val
@ -1731,8 +1753,6 @@ THEN
END IF; END IF;
out_conflict=FALSE; out_conflict=FALSE;
ASSERT NOT my_finished, 'internal invariant failed';
-- Initialize reserve, if not yet exists. -- Initialize reserve, if not yet exists.
INSERT INTO reserves INSERT INTO reserves
@ -1745,8 +1765,26 @@ INSERT INTO reserves
,in_expiration_date) ,in_expiration_date)
ON CONFLICT DO NOTHING; ON CONFLICT DO NOTHING;
-- Remember how this purse was finished.
INSERT INTO purse_decision
(purse_pub
,action_timestamp
,refunded)
VALUES
(in_purse_pub
,in_merge_timestamp
,FALSE);
IF (my_in_reserve_quota)
THEN
UPDATE reserves
SET purses_active=purses_active-1
WHERE reserve_pub IN
(SELECT reserve_pub
FROM exchange.purse_merges
WHERE purse_pub=my_purse_pub
LIMIT 1);
END IF;
-- Store account merge signature. -- Store account merge signature.
INSERT INTO exchange.account_merges INSERT INTO exchange.account_merges
@ -1794,10 +1832,6 @@ ELSE
END END
WHERE reserve_pub=in_reserve_pub; WHERE reserve_pub=in_reserve_pub;
-- ... and mark purse as finished.
UPDATE exchange.purse_requests
SET finished=true
WHERE purse_pub=in_purse_pub;
END IF; END IF;
@ -1969,6 +2003,7 @@ END $$;
CREATE OR REPLACE FUNCTION exchange_do_expire_purse( CREATE OR REPLACE FUNCTION exchange_do_expire_purse(
IN in_start_time INT8, IN in_start_time INT8,
IN in_end_time INT8, IN in_end_time INT8,
IN in_now INT8,
OUT out_found BOOLEAN) OUT out_found BOOLEAN)
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
@ -1976,15 +2011,21 @@ DECLARE
my_purse_pub BYTEA; my_purse_pub BYTEA;
DECLARE DECLARE
my_deposit record; my_deposit record;
DECLARE
my_in_reserve_quota BOOLEAN;
BEGIN BEGIN
-- FIXME: we should probably do this in a loop
-- and expire all at once, instead of one per query
SELECT purse_pub SELECT purse_pub
,in_reserve_quota
INTO my_purse_pub INTO my_purse_pub
,my_in_reserve_quota
FROM exchange.purse_requests FROM exchange.purse_requests
WHERE (purse_expiration >= in_start_time) AND WHERE (purse_expiration >= in_start_time) AND
(purse_expiration < in_end_time) AND (purse_expiration < in_end_time) AND
(NOT finished) AND purse_pub NOT IN (SELECT purse_pub
(NOT refunded) FROM purse_decision)
ORDER BY purse_expiration ASC ORDER BY purse_expiration ASC
LIMIT 1; LIMIT 1;
out_found = FOUND; out_found = FOUND;
@ -1993,15 +2034,25 @@ THEN
RETURN; RETURN;
END IF; END IF;
UPDATE exchange.purse_requests INSERT INTO purse_decision
SET refunded=TRUE, (purse_pub
finished=TRUE ,action_timestamp
WHERE purse_pub=my_purse_pub; ,refunded)
VALUES
(my_purse_pub
,in_now
,TRUE);
INSERT INTO exchange.purse_refunds IF (my_in_reserve_quota)
(purse_pub) THEN
VALUES UPDATE reserves
(my_purse_pub); SET purses_active=purses_active-1
WHERE reserve_pub IN
(SELECT reserve_pub
FROM exchange.purse_merges
WHERE purse_pub=my_purse_pub
LIMIT 1);
END IF;
-- restore balance to each coin deposited into the purse -- restore balance to each coin deposited into the purse
FOR my_deposit IN FOR my_deposit IN
@ -2028,7 +2079,7 @@ LOOP
END LOOP; END LOOP;
END $$; END $$;
COMMENT ON FUNCTION exchange_do_expire_purse(INT8,INT8) COMMENT ON FUNCTION exchange_do_expire_purse(INT8,INT8,INT8)
IS 'Finds an expired purse in the given time range and refunds the coins (if any).'; IS 'Finds an expired purse in the given time range and refunds the coins (if any).';

View File

@ -101,8 +101,8 @@ BEGIN
PERFORM create_table_purse_requests(shard_suffix); PERFORM create_table_purse_requests(shard_suffix);
PERFORM add_constraints_to_purse_requests_partition(shard_suffix); PERFORM add_constraints_to_purse_requests_partition(shard_suffix);
PERFORM create_table_purse_refunds(shard_suffix); PERFORM create_table_purse_decision(shard_suffix);
PERFORM add_constraints_to_purse_refunds_partition(shard_suffix); PERFORM add_constraints_to_purse_decision_partition(shard_suffix);
PERFORM create_table_purse_merges(shard_suffix); PERFORM create_table_purse_merges(shard_suffix);
PERFORM add_constraints_to_purse_merges_partition(shard_suffix); PERFORM add_constraints_to_purse_merges_partition(shard_suffix);

View File

@ -31,3 +31,6 @@ LEGAL_RESERVE_EXPIRATION_TIME = 7 years
# Shift to apply before aggregating. # Shift to apply before aggregating.
AGGREGATOR_SHIFT = 1s AGGREGATOR_SHIFT = 1s
# Number of purses per account by default.
DEFAULT_PURSE_LIMIT = 1

View File

@ -1809,7 +1809,8 @@ run (void *cls)
sndr, sndr,
&wire_out_wtid, &wire_out_wtid,
&amount_with_fee, &amount_with_fee,
&fee_closing)); &fee_closing,
0));
FAILIF (GNUNET_OK != FAILIF (GNUNET_OK !=
check_reserve (&reserve_pub2, check_reserve (&reserve_pub2,
0, 0,
@ -1823,7 +1824,8 @@ run (void *cls)
sndr, sndr,
&wire_out_wtid, &wire_out_wtid,
&value, &value,
&fee_closing)); &fee_closing,
0));
FAILIF (GNUNET_OK != FAILIF (GNUNET_OK !=
check_reserve (&reserve_pub, check_reserve (&reserve_pub,
0, 0,

View File

@ -129,6 +129,25 @@ struct TALER_AUDITORDB_WireAccountProgressPoint
}; };
/**
* Structure for remembering the wire auditor's progress
* with respect to the bank transaction histories.
*/
struct TALER_AUDITORDB_BankAccountProgressPoint
{
/**
* How far are we in the incoming wire transaction history
*/
uint64_t in_wire_off;
/**
* How far are we in the outgoing wire transaction history
*/
uint64_t out_wire_off;
};
/** /**
* Structure for remembering the auditor's progress over the various * Structure for remembering the auditor's progress over the various
* tables and (auditor) transactions when analyzing reserves. * tables and (auditor) transactions when analyzing reserves.
@ -141,7 +160,7 @@ struct TALER_AUDITORDB_ProgressPointReserve
uint64_t last_reserve_in_serial_id; uint64_t last_reserve_in_serial_id;
/** /**
* serial ID of the last reserve_out the auditor processed * serial ID of the last reserve_out (withdraw) the auditor processed
*/ */
uint64_t last_reserve_out_serial_id; uint64_t last_reserve_out_serial_id;
@ -152,40 +171,64 @@ struct TALER_AUDITORDB_ProgressPointReserve
uint64_t last_reserve_recoup_serial_id; uint64_t last_reserve_recoup_serial_id;
/** /**
* serial ID of the last reserve_close * serial ID of the last open_requests entry the auditor processed.
* entry the auditor processed. */
uint64_t last_reserve_open_serial_id;
/**
* serial ID of the last reserve_close entry the auditor processed.
*/ */
uint64_t last_reserve_close_serial_id; uint64_t last_reserve_close_serial_id;
/** /**
* serial ID of the last purse_merges * Serial ID of the last purse_decisions entry the auditor processed.
* entry the auditor processed.
*/ */
uint64_t last_purse_merges_serial_id; uint64_t last_purse_decisions_serial_id;
/** /**
* Serial ID of the last purse_deposits * serial ID of the last account_merges entry the auditor processed.
* entry the auditor processed.
*/
uint64_t last_purse_deposits_serial_id;
/**
* serial ID of the last account_merges
* entry the auditor processed.
*/ */
uint64_t last_account_merges_serial_id; uint64_t last_account_merges_serial_id;
/** /**
* serial ID of the last history_requests * serial ID of the last history_requests entry the auditor processed.
* entry the auditor processed.
*/ */
uint64_t last_history_requests_serial_id; uint64_t last_history_requests_serial_id;
};
/**
* Structure for remembering the auditor's progress over the various
* tables and (auditor) transactions when analyzing purses.
*/
struct TALER_AUDITORDB_ProgressPointPurse
{
/** /**
* serial ID of the last close_requests * serial ID of the last purse_request transfer the auditor processed
* entry the auditor processed.
*/ */
uint64_t last_close_requests_serial_id; uint64_t last_purse_request_serial_id;
/**
* serial ID of the last purse_decision the auditor processed
*/
uint64_t last_purse_decision_serial_id;
/**
* serial ID of the last purse_merge entry the auditor processed when
* considering reserves.
*/
uint64_t last_purse_merge_serial_id;
/**
* serial ID of the last account_merge entry the auditor processed.
*/
uint64_t last_account_merge_serial_id;
/**
* serial ID of the last purse_deposits entry the auditor processed.
*/
uint64_t last_purse_deposits_serial_id;
}; };
@ -254,6 +297,11 @@ struct TALER_AUDITORDB_ProgressPointCoin
*/ */
uint64_t last_recoup_refresh_serial_id; uint64_t last_recoup_refresh_serial_id;
/**
* Serial ID of the last reserve_open_deposits operation the auditor processed.
*/
uint64_t last_open_deposits_serial_id;
/** /**
* Serial ID of the last purse_deposits operation the auditor processed. * Serial ID of the last purse_deposits operation the auditor processed.
*/ */
@ -389,6 +437,140 @@ struct TALER_AUDITORDB_DepositConfirmation
}; };
/**
* Balance values for a reserve (or all reserves).
*/
struct TALER_AUDITORDB_ReserveFeeBalance
{
/**
* Remaining funds.
*/
struct TALER_Amount reserve_balance;
/**
* Losses from operations that should not have
* happened (e.g. negative balance).
*/
struct TALER_Amount reserve_loss;
/**
* Fees charged for withdraw.
*/
struct TALER_Amount withdraw_fee_balance;
/**
* Fees charged for closing.
*/
struct TALER_Amount close_fee_balance;
/**
* Fees charged for purse creation.
*/
struct TALER_Amount purse_fee_balance;
/**
* Opening fees charged.
*/
struct TALER_Amount open_fee_balance;
/**
* History fees charged.
*/
struct TALER_Amount history_fee_balance;
};
/**
* Balance data for denominations in circulation.
*/
struct TALER_AUDITORDB_DenominationCirculationData
{
/**
* Amount of outstanding coins in circulation.
*/
struct TALER_Amount denom_balance;
/**
* Amount lost due coins illicitly accepted (effectively, a
* negative @a denom_balance).
*/
struct TALER_Amount denom_loss;
/**
* Total amount that could still be theoretically lost in the future due to
* recoup operations. (Total put into circulation minus @e recoup_loss).
*/
struct TALER_Amount denom_risk;
/**
* Amount lost due to recoups.
*/
struct TALER_Amount recoup_loss;
/**
* Number of coins of this denomination that the exchange signed into
* existence.
*/
uint64_t num_issued;
};
/**
* Balance values for all denominations.
*/
struct TALER_AUDITORDB_GlobalCoinBalance
{
/**
* Amount of outstanding coins in circulation.
*/
struct TALER_Amount total_escrowed;
/**
* Amount collected in deposit fees.
*/
struct TALER_Amount deposit_fee_balance;
/**
* Amount collected in melt fees.
*/
struct TALER_Amount melt_fee_balance;
/**
* Amount collected in refund fees.
*/
struct TALER_Amount refund_fee_balance;
/**
* Amount collected in purse fees from coins.
*/
struct TALER_Amount purse_fee_balance;
/**
* Amount collected in reserve open deposit fees from coins.
*/
struct TALER_Amount open_deposit_fee_balance;
/**
* Total amount that could still be theoretically
* lost in the future due to recoup operations.
* (Total put into circulation minus @e loss
* and @e irregular_recoup.)
*/
struct TALER_Amount risk;
/**
* Amount lost due to recoups.
*/
struct TALER_Amount loss;
/**
* Amount lost due to coin operations that the exchange
* should not have permitted.
*/
struct TALER_Amount irregular_loss;
};
/** /**
* Function called with deposit confirmations stored in * Function called with deposit confirmations stored in
* the auditor's database. * the auditor's database.
@ -639,14 +821,14 @@ struct TALER_AUDITORDB_Plugin
struct TALER_AUDITORDB_ProgressPointCoin *ppc); struct TALER_AUDITORDB_ProgressPointCoin *ppc);
/** /**
* Insert information about the auditor's progress with an exchange's * Insert information about the auditor's progress with an exchange's
* data. * data.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param ppr where is the auditor in processing * @param ppr where is the auditor in processing
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_auditor_progress_reserve)( (*insert_auditor_progress_reserve)(
void *cls, void *cls,
@ -684,6 +866,53 @@ struct TALER_AUDITORDB_Plugin
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_AUDITORDB_ProgressPointReserve *ppr); struct TALER_AUDITORDB_ProgressPointReserve *ppr);
/**
* Insert information about the auditor's progress with an exchange's
* data.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange
* @param ppp where is the auditor in processing
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*insert_auditor_progress_purse)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_AUDITORDB_ProgressPointPurse *ppp);
/**
* Update information about the progress of the auditor. There
* must be an existing record for the exchange.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange
* @param ppp where is the auditor in processing
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*update_auditor_progress_purse)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_AUDITORDB_ProgressPointPurse *ppp);
/**
* Get information about the progress of the auditor.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange
* @param[out] ppp set to where the auditor is in processing
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*get_auditor_progress_purse)(
void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_AUDITORDB_ProgressPointPurse *ppp);
/** /**
* Insert information about the auditor's progress with an exchange's * Insert information about the auditor's progress with an exchange's
* data. * data.
@ -786,8 +1015,7 @@ struct TALER_AUDITORDB_Plugin
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param account_name name of the wire account we are auditing * @param account_name name of the wire account we are auditing
* @param pp where is the auditor in processing * @param pp where is the auditor in processing
* @param in_wire_off how far are we in the incoming wire transaction history * @param bapp progress in wire transaction histories
* @param out_wire_off how far are we in the outgoing wire transaction history
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -796,8 +1024,7 @@ struct TALER_AUDITORDB_Plugin
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const char *account_name, const char *account_name,
const struct TALER_AUDITORDB_WireAccountProgressPoint *pp, const struct TALER_AUDITORDB_WireAccountProgressPoint *pp,
uint64_t in_wire_off, const struct TALER_AUDITORDB_BankAccountProgressPoint *bapp);
uint64_t out_wire_off);
/** /**
@ -808,8 +1035,7 @@ struct TALER_AUDITORDB_Plugin
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param account_name name of the wire account we are auditing * @param account_name name of the wire account we are auditing
* @param pp where is the auditor in processing * @param pp where is the auditor in processing
* @param in_wire_off how far are we in the incoming wire transaction history * @param bapp progress in wire transaction histories
* @param out_wire_off how far are we in the outgoing wire transaction history
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -818,8 +1044,7 @@ struct TALER_AUDITORDB_Plugin
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const char *account_name, const char *account_name,
const struct TALER_AUDITORDB_WireAccountProgressPoint *pp, const struct TALER_AUDITORDB_WireAccountProgressPoint *pp,
uint64_t in_wire_off, const struct TALER_AUDITORDB_BankAccountProgressPoint *bapp);
uint64_t out_wire_off);
/** /**
@ -829,8 +1054,7 @@ struct TALER_AUDITORDB_Plugin
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param account_name name of the wire account we are auditing * @param account_name name of the wire account we are auditing
* @param[out] pp where is the auditor in processing * @param[out] pp where is the auditor in processing
* @param[out] in_wire_off how far are we in the incoming wire transaction history * @param[out] bapp how far are we in the wire transaction histories
* @param[out] out_wire_off how far are we in the outgoing wire transaction history
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -839,8 +1063,7 @@ struct TALER_AUDITORDB_Plugin
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const char *account_name, const char *account_name,
struct TALER_AUDITORDB_WireAccountProgressPoint *pp, struct TALER_AUDITORDB_WireAccountProgressPoint *pp,
uint64_t *in_wire_off, struct TALER_AUDITORDB_BankAccountProgressPoint *bapp);
uint64_t *out_wire_off);
/** /**
@ -887,9 +1110,10 @@ struct TALER_AUDITORDB_Plugin
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*get_wire_auditor_progress)(void *cls, (*get_wire_auditor_progress)(
const struct TALER_MasterPublicKeyP *master_pub, void *cls,
struct TALER_AUDITORDB_WireProgressPoint *pp); const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_AUDITORDB_WireProgressPoint *pp);
/** /**
@ -899,21 +1123,19 @@ struct TALER_AUDITORDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param reserve_pub public key of the reserve * @param reserve_pub public key of the reserve
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param reserve_balance amount stored in the reserve * @param rfb balance amounts for the reserve
* @param withdraw_fee_balance amount the exchange gained in withdraw fees
* due to withdrawals from this reserve
* @param expiration_date expiration date of the reserve * @param expiration_date expiration date of the reserve
* @param origin_account where did the money in the reserve originally come from * @param origin_account where did the money in the reserve originally come from
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_reserve_info)(void *cls, (*insert_reserve_info)(
const struct TALER_ReservePublicKeyP *reserve_pub, void *cls,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *reserve_balance, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *withdraw_fee_balance, const struct TALER_AUDITORDB_ReserveFeeBalance *rfb,
struct GNUNET_TIME_Timestamp expiration_date, struct GNUNET_TIME_Timestamp expiration_date,
const char *origin_account); const char *origin_account);
/** /**
@ -923,19 +1145,17 @@ struct TALER_AUDITORDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param reserve_pub public key of the reserve * @param reserve_pub public key of the reserve
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param reserve_balance amount stored in the reserve * @param rfb balance amounts for the reserve
* @param withdraw_fee_balance amount the exchange gained in withdraw fees
* due to withdrawals from this reserve
* @param expiration_date expiration date of the reserve * @param expiration_date expiration date of the reserve
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*update_reserve_info)(void *cls, (*update_reserve_info)(
const struct TALER_ReservePublicKeyP *reserve_pub, void *cls,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *reserve_balance, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *withdraw_fee_balance, const struct TALER_AUDITORDB_ReserveFeeBalance *rfb,
struct GNUNET_TIME_Timestamp expiration_date); struct GNUNET_TIME_Timestamp expiration_date);
/** /**
@ -945,22 +1165,20 @@ struct TALER_AUDITORDB_Plugin
* @param reserve_pub public key of the reserve * @param reserve_pub public key of the reserve
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param[out] rowid which row did we get the information from * @param[out] rowid which row did we get the information from
* @param[out] reserve_balance amount stored in the reserve * @param[out] rfb set to balances associated with the reserve
* @param[out] withdraw_fee_balance amount the exchange gained in withdraw fees
* due to withdrawals from this reserve
* @param[out] expiration_date expiration date of the reserve * @param[out] expiration_date expiration date of the reserve
* @param[out] sender_account from where did the money in the reserve originally come from * @param[out] sender_account from where did the money in the reserve originally come from
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*get_reserve_info)(void *cls, (*get_reserve_info)(
const struct TALER_ReservePublicKeyP *reserve_pub, void *cls,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
uint64_t *rowid, const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *reserve_balance, uint64_t *rowid,
struct TALER_Amount *withdraw_fee_balance, struct TALER_AUDITORDB_ReserveFeeBalance *rfb,
struct GNUNET_TIME_Timestamp *expiration_date, struct GNUNET_TIME_Timestamp *expiration_date,
char **sender_account); char **sender_account);
/** /**
@ -983,19 +1201,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param reserve_balance amount stored in the reserve * @param rfb reserve balances summary to store
* @param withdraw_fee_balance amount the exchange gained in withdraw fees
* @param purse_fee_balance amount the exchange gained in purse fees
* @param history_fee_balance amount the exchange gained in history fees
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_reserve_summary)(void *cls, (*insert_reserve_summary)(
const struct TALER_MasterPublicKeyP *master_pub, void *cls,
const struct TALER_Amount *reserve_balance, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *withdraw_fee_balance, const struct TALER_AUDITORDB_ReserveFeeBalance *rfb);
const struct TALER_Amount *purse_fee_balance,
const struct TALER_Amount *history_fee_balance);
/** /**
@ -1004,19 +1217,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param reserve_balance amount stored in the reserve * @param rfb reserve balances summary to store
* @param withdraw_fee_balance amount the exchange gained in withdraw fees
* @param purse_fee_balance amount the exchange gained in purse fees
* @param history_fee_balance amount the exchange gained in history fees
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*update_reserve_summary)(void *cls, (*update_reserve_summary)(
const struct TALER_MasterPublicKeyP *master_pub, void *cls,
const struct TALER_Amount *reserve_balance, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *withdraw_fee_balance, const struct TALER_AUDITORDB_ReserveFeeBalance *rfb);
const struct TALER_Amount *purse_fee_balance,
const struct TALER_Amount *history_fee_balance);
/** /**
@ -1024,19 +1232,13 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param[out] reserve_balance amount stored in reserves * @param[out] rfb reserve balances summary to initialize
* @param[out] withdraw_fee_balance amount the exchange gained in withdraw fees
* @param[out] purse_fee_balance amount the exchange gained in purse fees
* @param[out] history_fee_balance amount the exchange gained in history fees
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*get_reserve_summary)(void *cls, (*get_reserve_summary)(void *cls,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *reserve_balance, struct TALER_AUDITORDB_ReserveFeeBalance *rfb);
struct TALER_Amount *withdraw_fee_balance,
struct TALER_Amount *purse_fee_balance,
struct TALER_Amount *history_fee_balance);
/** /**
@ -1089,22 +1291,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param denom_pub_hash hash of the denomination public key * @param denom_pub_hash hash of the denomination public key
* @param denom_balance value of coins outstanding with this denomination key * @param dcd denomination circulation data to store
* @param denom_loss value of coins redeemed that were not outstanding (effectively, negative @a denom_balance)
* @param denom_risk value of coins issued with this denomination key
* @param denom_recoup value of coins paid back if this denomination key was revoked
* @param num_issued how many coins of this denomination did the exchange blind-sign
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_denomination_balance)( (*insert_denomination_balance)(
void *cls, void *cls,
const struct TALER_DenominationHashP *denom_pub_hash, const struct TALER_DenominationHashP *denom_pub_hash,
const struct TALER_Amount *denom_balance, const struct TALER_AUDITORDB_DenominationCirculationData *dcd);
const struct TALER_Amount *denom_loss,
const struct TALER_Amount *denom_risk,
const struct TALER_Amount *recoup_loss,
uint64_t num_issued);
/** /**
@ -1113,22 +1307,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param denom_pub_hash hash of the denomination public key * @param denom_pub_hash hash of the denomination public key
* @param denom_balance value of coins outstanding with this denomination key * @param dcd denomination circulation data to store
* @param denom_loss value of coins redeemed that were not outstanding (effectively, negative @a denom_balance)
* @param denom_risk value of coins issued with this denomination key
* @param denom_recoup value of coins paid back if this denomination key was revoked
* @param num_issued how many coins of this denomination did the exchange blind-sign
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*update_denomination_balance)( (*update_denomination_balance)(
void *cls, void *cls,
const struct TALER_DenominationHashP *denom_pub_hash, const struct TALER_DenominationHashP *denom_pub_hash,
const struct TALER_Amount *denom_balance, const struct TALER_AUDITORDB_DenominationCirculationData *dcd);
const struct TALER_Amount *denom_loss,
const struct TALER_Amount *denom_risk,
const struct TALER_Amount *recoup_loss,
uint64_t num_issued);
/** /**
@ -1136,22 +1322,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param denom_pub_hash hash of the denomination public key * @param denom_pub_hash hash of the denomination public key
* @param[out] denom_balance value of coins outstanding with this denomination key * @param[out] dcd denomination circulation data to initialize
* @param[out] denom_loss value of coins redeemed that were not outstanding (effectively, negative @a denom_balance)
* @param[out] denom_risk value of coins issued with this denomination key
* @param[out] denom_recoup value of coins paid back if this denomination key was revoked
* @param[out] num_issued how many coins of this denomination did the exchange blind-sign
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*get_denomination_balance)( (*get_denomination_balance)(
void *cls, void *cls,
const struct TALER_DenominationHashP *denom_pub_hash, const struct TALER_DenominationHashP *denom_pub_hash,
struct TALER_Amount *denom_balance, struct TALER_AUDITORDB_DenominationCirculationData *dcd);
struct TALER_Amount *denom_loss,
struct TALER_Amount *denom_risk,
struct TALER_Amount *recoup_loss,
uint64_t *num_issued);
/** /**
@ -1173,26 +1351,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param denom_balance value of coins outstanding with this denomination key * @param dfb denomination balance data to store
* @param deposit_fee_balance total deposit fees collected for this DK
* @param melt_fee_balance total melt fees collected for this DK
* @param refund_fee_balance total refund fees collected for this DK
* @param risk maximum risk exposure of the exchange
* @param recoup_loss actual losses from recoup (actualized @a risk)
* @param irregular_recoups recoups made of non-revoked coins (reduces
* risk, but should never happen)
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_balance_summary)(void *cls, (*insert_balance_summary)(
const struct TALER_MasterPublicKeyP *master_pub, void *cls,
const struct TALER_Amount *denom_balance, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *deposit_fee_balance, const struct TALER_AUDITORDB_GlobalCoinBalance *dfb);
const struct TALER_Amount *melt_fee_balance,
const struct TALER_Amount *refund_fee_balance,
const struct TALER_Amount *risk,
const struct TALER_Amount *recoup_loss,
const struct TALER_Amount *irregular_recoups);
/** /**
@ -1201,26 +1367,14 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param denom_balance value of coins outstanding with this denomination key * @param dfb denomination balance data to store
* @param deposit_fee_balance total deposit fees collected for this DK
* @param melt_fee_balance total melt fees collected for this DK
* @param refund_fee_balance total refund fees collected for this DK
* @param risk maximum risk exposure of the exchange
* @param recoup_loss actual losses from recoup (actualized @a risk)
* @param irregular_recoups recoups made of non-revoked coins (reduces
* risk, but should never happen)
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*update_balance_summary)(void *cls, (*update_balance_summary)(
const struct TALER_MasterPublicKeyP *master_pub, void *cls,
const struct TALER_Amount *denom_balance, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *deposit_fee_balance, const struct TALER_AUDITORDB_GlobalCoinBalance *dfb);
const struct TALER_Amount *melt_fee_balance,
const struct TALER_Amount *refund_fee_balance,
const struct TALER_Amount *risk,
const struct TALER_Amount *recoup_loss,
const struct TALER_Amount *irregular_recoups);
/** /**
@ -1228,26 +1382,13 @@ struct TALER_AUDITORDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param master_pub master key of the exchange * @param master_pub master key of the exchange
* @param[out] denom_balance value of coins outstanding with this denomination key * @param[out] dfb where to return the denomination balances
* @param[out] deposit_fee_balance total deposit fees collected for this DK
* @param[out] melt_fee_balance total melt fees collected for this DK
* @param[out] refund_fee_balance total refund fees collected for this DK
* @param[out] risk maximum risk exposure of the exchange
* @param[out] recoup_loss actual losses from recoup (actualized @a risk)
* @param[out] irregular_recoups recoups made of non-revoked coins (reduces
* risk, but should never happen)
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*get_balance_summary)(void *cls, (*get_balance_summary)(void *cls,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *denom_balance, struct TALER_AUDITORDB_GlobalCoinBalance *dfb);
struct TALER_Amount *deposit_fee_balance,
struct TALER_Amount *melt_fee_balance,
struct TALER_Amount *refund_fee_balance,
struct TALER_Amount *risk,
struct TALER_Amount *recoup_loss,
struct TALER_Amount *irregular_recoup);
/** /**

View File

@ -222,7 +222,7 @@ enum TALER_EXCHANGEDB_ReplicatedTable
TALER_EXCHANGEDB_RT_EXTENSIONS, TALER_EXCHANGEDB_RT_EXTENSIONS,
TALER_EXCHANGEDB_RT_EXTENSION_DETAILS, TALER_EXCHANGEDB_RT_EXTENSION_DETAILS,
TALER_EXCHANGEDB_RT_PURSE_REQUESTS, TALER_EXCHANGEDB_RT_PURSE_REQUESTS,
TALER_EXCHANGEDB_RT_PURSE_REFUNDS, TALER_EXCHANGEDB_RT_PURSE_DECISION,
TALER_EXCHANGEDB_RT_PURSE_MERGES, TALER_EXCHANGEDB_RT_PURSE_MERGES,
TALER_EXCHANGEDB_RT_PURSE_DEPOSITS, TALER_EXCHANGEDB_RT_PURSE_DEPOSITS,
TALER_EXCHANGEDB_RT_ACCOUNT_MERGES, TALER_EXCHANGEDB_RT_ACCOUNT_MERGES,
@ -536,7 +536,9 @@ struct TALER_EXCHANGEDB_TableData
struct struct
{ {
struct TALER_PurseContractPublicKeyP purse_pub; struct TALER_PurseContractPublicKeyP purse_pub;
} purse_refunds; struct GNUNET_TIME_Timestamp action_timestamp;
bool refunded;
} purse_decision;
struct struct
{ {
@ -2348,19 +2350,23 @@ typedef enum GNUNET_GenericReturnValue
/** /**
* Function called with details about purse refunds that have been made, with * Function called with details about purse decisions that have been made, with
* the goal of auditing the purse refund's execution. * the goal of auditing the purse's execution.
* *
* @param cls closure * @param cls closure
* @param rowid unique serial ID for the deposit in our DB * @param rowid unique serial ID for the deposit in our DB
* @param purse_pub public key of the refunded purse * @param purse_pub public key of the purse
* @param reserve_pub public key of the target reserve, NULL if not known
* @param purse_value what is the (target) value of the purse
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/ */
typedef enum GNUNET_GenericReturnValue typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_PurseRefundCallback)( (*TALER_EXCHANGEDB_PurseDecisionCallback)(
void *cls, void *cls,
uint64_t rowid, uint64_t rowid,
const struct TALER_PurseContractPublicKeyP *purse_pub); const struct TALER_PurseContractPublicKeyP *purse_pub,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *purse_value);
/** /**
@ -2849,6 +2855,33 @@ typedef enum GNUNET_GenericReturnValue
const union TALER_DenominationBlindingKeyP *coin_blind); const union TALER_DenominationBlindingKeyP *coin_blind);
/**
* Function called about reserve opening operations.
*
* @param cls closure
* @param rowid row identifier used to uniquely identify the reserve closing operation
* @param reserve_payment how much to pay from the
* reserve's own balance for opening the reserve
* @param request_timestamp when was the request created
* @param reserve_expiration desired expiration time for the reserve
* @param purse_limit minimum number of purses the client
* wants to have concurrently open for this reserve
* @param reserve_pub public key of the reserve
* @param reserve_sig signature affirming the operation
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_ReserveOpenCallback)(
void *cls,
uint64_t rowid,
const struct TALER_Amount *reserve_payment,
struct GNUNET_TIME_Timestamp request_timestamp,
struct GNUNET_TIME_Timestamp reserve_expiration,
uint32_t purse_limit,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_ReserveSignatureP *reserve_sig);
/** /**
* Function called about reserve closing operations * Function called about reserve closing operations
* the aggregator triggered. * the aggregator triggered.
@ -2861,6 +2894,8 @@ typedef enum GNUNET_GenericReturnValue
* @param reserve_pub public key of the reserve * @param reserve_pub public key of the reserve
* @param receiver_account where did we send the funds, in payto://-format * @param receiver_account where did we send the funds, in payto://-format
* @param wtid identifier used for the wire transfer * @param wtid identifier used for the wire transfer
* @param close_request_row row with the responsible close
* request, 0 if regular expiration triggered close
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/ */
typedef enum GNUNET_GenericReturnValue typedef enum GNUNET_GenericReturnValue
@ -2872,7 +2907,8 @@ typedef enum GNUNET_GenericReturnValue
const struct TALER_Amount *closing_fee, const struct TALER_Amount *closing_fee,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const char *receiver_account, const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid); const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t close_request_row);
/** /**
@ -2895,6 +2931,8 @@ typedef void
* @param left amount left in the reserve * @param left amount left in the reserve
* @param account_details information about the reserve's bank account, in payto://-format * @param account_details information about the reserve's bank account, in payto://-format
* @param expiration_date when did the reserve expire * @param expiration_date when did the reserve expire
* @param close_request_row row that caused the reserve
* to be closed, 0 if it expired without request
* @return #GNUNET_OK on success, * @return #GNUNET_OK on success,
* #GNUNET_NO to retry * #GNUNET_NO to retry
* #GNUNET_SYSERR on hard failures (exit) * #GNUNET_SYSERR on hard failures (exit)
@ -2905,7 +2943,8 @@ typedef enum GNUNET_GenericReturnValue
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *left, const struct TALER_Amount *left,
const char *account_details, const char *account_details,
struct GNUNET_TIME_Timestamp expiration_date); struct GNUNET_TIME_Timestamp expiration_date,
uint64_t close_request_row);
/** /**
@ -4361,6 +4400,33 @@ struct TALER_EXCHANGEDB_Plugin
char **payto_uri); char **payto_uri);
/**
* Select information about reserve close requests.
*
* @param cls closure
* @param reserve_pub which reserve is this about?
* @param rowid row ID of the close request
* @param[out] reserve_sig reserve signature affirming
* @param[out] request_timestamp when was the request made
* @param[out] close_balance reserve balance at close time
* @param[out] close_fee closing fee to be charged
* @param[out] payto_uri set to URL of account that
* should receive the money;
* could be set to NULL for origin
* @return transaction status code, 0 if reserve unknown
*/
enum GNUNET_DB_QueryStatus
(*select_reserve_close_request_info)(
void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
uint64_t rowid,
struct TALER_ReserveSignatureP *reserve_sig,
struct GNUNET_TIME_Timestamp *request_timestamp,
struct TALER_Amount *close_balance,
struct TALER_Amount *close_fee,
char **payto_uri);
/** /**
* Select information needed for KYC checks on reserve close: historic * Select information needed for KYC checks on reserve close: historic
* reserve closures going to the same account. * reserve closures going to the same account.
@ -4392,6 +4458,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param wtid identifier for the wire transfer * @param wtid identifier for the wire transfer
* @param amount_with_fee amount we charged to the reserve * @param amount_with_fee amount we charged to the reserve
* @param closing_fee how high is the closing fee * @param closing_fee how high is the closing fee
* @param close_request_row identifies explicit close request, 0 for none
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -4401,7 +4468,8 @@ struct TALER_EXCHANGEDB_Plugin
const char *receiver_account, const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *closing_fee); const struct TALER_Amount *closing_fee,
uint64_t close_request_row);
/** /**
@ -4604,15 +4672,17 @@ struct TALER_EXCHANGEDB_Plugin
* *
* @param cls closure * @param cls closure
* @param serial_id highest serial ID to exclude (select strictly larger) * @param serial_id highest serial ID to exclude (select strictly larger)
* @param refunded which refund status to select for
* @param cb function to call on each result * @param cb function to call on each result
* @param cb_cls closure for @a cb * @param cb_cls closure for @a cb
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*select_purse_refunds_above_serial_id)( (*select_purse_decisions_above_serial_id)(
void *cls, void *cls,
uint64_t serial_id, uint64_t serial_id,
TALER_EXCHANGEDB_PurseRefundCallback cb, bool refunded,
TALER_EXCHANGEDB_PurseDecisionCallback cb,
void *cb_cls); void *cb_cls);
@ -4795,8 +4865,8 @@ struct TALER_EXCHANGEDB_Plugin
/** /**
* Function called to select reserve close operations the aggregator * Function called to select reserve open operations, ordered by serial ID
* triggered, ordered by serial ID (monotonically increasing). * (monotonically increasing).
* *
* @param cls closure * @param cls closure
* @param serial_id lowest serial ID to include (select larger or equal) * @param serial_id lowest serial ID to include (select larger or equal)
@ -4805,6 +4875,24 @@ struct TALER_EXCHANGEDB_Plugin
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*select_reserve_open_above_serial_id)(
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_ReserveOpenCallback cb,
void *cb_cls);
/**
* Function called to select reserve close operations the aggregator
* triggered, ordered by serial ID (monotonically increasing).
*
* @param cls closure
* @param serial_id lowest serial ID to include (select larger or equal)
* @param cb function to call
* @param cb_cls closure for @a cb
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*select_reserve_closed_above_serial_id)( (*select_reserve_closed_above_serial_id)(
void *cls, void *cls,
uint64_t serial_id, uint64_t serial_id,

View File

@ -303,7 +303,7 @@ handle_purse_create_deposit_finished (void *cls,
TALER_amount_cmp (&left, TALER_amount_cmp (&left,
&deposit->contribution)) &deposit->contribution))
{ {
/* Balance was sufficient after all; recoup MAY have still been possible */ /* Balance was sufficient after all; operation MAY have still been possible */
GNUNET_break_op (0); GNUNET_break_op (0);
continue; continue;
} }