summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-03-15 14:19:57 +0100
committerChristian Grothoff <christian@grothoff.org>2017-03-15 14:19:57 +0100
commit36195e85ea55eb95152f0b9b10210e9d1b35903a (patch)
tree07814407a9b57412ce5d006694b400680a2413a9
parent54b3a9e9305bd1edd2529e5d0b95cf6943026fc6 (diff)
downloadexchange-36195e85ea55eb95152f0b9b10210e9d1b35903a.tar.gz
exchange-36195e85ea55eb95152f0b9b10210e9d1b35903a.tar.bz2
exchange-36195e85ea55eb95152f0b9b10210e9d1b35903a.zip
skeleton logic for analyze_coins()
-rw-r--r--src/auditor/taler-auditor.c361
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c2
-rw-r--r--src/include/taler_auditordb_plugin.h2
3 files changed, 360 insertions, 5 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index 94a72632d..b4bd37637 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -25,6 +25,7 @@
* given in the aggregation_tracking table. This needs to be checked separately!
*
* TODO:
+ * - initialize 'currency' (URGENT!)
* - modify auditordb to allow multiple last serial IDs per table in progress tracking
* - implement coin/denomination audit
* - implement merchant deposit audit
@@ -55,6 +56,11 @@ static int global_ret;
static struct TALER_EXCHANGEDB_Plugin *edb;
/**
+ * Which currency are we doing the audit for?
+ */
+static char *currency;
+
+/**
* Our session with the #edb.
*/
static struct TALER_EXCHANGEDB_Session *esession;
@@ -891,6 +897,7 @@ analyze_reserves (void *cls)
&rc.total_balance,
&rc.total_fee_balance);
}
+ // FIXME: handle error in 'ret'!
report_reserve_balance (&rc.total_balance,
&rc.total_fee_balance);
return GNUNET_OK;
@@ -902,7 +909,6 @@ analyze_reserves (void *cls)
coin, checking deposits, refunds, refresh* and known_coins
tables */
-/* TODO! */
/**
* Summary data we keep per coin.
*/
@@ -971,6 +977,13 @@ struct DenominationSummary
* Up to which point have we processed refunds?
*/
uint64_t last_refund_serial_id;
+
+ /**
+ * #GNUNET_YES if this record already existed in the DB.
+ * Used to decide between insert/update in
+ * #sync_denomination().
+ */
+ int in_db;
};
@@ -990,10 +1003,229 @@ struct CoinContext
*/
struct GNUNET_CONTAINER_MultiHashMap *denominations;
+ /**
+ * Total outstanding balances across all denomination keys.
+ */
+ struct TALER_Amount 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;
+
};
/**
+ * Initialize information about denomination from the database.
+ *
+ * @param denom_hash hash of the public key of the denomination
+ * @param[out] ds summary to initialize
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+init_denomination (const struct GNUNET_HashCode *denom_hash,
+ struct DenominationSummary *ds)
+{
+ int ret;
+
+ ret = adb->get_denomination_balance (adb->cls,
+ asession,
+ denom_hash,
+ &ds->denom_balance,
+ &ds->deposit_fee_balance,
+ &ds->melt_fee_balance,
+ &ds->refund_fee_balance,
+ &ds->last_reserve_out_serial_id,
+ &ds->last_deposit_serial_id,
+ &ds->last_melt_serial_id,
+ &ds->last_refund_serial_id);
+ if (GNUNET_OK == ret)
+ {
+ ds->in_db = GNUNET_YES;
+ return GNUNET_OK;
+ }
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (currency,
+ &ds->denom_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (currency,
+ &ds->deposit_fee_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (currency,
+ &ds->melt_fee_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (currency,
+ &ds->refund_fee_balance));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Obtain the denomination summary for the given @a dh
+ *
+ * @param cc our execution context
+ * @param dh the denomination hash to use for the lookup
+ * @return NULL on error
+ */
+static struct DenominationSummary *
+get_denomination_summary (struct CoinContext *cc,
+ const struct GNUNET_HashCode *dh)
+{
+ struct DenominationSummary *ds;
+
+ ds = GNUNET_CONTAINER_multihashmap_get (cc->denominations,
+ dh);
+ if (NULL != ds)
+ return ds;
+ ds = GNUNET_new (struct DenominationSummary);
+ if (GNUNET_OK !=
+ init_denomination (dh,
+ ds))
+ {
+ GNUNET_break (0);
+ GNUNET_free (ds);
+ return NULL;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (cc->denominations,
+ dh,
+ ds,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ return ds;
+}
+
+
+/**
+ * Write information about the current knowledge about a denomination key
+ * back to the database and update our global reporting data about the
+ * denomination. Also remove and free the memory of @a value.
+ *
+ * @param cls the `struct CoinContext`
+ * @param key the hash of the denomination key
+ * @param value a `struct DenominationSummary`
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+sync_denomination (void *cls,
+ const struct GNUNET_HashCode *denom_hash,
+ void *value)
+{
+ struct CoinContext *cc = cls;
+ struct DenominationSummary *ds = value;
+ int ret;
+
+ // FIXME: if expired, insert into historic denomination revenue
+ // and DELETE denomination balance.
+
+ // FIXME: update "global" info about denominations (here?)
+
+ if (ds->in_db)
+ ret = adb->update_denomination_balance (adb->cls,
+ asession,
+ denom_hash,
+ &ds->denom_balance,
+ &ds->deposit_fee_balance,
+ &ds->melt_fee_balance,
+ &ds->refund_fee_balance,
+ ds->last_reserve_out_serial_id,
+ ds->last_deposit_serial_id,
+ ds->last_melt_serial_id,
+ ds->last_refund_serial_id);
+ else
+ ret = adb->insert_denomination_balance (adb->cls,
+ asession,
+ denom_hash,
+ &ds->denom_balance,
+ &ds->deposit_fee_balance,
+ &ds->melt_fee_balance,
+ &ds->refund_fee_balance,
+ ds->last_reserve_out_serial_id,
+ ds->last_deposit_serial_id,
+ ds->last_melt_serial_id,
+ ds->last_refund_serial_id);
+
+ // FIXME handle errors in 'ret'
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (cc->denominations,
+ denom_hash,
+ ds));
+ GNUNET_free (ds);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with details about all withdraw operations.
+ *
+ * @param cls our `struct CoinContext`
+ * @param rowid unique serial ID for the refresh session in our DB
+ * @param h_blind_ev blinded hash of the coin's public key
+ * @param denom_pub public denomination key of the deposited coin
+ * @param denom_sig signature over the deposited coin
+ * @param reserve_pub public key of the reserve
+ * @param reserve_sig signature over the withdraw operation
+ * @param execution_date when did the wallet withdraw the coin
+ * @param amount_with_fee amount that was withdrawn
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static int
+withdraw_cb (void *cls,
+ uint64_t rowid,
+ const struct GNUNET_HashCode *h_blind_ev,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ const struct TALER_DenominationSignature *denom_sig,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_ReserveSignatureP *reserve_sig,
+ struct GNUNET_TIME_Absolute execution_date,
+ const struct TALER_Amount *amount_with_fee)
+{
+ struct CoinContext *cc = cls;
+ struct DenominationSummary *ds;
+ struct GNUNET_HashCode dh;
+ const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki;
+
+ if (GNUNET_OK !=
+ get_denomination_info (denom_pub,
+ &dki,
+ &dh))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ ds = get_denomination_summary (cc,
+ &dh);
+ // FIXME: use ds, dki, etc.
+ return GNUNET_OK;
+}
+
+
+
+
+
+/**
* Analyze the exchange's processing of coins.
*
* @param cls closure
@@ -1003,16 +1235,139 @@ static int
analyze_coins (void *cls)
{
struct CoinContext cc;
+ int dret;
+ int rret;
+
+ /* setup 'cc' */
+ dret = adb->get_denomination_summary (adb->cls,
+ asession,
+ &master_pub,
+ &cc.denom_balance,
+ &cc.deposit_fee_balance,
+ &cc.melt_fee_balance,
+ &cc.refund_fee_balance);
+ if (GNUNET_SYSERR == dret)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_NO == dret)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (currency,
+ &cc.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));
+ }
+ rret = adb->get_risk_summary (adb->cls,
+ asession,
+ &master_pub,
+ &cc.risk);
+ if (GNUNET_SYSERR == dret)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_NO == dret)
+ {
+ /* FIXME: initialize cc->risk by other means... */
+ }
cc.coins = GNUNET_CONTAINER_multihashmap_create (1024,
- GNUNET_YES);
+ GNUNET_NO);
cc.denominations = GNUNET_CONTAINER_multihashmap_create (256,
- GNUNET_YES);
+ GNUNET_NO);
+
+ /* process withdrawals */
+ if (GNUNET_OK !=
+ edb->select_reserves_out_above_serial_id (edb->cls,
+ esession,
+ 42LL, // FIXME
+ &withdraw_cb,
+ &cc))
+ {
+ // FIXME...
+ }
+
+ /* process refreshs */
+ if (GNUNET_OK !=
+ edb->select_refreshs_above_serial_id (edb->cls,
+ esession,
+ 42LL, // FIXME
+ NULL, // FIXME
+ &cc))
+ {
+ // FIXME...
+ }
+
+ /* process deposits */
+ if (GNUNET_OK !=
+ edb->select_deposits_above_serial_id (edb->cls,
+ esession,
+ 42LL, // FIXME
+ NULL, // FIXME
+ &cc))
+ {
+ // FIXME...
+ }
+ /* process refunds */
+ if (GNUNET_OK !=
+ edb->select_refunds_above_serial_id (edb->cls,
+ esession,
+ 42LL, // FIXME
+ NULL, // FIXME
+ &cc))
+ {
+ // FIXME...
+ }
+ // FIXME...
+
+ /* FIXME: check invariants */
+
+ /* sync 'cc' back to disk */
+ GNUNET_CONTAINER_multihashmap_iterate (cc.denominations,
+ &sync_denomination,
+ &cc);
GNUNET_CONTAINER_multihashmap_destroy (cc.denominations);
GNUNET_CONTAINER_multihashmap_destroy (cc.coins);
+ if (GNUNET_YES == rret)
+ rret = adb->update_risk_summary (adb->cls,
+ asession,
+ &master_pub,
+ &cc.risk);
+ else
+ rret = adb->insert_risk_summary (adb->cls,
+ asession,
+ &master_pub,
+ &cc.risk);
+ // FIXME: handle error in 'rret'!
+ if (GNUNET_YES == dret)
+ dret = adb->update_denomination_summary (adb->cls,
+ asession,
+ &master_pub,
+ &cc.denom_balance,
+ &cc.deposit_fee_balance,
+ &cc.melt_fee_balance,
+ &cc.refund_fee_balance);
+ else
+ dret = adb->insert_denomination_summary (adb->cls,
+ asession,
+ &master_pub,
+ &cc.denom_balance,
+ &cc.deposit_fee_balance,
+ &cc.melt_fee_balance,
+ &cc.refund_fee_balance);
+ // FIXME: handle error in 'dret'!
return GNUNET_OK;
}
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index 1784fdf5e..ebcd0ef85 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -2049,7 +2049,7 @@ postgres_update_denomination_balance (void *cls,
* melts for the above information
* @param[out] last_refund_serial_id up to which point did we consider
* refunds for the above information
- * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ * @return #GNUNET_OK on success; #GNUNET_NO if no record found, #GNUNET_SYSERR on failure
*/
static int
postgres_get_denomination_balance (void *cls,
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index 80e6eb243..15d9a4ca6 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -603,7 +603,7 @@ struct TALER_AUDITORDB_Plugin
* melts for the above information
* @param[out] last_refund_serial_id up to which point did we consider
* refunds for the above information
- * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ * @return #GNUNET_OK on success; #GNUNET_NO if no record found, #GNUNET_SYSERR on failure
*/
int
(*get_denomination_balance)(void *cls,