completing reserves_in logic of taler-wire-auditor, but not tested
This commit is contained in:
parent
cc5d09cf1d
commit
600d1684e3
@ -21,7 +21,7 @@
|
|||||||
* - First, this auditor verifies that 'reserves_in' actually matches
|
* - First, this auditor verifies that 'reserves_in' actually matches
|
||||||
* the incoming wire transfers from the bank.
|
* the incoming wire transfers from the bank.
|
||||||
* - Second, we check that the outgoing wire transfers match those
|
* - Second, we check that the outgoing wire transfers match those
|
||||||
* given in the 'wire_out' table.
|
* given in the 'wire_out' table (TODO!)
|
||||||
*/
|
*/
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include <gnunet/gnunet_util_lib.h>
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
@ -62,6 +62,12 @@ static char *currency;
|
|||||||
*/
|
*/
|
||||||
static const struct GNUNET_CONFIGURATION_Handle *cfg;
|
static const struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map with information about incoming wire transfers.
|
||||||
|
* Maps hashes of the wire offsets to `struct ReserveInInfo`s.
|
||||||
|
*/
|
||||||
|
static struct GNUNET_CONTAINER_MultiHashMap *in_map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our session with the #edb.
|
* Our session with the #edb.
|
||||||
*/
|
*/
|
||||||
@ -120,6 +126,61 @@ static size_t wire_off_size;
|
|||||||
|
|
||||||
/* ***************************** Shutdown **************************** */
|
/* ***************************** Shutdown **************************** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry in map with wire information we expect to obtain from the
|
||||||
|
* #edb later.
|
||||||
|
*/
|
||||||
|
struct ReserveInInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash of expected row offset.
|
||||||
|
*/
|
||||||
|
struct GNUNET_HashCode row_off_hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes in @e row_off.
|
||||||
|
*/
|
||||||
|
size_t row_off_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected details about the wire transfer.
|
||||||
|
*/
|
||||||
|
struct TALER_WIRE_TransferDetails details;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RowID in reserves_in table.
|
||||||
|
*/
|
||||||
|
uint64_t rowid;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free entry in #in_map.
|
||||||
|
*
|
||||||
|
* @param cls NULL
|
||||||
|
* @param key unused key
|
||||||
|
* @param value the `struct ReserveInInfo` to free
|
||||||
|
* @return #GNUNET_OK
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
free_rii (void *cls,
|
||||||
|
const struct GNUNET_HashCode *key,
|
||||||
|
void *value)
|
||||||
|
{
|
||||||
|
struct ReserveInInfo *rii = value;
|
||||||
|
|
||||||
|
GNUNET_assert (GNUNET_YES ==
|
||||||
|
GNUNET_CONTAINER_multihashmap_remove (in_map,
|
||||||
|
key,
|
||||||
|
rii));
|
||||||
|
json_decref (rii->details.account_details);
|
||||||
|
GNUNET_free (rii);
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task run on shutdown.
|
* Task run on shutdown.
|
||||||
*
|
*
|
||||||
@ -134,6 +195,14 @@ do_shutdown (void *cls)
|
|||||||
hh);
|
hh);
|
||||||
hh = NULL;
|
hh = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != in_map)
|
||||||
|
{
|
||||||
|
GNUNET_CONTAINER_multihashmap_iterate (in_map,
|
||||||
|
&free_rii,
|
||||||
|
NULL);
|
||||||
|
GNUNET_CONTAINER_multihashmap_destroy (in_map);
|
||||||
|
in_map = NULL;
|
||||||
|
}
|
||||||
if (NULL != wp)
|
if (NULL != wp)
|
||||||
{
|
{
|
||||||
TALER_WIRE_plugin_unload (wp);
|
TALER_WIRE_plugin_unload (wp);
|
||||||
@ -154,7 +223,6 @@ do_shutdown (void *cls)
|
|||||||
|
|
||||||
/* ***************************** Report logic **************************** */
|
/* ***************************** Report logic **************************** */
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* Report a (serious) inconsistency in the exchange's database.
|
* Report a (serious) inconsistency in the exchange's database.
|
||||||
*
|
*
|
||||||
@ -196,7 +264,6 @@ report_row_minor_inconsistency (const char *table,
|
|||||||
(unsigned long long) rowid,
|
(unsigned long long) rowid,
|
||||||
diagnostic);
|
diagnostic);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* *************************** General transaction logic ****************** */
|
/* *************************** General transaction logic ****************** */
|
||||||
@ -291,9 +358,102 @@ commit (enum GNUNET_DB_QueryStatus qs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************************** Analyze reserves_out ************************ */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main functin for processing reserves_out data.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
process_debits ()
|
||||||
|
{
|
||||||
|
/* TODO: also check DEBITs! */
|
||||||
|
|
||||||
|
/* conclude with: */
|
||||||
|
commit (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT);
|
||||||
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ***************************** Analyze reserves_in ************************ */
|
/* ***************************** Analyze reserves_in ************************ */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called with details about incoming wire transfers
|
||||||
|
* as claimed by the exchange DB.
|
||||||
|
*
|
||||||
|
* @param cls NULL
|
||||||
|
* @param rowid unique serial ID for the refresh session in our DB
|
||||||
|
* @param reserve_pub public key of the reserve (also the WTID)
|
||||||
|
* @param credit amount that was received
|
||||||
|
* @param sender_account_details information about the sender's bank account
|
||||||
|
* @param wire_reference unique identifier for the wire transfer (plugin-specific format)
|
||||||
|
* @param wire_reference_size number of bytes in @a wire_reference
|
||||||
|
* @param execution_date when did we receive the funds
|
||||||
|
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
reserve_in_cb (void *cls,
|
||||||
|
uint64_t rowid,
|
||||||
|
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
|
const struct TALER_Amount *credit,
|
||||||
|
const json_t *sender_account_details,
|
||||||
|
const void *wire_reference,
|
||||||
|
size_t wire_reference_size,
|
||||||
|
struct GNUNET_TIME_Absolute execution_date)
|
||||||
|
|
||||||
|
{
|
||||||
|
struct ReserveInInfo *rii;
|
||||||
|
|
||||||
|
rii = GNUNET_new (struct ReserveInInfo);
|
||||||
|
GNUNET_CRYPTO_hash (wire_reference,
|
||||||
|
wire_reference_size,
|
||||||
|
&rii->row_off_hash);
|
||||||
|
rii->row_off_size = wire_reference_size;
|
||||||
|
rii->details.amount = *credit;
|
||||||
|
rii->details.execution_date = execution_date;
|
||||||
|
rii->details.reserve_pub = *reserve_pub;
|
||||||
|
rii->details.account_details = json_incref ((json_t *) sender_account_details);
|
||||||
|
rii->rowid = rowid;
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CONTAINER_multihashmap_put (in_map,
|
||||||
|
&rii->row_off_hash,
|
||||||
|
rii,
|
||||||
|
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0); /* duplicate wire offset is not allowed! */
|
||||||
|
report_row_inconsistency ("reserves_in",
|
||||||
|
rowid,
|
||||||
|
"duplicate wire offset");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
pp.last_reserve_in_serial_id = rowid + 1;
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complain that we failed to match an entry from #in_map.
|
||||||
|
*
|
||||||
|
* @param cls NULL
|
||||||
|
* @param key unused key
|
||||||
|
* @param value the `struct ReserveInInfo` to free
|
||||||
|
* @return #GNUNET_OK
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
complain_not_found (void *cls,
|
||||||
|
const struct GNUNET_HashCode *key,
|
||||||
|
void *value)
|
||||||
|
{
|
||||||
|
struct ReserveInInfo *rii = value;
|
||||||
|
|
||||||
|
report_row_inconsistency ("reserves_in",
|
||||||
|
rii->rowid,
|
||||||
|
"matching wire transfer not found");
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks of this type are used to serve the result of asking
|
* Callbacks of this type are used to serve the result of asking
|
||||||
* the bank for the transaction history.
|
* the bank for the transaction history.
|
||||||
@ -312,21 +472,107 @@ history_credit_cb (void *cls,
|
|||||||
size_t row_off_size,
|
size_t row_off_size,
|
||||||
const struct TALER_WIRE_TransferDetails *details)
|
const struct TALER_WIRE_TransferDetails *details)
|
||||||
{
|
{
|
||||||
if (NULL == details)
|
struct ReserveInInfo *rii;
|
||||||
|
struct GNUNET_HashCode key;
|
||||||
|
|
||||||
|
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||||
{
|
{
|
||||||
/* end of operation */
|
/* end of operation */
|
||||||
hh = NULL;
|
hh = NULL;
|
||||||
/* TODO: also check DEBITs! */
|
GNUNET_CONTAINER_multihashmap_iterate (in_map,
|
||||||
commit (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT);
|
&complain_not_found,
|
||||||
|
NULL);
|
||||||
|
/* clean up before 2nd phase */
|
||||||
|
GNUNET_CONTAINER_multihashmap_iterate (in_map,
|
||||||
|
&free_rii,
|
||||||
|
NULL);
|
||||||
|
GNUNET_CONTAINER_multihashmap_destroy (in_map);
|
||||||
|
in_map = NULL;
|
||||||
|
process_debits ();
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
GNUNET_CRYPTO_hash (row_off,
|
||||||
|
row_off_size,
|
||||||
|
&key);
|
||||||
|
rii = GNUNET_CONTAINER_multihashmap_get (in_map,
|
||||||
|
&key);
|
||||||
|
if (NULL == rii)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"Failed to find wire transfer at `%s' in exchange database. Audit ends at this point in time.\n",
|
||||||
|
GNUNET_STRINGS_absolute_time_to_string (details->execution_date));
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update offset */
|
||||||
|
if (NULL == in_wire_off)
|
||||||
|
{
|
||||||
|
wire_off_size = row_off_size;
|
||||||
|
in_wire_off = GNUNET_malloc (row_off_size);
|
||||||
|
}
|
||||||
|
if (wire_off_size != row_off_size)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
commit (GNUNET_DB_STATUS_HARD_ERROR);
|
||||||
GNUNET_SCHEDULER_shutdown ();
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
/* TODO: implement actual checks! */
|
memcpy (in_wire_off,
|
||||||
|
row_off,
|
||||||
|
row_off_size);
|
||||||
|
|
||||||
|
/* compare records with expected data */
|
||||||
|
if (row_off_size != rii->row_off_size)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
report_row_inconsistency ("reserves_in",
|
||||||
|
rii->rowid,
|
||||||
|
"wire reference size missmatch");
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
if (0 != TALER_amount_cmp (&rii->details.amount,
|
||||||
|
&details->amount))
|
||||||
|
{
|
||||||
|
report_row_inconsistency ("reserves_in",
|
||||||
|
rii->rowid,
|
||||||
|
"wire amount missmatch");
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
if (details->execution_date.abs_value_us !=
|
||||||
|
rii->details.execution_date.abs_value_us)
|
||||||
|
{
|
||||||
|
report_row_minor_inconsistency ("reserves_in",
|
||||||
|
rii->rowid,
|
||||||
|
"execution date missmatch");
|
||||||
|
}
|
||||||
|
if (0 != memcmp (&details->reserve_pub,
|
||||||
|
&rii->details.reserve_pub,
|
||||||
|
sizeof (struct TALER_ReservePublicKeyP)))
|
||||||
|
{
|
||||||
|
report_row_inconsistency ("reserves_in",
|
||||||
|
rii->rowid,
|
||||||
|
"reserve public key / wire subject missmatch");
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
if (! json_equal (details->account_details,
|
||||||
|
rii->details.account_details))
|
||||||
|
{
|
||||||
|
report_row_minor_inconsistency ("reserves_in",
|
||||||
|
rii->rowid,
|
||||||
|
"sender account missmatch");
|
||||||
|
}
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
GNUNET_CONTAINER_multihashmap_remove (in_map,
|
||||||
|
&key,
|
||||||
|
rii));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
free_rii (NULL,
|
||||||
|
&key,
|
||||||
|
rii));
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ***************************** Setup logic ************************ */
|
/* ***************************** Setup logic ************************ */
|
||||||
|
|
||||||
|
|
||||||
@ -344,6 +590,7 @@ run (void *cls,
|
|||||||
const char *cfgfile,
|
const char *cfgfile,
|
||||||
const struct GNUNET_CONFIGURATION_Handle *c)
|
const struct GNUNET_CONFIGURATION_Handle *c)
|
||||||
{
|
{
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
@ -475,6 +722,27 @@ run (void *cls,
|
|||||||
(unsigned long long) pp.last_reserve_out_serial_id);
|
(unsigned long long) pp.last_reserve_out_serial_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
in_map = GNUNET_CONTAINER_multihashmap_create (1024,
|
||||||
|
GNUNET_YES);
|
||||||
|
qs = edb->select_reserves_in_above_serial_id (edb->cls,
|
||||||
|
esession,
|
||||||
|
pp.last_reserve_in_serial_id,
|
||||||
|
&reserve_in_cb,
|
||||||
|
NULL);
|
||||||
|
if (0 > qs)
|
||||||
|
{
|
||||||
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
|
||||||
|
global_ret = 1;
|
||||||
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
|
||||||
|
"No new incoming transactions available, skipping CREDIT phase\n");
|
||||||
|
process_debits ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
hh = wp->get_history (wp->cls,
|
hh = wp->get_history (wp->cls,
|
||||||
TALER_BANK_DIRECTION_CREDIT,
|
TALER_BANK_DIRECTION_CREDIT,
|
||||||
in_wire_off,
|
in_wire_off,
|
||||||
|
Loading…
Reference in New Issue
Block a user