-more work on taler-helper-auditor-reserve p2p audits

This commit is contained in:
Christian Grothoff 2022-06-18 20:36:44 +02:00
parent f6a7d4a1ed
commit 8da74a6ca7
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 303 additions and 145 deletions

View File

@ -399,6 +399,54 @@ struct ReserveContext
}; };
/**
* Create a new reserve for @a reserve_pub in @a rc.
*
* @param[in,out] rc context to update
* @param reserve_pub key for which to create a reserve
* @return NULL on error
*/
static struct ReserveSummary *
setup_reserve (struct ReserveContext *rc,
const struct TALER_ReservePublicKeyP *reserve_pub)
{
struct ReserveSummary *rs;
struct GNUNET_HashCode key;
enum GNUNET_DB_QueryStatus qs;
GNUNET_CRYPTO_hash (reserve_pub,
sizeof (*reserve_pub),
&key);
rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key);
if (NULL != rs)
return rs;
rs = GNUNET_new (struct ReserveSummary);
rs->reserve_pub = *reserve_pub;
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&rs->total_in));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&rs->total_out));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TALER_ARL_currency,
&rs->total_fee));
if (0 > (qs = load_auditor_reserve_summary (rs)))
{
GNUNET_free (rs);
rc->qs = qs;
return NULL;
}
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key,
rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
return rs;
}
/** /**
* Function called with details about incoming wire transfers. * Function called with details about incoming wire transfers.
* *
@ -421,54 +469,26 @@ handle_reserve_in (void *cls,
struct GNUNET_TIME_Timestamp execution_date) struct GNUNET_TIME_Timestamp execution_date)
{ {
struct ReserveContext *rc = cls; struct ReserveContext *rc = cls;
struct GNUNET_HashCode key;
struct ReserveSummary *rs; struct ReserveSummary *rs;
struct GNUNET_TIME_Timestamp expiry; struct GNUNET_TIME_Timestamp expiry;
enum GNUNET_DB_QueryStatus qs;
(void) wire_reference; (void) wire_reference;
/* should be monotonically increasing */ /* should be monotonically increasing */
GNUNET_assert (rowid >= ppr.last_reserve_in_serial_id); GNUNET_assert (rowid >= ppr.last_reserve_in_serial_id);
ppr.last_reserve_in_serial_id = rowid + 1; ppr.last_reserve_in_serial_id = rowid + 1;
GNUNET_CRYPTO_hash (reserve_pub, rs = setup_reserve (rc,
sizeof (*reserve_pub), reserve_pub);
&key);
rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key);
if (NULL == rs) if (NULL == rs)
{ {
rs = GNUNET_new (struct ReserveSummary); GNUNET_break (0);
return GNUNET_SYSERR;
}
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
credit);
if (NULL == rs->sender_account)
rs->sender_account = GNUNET_strdup (sender_account_details); rs->sender_account = GNUNET_strdup (sender_account_details);
rs->reserve_pub = *reserve_pub;
rs->total_in = *credit;
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (credit->currency,
&rs->total_out));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (credit->currency,
&rs->total_fee));
if (0 > (qs = load_auditor_reserve_summary (rs)))
{
GNUNET_break (0);
GNUNET_free (rs);
rc->qs = qs;
return GNUNET_SYSERR;
}
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key,
rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
else
{
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
credit);
if (NULL == rs->sender_account)
rs->sender_account = GNUNET_strdup (sender_account_details);
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Additional incoming wire transfer for reserve `%s' of %s\n", "Additional incoming wire transfer for reserve `%s' of %s\n",
TALER_B2S (reserve_pub), TALER_B2S (reserve_pub),
@ -509,7 +529,6 @@ handle_reserve_out (void *cls,
const struct TALER_Amount *amount_with_fee) const struct TALER_Amount *amount_with_fee)
{ {
struct ReserveContext *rc = cls; struct ReserveContext *rc = cls;
struct GNUNET_HashCode key;
struct ReserveSummary *rs; struct ReserveSummary *rs;
const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue;
struct TALER_Amount auditor_amount_with_fee; struct TALER_Amount auditor_amount_with_fee;
@ -608,44 +627,16 @@ handle_reserve_out (void *cls,
rowid, rowid,
"amount with fee from exchange does not match denomination value plus fee"); "amount with fee from exchange does not match denomination value plus fee");
} }
rs = setup_reserve (rc,
reserve_pub);
GNUNET_CRYPTO_hash (reserve_pub,
sizeof (*reserve_pub),
&key);
rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key);
if (NULL == rs) if (NULL == rs)
{ {
rs = GNUNET_new (struct ReserveSummary); GNUNET_break (0);
rs->reserve_pub = *reserve_pub; return GNUNET_SYSERR;
rs->total_out = auditor_amount_with_fee;
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (amount_with_fee->currency,
&rs->total_in));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (amount_with_fee->currency,
&rs->total_fee));
qs = load_auditor_reserve_summary (rs);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
GNUNET_free (rs);
rc->qs = qs;
return GNUNET_SYSERR;
}
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key,
rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
else
{
TALER_ARL_amount_add (&rs->total_out,
&rs->total_out,
&auditor_amount_with_fee);
} }
TALER_ARL_amount_add (&rs->total_out,
&rs->total_out,
&auditor_amount_with_fee);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Reserve `%s' reduced by %s from withdraw\n", "Reserve `%s' reduced by %s from withdraw\n",
TALER_B2S (reserve_pub), TALER_B2S (reserve_pub),
@ -691,7 +682,6 @@ handle_recoup_by_reserve (
const union TALER_DenominationBlindingKeyP *coin_blind) const union TALER_DenominationBlindingKeyP *coin_blind)
{ {
struct ReserveContext *rc = cls; struct ReserveContext *rc = cls;
struct GNUNET_HashCode key;
struct ReserveSummary *rs; struct ReserveSummary *rs;
struct GNUNET_TIME_Timestamp expiry; struct GNUNET_TIME_Timestamp expiry;
struct TALER_MasterSignatureP msig; struct TALER_MasterSignatureP msig;
@ -794,42 +784,16 @@ handle_recoup_by_reserve (
amount); amount);
} }
GNUNET_CRYPTO_hash (reserve_pub, rs = setup_reserve (rc,
sizeof (*reserve_pub), reserve_pub);
&key);
rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key);
if (NULL == rs) if (NULL == rs)
{ {
rs = GNUNET_new (struct ReserveSummary); GNUNET_break (0);
rs->reserve_pub = *reserve_pub; return GNUNET_SYSERR;
rs->total_in = *amount;
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (amount->currency,
&rs->total_out));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (amount->currency,
&rs->total_fee));
qs = load_auditor_reserve_summary (rs);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
GNUNET_free (rs);
rc->qs = qs;
return GNUNET_SYSERR;
}
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key,
rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
else
{
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
amount);
} }
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
amount);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Additional /recoup value to for reserve `%s' of %s\n", "Additional /recoup value to for reserve `%s' of %s\n",
TALER_B2S (reserve_pub), TALER_B2S (reserve_pub),
@ -923,44 +887,20 @@ handle_reserve_closed (
const struct TALER_WireTransferIdentifierRawP *transfer_details) const struct TALER_WireTransferIdentifierRawP *transfer_details)
{ {
struct ReserveContext *rc = cls; struct ReserveContext *rc = cls;
struct GNUNET_HashCode key;
struct ReserveSummary *rs; struct ReserveSummary *rs;
enum GNUNET_DB_QueryStatus qs;
(void) transfer_details; (void) transfer_details;
/* should be monotonically increasing */ /* should be monotonically increasing */
GNUNET_assert (rowid >= ppr.last_reserve_close_serial_id); GNUNET_assert (rowid >= ppr.last_reserve_close_serial_id);
ppr.last_reserve_close_serial_id = rowid + 1; ppr.last_reserve_close_serial_id = rowid + 1;
GNUNET_CRYPTO_hash (reserve_pub, rs = setup_reserve (rc,
sizeof (*reserve_pub), reserve_pub);
&key);
rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key);
if (NULL == rs) if (NULL == rs)
{ {
rs = GNUNET_new (struct ReserveSummary); GNUNET_break (0);
rs->reserve_pub = *reserve_pub; return GNUNET_SYSERR;
rs->total_out = *amount_with_fee;
rs->total_fee = *closing_fee;
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (amount_with_fee->currency,
&rs->total_in));
qs = load_auditor_reserve_summary (rs);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
GNUNET_free (rs);
rc->qs = qs;
return GNUNET_SYSERR;
}
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key,
rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
} }
else
{ {
struct TALER_Amount expected_fee; struct TALER_Amount expected_fee;
@ -1088,7 +1028,7 @@ verify_reserve_balance (void *cls,
making an illegitimate gain over the amount it dropped. making an illegitimate gain over the amount it dropped.
We don't add the amount to some total simply because it is We don't add the amount to some total simply because it is
not an actualized gain and could be trivially corrected by not an actualized gain and could be trivially corrected by
restoring the summary. */// restoring the summary. */
TALER_ARL_report (report_reserve_balance_insufficient_inconsistencies, TALER_ARL_report (report_reserve_balance_insufficient_inconsistencies,
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("reserve_pub", GNUNET_JSON_pack_data_auto ("reserve_pub",
@ -1325,7 +1265,36 @@ handle_purse_deposits (
const struct TALER_EXCHANGEDB_PurseDeposit *deposit, const struct TALER_EXCHANGEDB_PurseDeposit *deposit,
const struct TALER_DenominationPublicKey *denom_pub) const struct TALER_DenominationPublicKey *denom_pub)
{ {
const char *base_url
= (NULL == deposit->exchange_base_url)
? TALER_ARL_exchange_url
: deposit->exchange_base_url;
if (GNUNET_OK !=
TALER_wallet_purse_deposit_verify (base_url,
&deposit->purse_pub,
&deposit->amount,
&deposit->coin_pub,
&deposit->coin_sig))
{
TALER_ARL_report (report_bad_sig_losses,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("operation",
"purse-deposit"),
GNUNET_JSON_pack_uint64 ("row",
rowid),
TALER_JSON_pack_amount ("loss",
&deposit->amount),
GNUNET_JSON_pack_data_auto ("key_pub",
&deposit->coin_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss,
&total_bad_sig_loss,
&deposit->amount);
return GNUNET_OK;
}
GNUNET_break (0); // FIXME GNUNET_break (0); // FIXME
// FIXME: need flags + total deposited!
/* Credit purse value (if last op)! */ /* Credit purse value (if last op)! */
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
@ -1353,9 +1322,65 @@ handle_purse_merged (
const struct TALER_PurseContractPublicKeyP *purse_pub, const struct TALER_PurseContractPublicKeyP *purse_pub,
struct GNUNET_TIME_Timestamp merge_timestamp) struct GNUNET_TIME_Timestamp merge_timestamp)
{ {
GNUNET_break (0); // FIXME struct ReserveContext *rc = cls;
/* Credit purse value (if last op)! */ struct ReserveSummary *rs;
return GNUNET_SYSERR; char *reserve_url;
reserve_url
= TALER_reserve_make_payto (NULL == partner_base_url
? TALER_ARL_exchange_url
: partner_base_url,
reserve_pub);
if (GNUNET_OK !=
TALER_wallet_purse_merge_verify (reserve_url,
merge_timestamp,
purse_pub,
merge_pub,
merge_sig))
{
GNUNET_free (reserve_url);
TALER_ARL_report (report_bad_sig_losses,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("operation",
"merge-purse"),
GNUNET_JSON_pack_uint64 ("row",
rowid),
TALER_JSON_pack_amount ("loss",
amount),
GNUNET_JSON_pack_data_auto ("key_pub",
merge_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss,
&total_bad_sig_loss,
amount);
return GNUNET_OK;
}
GNUNET_free (reserve_url);
if (TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE ==
(flags & TALER_WAMF_MERGE_MODE_MASK))
{
/* This just created the purse, actual credit to
the reserve will be done in handle_purse_deposits() */
return GNUNET_OK;
}
if ( (NULL != partner_base_url) &&
(0 != strcmp (partner_base_url,
TALER_ARL_exchange_url)) )
{
/* credited reserve is at another exchange, do NOT credit here! */
return GNUNET_OK;
}
rs = setup_reserve (rc,
reserve_pub);
if (NULL == rs)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
TALER_ARL_amount_add (&rs->total_in,
&rs->total_in,
amount);
// rs->a_expiration_date = FIXME: set to what?;
return GNUNET_OK;
} }
@ -1383,9 +1408,50 @@ handle_account_merged (
struct GNUNET_TIME_Timestamp merge_timestamp, struct GNUNET_TIME_Timestamp merge_timestamp,
const struct TALER_ReserveSignatureP *reserve_sig) const struct TALER_ReserveSignatureP *reserve_sig)
{ {
GNUNET_break (0); // FIXME struct ReserveContext *rc = cls;
/* Debit purse fee */ struct ReserveSummary *rs;
return GNUNET_SYSERR;
if (GNUNET_OK !=
TALER_wallet_account_merge_verify (merge_timestamp,
purse_pub,
purse_expiration,
h_contract_terms,
amount,
purse_fee,
min_age,
flags,
reserve_pub,
reserve_sig))
{
TALER_ARL_report (report_bad_sig_losses,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("operation",
"account-merge"),
GNUNET_JSON_pack_uint64 ("row",
rowid),
TALER_JSON_pack_amount ("loss",
purse_fee),
GNUNET_JSON_pack_data_auto ("key_pub",
reserve_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss,
&total_bad_sig_loss,
purse_fee);
return GNUNET_OK;
}
rs = setup_reserve (rc,
reserve_pub);
if (NULL == rs)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
TALER_ARL_amount_add (&total_purse_fee_income,
&total_purse_fee_income,
purse_fee);
TALER_ARL_amount_add (&rs->total_out,
&rs->total_out,
purse_fee);
return GNUNET_OK;
} }
@ -1407,9 +1473,44 @@ handle_history_request (
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_ReserveSignatureP *reserve_sig) const struct TALER_ReserveSignatureP *reserve_sig)
{ {
GNUNET_break (0); // FIXME struct ReserveContext *rc = cls;
/* Debit purse fee */ struct ReserveSummary *rs;
return GNUNET_SYSERR;
if (GNUNET_OK !=
TALER_wallet_reserve_history_verify (ts,
history_fee,
reserve_pub,
reserve_sig))
{
TALER_ARL_report (report_bad_sig_losses,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("operation",
"account-history"),
GNUNET_JSON_pack_uint64 ("row",
rowid),
TALER_JSON_pack_amount ("loss",
history_fee),
GNUNET_JSON_pack_data_auto ("key_pub",
reserve_pub)));
TALER_ARL_amount_add (&total_bad_sig_loss,
&total_bad_sig_loss,
history_fee);
return GNUNET_OK;
}
rs = setup_reserve (rc,
reserve_pub);
if (NULL == rs)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
TALER_ARL_amount_add (&total_history_fee_income,
&total_history_fee_income,
history_fee);
TALER_ARL_amount_add (&rs->total_out,
&rs->total_out,
history_fee);
return GNUNET_OK;
} }

View File

@ -417,6 +417,19 @@ char *
TALER_payto_validate (const char *payto_uri); TALER_payto_validate (const char *payto_uri);
/**
* Create payto://-URI for a given exchange base URL
* and a @a reserve_pub.
*
* @param exchange_url the base URL of the exchange
* @param reserve_pub the public key of the reserve
* @return payto://-URI for the reserve (without receiver-name!)
*/
char *
TALER_reserve_make_payto (const char *exchange_url,
const struct TALER_ReservePublicKeyP *reserve_pub);
/** /**
* Check that an IBAN number is well-formed. * Check that an IBAN number is well-formed.
* *

View File

@ -312,4 +312,48 @@ TALER_payto_from_reserve (const char *exchange_base_url,
} }
char *
TALER_reserve_make_payto (const char *exchange_url,
const struct TALER_ReservePublicKeyP *reserve_pub)
{
char pub_str[sizeof (*reserve_pub) * 2];
char *end;
bool is_http;
char *reserve_url;
end = GNUNET_STRINGS_data_to_string (
reserve_pub,
sizeof (*reserve_pub),
pub_str,
sizeof (pub_str));
*end = '\0';
if (0 == strncmp (exchange_url,
"http://",
strlen ("http://")))
{
is_http = true;
exchange_url = &exchange_url[strlen ("http://")];
}
else if (0 == strncmp (exchange_url,
"https://",
strlen ("https://")))
{
is_http = false;
exchange_url = &exchange_url[strlen ("https://")];
}
else
{
GNUNET_break (0);
return NULL;
}
/* exchange_url includes trailing '/' */
GNUNET_asprintf (&reserve_url,
"payto://%s/%s%s",
is_http ? "taler+http" : "taler",
exchange_url,
pub_str);
return reserve_url;
}
/* end of payto.c */ /* end of payto.c */