-towards returning reserve open deposits in coin history
This commit is contained in:
parent
97b4bd3b34
commit
1ee69f6f1d
@ -68,8 +68,10 @@ plugin_LTLIBRARIES = \
|
||||
endif
|
||||
|
||||
libtaler_plugin_exchangedb_postgres_la_SOURCES = \
|
||||
plugin_exchangedb_common.c plugin_exchangedb_common.h \
|
||||
plugin_exchangedb_postgres.c pg_helper.h \
|
||||
pg_do_reserve_open.c pg_do_reserve_open.h \
|
||||
pg_get_coin_transactions.c pg_get_coin_transactions.h \
|
||||
pg_get_expired_reserves.c pg_get_expired_reserves.h \
|
||||
pg_get_unfinished_close_requests.c pg_get_unfinished_close_requests.h \
|
||||
pg_insert_close_request.c pg_insert_close_request.h \
|
||||
|
866
src/exchangedb/pg_get_coin_transactions.c
Normal file
866
src/exchangedb/pg_get_coin_transactions.c
Normal file
@ -0,0 +1,866 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file pg_get_coin_transactions.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_get_coin_transactions.h"
|
||||
#include "pg_helper.h"
|
||||
#include "plugin_exchangedb_common.h"
|
||||
|
||||
|
||||
/**
|
||||
* Closure for callbacks called from #postgres_get_coin_transactions()
|
||||
*/
|
||||
struct CoinHistoryContext
|
||||
{
|
||||
/**
|
||||
* Head of the coin's history list.
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_TransactionList *head;
|
||||
|
||||
/**
|
||||
* Public key of the coin we are building the history for.
|
||||
*/
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub;
|
||||
|
||||
/**
|
||||
* Closure for all callbacks of this database plugin.
|
||||
*/
|
||||
void *db_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
|
||||
/**
|
||||
* Set to 'true' if the transaction failed.
|
||||
*/
|
||||
bool failed;
|
||||
|
||||
/**
|
||||
* Set to 'true' if we found a deposit or melt (for invariant check).
|
||||
*/
|
||||
bool have_deposit_or_melt;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_deposit (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i < num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_DepositListEntry *deposit;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
chc->have_deposit_or_melt = true;
|
||||
deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&deposit->amount_with_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
&deposit->deposit_fee),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&deposit->h_denom_pub),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
|
||||
&deposit->h_age_commitment),
|
||||
&deposit->no_age_commitment),
|
||||
GNUNET_PQ_result_spec_timestamp ("wallet_timestamp",
|
||||
&deposit->timestamp),
|
||||
GNUNET_PQ_result_spec_timestamp ("refund_deadline",
|
||||
&deposit->refund_deadline),
|
||||
GNUNET_PQ_result_spec_timestamp ("wire_deadline",
|
||||
&deposit->wire_deadline),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
|
||||
&deposit->merchant_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
&deposit->h_contract_terms),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
|
||||
&deposit->wire_salt),
|
||||
GNUNET_PQ_result_spec_string ("payto_uri",
|
||||
&deposit->receiver_wire_account),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&deposit->csig),
|
||||
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("done",
|
||||
&deposit->done),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (deposit);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_DEPOSIT;
|
||||
tl->details.deposit = deposit;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_purse_deposit (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i < num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_PurseDepositListEntry *deposit;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
chc->have_deposit_or_melt = true;
|
||||
deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&deposit->amount),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
&deposit->deposit_fee),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
|
||||
&deposit->purse_pub),
|
||||
GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("partner_base_url",
|
||||
&deposit->exchange_base_url),
|
||||
NULL),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&deposit->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
|
||||
&deposit->h_age_commitment),
|
||||
GNUNET_PQ_result_spec_bool ("refunded",
|
||||
&deposit->refunded),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (deposit);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
deposit->no_age_commitment = GNUNET_is_zero (&deposit->h_age_commitment);
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_PURSE_DEPOSIT;
|
||||
tl->details.purse_deposit = deposit;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_melt (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_MeltListEntry *melt;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
chc->have_deposit_or_melt = true;
|
||||
melt = GNUNET_new (struct TALER_EXCHANGEDB_MeltListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("rc",
|
||||
&melt->rc),
|
||||
/* oldcoin_index not needed */
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&melt->h_denom_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
|
||||
&melt->coin_sig),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&melt->amount_with_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
|
||||
&melt->melt_fee),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
|
||||
&melt->h_age_commitment),
|
||||
&melt->no_age_commitment),
|
||||
GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (melt);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_MELT;
|
||||
tl->details.melt = melt;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_refund (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RefundListEntry *refund;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
refund = GNUNET_new (struct TALER_EXCHANGEDB_RefundListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
|
||||
&refund->merchant_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_sig",
|
||||
&refund->merchant_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
&refund->h_contract_terms),
|
||||
GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
|
||||
&refund->rtransaction_id),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&refund->refund_amount),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
|
||||
&refund->refund_fee),
|
||||
GNUNET_PQ_result_spec_uint64 ("refund_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (refund);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_REFUND;
|
||||
tl->details.refund = refund;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_old_coin_recoup (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
|
||||
&recoup->coin.coin_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&recoup->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
|
||||
&recoup->coin_blind),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&recoup->value),
|
||||
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
|
||||
&recoup->timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&recoup->coin.denom_pub_hash),
|
||||
TALER_PQ_result_spec_denom_sig ("denom_sig",
|
||||
&recoup->coin.denom_sig),
|
||||
GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (recoup);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
recoup->old_coin_pub = *chc->coin_pub;
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP;
|
||||
tl->details.old_coin_recoup = recoup;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_recoup (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RecoupListEntry *recoup;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||
&recoup->reserve_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&recoup->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&recoup->h_denom_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
|
||||
&recoup->coin_blind),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&recoup->value),
|
||||
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
|
||||
&recoup->timestamp),
|
||||
GNUNET_PQ_result_spec_uint64 ("recoup_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (recoup);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_RECOUP;
|
||||
tl->details.recoup = recoup;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_recoup_refresh (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
|
||||
&recoup->old_coin_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&recoup->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
|
||||
&recoup->coin_blind),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&recoup->value),
|
||||
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
|
||||
&recoup->timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&recoup->coin.denom_pub_hash),
|
||||
TALER_PQ_result_spec_denom_sig ("denom_sig",
|
||||
&recoup->coin.denom_sig),
|
||||
GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (recoup);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
recoup->coin.coin_pub = *chc->coin_pub;
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_RECOUP_REFRESH;
|
||||
tl->details.recoup_refresh = recoup;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_reserve_open (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_ReserveOpenListEntry *role;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
role = GNUNET_new (struct TALER_EXCHANGEDB_ReserveOpenListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
|
||||
&role->reserve_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&role->coin_sig),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("contribution",
|
||||
&role->coin_contribution),
|
||||
GNUNET_PQ_result_spec_uint64 ("reserve_open_deposit_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (role);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_RESERVE_OPEN;
|
||||
tl->details.reserve_open = role;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work we need to do.
|
||||
*/
|
||||
struct Work
|
||||
{
|
||||
/**
|
||||
* SQL prepared statement name.
|
||||
*/
|
||||
const char *statement;
|
||||
|
||||
/**
|
||||
* Function to call to handle the result(s).
|
||||
*/
|
||||
GNUNET_PQ_PostgresResultHandler cb;
|
||||
};
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_get_coin_transactions (
|
||||
void *cls,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
struct TALER_EXCHANGEDB_TransactionList **tlp)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
static const struct Work work[] = {
|
||||
/** #TALER_EXCHANGEDB_TT_DEPOSIT */
|
||||
{ "get_deposit_with_coin_pub",
|
||||
&add_coin_deposit },
|
||||
/** #TALER_EXCHANGEDB_TT_MELT */
|
||||
{ "get_refresh_session_by_coin",
|
||||
&add_coin_melt },
|
||||
/** #TALER_EXCHANGEDB_TT_PURSE_DEPOSIT */
|
||||
{ "get_purse_deposit_by_coin_pub",
|
||||
&add_coin_purse_deposit },
|
||||
/** #TALER_EXCHANGEDB_TT_REFUND */
|
||||
{ "get_refunds_by_coin",
|
||||
&add_coin_refund },
|
||||
/** #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP */
|
||||
{ "recoup_by_old_coin",
|
||||
&add_old_coin_recoup },
|
||||
/** #TALER_EXCHANGEDB_TT_RECOUP */
|
||||
{ "recoup_by_coin",
|
||||
&add_coin_recoup },
|
||||
/** #TALER_EXCHANGEDB_TT_RECOUP_REFRESH */
|
||||
{ "recoup_by_refreshed_coin",
|
||||
&add_coin_recoup_refresh },
|
||||
/** #TALER_EXCHANGEDB_TT_RESERVE_OPEN */
|
||||
{ "reserve_open_by_coin",
|
||||
&add_coin_reserve_open },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (coin_pub),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
struct CoinHistoryContext chc = {
|
||||
.head = NULL,
|
||||
.coin_pub = coin_pub,
|
||||
.pg = pg,
|
||||
.db_cls = cls
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"get_deposit_with_coin_pub",
|
||||
"SELECT"
|
||||
" dep.amount_with_fee_val"
|
||||
",dep.amount_with_fee_frac"
|
||||
",denoms.fee_deposit_val"
|
||||
",denoms.fee_deposit_frac"
|
||||
",denoms.denom_pub_hash"
|
||||
",kc.age_commitment_hash"
|
||||
",dep.wallet_timestamp"
|
||||
",dep.refund_deadline"
|
||||
",dep.wire_deadline"
|
||||
",dep.merchant_pub"
|
||||
",dep.h_contract_terms"
|
||||
",dep.wire_salt"
|
||||
",wt.payto_uri"
|
||||
",dep.coin_sig"
|
||||
",dep.deposit_serial_id"
|
||||
",dep.done"
|
||||
" FROM deposits dep"
|
||||
" JOIN wire_targets wt"
|
||||
" USING (wire_target_h_payto)"
|
||||
" JOIN known_coins kc"
|
||||
" ON (kc.coin_pub = dep.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE dep.coin_pub=$1;");
|
||||
PREPARE (pg,
|
||||
"get_refresh_session_by_coin",
|
||||
"SELECT"
|
||||
" rc"
|
||||
",old_coin_sig"
|
||||
",amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
",denoms.denom_pub_hash"
|
||||
",denoms.fee_refresh_val"
|
||||
",denoms.fee_refresh_frac"
|
||||
",kc.age_commitment_hash"
|
||||
",melt_serial_id"
|
||||
" FROM refresh_commitments"
|
||||
" JOIN known_coins kc"
|
||||
" ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE old_coin_pub=$1;");
|
||||
PREPARE (pg,
|
||||
"get_purse_deposit_by_coin_pub",
|
||||
"SELECT"
|
||||
" partner_base_url"
|
||||
",pd.amount_with_fee_val"
|
||||
",pd.amount_with_fee_frac"
|
||||
",denoms.fee_deposit_val"
|
||||
",denoms.fee_deposit_frac"
|
||||
",pd.purse_pub"
|
||||
",kc.age_commitment_hash"
|
||||
",pd.coin_sig"
|
||||
",pd.purse_deposit_serial_id"
|
||||
",pr.refunded"
|
||||
" FROM purse_deposits pd"
|
||||
" LEFT JOIN partners"
|
||||
" USING (partner_serial_id)"
|
||||
" JOIN purse_requests pr"
|
||||
" USING (purse_pub)"
|
||||
" JOIN known_coins kc"
|
||||
" ON (pd.coin_pub = kc.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
// FIXME: use to-be-created materialized index
|
||||
// on coin_pub (query crosses partitions!)
|
||||
" WHERE pd.coin_pub=$1;");
|
||||
PREPARE (pg,
|
||||
"get_refunds_by_coin",
|
||||
"SELECT"
|
||||
" dep.merchant_pub"
|
||||
",ref.merchant_sig"
|
||||
",dep.h_contract_terms"
|
||||
",ref.rtransaction_id"
|
||||
",ref.amount_with_fee_val"
|
||||
",ref.amount_with_fee_frac"
|
||||
",denom.fee_refund_val "
|
||||
",denom.fee_refund_frac "
|
||||
",ref.refund_serial_id"
|
||||
" FROM refunds ref"
|
||||
" JOIN deposits dep"
|
||||
" ON (ref.coin_pub = dep.coin_pub AND ref.deposit_serial_id = dep.deposit_serial_id)"
|
||||
" JOIN known_coins kc"
|
||||
" ON (ref.coin_pub = kc.coin_pub)"
|
||||
" JOIN denominations denom"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE ref.coin_pub=$1;");
|
||||
PREPARE (pg,
|
||||
"recoup_by_old_coin",
|
||||
"SELECT"
|
||||
" coins.coin_pub"
|
||||
",coin_sig"
|
||||
",coin_blind"
|
||||
",amount_val"
|
||||
",amount_frac"
|
||||
",recoup_timestamp"
|
||||
",denoms.denom_pub_hash"
|
||||
",coins.denom_sig"
|
||||
",recoup_refresh_uuid"
|
||||
" FROM recoup_refresh"
|
||||
" JOIN known_coins coins"
|
||||
" USING (coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE rrc_serial IN"
|
||||
" (SELECT rrc.rrc_serial"
|
||||
" FROM refresh_commitments"
|
||||
" JOIN refresh_revealed_coins rrc"
|
||||
" USING (melt_serial_id)"
|
||||
" WHERE old_coin_pub=$1);");
|
||||
PREPARE (pg,
|
||||
"recoup_by_coin",
|
||||
"SELECT"
|
||||
" reserves.reserve_pub"
|
||||
",denoms.denom_pub_hash"
|
||||
",coin_sig"
|
||||
",coin_blind"
|
||||
",amount_val"
|
||||
",amount_frac"
|
||||
",recoup_timestamp"
|
||||
",recoup_uuid"
|
||||
" FROM recoup rcp"
|
||||
/* NOTE: suboptimal JOIN follows: crosses shards!
|
||||
Could theoretically be improved via a materialized
|
||||
index. But likely not worth it (query is rare and
|
||||
number of reserve shards might be limited) */
|
||||
" JOIN reserves_out ro"
|
||||
" USING (reserve_out_serial_id)"
|
||||
" JOIN reserves"
|
||||
" USING (reserve_uuid)"
|
||||
" JOIN known_coins coins"
|
||||
" USING (coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" ON (denoms.denominations_serial = coins.denominations_serial)"
|
||||
" WHERE coins.coin_pub=$1;");
|
||||
/* Used in #postgres_get_coin_transactions() to obtain recoup transactions
|
||||
for a refreshed coin */
|
||||
PREPARE (pg,
|
||||
"recoup_by_refreshed_coin",
|
||||
"SELECT"
|
||||
" old_coins.coin_pub AS old_coin_pub"
|
||||
",coin_sig"
|
||||
",coin_blind"
|
||||
",amount_val"
|
||||
",amount_frac"
|
||||
",recoup_timestamp"
|
||||
",denoms.denom_pub_hash"
|
||||
",coins.denom_sig"
|
||||
",recoup_refresh_uuid"
|
||||
" FROM recoup_refresh"
|
||||
" JOIN refresh_revealed_coins rrc"
|
||||
" USING (rrc_serial)"
|
||||
" JOIN refresh_commitments rfc"
|
||||
" ON (rrc.melt_serial_id = rfc.melt_serial_id)"
|
||||
" JOIN known_coins old_coins"
|
||||
" ON (rfc.old_coin_pub = old_coins.coin_pub)"
|
||||
" JOIN known_coins coins"
|
||||
" ON (recoup_refresh.coin_pub = coins.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" ON (denoms.denominations_serial = coins.denominations_serial)"
|
||||
" WHERE coins.coin_pub=$1;");
|
||||
PREPARE (pg,
|
||||
"reserve_open_by_coin",
|
||||
"SELECT"
|
||||
" reserve_open_deposit_uuid"
|
||||
",coin_sig"
|
||||
",reserve_sig"
|
||||
",contribution_val"
|
||||
",contribution_frac"
|
||||
" FROM reserves_open_deposits"
|
||||
" WHERE coin_pub=$1;");
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
"Getting transactions for coin %s\n",
|
||||
TALER_B2S (coin_pub));
|
||||
for (unsigned int i = 0; NULL != work[i].statement; i++)
|
||||
{
|
||||
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||
work[i].statement,
|
||||
params,
|
||||
work[i].cb,
|
||||
&chc);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Coin %s yielded %d transactions of type %s\n",
|
||||
TALER_B2S (coin_pub),
|
||||
qs,
|
||||
work[i].statement);
|
||||
if ( (0 > qs) ||
|
||||
(chc.failed) )
|
||||
{
|
||||
if (NULL != chc.head)
|
||||
TEH_COMMON_free_coin_transaction_list (cls,
|
||||
chc.head);
|
||||
*tlp = NULL;
|
||||
if (chc.failed)
|
||||
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
||||
return qs;
|
||||
}
|
||||
}
|
||||
*tlp = chc.head;
|
||||
if (NULL == chc.head)
|
||||
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||
}
|
44
src/exchangedb/pg_get_coin_transactions.h
Normal file
44
src/exchangedb/pg_get_coin_transactions.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file pg_get_coin_transactions.h
|
||||
* @brief implementation of the get_coin_transactions function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_GET_COIN_TRANSACTIONS_H
|
||||
#define PG_GET_COIN_TRANSACTIONS_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Compile a list of all (historic) transactions performed with the given coin
|
||||
* (/refresh/melt, /deposit, /refund and /recoup operations).
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param coin_pub coin to investigate
|
||||
* @param[out] tlp set to list of transactions, NULL if coin is fresh
|
||||
* @return database transaction status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_get_coin_transactions (
|
||||
void *cls,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
struct TALER_EXCHANGEDB_TransactionList **tlp);
|
||||
|
||||
#endif
|
@ -19,16 +19,14 @@
|
||||
* included in each plugin.
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "plugin_exchangedb_common.h"
|
||||
|
||||
/**
|
||||
* Free memory associated with the given reserve history.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state (unused)
|
||||
* @param rh history to free.
|
||||
*/
|
||||
static void
|
||||
common_free_reserve_history (void *cls,
|
||||
struct TALER_EXCHANGEDB_ReserveHistory *rh)
|
||||
|
||||
void
|
||||
TEH_COMMON_free_reserve_history (
|
||||
void *cls,
|
||||
struct TALER_EXCHANGEDB_ReserveHistory *rh)
|
||||
{
|
||||
(void) cls;
|
||||
while (NULL != rh)
|
||||
@ -99,15 +97,10 @@ common_free_reserve_history (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free linked list of transactions.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state (unused)
|
||||
* @param tl list to free
|
||||
*/
|
||||
static void
|
||||
common_free_coin_transaction_list (void *cls,
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl)
|
||||
void
|
||||
TEH_COMMON_free_coin_transaction_list (
|
||||
void *cls,
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl)
|
||||
{
|
||||
(void) cls;
|
||||
while (NULL != tl)
|
||||
|
51
src/exchangedb/plugin_exchangedb_common.h
Normal file
51
src/exchangedb/plugin_exchangedb_common.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file plugin_exchangedb_common.h
|
||||
* @brief implementation of database-independent functions
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PLUGIN_EXCHANGEDB_COMMON_H
|
||||
#define PLUGIN_EXCHANGEDB_COMMON_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
/**
|
||||
* Free memory associated with the given reserve history.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state (unused)
|
||||
* @param[in] rh history to free.
|
||||
*/
|
||||
void
|
||||
TEH_COMMON_free_reserve_history (
|
||||
void *cls,
|
||||
struct TALER_EXCHANGEDB_ReserveHistory *rh);
|
||||
|
||||
|
||||
/**
|
||||
* Free linked list of transactions.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state (unused)
|
||||
* @param[in] tl list to free
|
||||
*/
|
||||
void
|
||||
TEH_COMMON_free_coin_transaction_list (
|
||||
void *cls,
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl);
|
||||
|
||||
#endif
|
@ -29,8 +29,10 @@
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
#include "plugin_exchangedb_common.h"
|
||||
#include "pg_helper.h"
|
||||
#include "pg_do_reserve_open.h"
|
||||
#include "pg_get_coin_transactions.h"
|
||||
#include "pg_get_expired_reserves.h"
|
||||
#include "pg_get_unfinished_close_requests.h"
|
||||
#include "pg_insert_close_request.h"
|
||||
@ -45,7 +47,6 @@
|
||||
#include <pthread.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
#include "plugin_exchangedb_common.c"
|
||||
|
||||
/**
|
||||
* Set to 1 to enable Postgres auto_explain module. This will
|
||||
@ -1177,53 +1178,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" ON (kc.denominations_serial = denom.denominations_serial)"
|
||||
" WHERE melt_serial_id>=$1"
|
||||
" ORDER BY melt_serial_id ASC;"),
|
||||
/* Query the 'refresh_commitments' by coin public key,
|
||||
used in #postgres_get_coin_transactions() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_refresh_session_by_coin",
|
||||
"SELECT"
|
||||
" rc"
|
||||
",old_coin_sig"
|
||||
",amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
",denoms.denom_pub_hash"
|
||||
",denoms.fee_refresh_val"
|
||||
",denoms.fee_refresh_frac"
|
||||
",kc.age_commitment_hash"
|
||||
",melt_serial_id"
|
||||
" FROM refresh_commitments"
|
||||
" JOIN known_coins kc"
|
||||
" ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE old_coin_pub=$1;"),
|
||||
/* Find purse deposits by coin,
|
||||
used in #postgres_get_coin_transactions() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_purse_deposit_by_coin_pub",
|
||||
"SELECT"
|
||||
" partner_base_url"
|
||||
",pd.amount_with_fee_val"
|
||||
",pd.amount_with_fee_frac"
|
||||
",denoms.fee_deposit_val"
|
||||
",denoms.fee_deposit_frac"
|
||||
",pd.purse_pub"
|
||||
",kc.age_commitment_hash"
|
||||
",pd.coin_sig"
|
||||
",pd.purse_deposit_serial_id"
|
||||
",pr.refunded"
|
||||
" FROM purse_deposits pd"
|
||||
" LEFT JOIN partners"
|
||||
" USING (partner_serial_id)"
|
||||
" JOIN purse_requests pr"
|
||||
" USING (purse_pub)"
|
||||
" JOIN known_coins kc"
|
||||
" ON (pd.coin_pub = kc.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
// FIXME: use to-be-created materialized index
|
||||
// on coin_pub (query crosses partitions!)
|
||||
" WHERE pd.coin_pub=$1;"),
|
||||
/* Store information about the desired denominations for a
|
||||
refresh operation, used in #postgres_insert_refresh_reveal() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
@ -1287,26 +1241,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" AND h_contract_terms=$4"
|
||||
" AND merchant_pub=$2"),
|
||||
/* Query the 'refunds' by coin public key */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_refunds_by_coin",
|
||||
"SELECT"
|
||||
" dep.merchant_pub"
|
||||
",ref.merchant_sig"
|
||||
",dep.h_contract_terms"
|
||||
",ref.rtransaction_id"
|
||||
",ref.amount_with_fee_val"
|
||||
",ref.amount_with_fee_frac"
|
||||
",denom.fee_refund_val "
|
||||
",denom.fee_refund_frac "
|
||||
",ref.refund_serial_id"
|
||||
" FROM refunds ref"
|
||||
" JOIN deposits dep"
|
||||
" ON (ref.coin_pub = dep.coin_pub AND ref.deposit_serial_id = dep.deposit_serial_id)"
|
||||
" JOIN known_coins kc"
|
||||
" ON (ref.coin_pub = kc.coin_pub)"
|
||||
" JOIN denominations denom"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE ref.coin_pub=$1;"),
|
||||
/* Query the 'refunds' by coin public key, merchant_pub and contract hash */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_refunds_by_coin_and_contract",
|
||||
@ -1727,36 +1661,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" WHERE wire_target_h_payto=$1"
|
||||
" AND wtid_raw=$2"),
|
||||
|
||||
/* Used in #postgres_get_coin_transactions() to obtain information
|
||||
about how a coin has been spend with /deposit requests. */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_deposit_with_coin_pub",
|
||||
"SELECT"
|
||||
" dep.amount_with_fee_val"
|
||||
",dep.amount_with_fee_frac"
|
||||
",denoms.fee_deposit_val"
|
||||
",denoms.fee_deposit_frac"
|
||||
",denoms.denom_pub_hash"
|
||||
",kc.age_commitment_hash"
|
||||
",dep.wallet_timestamp"
|
||||
",dep.refund_deadline"
|
||||
",dep.wire_deadline"
|
||||
",dep.merchant_pub"
|
||||
",dep.h_contract_terms"
|
||||
",dep.wire_salt"
|
||||
",wt.payto_uri"
|
||||
",dep.coin_sig"
|
||||
",dep.deposit_serial_id"
|
||||
",dep.done"
|
||||
" FROM deposits dep"
|
||||
" JOIN wire_targets wt"
|
||||
" USING (wire_target_h_payto)"
|
||||
" JOIN known_coins kc"
|
||||
" ON (kc.coin_pub = dep.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE dep.coin_pub=$1;"),
|
||||
|
||||
/* Used in #postgres_get_link_data(). */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_link",
|
||||
@ -2212,31 +2116,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" JOIN exchange_do_recoup_by_reserve($1) robr"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE recoup_timestamp>=$2;"),
|
||||
/* Used in #postgres_get_coin_transactions() to obtain recoup transactions
|
||||
affecting old coins of refreshed coins */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"recoup_by_old_coin",
|
||||
"SELECT"
|
||||
" coins.coin_pub"
|
||||
",coin_sig"
|
||||
",coin_blind"
|
||||
",amount_val"
|
||||
",amount_frac"
|
||||
",recoup_timestamp"
|
||||
",denoms.denom_pub_hash"
|
||||
",coins.denom_sig"
|
||||
",recoup_refresh_uuid"
|
||||
" FROM recoup_refresh"
|
||||
" JOIN known_coins coins"
|
||||
" USING (coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" USING (denominations_serial)"
|
||||
" WHERE rrc_serial IN"
|
||||
" (SELECT rrc.rrc_serial"
|
||||
" FROM refresh_commitments"
|
||||
" JOIN refresh_revealed_coins rrc"
|
||||
" USING (melt_serial_id)"
|
||||
" WHERE old_coin_pub=$1);"),
|
||||
/* Used in #postgres_get_reserve_history() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"close_by_reserve",
|
||||
@ -2348,57 +2227,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" AND request_timestamp>=$2;"),
|
||||
/* Used in #postgres_get_coin_transactions() to obtain recoup transactions
|
||||
for a coin */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"recoup_by_coin",
|
||||
"SELECT"
|
||||
" reserves.reserve_pub"
|
||||
",denoms.denom_pub_hash"
|
||||
",coin_sig"
|
||||
",coin_blind"
|
||||
",amount_val"
|
||||
",amount_frac"
|
||||
",recoup_timestamp"
|
||||
",recoup_uuid"
|
||||
" FROM recoup rcp"
|
||||
/* NOTE: suboptimal JOIN follows: crosses shards!
|
||||
Could theoretically be improved via a materialized
|
||||
index. But likely not worth it (query is rare and
|
||||
number of reserve shards might be limited) */
|
||||
" JOIN reserves_out ro"
|
||||
" USING (reserve_out_serial_id)"
|
||||
" JOIN reserves"
|
||||
" USING (reserve_uuid)"
|
||||
" JOIN known_coins coins"
|
||||
" USING (coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" ON (denoms.denominations_serial = coins.denominations_serial)"
|
||||
" WHERE coins.coin_pub=$1;"),
|
||||
/* Used in #postgres_get_coin_transactions() to obtain recoup transactions
|
||||
for a refreshed coin */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"recoup_by_refreshed_coin",
|
||||
"SELECT"
|
||||
" old_coins.coin_pub AS old_coin_pub"
|
||||
",coin_sig"
|
||||
",coin_blind"
|
||||
",amount_val"
|
||||
",amount_frac"
|
||||
",recoup_timestamp"
|
||||
",denoms.denom_pub_hash"
|
||||
",coins.denom_sig"
|
||||
",recoup_refresh_uuid"
|
||||
" FROM recoup_refresh"
|
||||
" JOIN refresh_revealed_coins rrc"
|
||||
" USING (rrc_serial)"
|
||||
" JOIN refresh_commitments rfc"
|
||||
" ON (rrc.melt_serial_id = rfc.melt_serial_id)"
|
||||
" JOIN known_coins old_coins"
|
||||
" ON (rfc.old_coin_pub = old_coins.coin_pub)"
|
||||
" JOIN known_coins coins"
|
||||
" ON (recoup_refresh.coin_pub = coins.coin_pub)"
|
||||
" JOIN denominations denoms"
|
||||
" ON (denoms.denominations_serial = coins.denominations_serial)"
|
||||
" WHERE coins.coin_pub=$1;"),
|
||||
/* Used in #postgres_get_reserve_by_h_blind() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"reserve_by_h_blind",
|
||||
@ -5580,8 +5408,8 @@ postgres_get_reserve_history (void *cls,
|
||||
if ( (qs < 0) ||
|
||||
(rhc.status != GNUNET_OK) )
|
||||
{
|
||||
common_free_reserve_history (cls,
|
||||
rhc.rh);
|
||||
TEH_COMMON_free_reserve_history (cls,
|
||||
rhc.rh);
|
||||
rhc.rh = NULL;
|
||||
if (qs >= 0)
|
||||
{
|
||||
@ -5691,8 +5519,8 @@ postgres_get_reserve_status (void *cls,
|
||||
if ( (qs < 0) ||
|
||||
(rhc.status != GNUNET_OK) )
|
||||
{
|
||||
common_free_reserve_history (cls,
|
||||
rhc.rh);
|
||||
TEH_COMMON_free_reserve_history (cls,
|
||||
rhc.rh);
|
||||
rhc.rh = NULL;
|
||||
if (qs >= 0)
|
||||
{
|
||||
@ -7150,620 +6978,6 @@ postgres_get_link_data (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closure for callbacks called from #postgres_get_coin_transactions()
|
||||
*/
|
||||
struct CoinHistoryContext
|
||||
{
|
||||
/**
|
||||
* Head of the coin's history list.
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_TransactionList *head;
|
||||
|
||||
/**
|
||||
* Public key of the coin we are building the history for.
|
||||
*/
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub;
|
||||
|
||||
/**
|
||||
* Closure for all callbacks of this database plugin.
|
||||
*/
|
||||
void *db_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
|
||||
/**
|
||||
* Set to 'true' if the transaction failed.
|
||||
*/
|
||||
bool failed;
|
||||
|
||||
/**
|
||||
* Set to 'true' if we found a deposit or melt (for invariant check).
|
||||
*/
|
||||
bool have_deposit_or_melt;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_deposit (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i < num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_DepositListEntry *deposit;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
chc->have_deposit_or_melt = true;
|
||||
deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&deposit->amount_with_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
&deposit->deposit_fee),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&deposit->h_denom_pub),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
|
||||
&deposit->h_age_commitment),
|
||||
&deposit->no_age_commitment),
|
||||
GNUNET_PQ_result_spec_timestamp ("wallet_timestamp",
|
||||
&deposit->timestamp),
|
||||
GNUNET_PQ_result_spec_timestamp ("refund_deadline",
|
||||
&deposit->refund_deadline),
|
||||
GNUNET_PQ_result_spec_timestamp ("wire_deadline",
|
||||
&deposit->wire_deadline),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
|
||||
&deposit->merchant_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
&deposit->h_contract_terms),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
|
||||
&deposit->wire_salt),
|
||||
GNUNET_PQ_result_spec_string ("payto_uri",
|
||||
&deposit->receiver_wire_account),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&deposit->csig),
|
||||
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("done",
|
||||
&deposit->done),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (deposit);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_DEPOSIT;
|
||||
tl->details.deposit = deposit;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_purse_deposit (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i < num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_PurseDepositListEntry *deposit;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
chc->have_deposit_or_melt = true;
|
||||
deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&deposit->amount),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
&deposit->deposit_fee),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
|
||||
&deposit->purse_pub),
|
||||
GNUNET_PQ_result_spec_uint64 ("purse_deposit_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("partner_base_url",
|
||||
&deposit->exchange_base_url),
|
||||
NULL),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&deposit->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
|
||||
&deposit->h_age_commitment),
|
||||
GNUNET_PQ_result_spec_bool ("refunded",
|
||||
&deposit->refunded),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (deposit);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
deposit->no_age_commitment = GNUNET_is_zero (&deposit->h_age_commitment);
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_PURSE_DEPOSIT;
|
||||
tl->details.purse_deposit = deposit;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_melt (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_MeltListEntry *melt;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
chc->have_deposit_or_melt = true;
|
||||
melt = GNUNET_new (struct TALER_EXCHANGEDB_MeltListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("rc",
|
||||
&melt->rc),
|
||||
/* oldcoin_index not needed */
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&melt->h_denom_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
|
||||
&melt->coin_sig),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&melt->amount_with_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
|
||||
&melt->melt_fee),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
|
||||
&melt->h_age_commitment),
|
||||
&melt->no_age_commitment),
|
||||
GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (melt);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_MELT;
|
||||
tl->details.melt = melt;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_refund (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RefundListEntry *refund;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
refund = GNUNET_new (struct TALER_EXCHANGEDB_RefundListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
|
||||
&refund->merchant_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_sig",
|
||||
&refund->merchant_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
&refund->h_contract_terms),
|
||||
GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
|
||||
&refund->rtransaction_id),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&refund->refund_amount),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
|
||||
&refund->refund_fee),
|
||||
GNUNET_PQ_result_spec_uint64 ("refund_serial_id",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (refund);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_REFUND;
|
||||
tl->details.refund = refund;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_old_coin_recoup (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
|
||||
&recoup->coin.coin_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&recoup->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
|
||||
&recoup->coin_blind),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&recoup->value),
|
||||
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
|
||||
&recoup->timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&recoup->coin.denom_pub_hash),
|
||||
TALER_PQ_result_spec_denom_sig ("denom_sig",
|
||||
&recoup->coin.denom_sig),
|
||||
GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (recoup);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
recoup->old_coin_pub = *chc->coin_pub;
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP;
|
||||
tl->details.old_coin_recoup = recoup;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_recoup (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RecoupListEntry *recoup;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||
&recoup->reserve_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&recoup->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&recoup->h_denom_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
|
||||
&recoup->coin_blind),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&recoup->value),
|
||||
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
|
||||
&recoup->timestamp),
|
||||
GNUNET_PQ_result_spec_uint64 ("recoup_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (recoup);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_RECOUP;
|
||||
tl->details.recoup = recoup;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the results of a SELECT statement
|
||||
* that has returned @a num_results results.
|
||||
*
|
||||
* @param cls closure of type `struct CoinHistoryContext`
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
add_coin_recoup_refresh (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct CoinHistoryContext *chc = cls;
|
||||
struct PostgresClosure *pg = chc->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
|
||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||
uint64_t serial_id;
|
||||
|
||||
recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
|
||||
&recoup->old_coin_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
|
||||
&recoup->coin_sig),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
|
||||
&recoup->coin_blind),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&recoup->value),
|
||||
GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
|
||||
&recoup->timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
&recoup->coin.denom_pub_hash),
|
||||
TALER_PQ_result_spec_denom_sig ("denom_sig",
|
||||
&recoup->coin.denom_sig),
|
||||
GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (recoup);
|
||||
chc->failed = true;
|
||||
return;
|
||||
}
|
||||
recoup->coin.coin_pub = *chc->coin_pub;
|
||||
}
|
||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||
tl->next = chc->head;
|
||||
tl->type = TALER_EXCHANGEDB_TT_RECOUP_REFRESH;
|
||||
tl->details.recoup_refresh = recoup;
|
||||
tl->serial_id = serial_id;
|
||||
chc->head = tl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work we need to do.
|
||||
*/
|
||||
struct Work
|
||||
{
|
||||
/**
|
||||
* SQL prepared statement name.
|
||||
*/
|
||||
const char *statement;
|
||||
|
||||
/**
|
||||
* Function to call to handle the result(s).
|
||||
*/
|
||||
GNUNET_PQ_PostgresResultHandler cb;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compile a list of all (historic) transactions performed with the given coin
|
||||
* (/refresh/melt, /deposit, /refund and /recoup operations).
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param coin_pub coin to investigate
|
||||
* @param[out] tlp set to list of transactions, NULL if coin is fresh
|
||||
* @return database transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_get_coin_transactions (
|
||||
void *cls,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
struct TALER_EXCHANGEDB_TransactionList **tlp)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
static const struct Work work[] = {
|
||||
/** #TALER_EXCHANGEDB_TT_DEPOSIT */
|
||||
{ "get_deposit_with_coin_pub",
|
||||
&add_coin_deposit },
|
||||
/** #TALER_EXCHANGEDB_TT_MELT */
|
||||
{ "get_refresh_session_by_coin",
|
||||
&add_coin_melt },
|
||||
/** #TALER_EXCHANGEDB_TT_PURSE_DEPOSIT */
|
||||
{ "get_purse_deposit_by_coin_pub",
|
||||
&add_coin_purse_deposit },
|
||||
/** #TALER_EXCHANGEDB_TT_REFUND */
|
||||
{ "get_refunds_by_coin",
|
||||
&add_coin_refund },
|
||||
/** #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP */
|
||||
{ "recoup_by_old_coin",
|
||||
&add_old_coin_recoup },
|
||||
/** #TALER_EXCHANGEDB_TT_RECOUP */
|
||||
{ "recoup_by_coin",
|
||||
&add_coin_recoup },
|
||||
/** #TALER_EXCHANGEDB_TT_RECOUP_REFRESH */
|
||||
{ "recoup_by_refreshed_coin",
|
||||
&add_coin_recoup_refresh },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (coin_pub),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
struct CoinHistoryContext chc = {
|
||||
.head = NULL,
|
||||
.coin_pub = coin_pub,
|
||||
.pg = pg,
|
||||
.db_cls = cls
|
||||
};
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
"Getting transactions for coin %s\n",
|
||||
TALER_B2S (coin_pub));
|
||||
for (unsigned int i = 0; NULL != work[i].statement; i++)
|
||||
{
|
||||
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||
work[i].statement,
|
||||
params,
|
||||
work[i].cb,
|
||||
&chc);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Coin %s yielded %d transactions of type %s\n",
|
||||
TALER_B2S (coin_pub),
|
||||
qs,
|
||||
work[i].statement);
|
||||
if ( (0 > qs) ||
|
||||
(chc.failed) )
|
||||
{
|
||||
if (NULL != chc.head)
|
||||
common_free_coin_transaction_list (cls,
|
||||
chc.head);
|
||||
*tlp = NULL;
|
||||
if (chc.failed)
|
||||
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
||||
return qs;
|
||||
}
|
||||
}
|
||||
*tlp = chc.head;
|
||||
if (NULL == chc.head)
|
||||
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #handle_wt_result.
|
||||
*/
|
||||
@ -14927,7 +14141,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin->get_reserve_balance = &postgres_get_reserve_balance;
|
||||
plugin->get_reserve_history = &postgres_get_reserve_history;
|
||||
plugin->get_reserve_status = &postgres_get_reserve_status;
|
||||
plugin->free_reserve_history = &common_free_reserve_history;
|
||||
plugin->count_known_coins = &postgres_count_known_coins;
|
||||
plugin->ensure_coin_known = &postgres_ensure_coin_known;
|
||||
plugin->get_known_coin = &postgres_get_known_coin;
|
||||
@ -14952,8 +14165,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin->insert_refresh_reveal = &postgres_insert_refresh_reveal;
|
||||
plugin->get_refresh_reveal = &postgres_get_refresh_reveal;
|
||||
plugin->get_link_data = &postgres_get_link_data;
|
||||
plugin->get_coin_transactions = &postgres_get_coin_transactions;
|
||||
plugin->free_coin_transaction_list = &common_free_coin_transaction_list;
|
||||
plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
|
||||
plugin->lookup_transfer_by_deposit = &postgres_lookup_transfer_by_deposit;
|
||||
plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
|
||||
@ -15133,6 +14344,12 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
/* NEW style, sort alphabetically! */
|
||||
plugin->do_reserve_open
|
||||
= &TEH_PG_do_reserve_open;
|
||||
plugin->free_coin_transaction_list
|
||||
= &TEH_COMMON_free_coin_transaction_list;
|
||||
plugin->free_reserve_history
|
||||
= &TEH_COMMON_free_reserve_history;
|
||||
plugin->get_coin_transactions
|
||||
= &TEH_PG_get_coin_transactions;
|
||||
plugin->get_expired_reserves
|
||||
= &TEH_PG_get_expired_reserves;
|
||||
plugin->get_unfinished_close_requests
|
||||
|
@ -1788,6 +1788,31 @@ struct TALER_EXCHANGEDB_PurseDepositListEntry
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Information about a /reserves/$RID/open operation in a coin transaction history.
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_ReserveOpenListEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* Signature of the reserve.
|
||||
*/
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
|
||||
/**
|
||||
* Contribution of the coin to the open fee, including
|
||||
* deposit fee.
|
||||
*/
|
||||
struct TALER_Amount coin_contribution;
|
||||
|
||||
/**
|
||||
* Signature by the coin affirming the open deposit.
|
||||
*/
|
||||
struct TALER_CoinSpendSignatureP coin_sig;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Information about a /purses/$PID/deposit operation.
|
||||
*/
|
||||
@ -1947,7 +1972,12 @@ enum TALER_EXCHANGEDB_TransactionType
|
||||
/**
|
||||
* Purse deposit operation.
|
||||
*/
|
||||
TALER_EXCHANGEDB_TT_PURSE_DEPOSIT = 6
|
||||
TALER_EXCHANGEDB_TT_PURSE_DEPOSIT = 6,
|
||||
|
||||
/**
|
||||
* Reserve open deposit operation.
|
||||
*/
|
||||
TALER_EXCHANGEDB_TT_RESERVE_OPEN = 7
|
||||
|
||||
};
|
||||
|
||||
@ -2023,6 +2053,12 @@ struct TALER_EXCHANGEDB_TransactionList
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_PurseDepositListEntry *purse_deposit;
|
||||
|
||||
/**
|
||||
* Coin was used to pay to open a reserve.
|
||||
* (#TALER_EXCHANGEDB_TT_RESERVE_OPEN)
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_ReserveOpenListEntry *reserve_open;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user