diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-11-06 00:03:08 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-11-06 00:03:08 +0100 |
commit | c5f9c0ca8872b8f2b4d23f3b53d2046e6fd53ef9 (patch) | |
tree | 21d3aa0b91178b8608039f8a91c1546f9cab9bd2 /src | |
parent | 2ddd4cb3306e8ce7f80118f58716a2720b00d9fa (diff) |
work on making auditor reports nicer (#4962)
Diffstat (limited to 'src')
-rw-r--r-- | src/auditor/taler-auditor.c | 405 | ||||
-rw-r--r-- | src/include/taler_json_lib.h | 10 | ||||
-rw-r--r-- | src/json/json_helper.c | 18 |
3 files changed, 199 insertions, 234 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 1e69e3108..4dbcaea89 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -145,19 +145,50 @@ static json_t *report_wire_out_inconsistencies; static json_t *report_coin_inconsistencies; /** - * Report about expected reserve balances. + * Report about aggregate wire transfer fee profits. */ -static json_t *report_reserve_balances; +static json_t *report_aggregation_fee_balances; /** - * Report about aggregate wire transfer fee profits. + * Total amount reported in all calls to #report_emergency(). */ -static json_t *report_aggregation_fee_balances; +static struct TALER_Amount reported_emergency_sum; + +/** + * Expected balance in the escrow account. + */ +static struct TALER_Amount total_escrow_balance; /** - * Report about denomination fee balances. + * Active risk exposure. */ -static json_t *report_denomination_balances; +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 **************************** */ @@ -168,7 +199,7 @@ static json_t *report_denomination_balances; * * @param array report array to append @a object to * @param object object to append, should be check that it is not NULL - */ + */ static void report (json_t *array, json_t *object) @@ -189,14 +220,28 @@ report (json_t *array, * denomination (and as an exchange suffer a huge financial loss). * * @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 -report_emergency (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki) +report_emergency (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki, + const struct TALER_Amount *risk) { report (report_emergencies, - json_pack ("{s:o}", + json_pack ("{s:o, s:o, s:s, s:s, s:o}", "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 ************************ */ /** @@ -663,16 +628,6 @@ struct ReserveContext 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. */ enum GNUNET_DB_QueryStatus qs; @@ -1261,16 +1216,16 @@ verify_reserve_balance (void *cls, goto cleanup; } if ( (GNUNET_YES != - TALER_amount_add (&rc->total_balance, - &rc->total_balance, + TALER_amount_add (&total_escrow_balance, + &total_escrow_balance, &rs->total_in)) || (GNUNET_SYSERR == - TALER_amount_subtract (&rc->total_balance, - &rc->total_balance, + TALER_amount_subtract (&total_escrow_balance, + &total_escrow_balance, &rs->total_out)) || (GNUNET_YES != - TALER_amount_add (&rc->total_fee_balance, - &rc->total_fee_balance, + TALER_amount_add (&total_withdraw_fee_income, + &total_withdraw_fee_income, &rs->total_fee)) ) { GNUNET_break (0); @@ -1367,23 +1322,13 @@ analyze_reserves (void *cls) qsx = adb->get_reserve_summary (adb->cls, asession, &master_pub, - &rc.total_balance, - &rc.total_fee_balance); + &total_escrow_balance, + &total_withdraw_fee_income); if (qsx < 0) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == 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, GNUNET_NO); rc.revoked = GNUNET_CONTAINER_multihashmap_create (4, @@ -1446,24 +1391,22 @@ analyze_reserves (void *cls) qs = adb->insert_reserve_summary (adb->cls, asession, &master_pub, - &rc.total_balance, - &rc.total_fee_balance); + &total_escrow_balance, + &total_withdraw_fee_income); } else { qs = adb->update_reserve_summary (adb->cls, asession, &master_pub, - &rc.total_balance, - &rc.total_fee_balance); + &total_escrow_balance, + &total_withdraw_fee_income); } if (0 >= qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - report_reserve_balance (&rc.total_balance, - &rc.total_fee_balance); return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; } @@ -1565,7 +1508,7 @@ struct AggregationContext /** * How much did we make in aggregation fees. */ - struct TALER_Amount total_aggregation_fees; + struct TALER_Amount total_aggregation_feesX; /** * Final result status. @@ -2341,8 +2284,8 @@ check_wire_out_cb (void *cls, /* Sum up aggregation fees (we simply include the rounding gains) */ if (GNUNET_OK != - TALER_amount_add (&ac->total_aggregation_fees, - &ac->total_aggregation_fees, + TALER_amount_add (&total_aggregation_fee_income, + &total_aggregation_fee_income, &exchange_gain)) { GNUNET_break (0); @@ -2393,16 +2336,12 @@ analyze_aggregations (void *cls) qsx = adb->get_wire_fee_summary (adb->cls, asession, &master_pub, - &ac.total_aggregation_fees); + &total_aggregation_fee_income); if (0 > qsx) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == 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; qs = edb->select_wire_out_above_serial_id (edb->cls, esession, @@ -2439,18 +2378,17 @@ analyze_aggregations (void *cls) ac.qs = adb->insert_wire_fee_summary (adb->cls, asession, &master_pub, - &ac.total_aggregation_fees); + &total_aggregation_fee_income); else ac.qs = adb->update_wire_fee_summary (adb->cls, asession, &master_pub, - &ac.total_aggregation_fees); + &total_aggregation_fee_income); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ac.qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == ac.qs); return ac.qs; } - report_aggregation_fee_balance (&ac.total_aggregation_fees); return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; } @@ -2503,32 +2441,6 @@ struct CoinContext 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. */ unsigned int summaries_off; @@ -2670,8 +2582,8 @@ sync_denomination (void *cls, book the remaining balance as profit, and reduce our risk exposure by the accumulated risk of the denomination. */ if (GNUNET_SYSERR == - TALER_amount_subtract (&cc->risk, - &cc->risk, + TALER_amount_subtract (&total_risk, + &total_risk, &ds->denom_risk)) { /* Holy smokes, our risk assessment was inconsistent! @@ -2815,8 +2727,8 @@ withdraw_cb (void *cls, GNUNET_h2s (&dh), TALER_amount2s (&ds->denom_balance)); if (GNUNET_OK != - TALER_amount_add (&cc->total_denom_balance, - &cc->total_denom_balance, + TALER_amount_add (&total_escrow_balance, + &total_escrow_balance, &value)) { GNUNET_break (0); @@ -2824,8 +2736,8 @@ withdraw_cb (void *cls, return GNUNET_SYSERR; } if (GNUNET_OK != - TALER_amount_add (&cc->risk, - &cc->risk, + TALER_amount_add (&total_risk, + &total_risk, &value)) { GNUNET_break (0); @@ -3058,8 +2970,8 @@ refresh_session_cb (void *cls, GNUNET_h2s (&new_dki[i]->properties.denom_hash), TALER_amount2s (&dsi->denom_balance)); if (GNUNET_OK != - TALER_amount_add (&cc->total_denom_balance, - &cc->total_denom_balance, + TALER_amount_add (&total_escrow_balance, + &total_escrow_balance, &value)) { GNUNET_break (0); @@ -3067,8 +2979,8 @@ refresh_session_cb (void *cls, return GNUNET_SYSERR; } if (GNUNET_OK != - TALER_amount_add (&cc->risk, - &cc->risk, + TALER_amount_add (&total_risk, + &total_risk, &value)) { GNUNET_break (0); @@ -3092,13 +3004,14 @@ refresh_session_cb (void *cls, &dso->denom_balance, amount_with_fee)) { - report_emergency (dki); + report_emergency (dki, + &dso->denom_risk); return GNUNET_SYSERR; } dso->denom_balance = tmp; if (GNUNET_SYSERR == - TALER_amount_subtract (&cc->total_denom_balance, - &cc->total_denom_balance, + TALER_amount_subtract (&total_escrow_balance, + &total_escrow_balance, amount_with_fee)) { /* This should not be possible, unless the AUDITOR @@ -3120,8 +3033,8 @@ refresh_session_cb (void *cls, TALER_amount_ntoh (&rfee, &dki->properties.fee_refresh); if (GNUNET_OK != - TALER_amount_add (&cc->melt_fee_balance, - &cc->melt_fee_balance, + TALER_amount_add (&total_melt_fee_income, + &total_melt_fee_income, &rfee)) { GNUNET_break (0); @@ -3241,14 +3154,15 @@ deposit_cb (void *cls, &ds->denom_balance, amount_with_fee)) { - report_emergency (dki); + report_emergency (dki, + &ds->denom_risk); cc->qs = GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_SYSERR; } ds->denom_balance = tmp; if (GNUNET_SYSERR == - TALER_amount_subtract (&cc->total_denom_balance, - &cc->total_denom_balance, + TALER_amount_subtract (&total_escrow_balance, + &total_escrow_balance, amount_with_fee)) { /* This should not be possible, unless the AUDITOR @@ -3270,8 +3184,8 @@ deposit_cb (void *cls, TALER_amount_ntoh (&dfee, &dki->properties.fee_deposit); if (GNUNET_OK != - TALER_amount_add (&cc->deposit_fee_balance, - &cc->deposit_fee_balance, + TALER_amount_add (&total_deposit_fee_income, + &total_deposit_fee_income, &dfee)) { GNUNET_break (0); @@ -3401,8 +3315,8 @@ refund_cb (void *cls, return GNUNET_SYSERR; } if (GNUNET_OK != - TALER_amount_add (&cc->total_denom_balance, - &cc->total_denom_balance, + TALER_amount_add (&total_escrow_balance, + &total_escrow_balance, &amount_without_fee)) { GNUNET_break (0); @@ -3410,8 +3324,8 @@ refund_cb (void *cls, return GNUNET_SYSERR; } if (GNUNET_OK != - TALER_amount_add (&cc->risk, - &cc->risk, + TALER_amount_add (&total_risk, + &total_risk, &amount_without_fee)) { GNUNET_break (0); @@ -3426,8 +3340,8 @@ refund_cb (void *cls, /* update total refund fee balance */ if (GNUNET_OK != - TALER_amount_add (&cc->refund_fee_balance, - &cc->refund_fee_balance, + TALER_amount_add (&total_refund_fee_income, + &total_refund_fee_income, &refund_fee)) { GNUNET_break (0); @@ -3461,34 +3375,16 @@ analyze_coins (void *cls) qsx = adb->get_balance_summary (adb->cls, asession, &master_pub, - &cc.total_denom_balance, - &cc.deposit_fee_balance, - &cc.melt_fee_balance, - &cc.refund_fee_balance, - &cc.risk); + &total_escrow_balance, + &total_deposit_fee_income, + &total_melt_fee_income, + &total_refund_fee_income, + &total_risk); if (0 > qsx) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == 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 */ if (0 > @@ -3553,30 +3449,25 @@ analyze_coins (void *cls) qs = adb->update_balance_summary (adb->cls, asession, &master_pub, - &cc.total_denom_balance, - &cc.deposit_fee_balance, - &cc.melt_fee_balance, - &cc.refund_fee_balance, - &cc.risk); + &total_escrow_balance, + &total_deposit_fee_income, + &total_melt_fee_income, + &total_refund_fee_income, + &total_risk); else qs = adb->insert_balance_summary (adb->cls, asession, &master_pub, - &cc.total_denom_balance, - &cc.deposit_fee_balance, - &cc.melt_fee_balance, - &cc.refund_fee_balance, - &cc.risk); + &total_escrow_balance, + &total_deposit_fee_income, + &total_melt_fee_income, + &total_refund_fee_income, + &total_risk); if (0 >= qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == 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; } @@ -3793,8 +3684,9 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { + struct TALER_Amount income_fee_total; json_t *report; - + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching auditor\n"); cfg = c; @@ -3861,6 +3753,30 @@ run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "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 != (report_emergencies = json_array ())); GNUNET_assert (NULL != @@ -3874,26 +3790,47 @@ run (void *cls, GNUNET_assert (NULL != (report_coin_inconsistencies = json_array ())); GNUNET_assert (NULL != - (report_reserve_balances = json_array ())); - GNUNET_assert (NULL != (report_aggregation_fee_balances = json_array ())); - GNUNET_assert (NULL != - (report_denomination_balances = json_array ())); setup_sessions_and_run (); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audit complete\n"); TALER_AUDITORDB_plugin_unload (adb); 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_risk_total", TALER_JSON_from_amount (&reported_emergency_sum), "row_inconsistencies", report_row_inconsistencies, "row_minor_inconsistencies", report_row_minor_inconsistencies, "reserve_inconsistencies", report_reserve_inconsistencies, + /* block */ "wire_out_inconsistencies", report_wire_out_inconsistencies, "coin_inconsistencies", report_coin_inconsistencies, - "reserve_balance", report_reserve_balances, - "aggregation_fee_balance", report_aggregation_fee_balances, - "report_denomination_balance", report_denomination_balances); + "total_aggregation_fee_income", TALER_JSON_from_amount (&total_aggregation_fee_income), + "total_escrow_balance", TALER_JSON_from_amount (&total_escrow_balance), + "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, stdout, JSON_INDENT (2)); diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index 248de9c45..6d019ecca 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -48,6 +48,16 @@ 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. * * @param name name of the amount field in the JSON diff --git a/src/json/json_helper.c b/src/json/json_helper.c index fec637bde..4f966c66f 100644 --- a/src/json/json_helper.c +++ b/src/json/json_helper.c @@ -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 * |