work on making auditor reports nicer (#4962)
This commit is contained in:
parent
2ddd4cb330
commit
c5f9c0ca88
@ -27,43 +27,86 @@ The active operational risk stands at
|
|||||||
|
|
||||||
\section{Income}
|
\section{Income}
|
||||||
|
|
||||||
|
This section analyzes the income of the exchange operator from fees.
|
||||||
|
|
||||||
\begin{table}[h!]
|
\begin{table}[h!]
|
||||||
\caption{Revenue}
|
\begin{center}
|
||||||
|
\caption{Fee revenue summary}
|
||||||
\label{table:revenue}
|
\label{table:revenue}
|
||||||
\begin{tabular}{l|rl}
|
\begin{tabular}{l|rl}
|
||||||
Category & Amount & \\ \hline \hline
|
Category & Amount & \\ \hline \hline
|
||||||
Withdraw fees &
|
Withdraw fees &
|
||||||
{{ data.reserve_balance[0].total_withdraw_fee_income.value }}.{{ data.reserve_balance[0].total_withdraw_fee_income.fraction }} &
|
{{ data.total_withdraw_fee_income.value }}.{{ data.total_withdraw_fee_income.fraction }} &
|
||||||
{{ data.reserve_balance[0].total_withdraw_fee_income.currency }} \\
|
{{ data.total_withdraw_fee_income.currency }} \\
|
||||||
Deposit fees &
|
Deposit fees &
|
||||||
{{ data.report_denomination_balance[0].total_deposit_fee_income.value }}.{{ data.report_denomination_balance[0].total_deposit_fee_income.fraction }} &
|
{{ data.total_deposit_fee_income.value }}.{{ data.total_deposit_fee_income.fraction }} &
|
||||||
{{ data.report_denomination_balance[0].total_deposit_fee_income.currency }} \\
|
{{ data.total_deposit_fee_income.currency }} \\
|
||||||
Melt fees &
|
Melt fees &
|
||||||
{{ data.report_denomination_balance[0].total_melt_fee_income.value }}.{{ data.report_denomination_balance[0].total_melt_fee_income.fraction }} &
|
{{ data.total_melt_fee_income.value }}.{{ data.total_melt_fee_income.fraction }} &
|
||||||
{{ data.report_denomination_balance[0].total_melt_fee_income.currency }} \\
|
{{ data.total_melt_fee_income.currency }} \\
|
||||||
Refund fees &
|
Refund fees &
|
||||||
{{ data.report_denomination_balance[0].total_refund_fee_income.value }}.{{ data.report_denomination_balance[0].total_refund_fee_income.fraction }} &
|
{{ data.total_refund_fee_income.value }}.{{ data.total_refund_fee_income.fraction }} &
|
||||||
{{ data.report_denomination_balance[0].total_refund_fee_income.currency }} \\
|
{{ data.total_refund_fee_income.currency }} \\
|
||||||
Aggregation fees &
|
Aggregation fees &
|
||||||
{{ data.aggregation_fee_balance[0].total_aggregation_fee_income.value }}.{{ data.aggregation_fee_balance[0].total_aggregation_fee_income.fraction }} &
|
{{ data.total_aggregation_fee_income.value }}.{{ data.total_aggregation_fee_income.fraction }} &
|
||||||
{{ data.aggregation_fee_balance[0].total_aggregation_fee_income.currency }} \\
|
{{ data.total_aggregation_fee_income.currency }} \\
|
||||||
{\bf Total} & TBD & TBD \\
|
{\bf Total} &
|
||||||
|
{{ data.income_fee_total.value }}.{{ data.income_fee_total.fraction }} &
|
||||||
|
{{ data.income_fee_total.currency }} \\
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
|
|
||||||
\section{Irregularities}
|
\section{Irregularities}
|
||||||
|
|
||||||
|
This section describes the possible irregularities that the auditor
|
||||||
|
has checked, and lists all of the actual irregularities encountered
|
||||||
|
in detail.
|
||||||
|
|
||||||
\subsection{Emergencies}
|
\subsection{Emergencies}
|
||||||
|
|
||||||
|
Emergencies are errors where more coins were deposited than the
|
||||||
|
exchange remembers issuing. This usually means that the private keys
|
||||||
|
of the exchange were compromised (stolen or factored) and subsequently
|
||||||
|
used to sign coins off the books. If this happens, all coins of the
|
||||||
|
respective denomination that the exchange has redeemed so far may have
|
||||||
|
been created by the attacker, and the exchange would have to refund
|
||||||
|
all of the outstanding coins from ordinary users. Thus, the {\bf risk
|
||||||
|
exposure} is the amount of coins in circulation for a particular
|
||||||
|
denominatin and the maximum loss for the exchange from this type of
|
||||||
|
compromise.
|
||||||
|
|
||||||
{% if data.emergencies|length() == 0 %}
|
{% if data.emergencies|length() == 0 %}
|
||||||
{\bf No emergencies detected.}
|
{\bf No emergencies detected.}
|
||||||
{% else %}
|
{% else %}
|
||||||
\begin{table}
|
\begin{longtable}{p{1.5cm}|rl|c|rl}
|
||||||
|
{\bf Public key hash} & {\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} \\ \hline \hline
|
||||||
|
\endfirsthead
|
||||||
|
{\bf Public key hash} & {\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} \\ \hline \hline
|
||||||
|
\endhead
|
||||||
|
\hline \hline
|
||||||
|
{\bf Public key hash} & {\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} \\
|
||||||
|
\endfoot
|
||||||
|
\hline
|
||||||
|
% FIXME: replace these with the summary column adding up the amounts!
|
||||||
|
\multicolumn{4}{|c|}{ {\bf Total risk from emergencies}} & {{ data.emergencies_risk_total }} \\
|
||||||
\caption{Emergencies.}
|
\caption{Emergencies.}
|
||||||
\label{table:emergencies}
|
\label{table:emergencies}
|
||||||
TBD.
|
\endlastfoot
|
||||||
\end{table}
|
{% for item in data.reserve_inconsistencies %}
|
||||||
{% endif %}
|
\multicolumn{6}{l}{ {\tt {{ item.denompub_hash }} } } \\
|
||||||
|
\nopagebreak
|
||||||
|
&
|
||||||
|
{{ item.value.value }}.{{ item.value.fraction }} &
|
||||||
|
{{ item.value.currency }} &
|
||||||
|
{{ item.start }} - {{ item.deposit_end }} &
|
||||||
|
{{ item.denom_risk.value }}.{{ item.denom_risk.fraction }} &
|
||||||
|
{{ item.denom_risk.currency }} \\ \hline
|
||||||
|
{% endfor %}
|
||||||
|
\end{longtable}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
\subsection{Reserve inconsistencies}
|
\subsection{Reserve inconsistencies}
|
||||||
|
|
||||||
|
@ -144,20 +144,51 @@ static json_t *report_wire_out_inconsistencies;
|
|||||||
*/
|
*/
|
||||||
static json_t *report_coin_inconsistencies;
|
static json_t *report_coin_inconsistencies;
|
||||||
|
|
||||||
/**
|
|
||||||
* Report about expected reserve balances.
|
|
||||||
*/
|
|
||||||
static json_t *report_reserve_balances;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report about aggregate wire transfer fee profits.
|
* Report about aggregate wire transfer fee profits.
|
||||||
*/
|
*/
|
||||||
static json_t *report_aggregation_fee_balances;
|
static json_t *report_aggregation_fee_balances;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report about denomination fee balances.
|
* Total amount reported in all calls to #report_emergency().
|
||||||
*/
|
*/
|
||||||
static json_t *report_denomination_balances;
|
static struct TALER_Amount reported_emergency_sum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected balance in the escrow account.
|
||||||
|
*/
|
||||||
|
static struct TALER_Amount total_escrow_balance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active risk exposure.
|
||||||
|
*/
|
||||||
|
static struct TALER_Amount total_risk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total withdraw fees earned.
|
||||||
|
*/
|
||||||
|
static struct TALER_Amount total_withdraw_fee_income;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total aggregation fees earned.
|
||||||
|
*/
|
||||||
|
static struct TALER_Amount total_aggregation_fee_income;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ***************************** Report logic **************************** */
|
/* ***************************** Report logic **************************** */
|
||||||
@ -189,14 +220,28 @@ report (json_t *array,
|
|||||||
* denomination (and as an exchange suffer a huge financial loss).
|
* denomination (and as an exchange suffer a huge financial loss).
|
||||||
*
|
*
|
||||||
* @param dki denomination key where the loss was detected
|
* @param dki denomination key where the loss was detected
|
||||||
|
* @param risk maximum risk that might have just become real (coins created by this @a dki)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
report_emergency (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki)
|
report_emergency (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki,
|
||||||
|
const struct TALER_Amount *risk)
|
||||||
{
|
{
|
||||||
report (report_emergencies,
|
report (report_emergencies,
|
||||||
json_pack ("{s:o}",
|
json_pack ("{s:o, s:o, s:s, s:s, s:o}",
|
||||||
"denompub_hash",
|
"denompub_hash",
|
||||||
GNUNET_JSON_from_data_auto (&dki->properties.denom_hash)));
|
GNUNET_JSON_from_data_auto (&dki->properties.denom_hash),
|
||||||
|
"denom_risk",
|
||||||
|
TALER_JSON_from_amount (risk),
|
||||||
|
"start",
|
||||||
|
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dki->properties.start)),
|
||||||
|
"deposit_end",
|
||||||
|
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dki->properties.expire_deposit)),
|
||||||
|
"value",
|
||||||
|
TALER_JSON_from_amount_nbo (&dki->properties.value)));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_add (&reported_emergency_sum,
|
||||||
|
&reported_emergency_sum,
|
||||||
|
risk));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -326,86 +371,6 @@ report_coin_inconsistency (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report the final result on the reserve balances of the exchange.
|
|
||||||
* The reserve must have @a total_balance in its escrow account just
|
|
||||||
* to cover outstanding reserve funds (outstanding coins are on top).
|
|
||||||
* The reserve has made @a total_fee_balance in profit from withdrawal
|
|
||||||
* operations alone.
|
|
||||||
*
|
|
||||||
* Note that this is for the "ongoing" reporting period. Historic
|
|
||||||
* revenue (as stored via the "insert_historic_reserve_revenue")
|
|
||||||
* is not included in the @a total_fee_balance.
|
|
||||||
*
|
|
||||||
* @param total_balance how much money (in total) is left in all of the
|
|
||||||
* reserves (that has not been withdrawn)
|
|
||||||
* @param total_fee_balance how much money (in total) did the reserve
|
|
||||||
* make from withdrawal fees
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
report_reserve_balance (const struct TALER_Amount *total_balance,
|
|
||||||
const struct TALER_Amount *total_fee_balance)
|
|
||||||
{
|
|
||||||
report (report_reserve_balances,
|
|
||||||
json_pack ("{s:o, s:o}",
|
|
||||||
"total_escrow_balance",
|
|
||||||
TALER_JSON_from_amount (total_balance),
|
|
||||||
"total_withdraw_fee_income",
|
|
||||||
TALER_JSON_from_amount (total_fee_balance)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report on the aggregation fees the exchange made.
|
|
||||||
*
|
|
||||||
* Note that this is for the "ongoing" reporting period. Historic
|
|
||||||
* revenue (as stored via the "insert_historic_reserve_revenue")
|
|
||||||
* is not included in the @a total_fee_balance.
|
|
||||||
*
|
|
||||||
* @param total_fee_balance how much money (in total) did the reserve
|
|
||||||
* make from aggregation fees
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
report_aggregation_fee_balance (const struct TALER_Amount *total_fee_balance)
|
|
||||||
{
|
|
||||||
report (report_aggregation_fee_balances,
|
|
||||||
json_pack ("{s:o}",
|
|
||||||
"total_aggregation_fee_income",
|
|
||||||
TALER_JSON_from_amount (total_fee_balance)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report state of denomination processing.
|
|
||||||
*
|
|
||||||
* @param total_balance total value of outstanding coins
|
|
||||||
* @param total_risk total value of issued coins in active denominations
|
|
||||||
* @param deposit_fees total deposit fees collected
|
|
||||||
* @param melt_fees total melt fees collected
|
|
||||||
* @param refund_fees total refund fees collected
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
report_denomination_balance (const struct TALER_Amount *total_balance,
|
|
||||||
const struct TALER_Amount *total_risk,
|
|
||||||
const struct TALER_Amount *deposit_fees,
|
|
||||||
const struct TALER_Amount *melt_fees,
|
|
||||||
const struct TALER_Amount *refund_fees)
|
|
||||||
{
|
|
||||||
report (report_denomination_balances,
|
|
||||||
json_pack ("{s:o, s:o, s:o, s:o, s:o}",
|
|
||||||
"total_escrow_balance",
|
|
||||||
TALER_JSON_from_amount (total_balance),
|
|
||||||
"total_active_risk",
|
|
||||||
TALER_JSON_from_amount (total_risk),
|
|
||||||
"total_deposit_fee_income",
|
|
||||||
TALER_JSON_from_amount (deposit_fees),
|
|
||||||
"total_melt_fee_income",
|
|
||||||
TALER_JSON_from_amount (melt_fees),
|
|
||||||
"total_refund_fee_income",
|
|
||||||
TALER_JSON_from_amount (refund_fees)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ************************* Transaction-global state ************************ */
|
/* ************************* Transaction-global state ************************ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -662,16 +627,6 @@ struct ReserveContext
|
|||||||
*/
|
*/
|
||||||
struct GNUNET_CONTAINER_MultiHashMap *revoked;
|
struct GNUNET_CONTAINER_MultiHashMap *revoked;
|
||||||
|
|
||||||
/**
|
|
||||||
* Total balance in all reserves (updated).
|
|
||||||
*/
|
|
||||||
struct TALER_Amount total_balance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total withdraw fees gotten in all reserves (updated).
|
|
||||||
*/
|
|
||||||
struct TALER_Amount total_fee_balance;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction status code, set to error codes if applicable.
|
* Transaction status code, set to error codes if applicable.
|
||||||
*/
|
*/
|
||||||
@ -1261,16 +1216,16 @@ verify_reserve_balance (void *cls,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if ( (GNUNET_YES !=
|
if ( (GNUNET_YES !=
|
||||||
TALER_amount_add (&rc->total_balance,
|
TALER_amount_add (&total_escrow_balance,
|
||||||
&rc->total_balance,
|
&total_escrow_balance,
|
||||||
&rs->total_in)) ||
|
&rs->total_in)) ||
|
||||||
(GNUNET_SYSERR ==
|
(GNUNET_SYSERR ==
|
||||||
TALER_amount_subtract (&rc->total_balance,
|
TALER_amount_subtract (&total_escrow_balance,
|
||||||
&rc->total_balance,
|
&total_escrow_balance,
|
||||||
&rs->total_out)) ||
|
&rs->total_out)) ||
|
||||||
(GNUNET_YES !=
|
(GNUNET_YES !=
|
||||||
TALER_amount_add (&rc->total_fee_balance,
|
TALER_amount_add (&total_withdraw_fee_income,
|
||||||
&rc->total_fee_balance,
|
&total_withdraw_fee_income,
|
||||||
&rs->total_fee)) )
|
&rs->total_fee)) )
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -1367,23 +1322,13 @@ analyze_reserves (void *cls)
|
|||||||
qsx = adb->get_reserve_summary (adb->cls,
|
qsx = adb->get_reserve_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&rc.total_balance,
|
&total_escrow_balance,
|
||||||
&rc.total_fee_balance);
|
&total_withdraw_fee_income);
|
||||||
if (qsx < 0)
|
if (qsx < 0)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
||||||
return qsx;
|
return qsx;
|
||||||
}
|
}
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qsx)
|
|
||||||
{
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&rc.total_balance));
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&rc.total_fee_balance));
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.reserves = GNUNET_CONTAINER_multihashmap_create (512,
|
rc.reserves = GNUNET_CONTAINER_multihashmap_create (512,
|
||||||
GNUNET_NO);
|
GNUNET_NO);
|
||||||
rc.revoked = GNUNET_CONTAINER_multihashmap_create (4,
|
rc.revoked = GNUNET_CONTAINER_multihashmap_create (4,
|
||||||
@ -1446,24 +1391,22 @@ analyze_reserves (void *cls)
|
|||||||
qs = adb->insert_reserve_summary (adb->cls,
|
qs = adb->insert_reserve_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&rc.total_balance,
|
&total_escrow_balance,
|
||||||
&rc.total_fee_balance);
|
&total_withdraw_fee_income);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qs = adb->update_reserve_summary (adb->cls,
|
qs = adb->update_reserve_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&rc.total_balance,
|
&total_escrow_balance,
|
||||||
&rc.total_fee_balance);
|
&total_withdraw_fee_income);
|
||||||
}
|
}
|
||||||
if (0 >= qs)
|
if (0 >= qs)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
report_reserve_balance (&rc.total_balance,
|
|
||||||
&rc.total_fee_balance);
|
|
||||||
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1565,7 +1508,7 @@ struct AggregationContext
|
|||||||
/**
|
/**
|
||||||
* How much did we make in aggregation fees.
|
* How much did we make in aggregation fees.
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount total_aggregation_fees;
|
struct TALER_Amount total_aggregation_feesX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Final result status.
|
* Final result status.
|
||||||
@ -2341,8 +2284,8 @@ check_wire_out_cb (void *cls,
|
|||||||
|
|
||||||
/* Sum up aggregation fees (we simply include the rounding gains) */
|
/* Sum up aggregation fees (we simply include the rounding gains) */
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&ac->total_aggregation_fees,
|
TALER_amount_add (&total_aggregation_fee_income,
|
||||||
&ac->total_aggregation_fees,
|
&total_aggregation_fee_income,
|
||||||
&exchange_gain))
|
&exchange_gain))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -2393,16 +2336,12 @@ analyze_aggregations (void *cls)
|
|||||||
qsx = adb->get_wire_fee_summary (adb->cls,
|
qsx = adb->get_wire_fee_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&ac.total_aggregation_fees);
|
&total_aggregation_fee_income);
|
||||||
if (0 > qsx)
|
if (0 > qsx)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
||||||
return qsx;
|
return qsx;
|
||||||
}
|
}
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qsx)
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&ac.total_aggregation_fees));
|
|
||||||
ac.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
ac.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||||
qs = edb->select_wire_out_above_serial_id (edb->cls,
|
qs = edb->select_wire_out_above_serial_id (edb->cls,
|
||||||
esession,
|
esession,
|
||||||
@ -2439,18 +2378,17 @@ analyze_aggregations (void *cls)
|
|||||||
ac.qs = adb->insert_wire_fee_summary (adb->cls,
|
ac.qs = adb->insert_wire_fee_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&ac.total_aggregation_fees);
|
&total_aggregation_fee_income);
|
||||||
else
|
else
|
||||||
ac.qs = adb->update_wire_fee_summary (adb->cls,
|
ac.qs = adb->update_wire_fee_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&ac.total_aggregation_fees);
|
&total_aggregation_fee_income);
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ac.qs)
|
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ac.qs)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == ac.qs);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == ac.qs);
|
||||||
return ac.qs;
|
return ac.qs;
|
||||||
}
|
}
|
||||||
report_aggregation_fee_balance (&ac.total_aggregation_fees);
|
|
||||||
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2502,32 +2440,6 @@ struct CoinContext
|
|||||||
*/
|
*/
|
||||||
struct GNUNET_CONTAINER_MultiHashMap *denom_summaries;
|
struct GNUNET_CONTAINER_MultiHashMap *denom_summaries;
|
||||||
|
|
||||||
/**
|
|
||||||
* Total outstanding balances across all denomination keys.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount total_denom_balance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total deposit fees earned so far.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount deposit_fee_balance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total melt fees earned so far.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount melt_fee_balance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total refund fees earned so far.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount refund_fee_balance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current financial risk of the exchange operator with respect
|
|
||||||
* to key compromise.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount risk;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current write/replace offset in the circular @e summaries buffer.
|
* Current write/replace offset in the circular @e summaries buffer.
|
||||||
*/
|
*/
|
||||||
@ -2670,8 +2582,8 @@ sync_denomination (void *cls,
|
|||||||
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. */
|
||||||
if (GNUNET_SYSERR ==
|
if (GNUNET_SYSERR ==
|
||||||
TALER_amount_subtract (&cc->risk,
|
TALER_amount_subtract (&total_risk,
|
||||||
&cc->risk,
|
&total_risk,
|
||||||
&ds->denom_risk))
|
&ds->denom_risk))
|
||||||
{
|
{
|
||||||
/* Holy smokes, our risk assessment was inconsistent!
|
/* Holy smokes, our risk assessment was inconsistent!
|
||||||
@ -2815,8 +2727,8 @@ withdraw_cb (void *cls,
|
|||||||
GNUNET_h2s (&dh),
|
GNUNET_h2s (&dh),
|
||||||
TALER_amount2s (&ds->denom_balance));
|
TALER_amount2s (&ds->denom_balance));
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->total_denom_balance,
|
TALER_amount_add (&total_escrow_balance,
|
||||||
&cc->total_denom_balance,
|
&total_escrow_balance,
|
||||||
&value))
|
&value))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -2824,8 +2736,8 @@ withdraw_cb (void *cls,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->risk,
|
TALER_amount_add (&total_risk,
|
||||||
&cc->risk,
|
&total_risk,
|
||||||
&value))
|
&value))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3058,8 +2970,8 @@ refresh_session_cb (void *cls,
|
|||||||
GNUNET_h2s (&new_dki[i]->properties.denom_hash),
|
GNUNET_h2s (&new_dki[i]->properties.denom_hash),
|
||||||
TALER_amount2s (&dsi->denom_balance));
|
TALER_amount2s (&dsi->denom_balance));
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->total_denom_balance,
|
TALER_amount_add (&total_escrow_balance,
|
||||||
&cc->total_denom_balance,
|
&total_escrow_balance,
|
||||||
&value))
|
&value))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3067,8 +2979,8 @@ refresh_session_cb (void *cls,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->risk,
|
TALER_amount_add (&total_risk,
|
||||||
&cc->risk,
|
&total_risk,
|
||||||
&value))
|
&value))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3092,13 +3004,14 @@ refresh_session_cb (void *cls,
|
|||||||
&dso->denom_balance,
|
&dso->denom_balance,
|
||||||
amount_with_fee))
|
amount_with_fee))
|
||||||
{
|
{
|
||||||
report_emergency (dki);
|
report_emergency (dki,
|
||||||
|
&dso->denom_risk);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
dso->denom_balance = tmp;
|
dso->denom_balance = tmp;
|
||||||
if (GNUNET_SYSERR ==
|
if (GNUNET_SYSERR ==
|
||||||
TALER_amount_subtract (&cc->total_denom_balance,
|
TALER_amount_subtract (&total_escrow_balance,
|
||||||
&cc->total_denom_balance,
|
&total_escrow_balance,
|
||||||
amount_with_fee))
|
amount_with_fee))
|
||||||
{
|
{
|
||||||
/* This should not be possible, unless the AUDITOR
|
/* This should not be possible, unless the AUDITOR
|
||||||
@ -3120,8 +3033,8 @@ refresh_session_cb (void *cls,
|
|||||||
TALER_amount_ntoh (&rfee,
|
TALER_amount_ntoh (&rfee,
|
||||||
&dki->properties.fee_refresh);
|
&dki->properties.fee_refresh);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->melt_fee_balance,
|
TALER_amount_add (&total_melt_fee_income,
|
||||||
&cc->melt_fee_balance,
|
&total_melt_fee_income,
|
||||||
&rfee))
|
&rfee))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3241,14 +3154,15 @@ deposit_cb (void *cls,
|
|||||||
&ds->denom_balance,
|
&ds->denom_balance,
|
||||||
amount_with_fee))
|
amount_with_fee))
|
||||||
{
|
{
|
||||||
report_emergency (dki);
|
report_emergency (dki,
|
||||||
|
&ds->denom_risk);
|
||||||
cc->qs = GNUNET_DB_STATUS_HARD_ERROR;
|
cc->qs = GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
ds->denom_balance = tmp;
|
ds->denom_balance = tmp;
|
||||||
if (GNUNET_SYSERR ==
|
if (GNUNET_SYSERR ==
|
||||||
TALER_amount_subtract (&cc->total_denom_balance,
|
TALER_amount_subtract (&total_escrow_balance,
|
||||||
&cc->total_denom_balance,
|
&total_escrow_balance,
|
||||||
amount_with_fee))
|
amount_with_fee))
|
||||||
{
|
{
|
||||||
/* This should not be possible, unless the AUDITOR
|
/* This should not be possible, unless the AUDITOR
|
||||||
@ -3270,8 +3184,8 @@ deposit_cb (void *cls,
|
|||||||
TALER_amount_ntoh (&dfee,
|
TALER_amount_ntoh (&dfee,
|
||||||
&dki->properties.fee_deposit);
|
&dki->properties.fee_deposit);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->deposit_fee_balance,
|
TALER_amount_add (&total_deposit_fee_income,
|
||||||
&cc->deposit_fee_balance,
|
&total_deposit_fee_income,
|
||||||
&dfee))
|
&dfee))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3401,8 +3315,8 @@ refund_cb (void *cls,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->total_denom_balance,
|
TALER_amount_add (&total_escrow_balance,
|
||||||
&cc->total_denom_balance,
|
&total_escrow_balance,
|
||||||
&amount_without_fee))
|
&amount_without_fee))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3410,8 +3324,8 @@ refund_cb (void *cls,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->risk,
|
TALER_amount_add (&total_risk,
|
||||||
&cc->risk,
|
&total_risk,
|
||||||
&amount_without_fee))
|
&amount_without_fee))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3426,8 +3340,8 @@ refund_cb (void *cls,
|
|||||||
|
|
||||||
/* update total refund fee balance */
|
/* update total refund fee balance */
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_amount_add (&cc->refund_fee_balance,
|
TALER_amount_add (&total_refund_fee_income,
|
||||||
&cc->refund_fee_balance,
|
&total_refund_fee_income,
|
||||||
&refund_fee))
|
&refund_fee))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -3461,34 +3375,16 @@ analyze_coins (void *cls)
|
|||||||
qsx = adb->get_balance_summary (adb->cls,
|
qsx = adb->get_balance_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&cc.total_denom_balance,
|
&total_escrow_balance,
|
||||||
&cc.deposit_fee_balance,
|
&total_deposit_fee_income,
|
||||||
&cc.melt_fee_balance,
|
&total_melt_fee_income,
|
||||||
&cc.refund_fee_balance,
|
&total_refund_fee_income,
|
||||||
&cc.risk);
|
&total_risk);
|
||||||
if (0 > qsx)
|
if (0 > qsx)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
||||||
return qsx;
|
return qsx;
|
||||||
}
|
}
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qsx)
|
|
||||||
{
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&cc.total_denom_balance));
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&cc.deposit_fee_balance));
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&cc.melt_fee_balance));
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&cc.refund_fee_balance));
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
TALER_amount_get_zero (currency,
|
|
||||||
&cc.risk));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process withdrawals */
|
/* process withdrawals */
|
||||||
if (0 >
|
if (0 >
|
||||||
@ -3553,30 +3449,25 @@ analyze_coins (void *cls)
|
|||||||
qs = adb->update_balance_summary (adb->cls,
|
qs = adb->update_balance_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&cc.total_denom_balance,
|
&total_escrow_balance,
|
||||||
&cc.deposit_fee_balance,
|
&total_deposit_fee_income,
|
||||||
&cc.melt_fee_balance,
|
&total_melt_fee_income,
|
||||||
&cc.refund_fee_balance,
|
&total_refund_fee_income,
|
||||||
&cc.risk);
|
&total_risk);
|
||||||
else
|
else
|
||||||
qs = adb->insert_balance_summary (adb->cls,
|
qs = adb->insert_balance_summary (adb->cls,
|
||||||
asession,
|
asession,
|
||||||
&master_pub,
|
&master_pub,
|
||||||
&cc.total_denom_balance,
|
&total_escrow_balance,
|
||||||
&cc.deposit_fee_balance,
|
&total_deposit_fee_income,
|
||||||
&cc.melt_fee_balance,
|
&total_melt_fee_income,
|
||||||
&cc.refund_fee_balance,
|
&total_refund_fee_income,
|
||||||
&cc.risk);
|
&total_risk);
|
||||||
if (0 >= qs)
|
if (0 >= qs)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
report_denomination_balance (&cc.total_denom_balance,
|
|
||||||
&cc.risk,
|
|
||||||
&cc.deposit_fee_balance,
|
|
||||||
&cc.melt_fee_balance,
|
|
||||||
&cc.refund_fee_balance);
|
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3793,6 +3684,7 @@ run (void *cls,
|
|||||||
const char *cfgfile,
|
const char *cfgfile,
|
||||||
const struct GNUNET_CONFIGURATION_Handle *c)
|
const struct GNUNET_CONFIGURATION_Handle *c)
|
||||||
{
|
{
|
||||||
|
struct TALER_Amount income_fee_total;
|
||||||
json_t *report;
|
json_t *report;
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
@ -3861,6 +3753,30 @@ run (void *cls,
|
|||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
"Starting audit\n");
|
"Starting audit\n");
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&reported_emergency_sum));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_escrow_balance));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_risk));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_withdraw_fee_income));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_deposit_fee_income));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_melt_fee_income));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_refund_fee_income));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&total_aggregation_fee_income));
|
||||||
GNUNET_assert (NULL !=
|
GNUNET_assert (NULL !=
|
||||||
(report_emergencies = json_array ()));
|
(report_emergencies = json_array ()));
|
||||||
GNUNET_assert (NULL !=
|
GNUNET_assert (NULL !=
|
||||||
@ -3873,27 +3789,48 @@ run (void *cls,
|
|||||||
(report_wire_out_inconsistencies = json_array ()));
|
(report_wire_out_inconsistencies = json_array ()));
|
||||||
GNUNET_assert (NULL !=
|
GNUNET_assert (NULL !=
|
||||||
(report_coin_inconsistencies = json_array ()));
|
(report_coin_inconsistencies = json_array ()));
|
||||||
GNUNET_assert (NULL !=
|
|
||||||
(report_reserve_balances = json_array ()));
|
|
||||||
GNUNET_assert (NULL !=
|
GNUNET_assert (NULL !=
|
||||||
(report_aggregation_fee_balances = json_array ()));
|
(report_aggregation_fee_balances = json_array ()));
|
||||||
GNUNET_assert (NULL !=
|
|
||||||
(report_denomination_balances = json_array ()));
|
|
||||||
setup_sessions_and_run ();
|
setup_sessions_and_run ();
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
"Audit complete\n");
|
"Audit complete\n");
|
||||||
TALER_AUDITORDB_plugin_unload (adb);
|
TALER_AUDITORDB_plugin_unload (adb);
|
||||||
TALER_EXCHANGEDB_plugin_unload (edb);
|
TALER_EXCHANGEDB_plugin_unload (edb);
|
||||||
report = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
|
|
||||||
|
GNUNET_assert (TALER_amount_add (&income_fee_total,
|
||||||
|
&total_withdraw_fee_income,
|
||||||
|
&total_deposit_fee_income));
|
||||||
|
GNUNET_assert (TALER_amount_add (&income_fee_total,
|
||||||
|
&income_fee_total,
|
||||||
|
&total_melt_fee_income));
|
||||||
|
GNUNET_assert (TALER_amount_add (&income_fee_total,
|
||||||
|
&income_fee_total,
|
||||||
|
&total_refund_fee_income));
|
||||||
|
GNUNET_assert (TALER_amount_add (&income_fee_total,
|
||||||
|
&income_fee_total,
|
||||||
|
&total_aggregation_fee_income));
|
||||||
|
report = json_pack ("{s:o, s:o, s:o, s:o, s:o,"
|
||||||
|
" s:o, s:o, s:o, s:o, s:o"
|
||||||
|
" s:o, s:o, s:o, s:o, s:o}",
|
||||||
|
/* blocks of 5 for easier counting/matching to format string */
|
||||||
"emergencies", report_emergencies,
|
"emergencies", report_emergencies,
|
||||||
|
"emergencies_risk_total", TALER_JSON_from_amount (&reported_emergency_sum),
|
||||||
"row_inconsistencies", report_row_inconsistencies,
|
"row_inconsistencies", report_row_inconsistencies,
|
||||||
"row_minor_inconsistencies", report_row_minor_inconsistencies,
|
"row_minor_inconsistencies", report_row_minor_inconsistencies,
|
||||||
"reserve_inconsistencies", report_reserve_inconsistencies,
|
"reserve_inconsistencies", report_reserve_inconsistencies,
|
||||||
|
/* block */
|
||||||
"wire_out_inconsistencies", report_wire_out_inconsistencies,
|
"wire_out_inconsistencies", report_wire_out_inconsistencies,
|
||||||
"coin_inconsistencies", report_coin_inconsistencies,
|
"coin_inconsistencies", report_coin_inconsistencies,
|
||||||
"reserve_balance", report_reserve_balances,
|
"total_aggregation_fee_income", TALER_JSON_from_amount (&total_aggregation_fee_income),
|
||||||
"aggregation_fee_balance", report_aggregation_fee_balances,
|
"total_escrow_balance", TALER_JSON_from_amount (&total_escrow_balance),
|
||||||
"report_denomination_balance", report_denomination_balances);
|
"total_active_risk", TALER_JSON_from_amount (&total_risk),
|
||||||
|
/* block */
|
||||||
|
"total_withdraw_fee_income", TALER_JSON_from_amount (&total_withdraw_fee_income),
|
||||||
|
"total_deposit_fee_income", TALER_JSON_from_amount (&total_deposit_fee_income),
|
||||||
|
"total_melt_fee_income", TALER_JSON_from_amount (&total_melt_fee_income),
|
||||||
|
"total_refund_fee_income", TALER_JSON_from_amount (&total_refund_fee_income),
|
||||||
|
"income_fee_total", TALER_JSON_from_amount (&income_fee_total)
|
||||||
|
);
|
||||||
json_dumpf (report,
|
json_dumpf (report,
|
||||||
stdout,
|
stdout,
|
||||||
JSON_INDENT (2));
|
JSON_INDENT (2));
|
||||||
|
@ -47,6 +47,16 @@ json_t *
|
|||||||
TALER_JSON_from_amount (const struct TALER_Amount *amount);
|
TALER_JSON_from_amount (const struct TALER_Amount *amount);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a TALER amount to a JSON object.
|
||||||
|
*
|
||||||
|
* @param amount the amount
|
||||||
|
* @return a json object describing the amount
|
||||||
|
*/
|
||||||
|
json_t *
|
||||||
|
TALER_JSON_from_amount_nbo (const struct TALER_AmountNBO *amount);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide specification to parse given JSON object to an amount.
|
* Provide specification to parse given JSON object to an amount.
|
||||||
*
|
*
|
||||||
|
@ -57,6 +57,24 @@ TALER_JSON_from_amount (const struct TALER_Amount *amount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a TALER amount to a JSON object.
|
||||||
|
*
|
||||||
|
* @param amount the amount
|
||||||
|
* @return a json object describing the amount
|
||||||
|
*/
|
||||||
|
json_t *
|
||||||
|
TALER_JSON_from_amount_nbo (const struct TALER_AmountNBO *amount)
|
||||||
|
{
|
||||||
|
struct TALER_Amount a;
|
||||||
|
|
||||||
|
TALER_amount_ntoh (&a,
|
||||||
|
amount);
|
||||||
|
return TALER_JSON_from_amount (&a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse given JSON object to Amount
|
* Parse given JSON object to Amount
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user