aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-04-04 15:38:58 +0200
committerChristian Grothoff <christian@grothoff.org>2017-04-04 15:38:58 +0200
commit4b82a591c54bec9720181358c8230caa3759363f (patch)
treec4f5ab8a5f93c6640ee1c8ce311b3bb6e13d3f86
parentcc3aa31732b2c214e6733206e713387d5ef8d39a (diff)
handle /payback in auditor when checking reserves
-rw-r--r--src/auditor/taler-auditor.c118
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c55
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c282
-rw-r--r--src/exchangedb/test_exchangedb.c4
-rw-r--r--src/include/taler_auditordb_plugin.h12
-rw-r--r--src/include/taler_exchangedb_plugin.h50
6 files changed, 418 insertions, 103 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index c58a8b151..b884e64bc 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -800,6 +800,89 @@ handle_reserve_out (void *cls,
/**
+ * Function called with details about withdraw operations. Verifies
+ * the signature and updates the reserve's balance.
+ *
+ * @param cls our `struct ReserveContext`
+ * @param rowid unique serial ID for the refresh session in our DB
+ * @param timestamp when did we receive the payback request
+ * @param amount how much should be added back to the reserve
+ * @param reserve_pub public key of the reserve
+ * @param coin_pub public key of the coin
+ * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_PAYBACK
+ * @param h_denom_pub hash of the denomination key of the coin
+ * @param coin_blind blinding factor used to blind the coin
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static int
+handle_payback_by_reserve (void *cls,
+ uint64_t rowid,
+ struct GNUNET_TIME_Absolute timestamp,
+ const struct TALER_Amount *amount,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ const struct GNUNET_HashCode *h_denom_pub,
+ const struct TALER_DenominationBlindingKeyP *coin_blind)
+{
+ struct ReserveContext *rc = cls;
+ struct GNUNET_HashCode key;
+ struct ReserveSummary *rs;
+ struct GNUNET_TIME_Absolute expiry;
+
+ /* should be monotonically increasing */
+ GNUNET_assert (rowid >= pp.last_reserve_payback_serial_id);
+ pp.last_reserve_payback_serial_id = rowid + 1;
+
+ GNUNET_CRYPTO_hash (reserve_pub,
+ sizeof (*reserve_pub),
+ &key);
+ rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
+ &key);
+ if (NULL == rs)
+ {
+ rs = GNUNET_new (struct ReserveSummary);
+ rs->reserve_pub = *reserve_pub;
+ rs->total_in = *amount;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (amount->currency,
+ &rs->total_out));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (amount->currency,
+ &rs->total_fee));
+ if (GNUNET_OK !=
+ load_auditor_reserve_summary (rs))
+ {
+ GNUNET_break (0);
+ GNUNET_free (rs);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (rc->reserves,
+ &key,
+ rs,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ }
+ else
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_add (&rs->total_in,
+ &rs->total_in,
+ amount));
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Additional /payback value to for reserve `%s' of %s\n",
+ TALER_B2S (reserve_pub),
+ TALER_amount2s (amount));
+ expiry = GNUNET_TIME_absolute_add (timestamp,
+ TALER_IDLE_RESERVE_EXPIRATION_TIME);
+ rs->a_expiration_date = GNUNET_TIME_absolute_max (rs->a_expiration_date,
+ expiry);
+ return GNUNET_OK;
+}
+
+
+/**
* Check that the reserve summary matches what the exchange database
* thinks about the reserve, and update our own state of the reserve.
*
@@ -1041,7 +1124,20 @@ analyze_reserves (void *cls)
GNUNET_break (0);
return GNUNET_SYSERR;
}
- /* TODO: iterate over table for reserve expiration refunds! (#4956) */
+ if (GNUNET_SYSERR ==
+ edb->select_payback_above_serial_id (edb->cls,
+ esession,
+ pp.last_reserve_payback_serial_id,
+ &handle_payback_by_reserve,
+ &rc))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+
+ /* TODO: iterate over table for reserve expiration refunds! (#4956);
+ should use pp.last_reserve_close_serial_id */
GNUNET_CONTAINER_multihashmap_iterate (rc.reserves,
&verify_reserve_balance,
@@ -1774,8 +1870,9 @@ get_wire_fee (struct AggregationContext *ac,
* @param wtid wire transfer subject
* @param wire wire transfer details of the receiver
* @param amount amount that was wired
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
-static void
+static int
check_wire_out_cb (void *cls,
uint64_t rowid,
struct GNUNET_TIME_Absolute date,
@@ -1809,7 +1906,7 @@ check_wire_out_cb (void *cls,
report_row_inconsistency ("wire_out",
rowid,
"specified wire address lacks type");
- return;
+ return GNUNET_OK;
}
wcc.method = json_string_value (method);
wcc.ok = GNUNET_OK;
@@ -1828,7 +1925,7 @@ check_wire_out_cb (void *cls,
report_row_inconsistency ("wire_out",
rowid,
"audit of associated transactions failed");
- return;
+ return GNUNET_OK;
}
/* Subtract aggregation fee from total */
@@ -1839,7 +1936,7 @@ check_wire_out_cb (void *cls,
{
GNUNET_break (0);
ac->ret = GNUNET_SYSERR;
- return;
+ return GNUNET_SYSERR;
}
if (GNUNET_SYSERR ==
TALER_amount_subtract (&final_amount,
@@ -1849,7 +1946,7 @@ check_wire_out_cb (void *cls,
report_row_inconsistency ("wire_out",
rowid,
"could not subtract wire fee from total amount");
- return;
+ return GNUNET_OK;
}
/* Round down to amount supported by wire method */
@@ -1860,7 +1957,7 @@ check_wire_out_cb (void *cls,
report_row_inconsistency ("wire_out",
rowid,
"could not load required wire plugin to validate");
- return;
+ return GNUNET_OK;
}
if (GNUNET_SYSERR ==
@@ -1880,7 +1977,7 @@ check_wire_out_cb (void *cls,
{
GNUNET_break (0);
ac->ret = GNUNET_SYSERR;
- return;
+ return GNUNET_SYSERR;
}
/* Sum up aggregation fees (we simply include the rounding gains) */
@@ -1891,7 +1988,7 @@ check_wire_out_cb (void *cls,
{
GNUNET_break (0);
ac->ret = GNUNET_SYSERR;
- return;
+ return GNUNET_SYSERR;
}
/* Check that calculated amount matches actual amount */
@@ -1903,11 +2000,12 @@ check_wire_out_cb (void *cls,
&final_amount,
amount,
"computed amount inconsistent with wire amount");
- return;
+ return GNUNET_OK;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Wire transfer %s is OK\n",
TALER_B2S (wtid));
+ return GNUNET_OK;
}
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index 380763904..b68708f0c 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -301,6 +301,8 @@ postgres_create_tables (void *cls)
"(master_pub BYTEA PRIMARY KEY CHECK (LENGTH(master_pub)=32)"
",last_reserve_in_serial_id INT8 NOT NULL"
",last_reserve_out_serial_id INT8 NOT NULL"
+ ",last_reserve_payback_serial_id INT8 NOT NULL"
+ ",last_reserve_close_serial_id INT8 NOT NULL"
",last_withdraw_serial_id INT8 NOT NULL"
",last_deposit_serial_id INT8 NOT NULL"
",last_melt_serial_id INT8 NOT NULL"
@@ -575,32 +577,38 @@ postgres_prepare (PGconn *db_conn)
"(master_pub"
",last_reserve_in_serial_id"
",last_reserve_out_serial_id"
+ ",last_reserve_payback_serial_id"
+ ",last_reserve_close_serial_id"
",last_withdraw_serial_id"
",last_deposit_serial_id"
",last_melt_serial_id"
",last_refund_serial_id"
",last_wire_out_serial_id"
- ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8);",
- 8, NULL);
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);",
+ 10, NULL);
/* Used in #postgres_update_auditor_progress() */
PREPARE ("auditor_progress_update",
"UPDATE auditor_progress SET "
" last_reserve_in_serial_id=$1"
",last_reserve_out_serial_id=$2"
- ",last_withdraw_serial_id=$3"
- ",last_deposit_serial_id=$4"
- ",last_melt_serial_id=$5"
- ",last_refund_serial_id=$6"
- ",last_wire_out_serial_id=$7"
- " WHERE master_pub=$8",
- 8, NULL);
+ ",last_reserve_payback_serial_id=$3"
+ ",last_reserve_close_serial_id=$4"
+ ",last_withdraw_serial_id=$5"
+ ",last_deposit_serial_id=$6"
+ ",last_melt_serial_id=$7"
+ ",last_refund_serial_id=$8"
+ ",last_wire_out_serial_id=$9"
+ " WHERE master_pub=$10",
+ 10, NULL);
/* Used in #postgres_get_auditor_progress() */
PREPARE ("auditor_progress_select",
"SELECT"
" last_reserve_in_serial_id"
",last_reserve_out_serial_id"
+ ",last_reserve_payback_serial_id"
+ ",last_reserve_close_serial_id"
",last_withdraw_serial_id"
",last_deposit_serial_id"
",last_melt_serial_id"
@@ -1310,6 +1318,8 @@ postgres_insert_auditor_progress (void *cls,
GNUNET_PQ_query_param_auto_from_type (master_pub),
GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_reserve_out_serial_id),
+ GNUNET_PQ_query_param_uint64 (&pp->last_reserve_payback_serial_id),
+ GNUNET_PQ_query_param_uint64 (&pp->last_reserve_close_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_withdraw_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_deposit_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_melt_serial_id),
@@ -1356,6 +1366,8 @@ postgres_update_auditor_progress (void *cls,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_reserve_out_serial_id),
+ GNUNET_PQ_query_param_uint64 (&pp->last_reserve_payback_serial_id),
+ GNUNET_PQ_query_param_uint64 (&pp->last_reserve_close_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_withdraw_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_deposit_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_melt_serial_id),
@@ -1405,13 +1417,24 @@ postgres_get_auditor_progress (void *cls,
};
PGresult *result;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("last_reserve_in_serial_id", &pp->last_reserve_in_serial_id),
- GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", &pp->last_reserve_out_serial_id),
- GNUNET_PQ_result_spec_uint64 ("last_withdraw_serial_id", &pp->last_withdraw_serial_id),
- GNUNET_PQ_result_spec_uint64 ("last_deposit_serial_id", &pp->last_deposit_serial_id),
- GNUNET_PQ_result_spec_uint64 ("last_melt_serial_id", &pp->last_melt_serial_id),
- GNUNET_PQ_result_spec_uint64 ("last_refund_serial_id", &pp->last_refund_serial_id),
- GNUNET_PQ_result_spec_uint64 ("last_wire_out_serial_id", &pp->last_wire_out_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_in_serial_id",
+ &pp->last_reserve_in_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id",
+ &pp->last_reserve_out_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_payback_serial_id",
+ &pp->last_reserve_payback_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_close_serial_id",
+ &pp->last_reserve_out_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_withdraw_serial_id",
+ &pp->last_withdraw_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_deposit_serial_id",
+ &pp->last_deposit_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_melt_serial_id",
+ &pp->last_melt_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_refund_serial_id",
+ &pp->last_refund_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_wire_out_serial_id",
+ &pp->last_wire_out_serial_id),
GNUNET_PQ_result_spec_end
};
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index e869bcd95..498b84864 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -515,7 +515,8 @@ postgres_create_tables (void *cls)
/* Table for /payback information */
SQLEXEC("CREATE TABLE IF NOT EXISTS payback "
- "(reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
+ "(payback_uuid BIGSERIAL"
+ ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)"
",coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)"
@@ -1418,6 +1419,26 @@ postgres_prepare (PGconn *db_conn)
"($1, $2, $3, $4, $5, $6, $7, $8, $9)",
9, NULL);
+ /* Used in #postgres_select_payback_above_serial_id() to obtain payback transactions */
+ PREPARE ("payback_get_incr",
+ "SELECT"
+ " payback_uuid"
+ ",timestamp"
+ ",reserve_pub"
+ ",coin_pub"
+ ",coin_sig"
+ ",coin_blind"
+ ",h_blind_ev"
+ ",denom.denom_pub"
+ ",amount_val"
+ ",amount_frac"
+ ",amount_curr"
+ " FROM payback"
+ " JOIN reserves_out denom USING (reserve_pub,h_blind_ev)"
+ " WHERE payback_uuid>=$1"
+ " ORDER BY payback_uuid ASC",
+ 1, NULL);
+
/* Used in #postgres_get_reserve_history() to obtain payback transactions
for a reserve */
PREPARE ("payback_by_reserve",
@@ -5057,7 +5078,7 @@ postgres_select_deposits_above_serial_id (void *cls,
return GNUNET_SYSERR;
}
int nrows;
- int i;
+ int ret;
nrows = PQntuples (result);
if (0 == nrows)
@@ -5067,7 +5088,7 @@ postgres_select_deposits_above_serial_id (void *cls,
PQclear (result);
return GNUNET_NO;
}
- for (i=0;i<nrows;i++)
+ for (int i=0;i<nrows;i++)
{
struct TALER_EXCHANGEDB_Deposit deposit;
struct TALER_DenominationPublicKey denom_pub;
@@ -5109,20 +5130,22 @@ postgres_select_deposits_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- cb (cb_cls,
- rowid,
- deposit.timestamp,
- &deposit.merchant_pub,
- &denom_pub,
- &deposit.coin.coin_pub,
- &deposit.csig,
- &deposit.amount_with_fee,
- &deposit.h_proposal_data,
- deposit.refund_deadline,
- deposit.wire_deadline,
- deposit.receiver_wire_account,
- done);
+ ret = cb (cb_cls,
+ rowid,
+ deposit.timestamp,
+ &deposit.merchant_pub,
+ &denom_pub,
+ &deposit.coin.coin_pub,
+ &deposit.csig,
+ &deposit.amount_with_fee,
+ &deposit.h_proposal_data,
+ deposit.refund_deadline,
+ deposit.wire_deadline,
+ deposit.receiver_wire_account,
+ done);
GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
}
PQclear (result);
return GNUNET_OK;
@@ -5153,6 +5176,10 @@ postgres_select_refreshs_above_serial_id (void *cls,
GNUNET_PQ_query_param_end
};
PGresult *result;
+ int nrows;
+ int i;
+ int ret;
+
result = GNUNET_PQ_exec_prepared (session->conn,
"audit_get_refresh_sessions_incr",
params);
@@ -5164,8 +5191,6 @@ postgres_select_refreshs_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- int nrows;
- int i;
nrows = PQntuples (result);
if (0 == nrows)
@@ -5215,16 +5240,18 @@ postgres_select_refreshs_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- cb (cb_cls,
- rowid,
- &denom_pub,
- &coin_pub,
- &coin_sig,
- &amount_with_fee,
- num_newcoins,
- noreveal_index,
- &session_hash);
+ ret = cb (cb_cls,
+ rowid,
+ &denom_pub,
+ &coin_pub,
+ &coin_sig,
+ &amount_with_fee,
+ num_newcoins,
+ noreveal_index,
+ &session_hash);
GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
}
PQclear (result);
return GNUNET_OK;
@@ -5255,6 +5282,9 @@ postgres_select_refunds_above_serial_id (void *cls,
GNUNET_PQ_query_param_end
};
PGresult *result;
+ int nrows;
+ int ret;
+
result = GNUNET_PQ_exec_prepared (session->conn,
"audit_get_refunds_incr",
params);
@@ -5265,8 +5295,6 @@ postgres_select_refunds_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- int nrows;
- int i;
nrows = PQntuples (result);
if (0 == nrows)
@@ -5276,7 +5304,7 @@ postgres_select_refunds_above_serial_id (void *cls,
PQclear (result);
return GNUNET_NO;
}
- for (i=0;i<nrows;i++)
+ for (int i=0;i<nrows;i++)
{
struct TALER_EXCHANGEDB_Refund refund;
struct TALER_DenominationPublicKey denom_pub;
@@ -5310,16 +5338,18 @@ postgres_select_refunds_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- cb (cb_cls,
- rowid,
- &denom_pub,
- &refund.coin.coin_pub,
- &refund.merchant_pub,
- &refund.merchant_sig,
- &refund.h_proposal_data,
- refund.rtransaction_id,
- &refund.refund_amount);
+ ret = cb (cb_cls,
+ rowid,
+ &denom_pub,
+ &refund.coin.coin_pub,
+ &refund.merchant_pub,
+ &refund.merchant_sig,
+ &refund.h_proposal_data,
+ refund.rtransaction_id,
+ &refund.refund_amount);
GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
}
PQclear (result);
return GNUNET_OK;
@@ -5361,7 +5391,7 @@ postgres_select_reserves_in_above_serial_id (void *cls,
return GNUNET_SYSERR;
}
int nrows;
- int i;
+ int ret;
nrows = PQntuples (result);
if (0 == nrows)
@@ -5372,7 +5402,7 @@ postgres_select_reserves_in_above_serial_id (void *cls,
return GNUNET_NO;
}
- for (i=0;i<nrows;i++)
+ for (int i=0;i<nrows;i++)
{
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_Amount credit;
@@ -5406,14 +5436,16 @@ postgres_select_reserves_in_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- cb (cb_cls,
- rowid,
- &reserve_pub,
- &credit,
- sender_account_details,
- transfer_details,
- execution_date);
+ ret = cb (cb_cls,
+ rowid,
+ &reserve_pub,
+ &credit,
+ sender_account_details,
+ transfer_details,
+ execution_date);
GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
}
PQclear (result);
@@ -5457,7 +5489,7 @@ postgres_select_reserves_out_above_serial_id (void *cls,
return GNUNET_SYSERR;
}
int nrows;
- int i;
+ int ret;
nrows = PQntuples (result);
if (0 == nrows)
@@ -5467,7 +5499,7 @@ postgres_select_reserves_out_above_serial_id (void *cls,
PQclear (result);
return GNUNET_NO;
}
- for (i=0;i<nrows;i++)
+ for (int i=0;i<nrows;i++)
{
struct GNUNET_HashCode h_blind_ev;
struct TALER_DenominationPublicKey denom_pub;
@@ -5506,16 +5538,18 @@ postgres_select_reserves_out_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- cb (cb_cls,
- rowid,
- &h_blind_ev,
- &denom_pub,
- &denom_sig,
- &reserve_pub,
- &reserve_sig,
- execution_date,
- &amount_with_fee);
+ ret = cb (cb_cls,
+ rowid,
+ &h_blind_ev,
+ &denom_pub,
+ &denom_sig,
+ &reserve_pub,
+ &reserve_sig,
+ execution_date,
+ &amount_with_fee);
GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
}
PQclear (result);
@@ -5548,6 +5582,9 @@ postgres_select_wire_out_above_serial_id (void *cls,
GNUNET_PQ_query_param_end
};
PGresult *result;
+ int nrows;
+ int ret;
+
result = GNUNET_PQ_exec_prepared (session->conn,
"audit_get_wire_incr",
params);
@@ -5558,7 +5595,6 @@ postgres_select_wire_out_above_serial_id (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
- int nrows;
nrows = PQntuples (result);
if (0 == nrows)
@@ -5600,13 +5636,126 @@ postgres_select_wire_out_above_serial_id (void *cls,
return GNUNET_SYSERR;
}
- cb (cb_cls,
- rowid,
- date,
- &wtid,
- wire,
- &amount);
+ ret = cb (cb_cls,
+ rowid,
+ date,
+ &wtid,
+ wire,
+ &amount);
+ GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
+ }
+
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to select payback requests the exchange
+ * received, ordered by serial ID (monotonically increasing).
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param serial_id lowest serial ID to include (select larger or equal)
+ * @param cb function to call for ONE unfinished item
+ * @param cb_cls closure for @a cb
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if there are no entries,
+ * #GNUNET_SYSERR on DB errors
+ */
+static int
+postgres_select_payback_above_serial_id (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_PaybackCallback cb,
+ void *cb_cls)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "payback_get_incr",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result, session->conn);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ int nrows;
+ int ret;
+
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_prepare_above_serial_id() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (int i=0;i<nrows;i++)
+ {
+ uint64_t rowid;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct TALER_DenominationBlindingKeyP coin_blind;
+ struct TALER_Amount amount;
+ struct GNUNET_HashCode h_blind_ev;
+ struct GNUNET_TIME_Absolute timestamp;
+ struct TALER_DenominationPublicKey denom_pub;
+ struct GNUNET_HashCode h_denom_pub;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("payback_uuid",
+ &rowid),
+ GNUNET_PQ_result_spec_absolute_time ("timestamp",
+ &timestamp),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ &reserve_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
+ &coin_sig),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
+ &coin_blind),
+ GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
+ &h_blind_ev),
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &denom_pub.rsa_public_key),
+ TALER_PQ_result_spec_amount ("amount",
+ &amount),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
+ &h_denom_pub);
+ ret = cb (cb_cls,
+ rowid,
+ timestamp,
+ &amount,
+ &reserve_pub,
+ &coin_pub,
+ &coin_sig,
+ &h_denom_pub,
+ &coin_blind);
GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != ret)
+ break;
}
PQclear (result);
@@ -5868,6 +6017,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->select_reserves_in_above_serial_id = &postgres_select_reserves_in_above_serial_id;
plugin->select_reserves_out_above_serial_id = &postgres_select_reserves_out_above_serial_id;
plugin->select_wire_out_above_serial_id = &postgres_select_wire_out_above_serial_id;
+ plugin->select_payback_above_serial_id = &postgres_select_payback_above_serial_id;
plugin->insert_payback_request = &postgres_insert_payback_request;
plugin->get_reserve_by_h_blind = &postgres_get_reserve_by_h_blind;
return plugin;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index e8fd21194..49cc64316 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1205,8 +1205,9 @@ static struct TALER_Amount wire_out_amount;
* @param wtid wire transfer subject
* @param wire wire transfer details of the receiver
* @param amount amount that was wired
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
-static void
+static int
audit_wire_cb (void *cls,
uint64_t rowid,
struct GNUNET_TIME_Absolute date,
@@ -1223,6 +1224,7 @@ audit_wire_cb (void *cls,
&wire_out_wtid,
sizeof (*wtid)));
GNUNET_assert (date.abs_value_us == wire_out_date.abs_value_us);
+ return GNUNET_OK;
}
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index 031df58cb..170a68fdd 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -122,6 +122,18 @@ struct TALER_AUDITORDB_ProgressPoint
uint64_t last_reserve_out_serial_id;
/**
+ * last_payback_serial_id serial ID of the last payback entry the auditor processed when
+ * considering reserves.
+ */
+ uint64_t last_reserve_payback_serial_id;
+
+ /**
+ * last_reserve_close_serial_id serial ID of the last reserve_close
+ * entry the auditor processed.
+ */
+ uint64_t last_reserve_close_serial_id;
+
+ /**
* last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
*/
uint64_t last_withdraw_serial_id;
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 322a30524..f6d78aba9 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -875,8 +875,9 @@ typedef void
* @param wtid wire transfer subject
* @param wire wire transfer details of the receiver
* @param amount amount that was wired
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
-typedef void
+typedef int
(*TALER_EXCHANGEDB_WireTransferOutCallback)(void *cls,
uint64_t rowid,
struct GNUNET_TIME_Absolute date,
@@ -894,8 +895,9 @@ typedef void
* @param buf transaction data that was persisted, NULL on error
* @param buf_size number of bytes in @a buf, 0 on error
* @param finished did we complete the transfer yet?
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
-typedef void
+typedef int
(*TALER_EXCHANGEDB_WirePreparationCallback)(void *cls,
uint64_t rowid,
const char *wire_method,
@@ -909,18 +911,25 @@ typedef void
*
* @param cls closure
* @param rowid row identifier used to uniquely identify the payback operation
- * @param deadline by when did we promise the payment
- * @param receiver_account_details to whom do we need to send the funds
- * @param amount how much should be transferred
- * @param wire_subject what should be the wire subject
+ * @param timestamp when did we receive the payback request
+ * @param amount how much should be added back to the reserve
+ * @param reserve_pub public key of the reserve
+ * @param coin_pub public key of the coin
+ * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_PAYBACK
+ * @param h_denom_pub hash of the denomination key of the coin
+ * @param coin_blind blinding factor used to blind the coin
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef void
+typedef int
(*TALER_EXCHANGEDB_PaybackCallback)(void *cls,
uint64_t rowid,
- struct GNUNET_TIME_Absolute deadline,
- const json_t *receiver_account_details,
+ struct GNUNET_TIME_Absolute timestamp,
const struct TALER_Amount *amount,
- const struct TALER_WireTransferIdentifierRawP *wtid);
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ const struct GNUNET_HashCode *h_denom_pub,
+ const struct TALER_DenominationBlindingKeyP *coin_blind);
/**
@@ -1940,6 +1949,27 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * Function called to select payback requests the exchange
+ * received, ordered by serial ID (monotonically increasing).
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param serial_id lowest serial ID to include (select larger or equal)
+ * @param cb function to call for ONE unfinished item
+ * @param cb_cls closure for @a cb
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if there are no entries,
+ * #GNUNET_SYSERR on DB errors
+ */
+ int
+ (*select_payback_above_serial_id)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ uint64_t serial_id,
+ TALER_EXCHANGEDB_PaybackCallback cb,
+ void *cb_cls);
+
+
+ /**
* Function called to add a request for an emergency payback for a
* coin. The funds are to be added back to the reserve. The
* function should return the @a deadline by which the exchange will