aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-11-07 14:39:15 +0100
committerChristian Grothoff <christian@grothoff.org>2016-11-07 14:39:15 +0100
commit1d740824fa8914e21c402abefc5f3d5a8cdfa4ca (patch)
tree74223d7b8931806183f5b5d8b09222c00d8a62c7
parent6d6a9dac39bd6c24a7d527186aaa2a1eec2d8c36 (diff)
parent247b8e33b3ea20407910929c78232ff0d44e8d9a (diff)
downloadexchange-1d740824fa8914e21c402abefc5f3d5a8cdfa4ca.tar.xz
resolving merge issue
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules3
-rw-r--r--default.nix84
-rw-r--r--doc/paper/taler.bib18
-rw-r--r--doc/paper/taler.tex348
m---------gnunet0
-rw-r--r--m4/libgcrypt.m4122
-rw-r--r--src/auditordb/Makefile.am23
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c1824
-rw-r--r--src/auditordb/test-auditor-db-postgres.conf7
-rw-r--r--src/auditordb/test_auditordb.c798
-rw-r--r--src/bank-lib/test_bank_api.c32
-rw-r--r--src/benchmark/taler-exchange-benchmark.c10
-rw-r--r--src/exchange-lib/Makefile.am2
-rw-r--r--src/exchange-lib/exchange_api_admin.c3
-rw-r--r--src/exchange-lib/exchange_api_common.c5
-rw-r--r--src/exchange-lib/exchange_api_common.h41
-rw-r--r--src/exchange-lib/exchange_api_deposit.c2
-rw-r--r--src/exchange-lib/exchange_api_refresh.c9
-rw-r--r--src/exchange-lib/exchange_api_refresh_link.c7
-rw-r--r--src/exchange-lib/exchange_api_refund.c2
-rw-r--r--src/exchange-lib/exchange_api_reserve.c11
-rw-r--r--src/exchange-lib/exchange_api_track_transaction.c2
-rw-r--r--src/exchange-lib/exchange_api_track_transfer.c3
-rw-r--r--src/exchange-lib/exchange_api_wire.c2
-rw-r--r--src/exchange-lib/test_exchange_api.c41
-rw-r--r--src/exchange/taler-exchange-httpd_admin.c2
-rw-r--r--src/exchange/taler-exchange-httpd_db.c179
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c88
-rw-r--r--src/exchange/taler-exchange-httpd_parsing.c12
-rw-r--r--src/exchange/taler-exchange-httpd_refresh.c24
-rw-r--r--src/exchange/taler-exchange-httpd_refund.c7
-rw-r--r--src/exchange/taler-exchange-httpd_reserve.c4
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c104
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h36
-rw-r--r--src/exchange/taler-exchange-httpd_test.c7
-rw-r--r--src/exchange/taler-exchange-httpd_tracking.c1
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c490
-rw-r--r--src/exchangedb/test_exchangedb.c229
-rw-r--r--src/include/taler_auditordb_plugin.h171
-rw-r--r--src/include/taler_error_codes.h1089
-rw-r--r--src/include/taler_exchange_service.h25
-rw-r--r--src/include/taler_json_lib.h12
-rw-r--r--src/include/taler_util.h2
-rw-r--r--src/json/json.c29
-rw-r--r--taler-exchange-dev.nix61
46 files changed, 5457 insertions, 515 deletions
diff --git a/.gitignore b/.gitignore
index d359e0c96..6a6c27d38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@ GTAGS
src/lib/test_exchange_api
doc/doxygen/doxygen_sqlite3.db
src/auditor/taler-auditor
+src/auditor/taler-auditor-sign
src/bank-lib/test_bank_api
src/bank-lib/test_bank_api_with_fakebank
src/exchange-lib/test_exchange_api
diff --git a/.gitmodules b/.gitmodules
index 7625aa983..381d9c129 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "doc/api"]
path = doc/api
url = git@git.taler.net:api
+[submodule "gnunet"]
+ path = gnunet
+ url = git://taler.net/gnunet.git
diff --git a/default.nix b/default.nix
new file mode 100644
index 000000000..358538e8f
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,84 @@
+# Nix package for GNUnet development
+#
+## INSTALL
+#
+# To build and install the package in the user environment, use:
+#
+# $ nix-env -f . -i
+#
+## BUILD ONLY
+#
+# To build the package and add it to the nix store, use:
+#
+# $ nix-build
+#
+## SHELL
+#
+# To launch a shell with all dependencies installed in the environment, use one of the following:
+# $ nix-shell
+#
+# After entering nix-shell, build it:
+#
+# $ configurePhase
+# $ buildPhase
+#
+## NIXPKGS
+#
+# For all of the above commands, nixpkgs to use can be set the following way:
+#
+# a) by default it uses nixpkgs pinned to a known working version
+#
+# b) use nixpkgs from the system:
+# --arg pkgs 0
+#
+# c) use nixpkgs at a given path
+# --arg pkgs /path/to/nixpkgs
+#
+## CCACHE
+#
+# To enable ccache, use the following:
+#
+# --argstr ccache_dir /var/cache/ccache
+
+# or when using nix-shell:
+# --argstr ccache_dir ~/.ccache
+#
+# and make sure the given directory is writable by the nixpkgs group when using nix-build or nix-env -i,
+# or the current user when using nix-shell
+#
+
+{
+ pkgs ? null,
+ ccache_dir ? "",
+}:
+
+let
+ syspkgs = import <nixpkgs> { };
+ pinpkgs = syspkgs.fetchFromGitHub {
+ owner = "NixOS";
+ repo = "nixpkgs";
+
+ # binary cache exists for revisions in https://nixos.org/releases/nixos/<release>/<build>/git-revision
+ rev = "c4469edac1fc1fa5e5b5aa2ceadeda8f3f92d30a"; # https://nixos.org/releases/nixos/16.09/nixos-16.09beta430.c4469ed/git-revision
+ sha256 = "1x6hmf815d5anfxrxl6iivfkk60q5qxa6waa9xnwhwkbc14rhvn9";
+ };
+ usepkgs = if null == pkgs then
+ import pinpkgs {}
+ else
+ if 0 == pkgs then
+ import <nixpkgs> { }
+ else
+ import pkgs {};
+ stdenv = usepkgs.stdenvAdapters.keepDebugInfo usepkgs.stdenv;
+
+in {
+ gnunet-dev = usepkgs.callPackage ./gnunet/gnunet-dev.nix {
+ inherit ccache_dir;
+ };
+ taler-exchange-dev = usepkgs.callPackage ./taler-exchange-dev.nix {
+ inherit ccache_dir;
+ gnunet-dev = usepkgs.callPackage ./gnunet/gnunet-dev.nix {
+ inherit ccache_dir;
+ };
+ };
+}
diff --git a/doc/paper/taler.bib b/doc/paper/taler.bib
index c9ae0893a..deaab570c 100644
--- a/doc/paper/taler.bib
+++ b/doc/paper/taler.bib
@@ -19,6 +19,13 @@
pages = {11-15},
}
+@misc{BOLT,
+ author = {Matthew Green and Ian Miers},
+ title = {Bolt: Anonymous Payment Channels for Decentralized Currencies},
+ howpublished = {Cryptology ePrint Archive, Report 2016/701},
+ year = {2016},
+ note = {\url{http://eprint.iacr.org/2016/701}},
+}
@Misc{greece2015cash,
author = {Reuters},
@@ -90,6 +97,13 @@
organization={Springer}
}
+@inproceedings{zerocash,
+ author = {Eli Ben-Sasson and Alessandro Chiesa and Christina Garman and Matthew Green and Ian Miers and Eran Tromer and Madars Virza},
+ title = {Zerocash: Decentralized Anonymous Payments from Bitcoin},
+ booktitle = {IEEE Symposium on Security \& Privacy},
+ year = {2014},
+}
+
@inproceedings{miers2013zerocoin,
title={Zerocoin: Anonymous distributed e-cash from bitcoin},
author={Miers, Ian and Garman, Christina and Green, Matthew and Rubin, Aviel D},
@@ -197,9 +211,9 @@
author="Bellare, Mihir and Namprempre, Chanathip and Pointcheval, David and Semanko, Michael",
editor="Syverson, Paul",
chapter="The Power of RSA Inversion Oracles and the Security of Chaum's RSA-Based Blind Signature Scheme",
- title="Financial Cryptography: 5th International Conference, FC 2001 Grand Cayman, British West Indies, February 19--22, 2001 Proceedings",
+ title="Financial Cryptography: 5th International Conference",
year="2002",
- publisher="Springer Berlin Heidelberg",
+ publisher="Springer",
address="Berlin, Heidelberg",
pages="319--338",
isbn="978-3-540-46088-6",
diff --git a/doc/paper/taler.tex b/doc/paper/taler.tex
index 0208f2a17..f52baf6c0 100644
--- a/doc/paper/taler.tex
+++ b/doc/paper/taler.tex
@@ -63,7 +63,7 @@
% - sharing = coin copying that should not be taxed
-\title{Refreshing Coins for Giving Change and Refunds \\ in Chaum-style Anonymous Payments}
+\title{Refreshing Coins for Giving Change and Refunds \\ in Chaum-style Anonymous Payment Systems}
\begin{document}
\mainmatter
@@ -77,7 +77,7 @@
\begin{abstract}
This paper introduces {\em Taler}, a Chaum-style digital currency that
enables anonymous payments while ensuring that entities that receive
-payments are auditable and thus taxable. In Taler, customers can
+payments are auditable. In Taler, customers can
never defraud anyone, merchants can only fail to deliver the
merchandise to the customer, and payment service providers can be
fully audited. All parties receive cryptographic evidence for all
@@ -88,10 +88,10 @@ systems that do not provide for privacy.
The key technical contribution underpinning Taler is a new {\em
refresh protocol} which allows fractional payments and refunds while
-maintaining anonymity of the customer and unlinkability of
-transactions. The refresh protocol combines an efficient
-cut-and-choose mechanism with a {\em link} step to ensure that
-refreshing is not abused for transactional payments.
+maintaining untraceability of the customer and unlinkability of
+transactions. The refresh protocol combines an
+efficient cut-and-choose mechanism with a {\em link} step to ensure
+that refreshing is not abused for transactional payments.
We argue that Taler provides a secure digital currency for modern
liberal societies as it is a flexible, libre and efficient protocol
@@ -106,11 +106,11 @@ developed nation states have adopted highly transparent payment systems,
such as the MasterCard and VisaCard credit card schemes and computerized
bank transactions such as SWIFT. These systems enable mass surveillance
by both governments and private companies. Aspects of this surveillance
-sometimes benifit society by providing information about tax evasion or
+sometimes benefit society by providing information about tax evasion or
crimes like extortion. % TODO : anti-money laundering later?
In particular, bribery and corruption are limited to elites who can
afford to escape the dragnet.
-
+%
At the other extreme, weaker developing nation states have economic
activity based largely on coins, paper money or even barter. Here,
the state is often unable to effectively monitor or tax economic
@@ -118,24 +118,23 @@ activity, and this limits the ability of the state to shape the
society. As bribery is virtually impossible to detect, corruption is
widespread and not limited to social elites.
%
-ZeroCoin~\cite{miers2013zerocoin} is an example for translating an
+Zerocoin~\cite{miers2013zerocoin} is an example for translating an
anarchistic economy into the digital realm.
This paper describes Taler, a simple and practical payment system for
-a modern social-liberal society, which is not being served well by
-current payment systems which enable either an authoritarian state in
-total control of the population, or create weak states with almost
-anarchistic economies.
+a social-liberal society, which is underserved by
+current payment systems.
The Taler protocol is influenced by ideas from
-Chaum~\cite{chaum1983blind} and also follows Chaum's basic architecture of
-customer, merchant and exchange (Figure~\ref{fig:cmm}).
-The two designs share the key first step where the {\em customer}
-withdraws digital {\em coins} from the {\em exchange} with unlinkability
-provided via blind signatures. The coins can then be spent at a
-{\em merchant} who {\em deposits} them at the exchange.
-Taler uses online detection of double-spending, thus assuring the merchant
-instantly that a transaction is valid.
+Chaum~\cite{chaum1983blind} and also follows Chaum's basic
+architecture of customer, merchant and exchange
+(Figure~\ref{fig:cmm}). The two designs share the key first step
+where the {\em customer} withdraws digital {\em coins} from the {\em
+ exchange} with unlinkability provided via blind signatures. The
+coins can then be spent at a {\em merchant} who {\em deposits} them at
+the exchange. Taler uses online detection of double-spending and
+provides excuplability via cryptographic proofs. Thus merchants are
+instantly assured that a transaction is valid.
\begin{figure}[h]
\centering
@@ -159,16 +158,14 @@ instantly that a transaction is valid.
\label{fig:cmm}
\end{figure}
-
A key issue for an efficient Chaumian digital payment system is the
need to provide change. For example, a customer may want to pay
-\EUR{49,99}, but has withdrawn a \EUR{100,00} coin. Withdrawng 10,000
-pieces with a denomination of \EUR{0,01} and transferring 4,999 would
-be too inefficient, even for modern systems. The customer should not
+\EUR{49,99}, but has withdrawn a \EUR{100,00} coin. Withdrawing 10,000
+coins with a denomination of \EUR{0,01} and transferring 4,999 coins would
+be too inefficient. The customer should not
withdraw exact change from her account, as doing so reduces anonymity
-due to the obvious corrolation. A practical payment system must thus
-support giving change in the form of spendable coins, say a \EUR{0,01}
-coin and a \EUR{50,00} coin.
+due to the obvious correlation. A practical payment system must thus
+support giving change.
Taler solves the problem of giving change by introducing a new
{\em refresh protocol}. Using this protocol, a customer can obtain
@@ -178,9 +175,11 @@ Additionally, the refresh protocol ensures that the change is owned by
the same entity which owned the original coin.
+\vspace{-0.3cm}
\section{Related Work}
+\vspace{-0.3cm}
-\subsection{Blockchain-based currencies}
+%\subsection{Blockchain-based currencies}
In recent years, a class of decentralized electronic payment systems,
based on collectively recorded and verified append-only public
@@ -191,13 +190,14 @@ transactions are recorded for eternity, which can enable
identification of users. In theory, this concern has been addressed
with the Zerocoin extension to the protocol~\cite{miers2013zerocoin}.
-These protocols dispense with the need for a central, trusted
-authority, while providing a useful measure of pseudonymity.
+The key contribution of blockchain-based protocols is that
+they dispense with the need for a central, trusted
+authority.
Yet, there are several major irredeemable problems inherent in their designs:
\begin{itemize}
\item The computational puzzles solved by Bitcoin nodes with the purpose
- of securing the block chain consume a considerable amount of energy.
+ of securing the blockchain consume a considerable amount of energy.
So Bitcoin is an environmentally irresponsible design.
\item Bitcoin transactions have pseduononymous recipients, making taxation
hard to systematically enforce.
@@ -216,6 +216,15 @@ Yet, there are several major irredeemable problems inherent in their designs:
% currency exchange and exacerbates the problems with currency fluctuations.
\end{itemize}
+Anonymity extensions for BitCoin such as Zerocoin~\cite{miers2013zerocoin}
+and BOLT~\cite{BOLT} are also limited to transactions with coins
+of fixed discrete value, creating problems with giving change we
+outlined in the introduction. Furthermore, these extensions have
+problems with aborted transactions, which can reduce the anonymity
+set. Taler's refresh protocol also addresses the problem of aborted
+transactions, ensuring that aborts cannot be used to attack the
+privacy assurances of the system.
+
%GreenCoinX\footnote{\url{https://www.greencoinx.com/}} is a more
%recent AltCoin where the company promises to identify the owner of
%each coin via e-mail addresses and phone numbers. While it is unclear
@@ -224,7 +233,7 @@ Yet, there are several major irredeemable problems inherent in their designs:
%would also merely impose a financial panopticon on a BitCoin-style
%money supply and transaction model.
-\subsection{Chaum-style electronic cash}
+%\subsection{Chaum-style electronic cash}
Chaum~\cite{chaum1983blind} proposed a digital payment system that
would provide some customer anonymity while disclosing the identity of
@@ -312,53 +321,64 @@ description of the Opencoin protocol is available to date.
%macropayment. It is therefore unclear how Peppercoin would actually
%reduce the computational burden on the exchange.
-
+%\vspace{-0.3cm}
\section{Design}
+%\vspace{-0.3cm}
The Taler system comprises three principal types of actors
(Figure~\ref{fig:cmm}): The \emph{customer} is interested in receiving
goods or services from the \emph{merchant} in exchange for payment.
-When making a transaction, both the customer and the merchant use the
-same \emph{exchange}, which serves as a payment service provider for
-the financial transaction between the two. The exchange is
-responsible for allowing the customer to convert financial reserves to
-the anonymous digital coins, and for enabling the merchant to convert
-spent digital coins back to funds in a financial reserve. In
-addition, we describe an \emph{auditor} who assures customers and
-merchants that the exchange operates correctly.
-
+To pay, the customer {\em spends} digital coins at the merchant. When
+making a transaction, both the customer and the merchant use the same
+\emph{exchange}, which serves as a payment service provider for the
+financial transaction between the two. The exchange is responsible
+for allowing the customer to withdraw anonymous digital coins from the
+customer's financial reserves, and for enabling the merchant to
+deposit digital coins in return for receiving credit at the merchant's
+financial reserve. In addition, Taler includes an \emph{auditor} who
+assures customers and merchants that the exchange operates correctly.
+
+%\vspace{-0.3cm}
\subsection{Security model}
-
-Taler's security model assumes that cryptographic primitives are
-secure and that each participant is under full control of his system.
-The contact information of the exchange is known to both customer and
-merchant from the start. We further assume that the customer can
-authenticate the merchant, e.g. using X.509
-certificates~\cite{rfc5280}. Finally, we assume that customer has an
-anonymous bi-directional channel, such as Tor, to communicate with
-both the exchange and the merchant.
-
-The exchange is trusted to hold funds of its customers and to forward
-them when receiving the respective deposit instructions from the
-merchants. Customer and merchant can have assurances about the
+%\vspace{-0.3cm}
+
+Taler assumes that each participant has full control over their
+system. We assume the contact information of the exchange is known to
+both customer and merchant from the start, including that the customer
+can authenticate the merchant, for example by using X.509
+certificates~\cite{rfc6818}. A Taler merchant is trusted to deliver
+the service or goods to the customer upon receiving payment. The
+customer can seek legal relief to achieve this, as the customer
+receives cryptographic evidence of the contract and the associated
+payment. We assume each Taler customer has an anonymous
+bi-directional channel, such as Tor, to communicate with both the
+exchange and the merchant.
+
+A Taler exchange is trusted to hold funds of its customers and to
+forward them when receiving the respective deposit instructions from
+the merchants. Customer and merchant can have assurances about the
exchange's liquidity and operation though published audits by
-financial regulators or other trusted third parties. If sufficently
-regular, audits of the exchange's accounts should reveal any possible
-fraud. Online signing keys expire regularly, allowing the exchange to
-destroy the corresponding accumulated cryptographic proofs.
-
-The merchant is trusted to deliver the service or goods to the
-customer upon receiving payment. The customer can seek legal relief
-to achieve this, as he receives cryptographic proofs of the contract
-and has proof that he paid his obligations.
-
-Neither the merchant nor the customer have any ability to {\em effectively}
-defraud the exchange or the state collecting taxes. Here, ``effectively''
-means that the expected return for fraud is negative.
-%
-Note that customers do not need to be trusted in any way, and that in
-particular it is never necessary for anyone to try to recover funds
-from customers using legal coersion.
+financial regulators or other trusted third parties. An exchange's
+signing keys expire regularly, allowing the exchange to eventually
+destroy the corresponding accumulated cryptographic proofs, and
+limiting the exchange's financial liability.
+
+On the cryptographic side, a Taler exchange demands that coins use a
+full domain hash (FDH) to make so-called ``one-more forgery'' attacks
+provably hard, assuming the RSA known-target inversion problem is
+hard~\cite[Theorem 12]{RSA-HDF-KTIvCTI}. For a withdrawn coin,
+violating the customers anonymity cryptographily requires recognizing
+a random blinding factor from a random element of the group of
+integers modulo the denomination key's RSA modulus, which appears
+impossible even with a quantum computers. For a refreshed coin,
+unlinkabiltiy requires the hardness of the discrete logarithm for
+Curve25519.
+
+The cut-and-choose protocol prevents merchants and customers from
+conspiring to conceal a merchants income. We assume that the maximum
+tax rate is below $1/\kappa$, and that expected transaction losses of
+a factor of $\kappa$ for tax evasion are thus unacceptable.
+
\subsection{Taxability and Entities}
@@ -396,15 +416,14 @@ could spend the associated funds. Assuming the payment system has
effective double-spending detection, this means that either entity has
to constantly fear that the funds might no longer be available to it.
It follows that sharing coins by copying a private key implies mutual
-trust between the two parties, in which case we treat them as the same
-entity for taxability.
+trust between the two parties.
In Taler, making funds available by copying a private key and thus
sharing control is {\bf not} considered a {\em transaction} and thus
{\bf not} recorded for taxation. Taler does, however, ensure
taxability when a merchant entity acquires exclusive control over the
value represented by a digital coins. For such transactions, the state
-can obtain information from the exchange, or a bank, that identifies
+can obtain information from the exchange that identifies
the entity that received the digital coins as well as the exact value
of those coins. Taler also allows the exchange, and hence the state,
to learn the value of digital coins withdrawn by a customer---but not
@@ -439,7 +458,7 @@ is unable to link the known identity of the customer that withdrew
anonymous digital coins to the {\em purchase} performed later at the
merchant.
-While the customer thus has anonymity for purchases, the exchange will
+While the customer thus has untraceability for purchases, the exchange will
always learn the merchant's identity in order to credit the merchant's
account. This is also necessary for taxation, as Taler deliberately
exposes these events as anchors for tax audits on income.
@@ -467,31 +486,30 @@ exposes these events as anchors for tax audits on income.
A \emph{coin} in Taler is a public-private key pair where the private
key is only known to the owner of the coin. A coin derives its
-financial value from an RSA signature over a the full domain hash
-(FDH) of the coin's public key. An FDH is used so that ``one-more
-forgery'' is provably hard assuming the RSA known-target inversion
-problem is hard~cite[Theorem 12]{RSA-HDF-KTIvCTI}. The exchange has
-multiple RSA {\em denomination key} pairs available for blind-signing
-coins of different value.
+financial value from an RSA signature over the FDH
+of the coin's public key. The exchange has multiple RSA {\em
+ denomination key} pairs available for blind-signing coins of
+different value.
Denomination keys have an expiration date, before which any coins
signed with it must be spent or refreshed. This allows the exchange
to eventually discard records of old transactions, thus limiting the
records that the exchange must retain and search to detect
-double-spending attempts. Furthermore, the exchange uses each
-denomination key only for a limited number of coins. In this way, if
-a private denomination key were to be compromised, the exchange would
-detect this once more coins were redeemed than the total that was
-signed into existence using that denomination key. In this case, the
-exchange can allow authentic customers to exchange their unspent
-coins that were signed with the compromised private key, while
-refusing further anonymous transactions involving those coins. As a
-result, the financial damage of losing a private signing key can be
-limited to at most twice the amount originally signed with that key.
-
-We also ensure that the exchange cannot deanonymize users by signing
+double-spending attempts. If a private denomination key were to be
+compromised, the exchange can detect this once more coins are redeemed
+than the total that was signed into existence using that denomination
+key. In this case, the exchange can allow authentic customers to
+redeem their unspent coins that were signed with the compromised
+private key, while refusing further deposits involving coins signed by
+the compromised denomination key. As a result, the financial damage
+of losing a private signing key is limited to at most the amount
+originally signed with that key, and denomination key rotation can be
+used to bound that risk.
+
+We ensure that the exchange cannot deanonymize users by signing
each coin with a fresh denomination key. For this, exchanges are
-required to publicly announce their denomination keys in advance.
+required to publicly announce their denomination keys in advance
+with validity periods that imply sufficiently strong anonymity sets.
These announcements are expected to be signed with an off-line
long-term private {\em master signing key} of the exchange and the
auditor. Additionally, customers should obtain these announcements
@@ -515,10 +533,12 @@ withdrawal message as proof that the reserve was debited correctly.
After a coin is issued, the customer is the only entity that knows the
private key of the coin, making him the \emph{owner} of the coin. Due
-to the use of blind signatures, the exchange does not even learn the
+to the use of blind signatures, the exchange does not learn the
public key during the withdrawal process. If the private key is
shared with others, they become co-owners of the coin. Knowledge of
-the private key of the coin enables the owner to spent the coin.
+the private key of the coin and the signature over the coin's public
+key by an exchange's denomination key enables spending the
+coin.
% \subsection{Coin spending}
@@ -612,9 +632,9 @@ purposes. The exchange's bank transfers dealing in traditional currency
are expected to be recorded for tax authorities to ensure taxability.
% FIXME: Auditor?
-We use RSA for denomination keys and EdDSA over some eliptic curve
-$\mathbb{E}$ for all other keys. Let $G$ denote the generator of
-our elliptic curve $\mathbb{E}$.
+$S_K$ denotes RSA signing with denomination key $K$ and EdDSA
+over eliptic curve $\mathbb{E}$ for other types of keys.
+$G$ denotes the generator of elliptic curve $\mathbb{E}$.
\subsection{Withdrawal}
@@ -639,25 +659,25 @@ Now the customer carries out the following interaction with the exchange:
\item coin key $C := (c_s,C_p)$ with private key $c_s$ and public key $C_p := c_s G$,
\item blinding factor $b$, and commits $\langle W, C, b \rangle$ to disk.
\end{itemize}
- \item[SEPA Send]
+ \item[Wire transfer send]
The customer transfers an amount of money corresponding to
at least $K_v$ to the exchange, with $W_p$ in the subject line
of the transaction.
- \item[SEPA Recieve]
+ \item[Wire transfer recieve]
The exchange receives the transaction and credits the reserve $W_p$
with the respective amount in its database.
\item[POST {\tt /withdraw/sign}]
The customer sends $S_W(B)$ where $B := B_b(\FDH_K(C_p))$ to
the exchange to request withdrawal of $C$; here, $B_b$ denotes
Chaum-style blinding with blinding factor $b$.
- \item[200 OK / 402 PAYMENT REQUIRED]
+ \item[200 OK / 403 FORBIDDEN]
The exchange checks if the same withdrawal request was issued before;
in this case, it sends a Chaum-style blind signature $S_K(B)$ with
private key $K_s$ to the customer. \\
If this is a fresh withdrawal request, the exchange performs the following transaction:
\begin{enumerate}
\item checks if the reserve $W_p$ has sufficient funds
- for a coin of value corresponding to $K$
+ for a coin of value corresponding to $K$,
\item stores the withdrawal request and response
$\langle S_W(B), S_K(B) \rangle$ in its database
for future reference,
@@ -668,9 +688,8 @@ Now the customer carries out the following interaction with the exchange:
error back to the customer, with proof that it operated correctly.
Assuming the signature was valid, this would involve showing the transaction
history for the reserve.
- % FIXME: Is it really the whole history?
\item[Done] The customer computes and verifies the unblinded signature
- $S_K(\FDH_K{C_p}) = U_b(S_K(B))$.
+ $S_K(\FDH_K(C_p)) = U_b(S_K(B))$.
Finally the customer saves the coin $\langle S_K(\FDH_K(C_p)), c_s \rangle$
to their local wallet on disk.
\end{description}
@@ -681,9 +700,9 @@ Now the customer carries out the following interaction with the exchange:
A customer can spend coins at a merchant, under the condition that the
merchant trusts the exchange that issued the coin.
% FIXME: Auditor here?
-Merchants are identified by their public key $M_p = m_s G$ which the
+Merchants are identified by their public key $M_p$ which the
customer's wallet learns through the merchant's webpage, which itself
-must be authenticated with X.509c.
+should be authenticated with X.509c.
% FIXME: Is this correct?
We now describe the protocol between the customer, merchant, and exchange
@@ -702,35 +721,37 @@ with signature $\widetilde{C} := S_K(\FDH_K(C_p))$
\item[Proposal]
The merchant creates a digitally signed contract
$\mathcal{A} := S_M(m, f, a, H(p, r), \vec{X})$
- where $m$ is an identifier for this transaction, $a$ is data relevant
+ where $m$ is an identifier for this transaction, $f$ is the price of the offer,
+ and $a$ is data relevant
to the contract indicating which services or goods the merchant will
- deliver to the customer, $f$ is the price of the offer, and
+ deliver to the customer, including the {\tt /merchant-specific} URI for the payment.
$p$ is the merchant's payment information (e.g. his IBAN number), and
$r$ is a random nonce. The merchant commits $\langle \mathcal{A} \rangle$
to disk and sends $\mathcal{A}$ to the customer.
\item[Customer Setup]
- The customer should already possess a coin issued by a exchange that is
- accepted by the merchant, meaning $K$ should be publicly signed by
+ The customer should already possess a coin $\widetilde{C}$ issued by a exchange that is
+ accepted by the merchant, meaning $K$ of $\widetilde{C}$ should be publicly signed by
some $X_j$ from $\vec{X}$, and has a value $\geq f$.
-\item[POST {\tt /???}] \label{deposit}
+\item[POST {\tt /merchant-specific}]
+ Let $X_j$ be the exchange which signed $\widetilde{C}$ with $K$.
The customer generates a \emph{deposit-permission}
$\mathcal{D} := S_c(\widetilde{C}, m, f, H(a), H(p,r), M_p)$
- and sends $\langle \mathcal{D}, X_j\rangle$ to the merchant,
- where $X_j$ is the exchange which signed $K$.
+ and sends $\langle \mathcal{D}, X_j\rangle$ to the merchant.
\item[POST {\tt/deposit}]
The merchant gives $(\mathcal{D}, p, r)$ to the exchange, thereby
revealing $p$ only to the exchange.
-\item[200 OK / 409 CONFLICT]
+\item[200 OK / 403 FORBIDDEN]
The exchange validates $\mathcal{D}$ and checks for double spending.
If the coin has been involved in previous transactions and the new
- one would exceed its remaining value, it sends an error
+ one would exceed its remaining value, it sends a ``403 FORBIDDEN'' error
with the records from the previous transactions back to the merchant. \\
%
If double spending is not found, the exchange commits $\langle \mathcal{D} \rangle$ to disk
- and notifies the merchant that the deposit operation was successful.
-\item[200 OK / ???]
+ and signs a ``200 OK'' message affirming the deposit operation was successful.
+\item[200 OK / 424 FAILED DEPENDENCY]
The merchant commits and forwards the notification from the exchange to the
- customer, confirming the success or failure of the operation.
+ customer, confirming the success (``200 OK'') or failure (``424 FAILED DEPENDENCY'')
+ of the operation.
\end{description}
We have simplified the exposition by assuming that one coin suffices,
@@ -738,12 +759,12 @@ but in practice a customer can use multiple coins from the same
exchange where the total value adds up to $f$ by running the above
steps for each of the coins.
-If a transaction is aborted after Step~\ref{deposit},
-subsequent transactions with the same coin could be linked to the coin,
-but not directly to the coin's owner. The same applies to partially
-spent coins where $f$ is smaller than the actual value of the coin.
-To unlink subsequent transactions from a coin, the customer has to
-execute the coin refreshing protocol with the exchange.
+If a transaction is aborted after the first POST, subsequent
+transactions with the same coin could be linked to this operation.
+The same applies to partially spent coins where $f$ is smaller than
+the actual value of the coin. To unlink subsequent transactions from
+a coin, the customer has to execute the following coin refreshing
+protocol with the exchange.
%\begin{figure}[h]
%\centering
@@ -785,17 +806,17 @@ denomination $K$ is melted to obtain a fresh coin $\widetilde{C}$
with the same denomination. In practice, Taler uses a natural
extension where multiple fresh coins are generated a the same time to
enable giving precise change matching any amount.
-In the protocol, $\kappa \ge 3$ is a security parameter for the
-cut-and-choose part of the protocol and $G$ is the
-generator of the elliptic curve.
-
-We note that $\kappa = 3$ is actually perfectly sufficient in most
-cases in practice, as the cut-and-choose protocol does not need to
-provide cryptographic security: If the maximum applicable tax is less
-than $\frac{2}{3}$, then detecting $\kappa = 3$ ensures that cheating
-results in a negative return on average as $\kappa - 1$ out of
-$\kappa$ attempts to cheat are detected. This makes the use of
-cut-and-choose practical and efficient in this context.
+
+In the protocol, $\kappa \ge 2$ is a security parameter for the
+cut-and-choose part of the protocol. $\kappa = 3$ is actually
+perfectly sufficient in most cases in practice, as the cut-and-choose
+protocol does not need to provide cryptographic security: If the
+maximum applicable tax is less than $\frac{2}{3}$, then $\kappa = 3$
+ensures that cheating results in a negative financial return on
+average as $\kappa - 1$ out of $\kappa$ attempts to hide from taxation
+are detected and penalized by a total loss. This makes our use of
+cut-and-choose practical and efficient, and in particularly faster
+than the comparable use of zk-SNARKs in ZeroCash~\cite{zerocash}.
% FIXME: I'm explicit about the rounds in postquantum.tex
@@ -805,16 +826,16 @@ cut-and-choose practical and efficient in this context.
a transfer private key $t^{(i)}_s$ and computes
\begin{itemize}
\item the transfer public key $T^{(i)}_p := t^{(i)}_s G$ and
- \item the new coin secret seed $L_i := H(c'_s T_p^{(i)})$.
+ \item the new coin secret seed $L^{(i)} := H(c'_s T_p^{(i)})$.
\end{itemize}
We have computed $L_i$ as a Diffie-Hellman shared secret between
the transfer key pair $T^{(i)} := \left(t^{(i)}_s,T^{(i)}_p\right)$
and old coin key pair $C' := \left(c_s', C_p'\right)$;
- as a result, $L_i = H(t^{(i)}_s C'_p)$ also holds.
- Now the customer applies key derivation functions $\KDF_?$ to $L_i$ to generate
+ as a result, $L^{(i)} = H(t^{(i)}_s C'_p)$ also holds.
+ Now the customer applies key derivation functions $\KDF_{\textrm{blinding}}$ and $\KDF_{\textrm{Ed25519}}$ to $L^{(i)}$ to generate
\begin{itemize}
- \item a blinding factor $b^{(i)} = \FDH_K(\KDF_{\textrm{blinding}}(L_i))$.
- \item $c_s^{(i)} = \KDF_{\textrm{Ed25519}}(L_i)$
+ \item a blinding factor $b^{(i)} = \FDH_K(\KDF_{\textrm{blinding}}(L^{(i)}))$.
+ \item $c_s^{(i)} = \KDF_{\textrm{Ed25519}}(L^{(i)})$
\end{itemize}
Now the customer can compute her new coin key pair
$C^{(i)} := \left(c_s^{(i)}, C_p^{(i)}\right)$
@@ -837,7 +858,7 @@ cut-and-choose practical and efficient in this context.
this time to prevent the exchange from assisting tax evasion. \\
%
The exchange sends $S_{K'}(C'_p, \gamma)$ to the customer where
- $K'$ is the exchange's message signing key.
+ $K'$ is the exchange's message signing key, thereby commmitting the exchange to $\gamma$.
\item[POST {\tt /refresh/reveal}]
The customer commits $\langle C', S_K(C'_p, \gamma) \rangle$ to disk.
Also, the customer assembles
@@ -850,16 +871,16 @@ cut-and-choose practical and efficient in this context.
\vspace{-2ex}
\begin{minipage}{5cm}
\begin{align*}
- \overline{L}_i :&= H(t_s^{(i)} C_p') \\
- \overline{c}_s^{(i)} :&= \KDF_{\textrm{Ed25519}}(\overline{L}_i) \\
- \overline{C^{(i)}_p} :&= \overline{c}_s^{(i)} G
+ \overline{L^{(i)}} :&= H(t_s^{(i)} C_p') \\
+ \overline{c_s^{(i)}} :&= \KDF_{\textrm{Ed25519}}(\overline{L^{(i)}}) \\
+ \overline{C^{(i)}_p} :&= \overline{c_s^{(i)}} G
\end{align*}
\end{minipage}
\begin{minipage}{5cm}
\begin{align*}
\overline{T_p^{(i)}} :&= t_s^{(i)} G \\
- \overline{b}^{(i)} :&= \FDH_K(\KDF_{\textrm{blinding}}(\overline{L}_i)) \\
- \overline{B^{(i)}} :&= B_{\overline{b_i}}(\overline{C_p^{(i)}})
+ \overline{b^{(i)}} :&= \FDH_K(\KDF_{\textrm{blinding}}(\overline{L^{(i)}})) \\
+ \overline{B^{(i)}} :&= B_{\overline{b^{(i)}}}(\overline{C_p^{(i)}})
\end{align*}
\end{minipage}
@@ -909,7 +930,7 @@ taxation model as with such trust they are assumed to be the same
entity.
The auditor can anonymously check if the exchange correctly implements the
-link request, thus preventing the exchange operator from legally disabling
+link request, thus preventing the exchange operator from secretly disabling
this protocol component. Without the link operation, Taler would
devolve into a payment system where both sides can be anonymous, and
thus no longer provide taxability.
@@ -942,13 +963,12 @@ faulty exchange.
The third case are transient failures, such as network failures or
temporary hardware failures at the exchange service provider. Here, the
client may receive an explicit protocol indication, such as an HTTP
-response code 500 ``internal server error'' or simply no response.
+response code ``500 INTERNAL SERVER ERROR'' or simply no response.
The appropriate behavior for the client is to automatically retry
after 1s, and twice more at randomized times within 1 minute.
If those three attempts fail, the user should be informed about the
delay. The client should then retry another three times within the
-next 24h, and after that time the auditor be informed about the outage.
-
+next 24h, and after that time the auditor should be informed about the outage.
Using this process, short term failures should be effectively obscured
from the user, while malicious behavior is reported to the auditor who
can then presumably rectify the situation, using methods such as
@@ -1041,7 +1061,7 @@ At network latencies above 10 ms, the delay
for executing a transaction is dominated by the network latency, as
local processing virtually always takes less than 10 ms.
-Database transactions are dominated by writes
+Database transactions are dominated by writes%
%(Figure~\ref{fig:read} vs. Figure~\ref{fig:write})
, as Taler mostly needs to log
transactions and occasionally needs to read to guard against
@@ -1092,7 +1112,7 @@ actually facilitates voluntary cooperation between the exchange and
criminals~\cite{sander1999escrow} and where the state could
deanonymize citizens.
-\subsection{Offline Payments}
+%\subsection{Offline Payments}
Chaum's original proposals for anonymous digital cash avoided the need
for online interactions with the exchange to detect double spending by
@@ -1115,7 +1135,7 @@ coin after restoring from backup.
%subjected to financial penalties by the state in relation to the
%amount transferred by the traditional currency transfer.
-\subsection{Cryptographic proof vs. evidence}
+% \subsection{Cryptographic proof vs. evidence}
In this paper we have use the term ``proof'' in many places as the
protocol provides cryptographic proofs of which parties behave
@@ -1167,11 +1187,11 @@ the participants have to disclose their core secrets.
\bibliographystyle{alpha}
\bibliography{taler,rfc}
-\vfill
-\begin{center}
- \Large Demonstration available at \url{https://demo.taler.net/}
-\end{center}
-\vfill
+%\vfill
+%\begin{center}
+% \Large Demonstration available at \url{https://demo.taler.net/}
+%\end{center}
+%\vfill
\newpage
\appendix
@@ -1241,13 +1261,13 @@ data being committed to disk are represented in between $\langle\rangle$.
\item[$\vec{b}$]{Vector of $b^{(i)}$}
\item[$B^{(i)}$]{Blinding of $C_p^{(i)}$}
\item[$\vec{B}$]{Vector of $B^{(i)}$}
- \item[$L_i$]{Link secret derived from ECDH operation via hashing}
-% \item[$E_{L_i}()$]{Symmetric encryption using key $L_i$}
+ \item[$L^{(i)}$]{Link secret derived from ECDH operation via hashing}
+% \item[$E_{L^{(i)}}()$]{Symmetric encryption using key $L^{(i)}$}
% \item[$E^{(i)}$]{$i$-th encryption of the private information $(c_s^{(i)}, b_i)$}
% \item[$\vec{E}$]{Vector of $E^{(i)}$}
\item[$\cal{R}$]{Tuple of revealed vectors in cut-and-choose protocol,
where the vectors exclude the selected index $\gamma$}
- \item[$\overline{L_i}$]{Link secrets derived by the verifier from DH}
+ \item[$\overline{L^{(i)}}$]{Link secrets derived by the verifier from DH}
\item[$\overline{B^{(i)}}$]{Blinded values derived by the verifier}
\item[$\overline{T_p^{(i)}}$]{Public transfer keys derived by the verifier from revealed private keys}
\item[$\overline{c_s^{(i)}}$]{Private keys obtained from decryption by the verifier}
diff --git a/gnunet b/gnunet
new file mode 160000
+Subproject 674d59da9956998c0e33ad1a3aa9facc3ba66d1
diff --git a/m4/libgcrypt.m4 b/m4/libgcrypt.m4
new file mode 100644
index 000000000..6cf482fcb
--- /dev/null
+++ b/m4/libgcrypt.m4
@@ -0,0 +1,122 @@
+dnl Autoconf macros for libgcrypt
+dnl Copyright (C) 2002, 2004, 2011 Free Software Foundation, Inc.
+dnl
+dnl This file is free software; as a special exception the author gives
+dnl unlimited permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+dnl
+dnl This file is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+
+dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS.
+dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed
+dnl with the API version to also check the API compatibility. Example:
+dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed
+dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using
+dnl this features allows to prevent build against newer versions of libgcrypt
+dnl with a changed API.
+dnl
+AC_DEFUN([AM_PATH_LIBGCRYPT],
+[ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_ARG_WITH(libgcrypt-prefix,
+ AC_HELP_STRING([--with-libgcrypt-prefix=PFX],
+ [prefix where LIBGCRYPT is installed (optional)]),
+ libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="")
+ if test x$libgcrypt_config_prefix != x ; then
+ if test x${LIBGCRYPT_CONFIG+set} != xset ; then
+ LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config
+ fi
+ fi
+
+ AC_PATH_TOOL(LIBGCRYPT_CONFIG, libgcrypt-config, no)
+ tmp=ifelse([$1], ,1:1.2.0,$1)
+ if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
+ req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
+ min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
+ else
+ req_libgcrypt_api=0
+ min_libgcrypt_version="$tmp"
+ fi
+
+ AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version)
+ ok=no
+ if test "$LIBGCRYPT_CONFIG" != "no" ; then
+ req_major=`echo $min_libgcrypt_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_libgcrypt_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_libgcrypt_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version`
+ major=`echo $libgcrypt_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+ minor=`echo $libgcrypt_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+ micro=`echo $libgcrypt_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
+ if test "$major" -gt "$req_major"; then
+ ok=yes
+ else
+ if test "$major" -eq "$req_major"; then
+ if test "$minor" -gt "$req_minor"; then
+ ok=yes
+ else
+ if test "$minor" -eq "$req_minor"; then
+ if test "$micro" -ge "$req_micro"; then
+ ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ AC_MSG_RESULT([yes ($libgcrypt_config_version)])
+ else
+ AC_MSG_RESULT(no)
+ fi
+ if test $ok = yes; then
+ # If we have a recent libgcrypt, we should also check that the
+ # API is compatible
+ if test "$req_libgcrypt_api" -gt 0 ; then
+ tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0`
+ if test "$tmp" -gt 0 ; then
+ AC_MSG_CHECKING([LIBGCRYPT API version])
+ if test "$req_libgcrypt_api" -eq "$tmp" ; then
+ AC_MSG_RESULT([okay])
+ else
+ ok=no
+ AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp])
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
+ LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
+ ifelse([$2], , :, [$2])
+ libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none`
+ if test x"$libgcrypt_config_host" != xnone ; then
+ if test x"$libgcrypt_config_host" != x"$host" ; then
+ AC_MSG_WARN([[
+***
+*** The config script $LIBGCRYPT_CONFIG was
+*** built for $libgcrypt_config_host and thus may not match the
+*** used host $host.
+*** You may want to use the configure option --with-libgcrypt-prefix
+*** to specify a matching config script.
+***]])
+ fi
+ fi
+ else
+ LIBGCRYPT_CFLAGS=""
+ LIBGCRYPT_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(LIBGCRYPT_CFLAGS)
+ AC_SUBST(LIBGCRYPT_LIBS)
+])
diff --git a/src/auditordb/Makefile.am b/src/auditordb/Makefile.am
index e8ec40272..640f95f25 100644
--- a/src/auditordb/Makefile.am
+++ b/src/auditordb/Makefile.am
@@ -12,7 +12,8 @@ pkgcfg_DATA = \
auditordb-postgres.conf
EXTRA_DIST = \
- auditordb-postgres.conf
+ auditordb-postgres.conf \
+ test-auditor-db-postgres.conf
plugindir = $(libdir)/taler
@@ -49,5 +50,21 @@ libtalerauditordb_la_LDFLAGS = \
-no-undefined
-EXTRA_test_auditordb_postgres_DEPENDENCIES = \
- libtaler_plugin_auditordb_postgres.la
+#EXTRA_test_auditordb_postgres_DEPENDENCIES = \
+# libtaler_plugin_auditordb_postgres.la
+
+
+check_PROGRAMS = \
+ test-auditordb-postgres
+
+AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
+TESTS = \
+ test-auditordb-postgres
+
+test_auditordb_postgres_SOURCES = \
+ test_auditordb.c
+test_auditordb_postgres_LDADD = \
+ libtalerauditordb.la \
+ $(top_srcdir)/src/pq/libtalerpq.la \
+ $(top_srcdir)/src/util/libtalerutil.la \
+ -lgnunetutil
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index 3205d489c..81c1b4369 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -17,9 +17,8 @@
/**
* @file plugin_auditordb_postgres.c
* @brief Low-level (statement-level) Postgres database access for the auditor
- * @author Florian Dold
* @author Christian Grothoff
- * @author Sree Harsha Totakura
+ * @author Gabor X Toth
*/
#include "platform.h"
#include "taler_pq_lib.h"
@@ -326,7 +325,7 @@ postgres_create_tables (void *cls)
of; "refund_serial_id" tells us the last entry in "refunds"
for this denom_pub that the auditor is aware of. */
SQLEXEC ("CREATE TABLE IF NOT EXISTS denomination_pending"
- "(denom_pub_hash BYTEA PRIMARY KEY REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE"
+ "(denom_pub_hash BYTEA PRIMARY KEY REFERENCES auditor_denominations (denom_pub_hash) ON DELETE CASCADE"
",denom_balance_val INT8 NOT NULL"
",denom_balance_frac INT4 NOT NULL"
",denom_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
@@ -435,8 +434,8 @@ postgres_create_tables (void *cls)
",reserve_profits_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
")");
- SQLEXEC_INDEX("CREATE INDEX historic_reserve_summary_by_master_pub_start_date"
- " ON historic_ledger(master_pub,start_date)");
+ SQLEXEC_INDEX("CREATE INDEX historic_reserve_summary_by_master_pub_start_date "
+ "ON historic_reserve_summary(master_pub,start_date)");
/* Table with historic business ledger; basically, when the exchange
@@ -510,13 +509,457 @@ postgres_prepare (PGconn *db_conn)
PQclear (result); result = NULL; \
} while (0);
- /* Used in #postgres_XXX() */
- PREPARE ("test_insert",
- "INSERT INTO test "
- "(test_pub"
- ") VALUES "
- "($1);",
+ /* Used in #postgres_insert_denomination_info() */
+ PREPARE ("auditor_denominations_insert",
+ "INSERT INTO auditor_denominations "
+ "(denom_pub_hash"
+ ",master_pub"
+ ",valid_from"
+ ",expire_withdraw"
+ ",expire_deposit"
+ ",expire_legal"
+ ",coin_val"
+ ",coin_frac"
+ ",coin_curr"
+ ",fee_withdraw_val"
+ ",fee_withdraw_frac"
+ ",fee_withdraw_curr"
+ ",fee_deposit_val"
+ ",fee_deposit_frac"
+ ",fee_deposit_curr"
+ ",fee_refresh_val"
+ ",fee_refresh_frac"
+ ",fee_refresh_curr"
+ ",fee_refund_val"
+ ",fee_refund_frac"
+ ",fee_refund_curr"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21);",
+ 21, NULL);
+
+ /* Used in #postgres_insert_denomination_info() */
+ PREPARE ("auditor_denominations_select",
+ "SELECT"
+ " denom_pub_hash"
+ ",valid_from"
+ ",expire_withdraw"
+ ",expire_deposit"
+ ",expire_legal"
+ ",coin_val"
+ ",coin_frac"
+ ",coin_curr"
+ ",fee_withdraw_val"
+ ",fee_withdraw_frac"
+ ",fee_withdraw_curr"
+ ",fee_deposit_val"
+ ",fee_deposit_frac"
+ ",fee_deposit_curr"
+ ",fee_refresh_val"
+ ",fee_refresh_frac"
+ ",fee_refresh_curr"
+ ",fee_refund_val"
+ ",fee_refund_frac"
+ ",fee_refund_curr"
+ " FROM auditor_denominations"
+ " WHERE master_pub=$1;",
1, NULL);
+
+ /* Used in #postgres_insert_auditor_progress() */
+ PREPARE ("auditor_progress_insert",
+ "INSERT INTO auditor_progress "
+ "(master_pub"
+ ",last_reserve_in_serial_id"
+ ",last_reserve_out_serial_id"
+ ",last_deposit_serial_id"
+ ",last_melt_serial_id"
+ ",last_refund_serial_id"
+ ",last_prewire_serial_id"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7);",
+ 7, 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_deposit_serial_id=$3"
+ ",last_melt_serial_id=$4"
+ ",last_refund_serial_id=$5"
+ ",last_prewire_serial_id=$6"
+ " WHERE master_pub=$7",
+ 7, NULL);
+
+ /* Used in #postgres_get_auditor_progress() */
+ PREPARE ("auditor_progress_select",
+ "SELECT"
+ " last_reserve_in_serial_id"
+ ",last_reserve_out_serial_id"
+ ",last_deposit_serial_id"
+ ",last_melt_serial_id"
+ ",last_refund_serial_id"
+ ",last_prewire_serial_id"
+ " FROM auditor_progress"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_insert_reserve_info() */
+ PREPARE ("auditor_reserves_insert",
+ "INSERT INTO auditor_reserves "
+ "(reserve_pub"
+ ",master_pub"
+ ",reserve_balance_val"
+ ",reserve_balance_frac"
+ ",reserve_balance_curr"
+ ",withdraw_fee_balance_val"
+ ",withdraw_fee_balance_frac"
+ ",withdraw_fee_balance_curr"
+ ",expiration_date"
+ ",last_reserve_in_serial_id"
+ ",last_reserve_out_serial_id"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);",
+ 11, NULL);
+
+ /* Used in #postgres_update_reserve_info() */
+ PREPARE ("auditor_reserves_update",
+ "UPDATE auditor_reserves SET"
+ " reserve_balance_val=$1"
+ ",reserve_balance_frac=$2"
+ ",reserve_balance_curr=$3"
+ ",withdraw_fee_balance_val=$4"
+ ",withdraw_fee_balance_frac=$5"
+ ",withdraw_fee_balance_curr=$6"
+ ",expiration_date=$7"
+ ",last_reserve_in_serial_id=$8"
+ ",last_reserve_out_serial_id=$9"
+ " WHERE reserve_pub=$10 AND master_pub=$11;",
+ 11, NULL);
+
+ /* Used in #postgres_get_reserve_info() */
+ PREPARE ("auditor_reserves_select",
+ "SELECT"
+ " reserve_balance_val"
+ ",reserve_balance_frac"
+ ",reserve_balance_curr"
+ ",withdraw_fee_balance_val"
+ ",withdraw_fee_balance_frac"
+ ",withdraw_fee_balance_curr"
+ ",expiration_date"
+ ",last_reserve_in_serial_id"
+ ",last_reserve_out_serial_id"
+ " FROM auditor_reserves"
+ " WHERE reserve_pub=$1 AND master_pub=$2;",
+ 2, NULL);
+
+ /* Used in #postgres_insert_reserve_summary() */
+ PREPARE ("auditor_reserve_balance_insert",
+ "INSERT INTO auditor_reserve_balance"
+ "(master_pub"
+ ",reserve_balance_val"
+ ",reserve_balance_frac"
+ ",reserve_balance_curr"
+ ",withdraw_fee_balance_val"
+ ",withdraw_fee_balance_frac"
+ ",withdraw_fee_balance_curr"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7)",
+ 7, NULL);
+
+ /* Used in #postgres_update_reserve_summary() */
+ PREPARE ("auditor_reserve_balance_update",
+ "UPDATE auditor_reserve_balance SET"
+ " reserve_balance_val=$1"
+ ",reserve_balance_frac=$2"
+ ",reserve_balance_curr=$3"
+ ",withdraw_fee_balance_val=$4"
+ ",withdraw_fee_balance_frac=$5"
+ ",withdraw_fee_balance_curr=$6"
+ " WHERE master_pub=$7;",
+ 7, NULL);
+
+ /* Used in #postgres_get_reserve_summary() */
+ PREPARE ("auditor_reserve_balance_select",
+ "SELECT"
+ " reserve_balance_val"
+ ",reserve_balance_frac"
+ ",reserve_balance_curr"
+ ",withdraw_fee_balance_val"
+ ",withdraw_fee_balance_frac"
+ ",withdraw_fee_balance_curr"
+ " FROM auditor_reserve_balance"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_insert_denomination_balance() */
+ PREPARE ("denomination_pending_insert",
+ "INSERT INTO denomination_pending "
+ "(denom_pub_hash"
+ ",denom_balance_val"
+ ",denom_balance_frac"
+ ",denom_balance_curr"
+ ",deposit_fee_balance_val"
+ ",deposit_fee_balance_frac"
+ ",deposit_fee_balance_curr"
+ ",melt_fee_balance_val"
+ ",melt_fee_balance_frac"
+ ",melt_fee_balance_curr"
+ ",refund_fee_balance_val"
+ ",refund_fee_balance_frac"
+ ",refund_fee_balance_curr"
+ ",last_reserve_out_serial_id"
+ ",last_deposit_serial_id"
+ ",last_melt_serial_id"
+ ",last_refund_serial_id"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);",
+ 17, NULL);
+
+ /* Used in #postgres_update_denomination_balance() */
+ PREPARE ("denomination_pending_update",
+ "UPDATE denomination_pending SET"
+ " denom_balance_val=$1"
+ ",denom_balance_frac=$2"
+ ",denom_balance_curr=$3"
+ ",deposit_fee_balance_val=$4"
+ ",deposit_fee_balance_frac=$5"
+ ",deposit_fee_balance_curr=$6"
+ ",melt_fee_balance_val=$7"
+ ",melt_fee_balance_frac=$8"
+ ",melt_fee_balance_curr=$9"
+ ",refund_fee_balance_val=$10"
+ ",refund_fee_balance_frac=$11"
+ ",refund_fee_balance_curr=$12"
+ ",last_reserve_out_serial_id=$13"
+ ",last_deposit_serial_id=$14"
+ ",last_melt_serial_id=$15"
+ ",last_refund_serial_id=$16"
+ " WHERE denom_pub_hash=$17",
+ 18, NULL);
+
+ /* Used in #postgres_get_denomination_balance() */
+ PREPARE ("denomination_pending_select",
+ "SELECT"
+ " denom_balance_val"
+ ",denom_balance_frac"
+ ",denom_balance_curr"
+ ",deposit_fee_balance_val"
+ ",deposit_fee_balance_frac"
+ ",deposit_fee_balance_curr"
+ ",melt_fee_balance_val"
+ ",melt_fee_balance_frac"
+ ",melt_fee_balance_curr"
+ ",refund_fee_balance_val"
+ ",refund_fee_balance_frac"
+ ",refund_fee_balance_curr"
+ ",last_reserve_out_serial_id"
+ ",last_deposit_serial_id"
+ ",last_melt_serial_id"
+ ",last_refund_serial_id"
+ " FROM denomination_pending"
+ " WHERE denom_pub_hash=$1",
+ 1, NULL);
+
+ /* Used in #postgres_insert_denomination_summary() */
+ PREPARE ("total_liabilities_insert",
+ "INSERT INTO total_liabilities "
+ "(master_pub"
+ ",denom_balance_val"
+ ",denom_balance_frac"
+ ",denom_balance_curr"
+ ",deposit_fee_balance_val"
+ ",deposit_fee_balance_frac"
+ ",deposit_fee_balance_curr"
+ ",melt_fee_balance_val"
+ ",melt_fee_balance_frac"
+ ",melt_fee_balance_curr"
+ ",refund_fee_balance_val"
+ ",refund_fee_balance_frac"
+ ",refund_fee_balance_curr"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);",
+ 13, NULL);
+
+ /* Used in #postgres_update_denomination_summary() */
+ PREPARE ("total_liabilities_update",
+ "UPDATE total_liabilities SET"
+ " denom_balance_val=$1"
+ ",denom_balance_frac=$2"
+ ",denom_balance_curr=$3"
+ ",deposit_fee_balance_val=$4"
+ ",deposit_fee_balance_frac=$5"
+ ",deposit_fee_balance_curr=$6"
+ ",melt_fee_balance_val=$7"
+ ",melt_fee_balance_frac=$8"
+ ",melt_fee_balance_curr=$9"
+ ",refund_fee_balance_val=$10"
+ ",refund_fee_balance_frac=$11"
+ ",refund_fee_balance_curr=$12"
+ " WHERE master_pub=$13;",
+ 13, NULL);
+
+ /* Used in #postgres_get_denomination_summary() */
+ PREPARE ("total_liabilities_select",
+ "SELECT"
+ " denom_balance_val"
+ ",denom_balance_frac"
+ ",denom_balance_curr"
+ ",deposit_fee_balance_val"
+ ",deposit_fee_balance_frac"
+ ",deposit_fee_balance_curr"
+ ",melt_fee_balance_val"
+ ",melt_fee_balance_frac"
+ ",melt_fee_balance_curr"
+ ",refund_fee_balance_val"
+ ",refund_fee_balance_frac"
+ ",refund_fee_balance_curr"
+ " FROM total_liabilities"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_insert_risk_summary() */
+ PREPARE ("total_risk_insert",
+ "INSERT INTO total_risk"
+ "(master_pub"
+ ",risk_val"
+ ",risk_frac"
+ ",risk_curr"
+ ") VALUES ($1,$2,$3,$4);",
+ 4, NULL);
+
+ /* Used in #postgres_update_risk_summary() */
+ PREPARE ("total_risk_update",
+ "UPDATE total_risk SET "
+ " risk_val=$1"
+ ",risk_frac=$2"
+ ",risk_curr=$3"
+ " WHERE master_pub=$4;",
+ 4, NULL);
+
+ /* Used in #postgres_get_risk_summary() */
+ PREPARE ("total_risk_select",
+ "SELECT"
+ " risk_val"
+ ",risk_frac"
+ ",risk_curr"
+ " FROM total_risk"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+
+ /* Used in #postgres_insert_historic_denom_revenue() */
+ PREPARE ("historic_denomination_revenue_insert",
+ "INSERT INTO historic_denomination_revenue"
+ "(master_pub"
+ ",denom_pub_hash"
+ ",revenue_timestamp"
+ ",revenue_balance_val"
+ ",revenue_balance_frac"
+ ",revenue_balance_curr"
+ ",deposit_fee_balance_val"
+ ",deposit_fee_balance_frac"
+ ",deposit_fee_balance_curr"
+ ",melt_fee_balance_val"
+ ",melt_fee_balance_frac"
+ ",melt_fee_balance_curr"
+ ",refund_fee_balance_val"
+ ",refund_fee_balance_frac"
+ ",refund_fee_balance_curr"
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15);",
+ 15, NULL);
+
+ /* Used in #postgres_select_historic_denom_revenue() */
+ PREPARE ("historic_denomination_revenue_select",
+ "SELECT"
+ " denom_pub_hash"
+ ",revenue_timestamp"
+ ",revenue_balance_val"
+ ",revenue_balance_frac"
+ ",revenue_balance_curr"
+ ",deposit_fee_balance_val"
+ ",deposit_fee_balance_frac"
+ ",deposit_fee_balance_curr"
+ ",melt_fee_balance_val"
+ ",melt_fee_balance_frac"
+ ",melt_fee_balance_curr"
+ ",refund_fee_balance_val"
+ ",refund_fee_balance_frac"
+ ",refund_fee_balance_curr"
+ " FROM historic_denomination_revenue"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_insert_historic_losses() */
+ PREPARE ("historic_losses_insert",
+ "INSERT INTO historic_losses"
+ "(master_pub"
+ ",denom_pub_hash"
+ ",loss_timestamp"
+ ",loss_balance_val"
+ ",loss_balance_frac"
+ ",loss_balance_curr"
+ ") VALUES ($1,$2,$3,$4,$5,$6);",
+ 6, NULL);
+
+ /* Used in #postgres_select_historic_losses() */
+ PREPARE ("historic_losses_select",
+ "SELECT"
+ " denom_pub_hash"
+ ",loss_timestamp"
+ ",loss_balance_val"
+ ",loss_balance_frac"
+ ",loss_balance_curr"
+ " FROM historic_losses"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_insert_historic_reserve_revenue() */
+ PREPARE ("historic_reserve_summary_insert",
+ "INSERT INTO historic_reserve_summary"
+ "(master_pub"
+ ",start_date"
+ ",end_date"
+ ",reserve_profits_val"
+ ",reserve_profits_frac"
+ ",reserve_profits_curr"
+ ") VALUES ($1,$2,$3,$4,$5,$6);",
+ 6, NULL);
+
+ /* Used in #postgres_select_historic_reserve_revenue() */
+ PREPARE ("historic_reserve_summary_select",
+ "SELECT"
+ " start_date"
+ ",end_date"
+ ",reserve_profits_val"
+ ",reserve_profits_frac"
+ ",reserve_profits_curr"
+ " FROM historic_reserve_summary"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_insert_predicted_result() */
+ PREPARE ("predicted_result_insert",
+ "INSERT INTO predicted_result"
+ "(master_pub"
+ ",balance_val"
+ ",balance_frac"
+ ",balance_curr"
+ ") VALUES ($1,$2,$3,$4);",
+ 4, NULL);
+
+ /* Used in #postgres_update_predicted_result() */
+ PREPARE ("predicted_result_update",
+ "UPDATE predicted_result SET"
+ " balance_val=$1"
+ ",balance_frac=$2"
+ ",balance_curr=$3"
+ " WHERE master_pub=$4;",
+ 4, NULL);
+
+ /* Used in #postgres_get_predicted_balance() */
+ PREPARE ("predicted_result_select",
+ "SELECT"
+ " balance_val"
+ ",balance_frac"
+ ",balance_curr"
+ " FROM predicted_result"
+ " WHERE master_pub=$1;",
+ 1, NULL);
+
return GNUNET_OK;
#undef PREPARE
}
@@ -743,8 +1186,55 @@ postgres_insert_denomination_info (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_DenominationKeyValidityPS *issue)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&issue->denom_hash),
+ GNUNET_PQ_query_param_auto_from_type (&issue->master),
+
+ GNUNET_PQ_query_param_auto_from_type (&issue->start),
+ GNUNET_PQ_query_param_auto_from_type (&issue->expire_withdraw),
+ GNUNET_PQ_query_param_auto_from_type (&issue->expire_deposit),
+ GNUNET_PQ_query_param_auto_from_type (&issue->expire_legal),
+
+ TALER_PQ_query_param_amount_nbo (&issue->value),
+ TALER_PQ_query_param_amount_nbo (&issue->fee_withdraw),
+ TALER_PQ_query_param_amount_nbo (&issue->fee_deposit),
+ TALER_PQ_query_param_amount_nbo (&issue->fee_refresh),
+ TALER_PQ_query_param_amount_nbo (&issue->fee_refund),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ /* check fees match coin currency */
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->value,
+ &issue->fee_withdraw));
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->value,
+ &issue->fee_deposit));
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->value,
+ &issue->fee_refresh));
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->value,
+ &issue->fee_refund));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_denominations_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -762,11 +1252,265 @@ static int
postgres_select_denomination_info (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: type! */
+ TALER_AUDITORDB_DenominationInfoDataCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_denominations_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int ret = GNUNET_OK;
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_select_denomination_info() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (int i = 0; i < nrows; i++)
+ {
+ struct TALER_DenominationKeyValidityPS issue = { .master = *master_pub };
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", &issue.denom_hash),
+
+ GNUNET_PQ_result_spec_auto_from_type ("valid_from", &issue.start),
+ GNUNET_PQ_result_spec_auto_from_type ("expire_withdraw", &issue.expire_withdraw),
+ GNUNET_PQ_result_spec_auto_from_type ("expire_deposit", &issue.expire_deposit),
+ GNUNET_PQ_result_spec_auto_from_type ("expire_legal", &issue.expire_legal),
+
+ TALER_PQ_result_spec_amount_nbo ("coin", &issue.value),
+ TALER_PQ_result_spec_amount_nbo ("fee_withdraw", &issue.fee_withdraw),
+ TALER_PQ_result_spec_amount_nbo ("fee_deposit", &issue.fee_deposit),
+ TALER_PQ_result_spec_amount_nbo ("fee_refresh", &issue.fee_refresh),
+ TALER_PQ_result_spec_amount_nbo ("fee_refund", &issue.fee_refund),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ ret = cb (cb_cls,
+ &issue);
+ switch (ret)
+ {
+ case GNUNET_OK:
+ break;
+
+ default:
+ i = nrows;
+ }
+ }
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Insert information about the auditor's progress with an exchange's
+ * data.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param master_pub master key of the exchange
+ * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed
+ * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
+ * @param last_deposit_serial_id serial ID of the last deposit the auditor processed
+ * @param last_melt_serial_id serial ID of the last refresh the auditor processed
+ * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ */
+int
+postgres_insert_auditor_progress (void *cls,
+ struct TALER_AUDITORDB_Session *session,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ uint64_t last_reserve_in_serial_id,
+ uint64_t last_reserve_out_serial_id,
+ uint64_t last_deposit_serial_id,
+ uint64_t last_melt_serial_id,
+ uint64_t last_refund_serial_id,
+ uint64_t last_prewire_serial_id)
+{
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_melt_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_refund_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_prewire_serial_id),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_progress_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Update information about the progress of the auditor. There
+ * must be an existing record for the exchange.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param master_pub master key of the exchange
+ * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed
+ * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
+ * @param last_deposit_serial_id serial ID of the last deposit the auditor processed
+ * @param last_melt_serial_id serial ID of the last refresh the auditor processed
+ * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ */
+int
+postgres_update_auditor_progress (void *cls,
+ struct TALER_AUDITORDB_Session *session,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ uint64_t last_reserve_in_serial_id,
+ uint64_t last_reserve_out_serial_id,
+ uint64_t last_deposit_serial_id,
+ uint64_t last_melt_serial_id,
+ uint64_t last_refund_serial_id,
+ uint64_t last_prewire_serial_id)
+{
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_melt_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_refund_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_prewire_serial_id),
+
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_progress_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Get information about the progress of the auditor.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param master_pub master key of the exchange
+ * @param[out] last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed
+ * @param[out] last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
+ * @param[out] last_deposit_serial_id serial ID of the last deposit the auditor processed
+ * @param[out] last_melt_serial_id serial ID of the last refresh the auditor processed
+ * @param[out] last_prewire_serial_id serial ID of the last prewire transfer the auditor processed
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure;
+ * #GNUNET_NO if we have no records for the @a master_pub
+ */
+int
+postgres_get_auditor_progress (void *cls,
+ struct TALER_AUDITORDB_Session *session,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ uint64_t *last_reserve_in_serial_id,
+ uint64_t *last_reserve_out_serial_id,
+ uint64_t *last_deposit_serial_id,
+ uint64_t *last_melt_serial_id,
+ uint64_t *last_refund_serial_id,
+ uint64_t *last_prewire_serial_id)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_progress_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_auditor_progress() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_in_serial_id", last_reserve_in_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", last_reserve_out_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_deposit_serial_id", last_deposit_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_melt_serial_id", last_melt_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_refund_serial_id", last_refund_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_prewire_serial_id", last_prewire_serial_id),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -799,8 +1543,42 @@ postgres_insert_reserve_info (void *cls,
uint64_t last_reserve_in_serial_id,
uint64_t last_reserve_out_serial_id)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ TALER_PQ_query_param_amount (reserve_balance),
+ TALER_PQ_query_param_amount (withdraw_fee_balance),
+
+ GNUNET_PQ_query_param_auto_from_type (&expiration_date),
+
+ GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (reserve_balance,
+ withdraw_fee_balance));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_reserves_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -833,8 +1611,42 @@ postgres_update_reserve_info (void *cls,
uint64_t last_reserve_in_serial_id,
uint64_t last_reserve_out_serial_id)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (reserve_balance),
+ TALER_PQ_query_param_amount (withdraw_fee_balance),
+
+ GNUNET_PQ_query_param_auto_from_type (&expiration_date),
+
+ GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id),
+
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (reserve_balance,
+ withdraw_fee_balance));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_reserves_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -867,8 +1679,54 @@ postgres_get_reserve_info (void *cls,
uint64_t *last_reserve_in_serial_id,
uint64_t *last_reserve_out_serial_id)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_reserves_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_reserve_info() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("reserve_balance", reserve_balance),
+ TALER_PQ_result_spec_amount ("withdraw_fee_balance", withdraw_fee_balance),
+
+ GNUNET_PQ_result_spec_auto_from_type ("expiration_date", expiration_date),
+
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_in_serial_id", last_reserve_in_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", last_reserve_out_serial_id),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -891,8 +1749,36 @@ postgres_insert_reserve_summary (void *cls,
const struct TALER_Amount *reserve_balance,
const struct TALER_Amount *withdraw_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ TALER_PQ_query_param_amount (reserve_balance),
+ TALER_PQ_query_param_amount (withdraw_fee_balance),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (reserve_balance,
+ withdraw_fee_balance));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_reserve_balance_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -915,8 +1801,32 @@ postgres_update_reserve_summary (void *cls,
const struct TALER_Amount *reserve_balance,
const struct TALER_Amount *withdraw_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (reserve_balance),
+ TALER_PQ_query_param_amount (withdraw_fee_balance),
+
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_reserve_balance_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -939,8 +1849,48 @@ postgres_get_reserve_summary (void *cls,
struct TALER_Amount *reserve_balance,
struct TALER_Amount *withdraw_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "auditor_reserve_balance_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_reserve_summary() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("reserve_balance", reserve_balance),
+ TALER_PQ_result_spec_amount ("withdraw_fee_balance", withdraw_fee_balance),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -978,8 +1928,51 @@ postgres_insert_denomination_balance (void *cls,
uint64_t last_melt_serial_id,
uint64_t last_refund_serial_id)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
+
+ TALER_PQ_query_param_amount (denom_balance),
+ TALER_PQ_query_param_amount (deposit_fee_balance),
+ TALER_PQ_query_param_amount (melt_fee_balance),
+ TALER_PQ_query_param_amount (refund_fee_balance),
+
+ GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_melt_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_refund_serial_id),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (denom_balance,
+ deposit_fee_balance));
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (denom_balance,
+ melt_fee_balance));
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (denom_balance,
+ refund_fee_balance));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "denomination_pending_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1017,8 +2010,39 @@ postgres_update_denomination_balance (void *cls,
uint64_t last_melt_serial_id,
uint64_t last_refund_serial_id)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (denom_balance),
+ TALER_PQ_query_param_amount (deposit_fee_balance),
+ TALER_PQ_query_param_amount (melt_fee_balance),
+ TALER_PQ_query_param_amount (refund_fee_balance),
+
+ GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_melt_serial_id),
+ GNUNET_PQ_query_param_uint64 (&last_refund_serial_id),
+
+ GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "denomination_pending_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1055,8 +2079,55 @@ postgres_get_denomination_balance (void *cls,
uint64_t *last_melt_serial_id,
uint64_t *last_refund_serial_id)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "denomination_pending_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_denomination_balance() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("denom_balance", denom_balance),
+ TALER_PQ_result_spec_amount ("deposit_fee_balance", deposit_fee_balance),
+ TALER_PQ_result_spec_amount ("melt_fee_balance", melt_fee_balance),
+ TALER_PQ_result_spec_amount ("refund_fee_balance", refund_fee_balance),
+
+ GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", last_reserve_out_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_deposit_serial_id", last_deposit_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_melt_serial_id", last_melt_serial_id),
+ GNUNET_PQ_result_spec_uint64 ("last_refund_serial_id", last_refund_serial_id),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -1082,8 +2153,46 @@ postgres_insert_denomination_summary (void *cls,
const struct TALER_Amount *melt_fee_balance,
const struct TALER_Amount *refund_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ TALER_PQ_query_param_amount (denom_balance),
+ TALER_PQ_query_param_amount (deposit_fee_balance),
+ TALER_PQ_query_param_amount (melt_fee_balance),
+ TALER_PQ_query_param_amount (refund_fee_balance),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (denom_balance,
+ deposit_fee_balance));
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (denom_balance,
+ melt_fee_balance));
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (denom_balance,
+ refund_fee_balance));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "total_liabilities_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1109,8 +2218,34 @@ postgres_update_denomination_summary (void *cls,
const struct TALER_Amount *melt_fee_balance,
const struct TALER_Amount *refund_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (denom_balance),
+ TALER_PQ_query_param_amount (deposit_fee_balance),
+ TALER_PQ_query_param_amount (melt_fee_balance),
+ TALER_PQ_query_param_amount (refund_fee_balance),
+
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "total_liabilities_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1136,8 +2271,50 @@ postgres_get_denomination_summary (void *cls,
struct TALER_Amount *melt_fee_balance,
struct TALER_Amount *refund_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "total_liabilities_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_denomination_summary() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("denom_balance", denom_balance),
+ TALER_PQ_result_spec_amount ("deposit_fee_balance", deposit_fee_balance),
+ TALER_PQ_result_spec_amount ("melt_fee_balance", melt_fee_balance),
+ TALER_PQ_result_spec_amount ("refund_fee_balance", refund_fee_balance),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -1157,8 +2334,31 @@ postgres_insert_risk_summary (void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *risk)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ TALER_PQ_query_param_amount (risk),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "total_risk_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1178,8 +2378,31 @@ postgres_update_risk_summary (void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *risk)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (risk),
+
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "total_risk_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1199,8 +2422,47 @@ postgres_get_risk_summary (void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *risk)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "total_risk_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_risk_summary() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("risk", risk),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -1232,8 +2494,49 @@ postgres_insert_historic_denom_revenue (void *cls,
const struct TALER_Amount *melt_fee_balance,
const struct TALER_Amount *refund_fee_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+ GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
+
+ GNUNET_PQ_query_param_auto_from_type (&revenue_timestamp),
+
+ TALER_PQ_query_param_amount (revenue_balance),
+ TALER_PQ_query_param_amount (deposit_fee_balance),
+ TALER_PQ_query_param_amount (melt_fee_balance),
+ TALER_PQ_query_param_amount (refund_fee_balance),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (revenue_balance,
+ deposit_fee_balance));
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (revenue_balance,
+ melt_fee_balance));
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (revenue_balance,
+ refund_fee_balance));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "historic_denomination_revenue_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1252,11 +2555,82 @@ static int
postgres_select_historic_denom_revenue (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: fix type */
+ TALER_AUDITORDB_HistoricDenominationRevenueDataCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "historic_denomination_revenue_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int ret = GNUNET_OK;
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_select_historic_denom_revenue() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (int i = 0; i < nrows; i++)
+ {
+ struct GNUNET_HashCode denom_pub_hash;
+ struct GNUNET_TIME_Absolute revenue_timestamp;
+ struct TALER_Amount revenue_balance;
+ struct TALER_Amount deposit_fee_balance;
+ struct TALER_Amount melt_fee_balance;
+ struct TALER_Amount refund_fee_balance;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", &denom_pub_hash),
+
+ GNUNET_PQ_result_spec_auto_from_type ("revenue_timestamp", &revenue_timestamp),
+
+ TALER_PQ_result_spec_amount ("revenue_balance", &revenue_balance),
+ TALER_PQ_result_spec_amount ("deposit_fee_balance", &deposit_fee_balance),
+ TALER_PQ_result_spec_amount ("melt_fee_balance", &melt_fee_balance),
+ TALER_PQ_result_spec_amount ("refund_fee_balance", &refund_fee_balance),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ ret = cb (cb_cls,
+ &denom_pub_hash,
+ revenue_timestamp,
+ &revenue_balance,
+ &deposit_fee_balance,
+ &melt_fee_balance,
+ &refund_fee_balance);
+ switch (ret)
+ {
+ case GNUNET_OK:
+ break;
+
+ default:
+ i = nrows;
+ }
+ }
+ PQclear (result);
+ return ret;
}
@@ -1283,8 +2657,34 @@ postgres_insert_historic_losses (void *cls,
struct GNUNET_TIME_Absolute loss_timestamp,
const struct TALER_Amount *loss_balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+ GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
+
+ GNUNET_PQ_query_param_auto_from_type (&loss_timestamp),
+
+ TALER_PQ_query_param_amount (loss_balance),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "historic_losses_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1303,11 +2703,72 @@ static int
postgres_select_historic_losses (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: fix type */
+ TALER_AUDITORDB_HistoricLossesDataCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "historic_losses_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int ret = GNUNET_OK;
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_select_historic_losses() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (int i = 0; i < nrows; i++)
+ {
+ struct GNUNET_HashCode denom_pub_hash;
+ struct GNUNET_TIME_Absolute loss_timestamp;
+ struct TALER_Amount loss_balance;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", &denom_pub_hash),
+
+ GNUNET_PQ_result_spec_auto_from_type ("loss_timestamp", &loss_timestamp),
+
+ TALER_PQ_result_spec_amount ("loss_balance", &loss_balance),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ ret = cb (cb_cls,
+ &denom_pub_hash,
+ loss_timestamp,
+ &loss_balance);
+ switch (ret)
+ {
+ case GNUNET_OK:
+ break;
+
+ default:
+ i = nrows;
+ }
+ }
+ PQclear (result);
+ return ret;
}
@@ -1330,8 +2791,34 @@ postgres_insert_historic_reserve_revenue (void *cls,
struct GNUNET_TIME_Absolute end_time,
const struct TALER_Amount *reserve_profits)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_auto_from_type (&start_time),
+ GNUNET_PQ_query_param_auto_from_type (&end_time),
+
+ TALER_PQ_query_param_amount (reserve_profits),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "historic_reserve_summary_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1349,11 +2836,71 @@ static int
postgres_select_historic_reserve_revenue (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: type */
+ TALER_AUDITORDB_HistoricReserveRevenueDataCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "historic_reserve_summary_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int ret = GNUNET_OK;
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_select_historic_reserve_revenue() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (int i = 0; i < nrows; i++)
+ {
+ struct GNUNET_TIME_Absolute start_date;
+ struct GNUNET_TIME_Absolute end_date;
+ struct TALER_Amount reserve_profits;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("start_date", &start_date),
+ GNUNET_PQ_result_spec_auto_from_type ("end_date", &end_date),
+
+ TALER_PQ_result_spec_amount ("reserve_profits", &reserve_profits),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ ret = cb (cb_cls,
+ start_date,
+ end_date,
+ &reserve_profits);
+ switch (ret)
+ {
+ case GNUNET_OK:
+ break;
+
+ default:
+ i = nrows;
+ }
+ }
+ PQclear (result);
+ return ret;
}
@@ -1373,8 +2920,30 @@ postgres_insert_predicted_result (void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+ TALER_PQ_query_param_amount (balance),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "predicted_result_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1394,8 +2963,30 @@ postgres_update_predicted_result (void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_Amount *balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (balance),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "predicted_result_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
}
@@ -1415,8 +3006,47 @@ postgres_get_predicted_balance (void *cls,
const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *balance)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "predicted_result_select",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ int nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "postgres_get_predicted_balance() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows);
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("balance", balance),
+
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -1472,32 +3102,46 @@ libtaler_plugin_auditordb_postgres_init (void *cls)
plugin->commit = &postgres_commit;
plugin->rollback = &postgres_rollback;
plugin->gc = &postgres_gc;
- plugin->get_predicted_balance = &postgres_get_predicted_balance;
- plugin->update_predicted_result = &postgres_update_predicted_result;
- plugin->insert_predicted_result = &postgres_insert_predicted_result;
- plugin->select_historic_reserve_revenue = &postgres_select_historic_reserve_revenue;
- plugin->insert_historic_reserve_revenue = &postgres_insert_historic_reserve_revenue;
- plugin->select_historic_losses = &postgres_select_historic_losses;
- plugin->insert_historic_losses = &postgres_insert_historic_losses;
- plugin->select_historic_denom_revenue = &postgres_select_historic_denom_revenue;
- plugin->insert_historic_denom_revenue = &postgres_insert_historic_denom_revenue;
- plugin->get_risk_summary = &postgres_get_risk_summary;
- plugin->update_risk_summary = &postgres_update_risk_summary;
- plugin->insert_risk_summary = &postgres_insert_risk_summary;
- plugin->get_denomination_summary = &postgres_get_denomination_summary;
- plugin->update_denomination_summary = &postgres_update_denomination_summary;
- plugin->insert_denomination_summary = &postgres_insert_denomination_summary;
- plugin->get_denomination_balance = &postgres_get_denomination_balance;
- plugin->update_denomination_balance = &postgres_update_denomination_balance;
- plugin->insert_denomination_balance = &postgres_insert_denomination_balance;
- plugin->get_reserve_summary = &postgres_get_reserve_summary;
- plugin->update_reserve_summary = &postgres_update_reserve_summary;
- plugin->insert_reserve_summary = &postgres_insert_reserve_summary;
+
+ plugin->select_denomination_info = &postgres_select_denomination_info;
+ plugin->insert_denomination_info = &postgres_insert_denomination_info;
+
+ plugin->get_auditor_progress = &postgres_get_auditor_progress;
+ plugin->update_auditor_progress = &postgres_update_auditor_progress;
+ plugin->insert_auditor_progress = &postgres_insert_auditor_progress;
+
plugin->get_reserve_info = &postgres_get_reserve_info;
plugin->update_reserve_info = &postgres_update_reserve_info;
plugin->insert_reserve_info = &postgres_insert_reserve_info;
- plugin->select_denomination_info = &postgres_select_denomination_info;
- plugin->insert_denomination_info = &postgres_insert_denomination_info;
+
+ plugin->get_reserve_summary = &postgres_get_reserve_summary;
+ plugin->update_reserve_summary = &postgres_update_reserve_summary;
+ plugin->insert_reserve_summary = &postgres_insert_reserve_summary;
+
+ plugin->get_denomination_balance = &postgres_get_denomination_balance;
+ plugin->update_denomination_balance = &postgres_update_denomination_balance;
+ plugin->insert_denomination_balance = &postgres_insert_denomination_balance;
+
+ plugin->get_denomination_summary = &postgres_get_denomination_summary;
+ plugin->update_denomination_summary = &postgres_update_denomination_summary;
+ plugin->insert_denomination_summary = &postgres_insert_denomination_summary;
+
+ plugin->get_risk_summary = &postgres_get_risk_summary;
+ plugin->update_risk_summary = &postgres_update_risk_summary;
+ plugin->insert_risk_summary = &postgres_insert_risk_summary;
+
+ plugin->select_historic_denom_revenue = &postgres_select_historic_denom_revenue;
+ plugin->insert_historic_denom_revenue = &postgres_insert_historic_denom_revenue;
+
+ plugin->select_historic_losses = &postgres_select_historic_losses;
+ plugin->insert_historic_losses = &postgres_insert_historic_losses;
+
+ plugin->select_historic_reserve_revenue = &postgres_select_historic_reserve_revenue;
+ plugin->insert_historic_reserve_revenue = &postgres_insert_historic_reserve_revenue;
+
+ plugin->get_predicted_balance = &postgres_get_predicted_balance;
+ plugin->update_predicted_result = &postgres_update_predicted_result;
+ plugin->insert_predicted_result = &postgres_insert_predicted_result;
return plugin;
}
diff --git a/src/auditordb/test-auditor-db-postgres.conf b/src/auditordb/test-auditor-db-postgres.conf
new file mode 100644
index 000000000..5c1e7fbc1
--- /dev/null
+++ b/src/auditordb/test-auditor-db-postgres.conf
@@ -0,0 +1,7 @@
+[auditor]
+# Which database backend do we use for the auditor?
+DB = postgres
+
+[auditordb-postgres]
+# Argument for Postgres for how to connect to the database.
+DB_CONN_STR = "postgres:///talercheck"
diff --git a/src/auditordb/test_auditordb.c b/src/auditordb/test_auditordb.c
new file mode 100644
index 000000000..93c279384
--- /dev/null
+++ b/src/auditordb/test_auditordb.c
@@ -0,0 +1,798 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V. and INRIA
+
+ 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 auditordb/test_auditordb.c
+ * @brief test cases for DB interaction functions
+ * @author Gabor X Toth
+ */
+#include "platform.h"
+#include "taler_auditordb_lib.h"
+#include "taler_auditordb_plugin.h"
+
+
+/**
+ * Global result from the testcase.
+ */
+static int result = -1;
+
+/**
+ * Report line of error if @a cond is true, and jump to label "drop".
+ */
+#define FAILIF(cond) \
+ do { \
+ if (!(cond)){ break;} \
+ GNUNET_break (0); \
+ goto drop; \
+ } while (0)
+
+
+/**
+ * Initializes @a ptr with random data.
+ */
+#define RND_BLK(ptr) \
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
+
+/**
+ * Initializes @a ptr with zeros.
+ */
+#define ZR_BLK(ptr) \
+ memset (ptr, 0, sizeof (*ptr))
+
+
+/**
+ * Currency we use.
+ */
+#define CURRENCY "EUR"
+
+/**
+ * Database plugin under test.
+ */
+static struct TALER_AUDITORDB_Plugin *plugin;
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure with config
+ */
+static void
+run (void *cls)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct TALER_AUDITORDB_Session *session;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "loading database plugin\n");
+
+ if (NULL ==
+ (plugin = TALER_AUDITORDB_plugin_load (cfg)))
+ {
+ result = 77;
+ return;
+ }
+
+ (void) plugin->drop_tables (plugin->cls);
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls))
+ {
+ result = 77;
+ goto drop;
+ }
+ if (NULL ==
+ (session = plugin->get_session (plugin->cls)))
+ {
+ result = 77;
+ goto drop;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "initializing\n");
+
+ struct TALER_Amount value, fee_withdraw, fee_deposit, fee_refresh, fee_refund;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.000010",
+ &value));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000011",
+ &fee_withdraw));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000012",
+ &fee_deposit));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000013",
+ &fee_refresh));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000014",
+ &fee_refund));
+
+ struct TALER_MasterPublicKeyP master_pub;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct GNUNET_HashCode rnd_hash;
+ RND_BLK (&master_pub);
+ RND_BLK (&reserve_pub);
+ RND_BLK (&rnd_hash);
+
+ struct TALER_DenominationPrivateKey denom_priv;
+ struct TALER_DenominationPublicKey denom_pub;
+ struct GNUNET_HashCode denom_pub_hash;
+ denom_priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (1024);
+ denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, &denom_pub_hash);
+
+ struct GNUNET_TIME_Absolute now, past, future, date;
+ now = GNUNET_TIME_absolute_get ();
+ past = GNUNET_TIME_absolute_subtract (now,
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
+ 4));
+ future = GNUNET_TIME_absolute_add (now,
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
+ 4));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_denomination_info\n");
+
+ struct TALER_DenominationKeyValidityPS issue = { 0 };
+ issue.master = master_pub;
+ issue.denom_hash = denom_pub_hash;
+
+ issue.start = GNUNET_TIME_absolute_hton (now);
+ issue.expire_withdraw = GNUNET_TIME_absolute_hton
+ (GNUNET_TIME_absolute_add (now,
+ GNUNET_TIME_UNIT_HOURS));
+ issue.expire_deposit = GNUNET_TIME_absolute_hton
+ (GNUNET_TIME_absolute_add
+ (now,
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 2)));
+ issue.expire_legal = GNUNET_TIME_absolute_hton
+ (GNUNET_TIME_absolute_add
+ (now,
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 3)));
+ TALER_amount_hton (&issue.value, &value);
+ TALER_amount_hton (&issue.fee_withdraw, &fee_withdraw);
+ TALER_amount_hton (&issue.fee_deposit, &fee_deposit);
+ TALER_amount_hton (&issue.fee_refresh, &fee_refresh);
+ TALER_amount_hton (&issue.fee_refund, &fee_refund);
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_denomination_info (plugin->cls,
+ session,
+ &issue));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: select_denomination_info\n");
+
+ int
+ select_denomination_info_result (void *cls,
+ const struct TALER_DenominationKeyValidityPS *issue2)
+ {
+ const struct TALER_DenominationKeyValidityPS *issue1 = cls;
+
+ if (0 != memcmp (issue1, issue2, sizeof (*issue2)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "select_denomination_info_result: issue does not match\n");
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+ }
+
+ FAILIF (GNUNET_OK !=
+ plugin->select_denomination_info (plugin->cls,
+ session,
+ &master_pub,
+ select_denomination_info_result,
+ &issue));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_auditor_progress\n");
+
+ uint64_t
+ last_reserve_in_serial_id = 1234,
+ last_reserve_out_serial_id = 5678,
+ last_deposit_serial_id = 123,
+ last_melt_serial_id = 456,
+ last_refund_serial_id = 789,
+ last_prewire_serial_id = 555,
+
+ last_reserve_in_serial_id2 = 0,
+ last_reserve_out_serial_id2 = 0,
+ last_deposit_serial_id2 = 0,
+ last_melt_serial_id2 = 0,
+ last_refund_serial_id2 = 0,
+ last_prewire_serial_id2 = 0;
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_auditor_progress (plugin->cls,
+ session,
+ &master_pub,
+ last_reserve_in_serial_id,
+ last_reserve_out_serial_id,
+ last_deposit_serial_id,
+ last_melt_serial_id,
+ last_refund_serial_id,
+ last_prewire_serial_id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_auditor_progress\n");
+
+ last_reserve_in_serial_id++;
+ last_reserve_out_serial_id++;
+ last_deposit_serial_id2++;
+ last_melt_serial_id2++;
+ last_refund_serial_id2++;
+ last_prewire_serial_id2++;
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_auditor_progress (plugin->cls,
+ session,
+ &master_pub,
+ last_reserve_in_serial_id,
+ last_reserve_out_serial_id,
+ last_deposit_serial_id,
+ last_melt_serial_id,
+ last_refund_serial_id,
+ last_prewire_serial_id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_auditor_progress\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_auditor_progress (plugin->cls,
+ session,
+ &master_pub,
+ &last_reserve_in_serial_id2,
+ &last_reserve_out_serial_id2,
+ &last_deposit_serial_id2,
+ &last_melt_serial_id2,
+ &last_refund_serial_id2,
+ &last_prewire_serial_id2));
+
+ FAILIF (last_reserve_in_serial_id2 != last_reserve_in_serial_id
+ || last_reserve_out_serial_id2 != last_reserve_out_serial_id
+ || last_deposit_serial_id2 != last_deposit_serial_id
+ || last_melt_serial_id2 != last_melt_serial_id
+ || last_refund_serial_id2 != last_refund_serial_id
+ || last_prewire_serial_id2 != last_prewire_serial_id);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_reserve_info\n");
+
+ struct TALER_Amount reserve_balance, withdraw_fee_balance;
+ struct TALER_Amount reserve_balance2 = {}, withdraw_fee_balance2 = {};
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":12.345678",
+ &reserve_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":23.456789",
+ &withdraw_fee_balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_reserve_info (plugin->cls,
+ session,
+ &reserve_pub,
+ &master_pub,
+ &reserve_balance,
+ &withdraw_fee_balance,
+ past,
+ last_reserve_in_serial_id,
+ last_reserve_out_serial_id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_reserve_info\n");
+
+ last_reserve_in_serial_id++;
+ last_reserve_out_serial_id++;
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_reserve_info (plugin->cls,
+ session,
+ &reserve_pub,
+ &master_pub,
+ &reserve_balance,
+ &withdraw_fee_balance,
+ future,
+ last_reserve_in_serial_id,
+ last_reserve_out_serial_id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_reserve_info\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_reserve_info (plugin->cls,
+ session,
+ &reserve_pub,
+ &master_pub,
+ &reserve_balance2,
+ &withdraw_fee_balance2,
+ &date,
+ &last_reserve_in_serial_id2,
+ &last_reserve_out_serial_id2));
+
+ FAILIF (0 != memcmp (&date, &future, sizeof (future))
+ || 0 != memcmp (&reserve_balance2, &reserve_balance, sizeof (reserve_balance))
+ || 0 != memcmp (&withdraw_fee_balance2, &withdraw_fee_balance, sizeof (withdraw_fee_balance))
+ || last_reserve_in_serial_id2 != last_reserve_in_serial_id
+ || last_reserve_out_serial_id2 != last_reserve_out_serial_id);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_reserve_summary\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_reserve_summary (plugin->cls,
+ session,
+ &master_pub,
+ &withdraw_fee_balance,
+ &reserve_balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_reserve_summary\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_reserve_summary (plugin->cls,
+ session,
+ &master_pub,
+ &reserve_balance,
+ &withdraw_fee_balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_reserve_summary\n");
+
+ ZR_BLK (&reserve_balance2);
+ ZR_BLK (&withdraw_fee_balance2);
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_reserve_summary (plugin->cls,
+ session,
+ &master_pub,
+ &reserve_balance2,
+ &withdraw_fee_balance2));
+
+ FAILIF (0 != memcmp (&reserve_balance2, &reserve_balance, sizeof (reserve_balance))
+ || 0 != memcmp (&withdraw_fee_balance2, &withdraw_fee_balance, sizeof (withdraw_fee_balance)));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_denomination_balance\n");
+
+ struct TALER_Amount denom_balance, deposit_fee_balance, melt_fee_balance, refund_fee_balance;
+ struct TALER_Amount denom_balance2, deposit_fee_balance2, melt_fee_balance2, refund_fee_balance2;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":12.345678",
+ &denom_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":23.456789",
+ &deposit_fee_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":34.567890",
+ &melt_fee_balance));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":45.678901",
+ &refund_fee_balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_denomination_balance (plugin->cls,
+ session,
+ &denom_pub_hash,
+ &refund_fee_balance,
+ &melt_fee_balance,
+ &deposit_fee_balance,
+ &denom_balance,
+ last_reserve_out_serial_id,
+ last_deposit_serial_id,
+ last_melt_serial_id,
+ last_refund_serial_id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_denomination_balance\n");
+
+ last_reserve_out_serial_id++;
+ last_deposit_serial_id++;
+ last_melt_serial_id++;
+ last_refund_serial_id++;
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_denomination_balance (plugin->cls,
+ session,
+ &denom_pub_hash,
+ &denom_balance,
+ &deposit_fee_balance,
+ &melt_fee_balance,
+ &refund_fee_balance,
+ last_reserve_out_serial_id,
+ last_deposit_serial_id,
+ last_melt_serial_id,
+ last_refund_serial_id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_denomination_balance\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_denomination_balance (plugin->cls,
+ session,
+ &denom_pub_hash,
+ &denom_balance2,
+ &deposit_fee_balance2,
+ &melt_fee_balance2,
+ &refund_fee_balance2,
+ &last_reserve_out_serial_id2,
+ &last_deposit_serial_id2,
+ &last_melt_serial_id2,
+ &last_refund_serial_id2));
+
+ FAILIF (0 != memcmp (&denom_balance2, &denom_balance, sizeof (denom_balance))
+ || 0 != memcmp (&deposit_fee_balance2, &deposit_fee_balance, sizeof (deposit_fee_balance))
+ || 0 != memcmp (&melt_fee_balance2, &melt_fee_balance, sizeof (melt_fee_balance))
+ || 0 != memcmp (&refund_fee_balance2, &refund_fee_balance, sizeof (refund_fee_balance))
+ || last_reserve_out_serial_id2 != last_reserve_out_serial_id
+ || last_deposit_serial_id2 != last_deposit_serial_id
+ || last_melt_serial_id2 != last_melt_serial_id
+ || last_refund_serial_id2 != last_refund_serial_id);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_denomination_summary\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_denomination_summary (plugin->cls,
+ session,
+ &master_pub,
+ &refund_fee_balance,
+ &melt_fee_balance,
+ &deposit_fee_balance,
+ &denom_balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_denomination_summary\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_denomination_summary (plugin->cls,
+ session,
+ &master_pub,
+ &denom_balance,
+ &deposit_fee_balance,
+ &melt_fee_balance,
+ &refund_fee_balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_denomination_summary\n");
+
+ ZR_BLK (&denom_balance2);
+ ZR_BLK (&deposit_fee_balance2);
+ ZR_BLK (&melt_fee_balance2);
+ ZR_BLK (&refund_fee_balance2);
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_denomination_summary (plugin->cls,
+ session,
+ &master_pub,
+ &denom_balance2,
+ &deposit_fee_balance2,
+ &melt_fee_balance2,
+ &refund_fee_balance2));
+
+ FAILIF (0 != memcmp (&denom_balance2, &denom_balance, sizeof (denom_balance))
+ || 0 != memcmp (&deposit_fee_balance2, &deposit_fee_balance, sizeof (deposit_fee_balance))
+ || 0 != memcmp (&melt_fee_balance2, &melt_fee_balance, sizeof (melt_fee_balance))
+ || 0 != memcmp (&refund_fee_balance2, &refund_fee_balance, sizeof (refund_fee_balance)));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_risk_summary\n");
+
+ struct TALER_Amount balance, balance2;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":13.57986",
+ &balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_risk_summary (plugin->cls,
+ session,
+ &master_pub,
+ &balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_risk_summary\n");
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":57.310986",
+ &balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_risk_summary (plugin->cls,
+ session,
+ &master_pub,
+ &balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_risk_summary\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_risk_summary (plugin->cls,
+ session,
+ &master_pub,
+ &balance2));
+
+ FAILIF (0 != memcmp (&balance2, &balance, sizeof (balance)));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_historic_denom_revenue\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_historic_denom_revenue (plugin->cls,
+ session,
+ &master_pub,
+ &denom_pub_hash,
+ past,
+ &balance,
+ &deposit_fee_balance,
+ &melt_fee_balance,
+ &refund_fee_balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_historic_denom_revenue (plugin->cls,
+ session,
+ &master_pub,
+ &rnd_hash,
+ now,
+ &balance,
+ &deposit_fee_balance,
+ &melt_fee_balance,
+ &refund_fee_balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: select_historic_denom_revenue\n");
+
+ int
+ select_historic_denom_revenue_result (void *cls,
+ const struct GNUNET_HashCode *denom_pub_hash2,
+ struct GNUNET_TIME_Absolute revenue_timestamp2,
+ const struct TALER_Amount *revenue_balance2,
+ const struct TALER_Amount *deposit_fee_balance2,
+ const struct TALER_Amount *melt_fee_balance2,
+ const struct TALER_Amount *refund_fee_balance2)
+ {
+ static int n = 0;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_historic_denom_revenue_result: row %u\n", n);
+
+ if (2 <= n++
+ || cls != NULL
+ || (0 != memcmp (&revenue_timestamp2, &past, sizeof (past))
+ && 0 != memcmp (&revenue_timestamp2, &now, sizeof (now)))
+ || (0 != memcmp (denom_pub_hash2, &denom_pub_hash, sizeof (denom_pub_hash))
+ && 0 != memcmp (denom_pub_hash2, &rnd_hash, sizeof (rnd_hash)))
+ || 0 != memcmp (revenue_balance2, &balance, sizeof (balance))
+ || 0 != memcmp (deposit_fee_balance2, &deposit_fee_balance, sizeof (deposit_fee_balance))
+ || 0 != memcmp (melt_fee_balance2, &melt_fee_balance, sizeof (melt_fee_balance))
+ || 0 != memcmp (refund_fee_balance2, &refund_fee_balance, sizeof (refund_fee_balance)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "select_historic_denom_revenue_result: result does not match\n");
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+ }
+
+ FAILIF (GNUNET_OK !=
+ plugin->select_historic_denom_revenue (plugin->cls,
+ session,
+ &master_pub,
+ select_historic_denom_revenue_result,
+ NULL));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_historic_losses\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_historic_losses (plugin->cls,
+ session,
+ &master_pub,
+ &denom_pub_hash,
+ past,
+ &balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_historic_losses (plugin->cls,
+ session,
+ &master_pub,
+ &rnd_hash,
+ past,
+ &balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: select_historic_losses\n");
+
+ int
+ select_historic_losses_result (void *cls,
+ const struct GNUNET_HashCode *denom_pub_hash2,
+ struct GNUNET_TIME_Absolute loss_timestamp2,
+ const struct TALER_Amount *loss_balance2)
+ {
+ static int n = 0;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_historic_losses_result: row %u\n", n);
+
+ if (2 <= n++
+ || cls != NULL
+ || (0 != memcmp (&loss_timestamp2, &past, sizeof (past))
+ && 0 != memcmp (&loss_timestamp2, &now, sizeof (now)))
+ || (0 != memcmp (denom_pub_hash2, &denom_pub_hash, sizeof (denom_pub_hash))
+ && 0 != memcmp (denom_pub_hash2, &rnd_hash, sizeof (rnd_hash)))
+ || 0 != memcmp (loss_balance2, &balance, sizeof (balance)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "select_historic_denom_revenue_result: result does not match\n");
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+ }
+
+ FAILIF (GNUNET_OK !=
+ plugin->select_historic_losses (plugin->cls,
+ session,
+ &master_pub,
+ select_historic_losses_result,
+ NULL));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_historic_reserve_revenue\n");
+
+ struct TALER_Amount reserve_profits;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":56.789012",
+ &reserve_profits));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_historic_reserve_revenue (plugin->cls,
+ session,
+ &master_pub,
+ past,
+ future,
+ &reserve_profits));
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_historic_reserve_revenue (plugin->cls,
+ session,
+ &master_pub,
+ now,
+ future,
+ &reserve_profits));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: select_historic_reserve_revenue\n");
+
+ int
+ select_historic_reserve_revenue_result (void *cls,
+ struct GNUNET_TIME_Absolute start_time2,
+ struct GNUNET_TIME_Absolute end_time2,
+ const struct TALER_Amount *reserve_profits2)
+ {
+ static int n = 0;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_historic_reserve_revenue_result: row %u\n", n);
+
+ if (2 <= n++
+ || cls != NULL
+ || (0 != memcmp (&start_time2, &past, sizeof (past))
+ && 0 != memcmp (&start_time2, &now, sizeof (now)))
+ || 0 != memcmp (&end_time2, &future, sizeof (future))
+ || 0 != memcmp (reserve_profits2, &reserve_profits, sizeof (reserve_profits)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "select_historic_reserve_revenue_result: result does not match\n");
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+ }
+
+ FAILIF (GNUNET_OK !=
+ plugin->select_historic_reserve_revenue (plugin->cls,
+ session,
+ &master_pub,
+ select_historic_reserve_revenue_result,
+ NULL));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: insert_predicted_result\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_predicted_result (plugin->cls,
+ session,
+ &master_pub,
+ &balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: update_predicted_result\n");
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":78.901234",
+ &balance));
+
+ FAILIF (GNUNET_OK !=
+ plugin->update_predicted_result (plugin->cls,
+ session,
+ &master_pub,
+ &balance));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Test: get_predicted_balance\n");
+
+ FAILIF (GNUNET_OK !=
+ plugin->get_predicted_balance (plugin->cls,
+ session,
+ &master_pub,
+ &balance2));
+
+ FAILIF (0 != memcmp (&balance2, &balance, sizeof (balance)));
+
+ result = 0;
+
+drop:
+
+ GNUNET_break (GNUNET_OK ==
+ plugin->drop_tables (plugin->cls));
+ TALER_AUDITORDB_plugin_unload (plugin);
+ plugin = NULL;
+}
+
+
+int
+main (int argc,
+ char *const argv[])
+{
+ const char *plugin_name;
+ char *config_filename;
+ char *testname;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ result = -1;
+ if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ GNUNET_log_setup (argv[0],
+ "WARNING",
+ NULL);
+ plugin_name++;
+ (void) GNUNET_asprintf (&testname,
+ "test-auditor-db-%s", plugin_name);
+ (void) GNUNET_asprintf (&config_filename,
+ "%s.conf", testname);
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_parse (cfg,
+ config_filename))
+ {
+ GNUNET_break (0);
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return 2;
+ }
+ GNUNET_SCHEDULER_run (&run, cfg);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return result;
+}
diff --git a/src/bank-lib/test_bank_api.c b/src/bank-lib/test_bank_api.c
index 88fe82451..88ca2fd24 100644
--- a/src/bank-lib/test_bank_api.c
+++ b/src/bank-lib/test_bank_api.c
@@ -67,22 +67,35 @@ main (int argc,
char * const *argv)
{
struct GNUNET_OS_Process *bankd;
+ struct GNUNET_OS_Process *bankd_admin;
unsigned int cnt;
int result;
GNUNET_log_setup ("test-bank-api",
"WARNING",
NULL);
+ bankd_admin = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-bank-manage",
+ "taler-bank-manage",
+ "--admin",
+ "serve-http",
+ "--port", "8081",
+ NULL);
bankd = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
"taler-bank-manage",
"taler-bank-manage",
"serve-http",
- "--port", "8081",
+ "--port", "8080",
NULL);
- if (NULL == bankd)
+
+
+ if ((NULL == bankd_admin) || (NULL == bankd))
{
+ /*FIXME: More accurate error message?*/
fprintf (stderr,
"taler-bank-manage not found, skipping test\n");
return 77; /* report 'skip' */
@@ -99,13 +112,26 @@ main (int argc,
if (cnt > 30)
break;
}
- while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/ -o /dev/null -O /dev/null"));
+ while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8080/ -o /dev/null -O /dev/null"));
+
+ do
+ {
+ fprintf (stderr, ".");
+ sleep (1);
+ cnt++;
+ if (cnt > 30)
+ break;
+ }
+ while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/admin/add/incoming -o /dev/null -O /dev/null"));
+
fprintf (stderr, "\n");
result = GNUNET_SYSERR;
if (cnt <= 30)
GNUNET_SCHEDULER_run (&run, &result);
GNUNET_OS_process_kill (bankd,
SIGTERM);
+ GNUNET_OS_process_kill (bankd_admin,
+ SIGTERM);
GNUNET_OS_process_wait (bankd);
GNUNET_OS_process_destroy (bankd);
if (cnt > 30)
diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c
index 40e5818bf..7b143a189 100644
--- a/src/benchmark/taler-exchange-benchmark.c
+++ b/src/benchmark/taler-exchange-benchmark.c
@@ -541,6 +541,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
* @param cls closure with the `struct Coin *`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error
@@ -549,6 +550,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
static void
reveal_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs,
@@ -617,6 +619,7 @@ reveal_cb (void *cls,
* @param cls closure with the `struct Coin *`
* @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error
* @param exchange_pub public key the exchange used for signing
@@ -625,6 +628,7 @@ reveal_cb (void *cls,
static void
melt_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
uint16_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *full_response)
@@ -776,6 +780,7 @@ refresh_coin (struct Coin *coin)
* @param cls closure with the `struct Coin` that we are processing
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key used by the exchange for signing
* @param obj the received JSON reply, should be kept as proof (and, in case of errors,
* be forwarded to the customer)
@@ -783,6 +788,7 @@ refresh_coin (struct Coin *coin)
static void
deposit_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj)
{
@@ -935,12 +941,14 @@ spend_coin (struct Coin *coin,
* @param cls closure with our `struct Coin`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors)
*/
static void
reserve_withdraw_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig,
const json_t *full_response)
{
@@ -1027,11 +1035,13 @@ withdraw_coin (struct Coin *coin)
* @param cls closure with the `struct Reserve *`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param full_response full response from the exchange (for logging, in case of errors)
*/
static void
add_incoming_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *full_response)
{
struct Reserve *r = cls;
diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am
index 83fcf1475..19c36744d 100644
--- a/src/exchange-lib/Makefile.am
+++ b/src/exchange-lib/Makefile.am
@@ -14,7 +14,7 @@ libtalerexchange_la_LDFLAGS = \
-no-undefined
libtalerexchange_la_SOURCES = \
- exchange_api_common.c exchange_api_common.h \
+ exchange_api_common.c \
exchange_api_handle.c exchange_api_handle.h \
exchange_api_admin.c \
exchange_api_deposit.c \
diff --git a/src/exchange-lib/exchange_api_admin.c b/src/exchange-lib/exchange_api_admin.c
index 524916e68..e6cb8101c 100644
--- a/src/exchange-lib/exchange_api_admin.c
+++ b/src/exchange-lib/exchange_api_admin.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
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
@@ -129,6 +129,7 @@ handle_admin_add_incoming_finished (void *cls,
}
aai->cb (aai->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
json);
TALER_EXCHANGE_admin_add_incoming_cancel (aai);
}
diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c
index acf90fce6..a531b1c39 100644
--- a/src/exchange-lib/exchange_api_common.c
+++ b/src/exchange-lib/exchange_api_common.c
@@ -20,7 +20,6 @@
* @author Christian Grothoff
*/
#include "platform.h"
-#include "exchange_api_common.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h"
@@ -38,8 +37,8 @@
*/
int
TALER_EXCHANGE_verify_coin_history (const char *currency,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- json_t *history,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ json_t *history,
struct TALER_Amount *total)
{
size_t len;
diff --git a/src/exchange-lib/exchange_api_common.h b/src/exchange-lib/exchange_api_common.h
deleted file mode 100644
index 5655f5d3b..000000000
--- a/src/exchange-lib/exchange_api_common.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- 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 exchange-lib/exchange_api_common.h
- * @brief common functions for the exchange API
- * @author Christian Grothoff
- */
-#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_exchange_service.h"
-
-/**
- * Verify a coins transaction history as returned by the exchange.
- *
- * @param currency expected currency for the coin
- * @param coin_pub public key of the coin
- * @param history history of the coin in json encoding
- * @param[out] total how much of the coin has been spent according to @a history
- * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
- */
-int
-TALER_EXCHANGE_verify_coin_history (const char *currency,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- json_t *history,
- struct TALER_Amount *total);
-
-/* end of exchange_api_common.h */
diff --git a/src/exchange-lib/exchange_api_deposit.c b/src/exchange-lib/exchange_api_deposit.c
index aa7e07ed8..9282bbfd1 100644
--- a/src/exchange-lib/exchange_api_deposit.c
+++ b/src/exchange-lib/exchange_api_deposit.c
@@ -29,7 +29,6 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
-#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
@@ -262,6 +261,7 @@ handle_deposit_finished (void *cls,
}
dh->cb (dh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
ep,
json);
TALER_EXCHANGE_deposit_cancel (dh);
diff --git a/src/exchange-lib/exchange_api_refresh.c b/src/exchange-lib/exchange_api_refresh.c
index 6d12a718c..c3216a6e6 100644
--- a/src/exchange-lib/exchange_api_refresh.c
+++ b/src/exchange-lib/exchange_api_refresh.c
@@ -28,7 +28,6 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
-#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
@@ -1115,6 +1114,7 @@ handle_refresh_melt_finished (void *cls,
{
rmh->melt_cb (rmh->melt_cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
noreveal_index,
(0 == response_code) ? NULL : &exchange_pub,
json);
@@ -1160,6 +1160,7 @@ handle_refresh_melt_finished (void *cls,
if (NULL != rmh->melt_cb)
rmh->melt_cb (rmh->melt_cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
UINT16_MAX,
NULL,
json);
@@ -1598,6 +1599,7 @@ handle_refresh_reveal_finished (void *cls,
{
rrh->reveal_cb (rrh->reveal_cb_cls,
MHD_HTTP_OK,
+ TALER_EC_NONE,
rrh->md->num_fresh_coins,
coin_privs,
sigs,
@@ -1634,7 +1636,10 @@ handle_refresh_reveal_finished (void *cls,
if (NULL != rrh->reveal_cb)
rrh->reveal_cb (rrh->reveal_cb_cls,
response_code,
- 0, NULL, NULL,
+ TALER_JSON_get_error_code (json),
+ 0,
+ NULL,
+ NULL,
json);
TALER_EXCHANGE_refresh_reveal_cancel (rrh);
}
diff --git a/src/exchange-lib/exchange_api_refresh_link.c b/src/exchange-lib/exchange_api_refresh_link.c
index a1dba9938..9b825138e 100644
--- a/src/exchange-lib/exchange_api_refresh_link.c
+++ b/src/exchange-lib/exchange_api_refresh_link.c
@@ -265,6 +265,7 @@ parse_refresh_link_ok (struct TALER_EXCHANGE_RefreshLinkHandle *rlh,
{
rlh->link_cb (rlh->link_cb_cls,
MHD_HTTP_OK,
+ TALER_EC_NONE,
num_coins,
coin_privs,
sigs,
@@ -345,7 +346,11 @@ handle_refresh_link_finished (void *cls,
if (NULL != rlh->link_cb)
rlh->link_cb (rlh->link_cb_cls,
response_code,
- 0, NULL, NULL, NULL,
+ TALER_JSON_get_error_code (json),
+ 0,
+ NULL,
+ NULL,
+ NULL,
json);
TALER_EXCHANGE_refresh_link_cancel (rlh);
}
diff --git a/src/exchange-lib/exchange_api_refund.c b/src/exchange-lib/exchange_api_refund.c
index f712f126a..be080c57b 100644
--- a/src/exchange-lib/exchange_api_refund.c
+++ b/src/exchange-lib/exchange_api_refund.c
@@ -28,7 +28,6 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
-#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
@@ -196,6 +195,7 @@ handle_refund_finished (void *cls,
}
rh->cb (rh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
ep,
json);
TALER_EXCHANGE_refund_cancel (rh);
diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c
index 0bff767e6..28f329c42 100644
--- a/src/exchange-lib/exchange_api_reserve.c
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -314,7 +314,8 @@ handle_reserve_status_finished (void *cls,
if (GNUNET_OK !=
GNUNET_JSON_parse (json,
spec,
- NULL, NULL))
+ NULL,
+ NULL))
{
GNUNET_break_op (0);
response_code = 0;
@@ -355,6 +356,7 @@ handle_reserve_status_finished (void *cls,
}
wsh->cb (wsh->cb_cls,
response_code,
+ TALER_EC_NONE,
json,
&balance,
len,
@@ -387,6 +389,7 @@ handle_reserve_status_finished (void *cls,
if (NULL != wsh->cb)
wsh->cb (wsh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
json,
NULL,
0, NULL);
@@ -589,6 +592,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
dsig.rsa_signature = sig;
wsh->cb (wsh->cb_cls,
MHD_HTTP_OK,
+ TALER_EC_NONE,
&dsig,
json);
/* make sure callback isn't called again after return */
@@ -599,7 +603,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
/**
- * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation.
+ * We got a 403 FORBIDDEN response for the /reserve/withdraw operation.
* Check the signatures on the withdraw transactions in the provided
* history and that the balances add up. We don't do anything directly
* with the information, as the JSON will be returned to the application.
@@ -723,7 +727,7 @@ handle_reserve_withdraw_finished (void *cls,
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
break;
- case MHD_HTTP_PAYMENT_REQUIRED:
+ case MHD_HTTP_FORBIDDEN:
/* The exchange says that the reserve has insufficient funds;
check the signatures in the history... */
if (GNUNET_OK !=
@@ -762,6 +766,7 @@ handle_reserve_withdraw_finished (void *cls,
if (NULL != wsh->cb)
wsh->cb (wsh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
NULL,
json);
TALER_EXCHANGE_reserve_withdraw_cancel (wsh);
diff --git a/src/exchange-lib/exchange_api_track_transaction.c b/src/exchange-lib/exchange_api_track_transaction.c
index c05115d57..7fd2efb21 100644
--- a/src/exchange-lib/exchange_api_track_transaction.c
+++ b/src/exchange-lib/exchange_api_track_transaction.c
@@ -28,7 +28,6 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
-#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
@@ -239,6 +238,7 @@ handle_deposit_wtid_finished (void *cls,
}
dwh->cb (dwh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
ep,
json,
wtid,
diff --git a/src/exchange-lib/exchange_api_track_transfer.c b/src/exchange-lib/exchange_api_track_transfer.c
index ffcb19b59..8ed5865d7 100644
--- a/src/exchange-lib/exchange_api_track_transfer.c
+++ b/src/exchange-lib/exchange_api_track_transfer.c
@@ -26,7 +26,6 @@
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
-#include "exchange_api_common.h"
#include "taler_json_lib.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
@@ -183,6 +182,7 @@ check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh
}
wdh->cb (wdh->cb_cls,
MHD_HTTP_OK,
+ TALER_EC_NONE,
&exchange_pub,
json,
&h_wire,
@@ -253,6 +253,7 @@ handle_track_transfer_finished (void *cls,
}
wdh->cb (wdh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
NULL,
json,
NULL,
diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c
index cb8df4944..7401e66d4 100644
--- a/src/exchange-lib/exchange_api_wire.c
+++ b/src/exchange-lib/exchange_api_wire.c
@@ -28,7 +28,6 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include "taler_wire_plugin.h"
-#include "exchange_api_common.h"
#include "exchange_api_handle.h"
@@ -210,6 +209,7 @@ handle_wire_finished (void *cls,
}
wh->cb (wh->cb_cls,
response_code,
+ TALER_JSON_get_error_code (json),
(NULL != keep) ? keep : json);
if (NULL != keep)
json_decref (keep);
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c
index 541a621d2..e25fa66cd 100644
--- a/src/exchange-lib/test_exchange_api.c
+++ b/src/exchange-lib/test_exchange_api.c
@@ -761,11 +761,13 @@ next_command (struct InterpreterState *is)
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param full_response full response from the exchange (for logging, in case of errors)
*/
static void
add_incoming_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *full_response)
{
struct InterpreterState *is = cls;
@@ -857,6 +859,7 @@ compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param[in] json original response in JSON format (useful only for diagnostics)
* @param balance current balance in the reserve, NULL on error
* @param history_length number of entries in the transaction history, 0 on error
@@ -865,6 +868,7 @@ compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h,
static void
reserve_status_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *json,
const struct TALER_Amount *balance,
unsigned int history_length,
@@ -924,7 +928,7 @@ reserve_status_cb (void *cls,
{
if (GNUNET_OK !=
compare_reserve_withdraw_history (&history[j],
- rel))
+ rel))
{
GNUNET_break (0);
fail (is);
@@ -973,12 +977,14 @@ reserve_status_cb (void *cls,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors)
*/
static void
reserve_withdraw_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig,
const json_t *full_response)
{
@@ -1009,7 +1015,7 @@ reserve_withdraw_cb (void *cls,
cmd->details.reserve_withdraw.sig.rsa_signature
= GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
break;
- case MHD_HTTP_PAYMENT_REQUIRED:
+ case MHD_HTTP_FORBIDDEN:
/* nothing to check */
break;
default:
@@ -1027,6 +1033,7 @@ reserve_withdraw_cb (void *cls,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key the exchange used for signing
* @param obj the received JSON reply, should be kept as proof (and, in case of errors,
* be forwarded to the customer)
@@ -1034,6 +1041,7 @@ reserve_withdraw_cb (void *cls,
static void
deposit_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj)
{
@@ -1061,6 +1069,7 @@ deposit_cb (void *cls,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error
* @param exchange_pub public key the exchange used for signing
@@ -1069,6 +1078,7 @@ deposit_cb (void *cls,
static void
melt_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
uint16_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *full_response)
@@ -1098,6 +1108,7 @@ melt_cb (void *cls,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error
@@ -1106,6 +1117,7 @@ melt_cb (void *cls,
static void
reveal_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs,
@@ -1160,6 +1172,7 @@ reveal_cb (void *cls,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error
@@ -1169,6 +1182,7 @@ reveal_cb (void *cls,
static void
link_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs,
@@ -1336,12 +1350,14 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param obj the received JSON reply, if successful this should be the wire
* format details as provided by /wire.
*/
static void
wire_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *obj)
{
struct InterpreterState *is = cls;
@@ -1391,6 +1407,7 @@ wire_cb (void *cls,
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key the exchange used for signing
* @param json original json reply (may include signatures, those have then been
* validated already)
@@ -1404,6 +1421,7 @@ wire_cb (void *cls,
static void
wire_deposits_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *json,
const struct GNUNET_HashCode *h_wire,
@@ -1521,6 +1539,7 @@ wire_deposits_cb (void *cls,
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key the exchange used for signing
* @param json original json reply (may include signatures, those have then been
* validated already)
@@ -1534,6 +1553,7 @@ wire_deposits_cb (void *cls,
static void
deposit_wtid_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *json,
const struct TALER_WireTransferIdentifierRawP *wtid,
@@ -1588,6 +1608,7 @@ deposit_wtid_cb (void *cls,
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key the exchange used for signing @a obj
* @param obj the received JSON reply, should be kept as proof (and, in particular,
* be forwarded to the customer)
@@ -1595,6 +1616,7 @@ deposit_wtid_cb (void *cls,
static void
refund_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj)
{
@@ -1782,9 +1804,9 @@ interpreter_run (void *cls)
&reserve_pub.eddsa_pub);
cmd->details.reserve_status.wsh
= TALER_EXCHANGE_reserve_status (exchange,
- &reserve_pub,
- &reserve_status_cb,
- is);
+ &reserve_pub,
+ &reserve_status_cb,
+ is);
return;
case OC_WITHDRAW_SIGN:
GNUNET_assert (NULL !=
@@ -2737,7 +2759,7 @@ run (void *cls)
/* Try to overdraw funds ... */
{ .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-2",
- .expected_response_code = MHD_HTTP_PAYMENT_REQUIRED,
+ .expected_response_code = MHD_HTTP_FORBIDDEN,
.details.reserve_withdraw.reserve_reference = "create-reserve-1",
.details.reserve_withdraw.amount = "EUR:5" },
@@ -3051,8 +3073,11 @@ main (int argc,
unsigned long code;
GNUNET_log_setup ("test-exchange-api",
- "WARNING",
- NULL);
+ "DEBUG",
+ "/tmp/logs");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test log\n");
+ return 0;
+
/* These might get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
diff --git a/src/exchange/taler-exchange-httpd_admin.c b/src/exchange/taler-exchange-httpd_admin.c
index e99448f87..72cdcb7d6 100644
--- a/src/exchange/taler-exchange-httpd_admin.c
+++ b/src/exchange/taler-exchange-httpd_admin.c
@@ -89,6 +89,7 @@ TEH_ADMIN_handler_admin_add_incoming (struct TEH_RequestHandler *rh,
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED,
"sender_account_details");
}
if (0 != strcasecmp (amount.currency,
@@ -100,6 +101,7 @@ TEH_ADMIN_handler_admin_add_incoming (struct TEH_RequestHandler *rh,
amount.currency);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED,
"amount:currency");
}
res = TEH_DB_execute_admin_add_incoming (connection,
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index 6b27a22a6..870f7a251 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -53,7 +53,8 @@ transaction_start_label: /* we will use goto for retries */ \
session)) \
{ \
GNUNET_break (0); \
- return TEH_RESPONSE_reply_internal_db_error (connection); \
+ return TEH_RESPONSE_reply_internal_db_error (connection, \
+ TALER_EC_DB_START_FAILED); \
}
/**
@@ -73,8 +74,9 @@ transaction_start_label: /* we will use goto for retries */ \
if (GNUNET_SYSERR == transaction_commit_result) \
{ \
TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
- return TEH_RESPONSE_reply_commit_error (connection); \
- } \
+ return TEH_RESPONSE_reply_commit_error (connection, \
+ TALER_EC_DB_COMMIT_FAILED_HARD); \
+ } \
if (GNUNET_NO == transaction_commit_result) \
{ \
TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
@@ -83,7 +85,8 @@ transaction_start_label: /* we will use goto for retries */ \
TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \
transaction_retries, \
__FUNCTION__); \
- return TEH_RESPONSE_reply_commit_error (connection); \
+ return TEH_RESPONSE_reply_commit_error (connection, \
+ TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \
} \
} /* end of scope opened by BEGIN_TRANSACTION */
@@ -197,7 +200,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
if (GNUNET_YES ==
TEH_plugin->have_deposit (TEH_plugin->cls,
@@ -225,8 +229,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
if (NULL == dki)
{
TEH_KS_release (mks);
- return TEH_RESPONSE_reply_arg_invalid (connection,
- "denom_pub");
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN);
}
TALER_amount_ntoh (&value,
&dki->issue.properties.value);
@@ -249,7 +253,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
session);
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DEPOSIT_HISTORY_DB_ERROR);
}
/* Check that cost of all transactions is smaller than
the value of the coin. */
@@ -274,7 +279,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DEPOSIT_STORE_DB_ERROR);
}
COMMIT_TRANSACTION(session, connection);
@@ -324,7 +330,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
dep = NULL;
ref = NULL;
@@ -337,7 +344,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls,
session);
return TEH_RESPONSE_reply_refund_failure (connection,
- MHD_HTTP_NOT_FOUND);
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_REFUND_COIN_NOT_FOUND);
}
deposit_found = GNUNET_NO;
refund_found = GNUNET_NO;
@@ -411,7 +419,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
session);
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
- return TEH_RESPONSE_reply_transaction_unknown (connection);
+ return TEH_RESPONSE_reply_transaction_unknown (connection,
+ TALER_EC_REFUND_DEPOSIT_NOT_FOUND);
}
/* handle if conflicting refund found */
if (GNUNET_SYSERR == refund_found)
@@ -449,7 +458,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls,
session);
return TEH_RESPONSE_reply_refund_failure (connection,
- MHD_HTTP_PRECONDITION_FAILED);
+ MHD_HTTP_PRECONDITION_FAILED,
+ TALER_EC_REFUND_CURRENCY_MISSMATCH);
}
/* check if we already send the money for the /deposit */
@@ -466,6 +476,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls,
session);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_REFUND_DB_INCONSISTENT,
"database inconsistent");
}
if (GNUNET_YES == done)
@@ -476,7 +487,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return TEH_RESPONSE_reply_refund_failure (connection,
- MHD_HTTP_GONE);
+ MHD_HTTP_GONE,
+ TALER_EC_REFUND_MERCHANT_ALREADY_PAID);
}
/* check refund amount is sufficiently low */
@@ -487,7 +499,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return TEH_RESPONSE_reply_refund_failure (connection,
- MHD_HTTP_PRECONDITION_FAILED);
+ MHD_HTTP_PRECONDITION_FAILED,
+ TALER_EC_REFUND_INSUFFICIENT_FUNDS);
}
/* Check refund fee matches fee of denomination key! */
@@ -504,6 +517,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND,
"denomination key not found");
}
TALER_amount_ntoh (&expect_fee,
@@ -519,6 +533,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFUND_FEE_TOO_LOW,
"refund_fee");
}
if (1 == fee_cmp)
@@ -538,7 +553,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TALER_LOG_WARNING ("Failed to store /refund information in database\n");
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFUND_STORE_DB_ERROR);
}
COMMIT_TRANSACTION(session, connection);
@@ -566,7 +582,8 @@ TEH_DB_execute_reserve_status (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
rh = TEH_plugin->get_reserve_history (TEH_plugin->cls,
session,
@@ -637,6 +654,7 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls,
session);
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_WITHDRAW_RESERVE_UNKNOWN,
"reserve_pub");
}
@@ -653,7 +671,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW);
}
/* calculate balance of the reserve */
@@ -673,7 +692,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW);
}
res |= 1;
break;
@@ -686,7 +706,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
GNUNET_break (0);
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND);
}
TALER_amount_ntoh (&value,
&tdki->issue.properties.value);
@@ -700,7 +721,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW);
}
res |= 2;
break;
@@ -708,9 +730,10 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
}
if (0 == (res & 1))
{
- /* did not encounter any deposit operations, how can we have a reserve? */
+ /* did not encounter any wire transfer operations, how can we have a reserve? */
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER);
}
if (0 == (res & 2))
{
@@ -748,6 +771,7 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls,
session);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_WITHDRAW_SIGNATURE_FAILED,
"Internal error");
}
collectable.sig = *denom_sig;
@@ -765,7 +789,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
GNUNET_break (0);
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_DB_STORE_ERROR);
}
COMMIT_TRANSACTION (session, connection);
@@ -811,7 +836,8 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
res = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
session,
@@ -820,7 +846,8 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
if (GNUNET_SYSERR == res)
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_WITHDRAW_DB_FETCH_ERROR);
}
/* Don't sign again if we have already signed the coin */
@@ -834,6 +861,7 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
}
GNUNET_assert (GNUNET_NO == res);
+ /* FIXME: do we have to do this a second time here? */
key_state = TEH_KS_acquire ();
dki = TEH_KS_denomination_key_lookup (key_state,
denomination_pub,
@@ -843,9 +871,11 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
TEH_KS_release (key_state);
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
- "{s:s}",
+ "{s:s, s:I}",
"error",
- "Denomination not found");
+ "Denomination not found",
+ "code",
+ (json_int_t) TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND);
}
denom_sig.rsa_signature = NULL;
res = execute_reserve_withdraw_transaction (connection,
@@ -901,8 +931,9 @@ refresh_check_melt (struct MHD_Connection *connection,
TEH_KS_DKU_DEPOSIT);
if (NULL == dk)
return (MHD_YES ==
- TEH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub"))
+ TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND,
+ "denomination key no longer available while executing transaction"))
? GNUNET_NO : GNUNET_SYSERR;
dki = &dk->issue;
TALER_amount_ntoh (&coin_value,
@@ -922,7 +953,8 @@ refresh_check_melt (struct MHD_Connection *connection,
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return (MHD_YES ==
- TEH_RESPONSE_reply_internal_db_error (connection))
+ TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED))
? GNUNET_NO : GNUNET_SYSERR;
}
/* Refuse to refresh when the coin's value is insufficient
@@ -995,7 +1027,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
START_TRANSACTION (session, connection);
res = TEH_plugin->get_refresh_session (TEH_plugin->cls,
@@ -1015,14 +1048,15 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_DB_FETCH_ERROR);
}
/* store 'global' session data */
refresh_session.num_newcoins = num_new_denoms;
refresh_session.noreveal_index
- = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
- TALER_CNC_KAPPA);
+ = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
+ TALER_CNC_KAPPA);
key_state = TEH_KS_acquire ();
if (GNUNET_OK !=
(res = refresh_check_melt (connection,
@@ -1047,7 +1081,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR);
}
/* store requested new denominations */
@@ -1060,7 +1095,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR);
}
if (GNUNET_OK !=
@@ -1072,7 +1108,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR);
}
if (GNUNET_OK !=
TEH_plugin->insert_refresh_transfer_public_key (TEH_plugin->cls,
@@ -1082,7 +1119,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR);
}
COMMIT_TRANSACTION (session, connection);
@@ -1126,8 +1164,6 @@ check_commitment (struct MHD_Connection *connection,
struct TALER_TransferSecretP transfer_secret;
unsigned int j;
- /* FIXME: instead of consulting DB, reconstruct everything
- from transfer_priv here! */
TALER_link_reveal_transfer_secret (transfer_priv,
&melt->coin.coin_pub,
&transfer_secret);
@@ -1158,8 +1194,10 @@ check_commitment (struct MHD_Connection *connection,
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Blind failed (bad denomination key!?)\n");
- return (MHD_YES == TEH_RESPONSE_reply_internal_error (connection,
- "Blinding error"))
+ return (MHD_YES ==
+ TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_REFRESH_REVEAL_BLINDING_ERROR,
+ "Blinding error"))
? GNUNET_NO : GNUNET_SYSERR;
}
GNUNET_CRYPTO_hash_context_read (hash_context,
@@ -1274,7 +1312,8 @@ execute_refresh_reveal_transaction (struct MHD_Connection *connection,
j);
if (NULL == ev_sigs[j].rsa_signature)
{
- ret = TEH_RESPONSE_reply_internal_db_error (connection);
+ ret = TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_REVEAL_SIGNING_ERROR);
goto cleanup;
}
}
@@ -1323,7 +1362,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
res = TEH_plugin->get_refresh_session (TEH_plugin->cls,
@@ -1332,10 +1372,12 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
&refresh_session);
if (GNUNET_NO == res)
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN,
"session_hash");
if ( (GNUNET_SYSERR == res) ||
(refresh_session.noreveal_index >= TALER_CNC_KAPPA) )
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR);
denom_pubs = GNUNET_new_array (refresh_session.num_newcoins,
struct TALER_DenominationPublicKey);
if (GNUNET_OK !=
@@ -1349,7 +1391,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
GNUNET_free (denom_pubs);
GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
- return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection))
+ return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR))
? GNUNET_NO : GNUNET_SYSERR;
}
@@ -1373,7 +1416,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
GNUNET_CRYPTO_hash_context_abort (hash_context);
- return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection))
+ return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR))
? GNUNET_NO : GNUNET_SYSERR;
}
GNUNET_CRYPTO_hash_context_read (hash_context,
@@ -1410,7 +1454,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
GNUNET_CRYPTO_hash_context_abort (hash_context);
- return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection))
+ return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR))
? GNUNET_NO : GNUNET_SYSERR;
}
for (i=0;i<refresh_session.num_newcoins;i++)
@@ -1463,7 +1508,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature);
GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
GNUNET_CRYPTO_hash_context_abort (hash_context);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR);
}
/* add envelopes to hash_context */
for (j=0;j<refresh_session.num_newcoins;j++)
@@ -1656,7 +1702,8 @@ TEH_DB_execute_refresh_link (struct MHD_Connection *connection,
if (NULL == (ctx.session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
ctx.connection = connection;
ctx.num_sessions = 0;
@@ -1680,6 +1727,7 @@ TEH_DB_execute_refresh_link (struct MHD_Connection *connection,
GNUNET_assert (GNUNET_OK == ctx.status);
if (0 == ctx.num_sessions)
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_REFRESH_LINK_COIN_UNKNOWN,
"coin_pub");
res = TEH_RESPONSE_reply_refresh_link_success (connection,
ctx.num_sessions,
@@ -1720,7 +1768,8 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
ret = TEH_plugin->reserves_in_insert (TEH_plugin->cls,
session,
@@ -1732,7 +1781,8 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
if (GNUNET_SYSERR == ret)
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_ADMIN_ADD_INCOMING_DB_STORE);
}
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
@@ -1913,7 +1963,8 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
ctx.is_valid = GNUNET_NO;
ctx.wdd_head = NULL;
@@ -1926,18 +1977,21 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
if (GNUNET_SYSERR == ret)
{
GNUNET_break (0);
- ret = TEH_RESPONSE_reply_internal_db_error (connection);
+ ret = TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED);
goto cleanup;
}
if (GNUNET_SYSERR == ctx.is_valid)
{
GNUNET_break (0);
- ret = TEH_RESPONSE_reply_internal_db_error (connection);
+ ret = TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT);
goto cleanup;
}
if (GNUNET_NO == ctx.is_valid)
{
ret = TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND,
"wtid");
goto cleanup;
}
@@ -2035,7 +2089,8 @@ handle_wtid_data (void *cls,
coin_fee))
{
GNUNET_break (0);
- ctx->res = TEH_RESPONSE_reply_internal_db_error (ctx->connection);
+ ctx->res = TEH_RESPONSE_reply_internal_db_error (ctx->connection,
+ TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT);
}
else
{
@@ -2079,7 +2134,8 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
}
ctx.connection = connection;
ctx.h_contract = *h_contract;
@@ -2100,17 +2156,20 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection,
{
GNUNET_break (0);
GNUNET_break (GNUNET_SYSERR == ctx.res);
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED);
}
if (GNUNET_NO == ret)
{
GNUNET_break (GNUNET_SYSERR == ctx.res);
- return TEH_RESPONSE_reply_transaction_unknown (connection);
+ return TEH_RESPONSE_reply_transaction_unknown (connection,
+ TALER_EC_TRACK_TRANSACTION_NOT_FOUND);
}
if (GNUNET_SYSERR == ctx.res)
{
GNUNET_break (0);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR,
"bug resolving deposit wtid");
}
return ctx.res;
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index a97dd0514..b0ab42e7f 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -48,12 +48,9 @@
*/
static int
verify_and_execute_deposit (struct MHD_Connection *connection,
- const struct TALER_EXCHANGEDB_Deposit *deposit)
+ const struct TALER_EXCHANGEDB_Deposit *deposit)
{
- struct TEH_KS_StateHandle *key_state;
struct TALER_DepositRequestPS dr;
- struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
- struct TALER_Amount fee_deposit;
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
@@ -76,39 +73,9 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
{
TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
return TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID,
"coin_sig");
}
- /* check denomination exists and is valid */
- key_state = TEH_KS_acquire ();
- dki = TEH_KS_denomination_key_lookup (key_state,
- &deposit->coin.denom_pub,
- TEH_KS_DKU_DEPOSIT);
- if (NULL == dki)
- {
- TEH_KS_release (key_state);
- TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n");
- return TEH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub");
- }
- /* check coin signature */
- if (GNUNET_YES !=
- TALER_test_coin_valid (&deposit->coin))
- {
- TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
- TEH_KS_release (key_state);
- return TEH_RESPONSE_reply_signature_invalid (connection,
- "ub_sig");
- }
- TALER_amount_ntoh (&fee_deposit,
- &dki->issue.properties.fee_deposit);
- if (0 < TALER_amount_cmp (&fee_deposit,
- &deposit->amount_with_fee))
- {
- TEH_KS_release (key_state);
- return TEH_RESPONSE_reply_external_error (connection,
- "deposited amount smaller than depositing fee");
- }
- TEH_KS_release (key_state);
return TEH_DB_execute_deposit (connection,
deposit);
@@ -141,12 +108,11 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
json_t *wire;
struct TALER_EXCHANGEDB_Deposit deposit;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
- struct TEH_KS_StateHandle *ks;
+ struct TEH_KS_StateHandle *key_state;
struct GNUNET_HashCode my_h_wire;
- struct TALER_Amount amount;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("wire", &wire),
- TALER_JSON_spec_amount ("f", &amount),
+ TALER_JSON_spec_amount ("f", &deposit.amount_with_fee),
TALER_JSON_spec_denomination_public_key ("denom_pub", &deposit.coin.denom_pub),
TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub),
@@ -180,11 +146,13 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
if (GNUNET_NO == res)
return MHD_YES; /* failure */
+ deposit.receiver_wire_account = wire;
if (deposit.refund_deadline.abs_value_us > deposit.wire_deadline.abs_value_us)
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
"refund_deadline");
}
@@ -194,6 +162,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
{
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT,
"wire");
}
if (GNUNET_OK !=
@@ -203,6 +172,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON,
"wire");
}
if (0 != memcmp (&deposit.h_wire,
@@ -212,32 +182,48 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
/* Client hashed contract differently than we did, reject */
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT,
"H_wire");
}
- ks = TEH_KS_acquire ();
- dki = TEH_KS_denomination_key_lookup (ks,
+
+ /* check denomination exists and is valid */
+ key_state = TEH_KS_acquire ();
+ dki = TEH_KS_denomination_key_lookup (key_state,
&deposit.coin.denom_pub,
TEH_KS_DKU_DEPOSIT);
if (NULL == dki)
{
- TEH_KS_release (ks);
- GNUNET_JSON_parse_free (spec);
+ TEH_KS_release (key_state);
+ TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n");
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN,
"denom_pub");
}
TALER_amount_ntoh (&deposit.deposit_fee,
&dki->issue.properties.fee_deposit);
- TEH_KS_release (ks);
- deposit.receiver_wire_account = wire;
- deposit.amount_with_fee = amount;
- if (-1 == TALER_amount_cmp (&deposit.amount_with_fee,
- &deposit.deposit_fee))
+ /* check coin signature */
+ if (GNUNET_YES !=
+ TALER_test_coin_valid (&deposit.coin))
{
- /* Total amount smaller than fee, invalid */
- GNUNET_JSON_parse_free (spec);
- return TEH_RESPONSE_reply_arg_invalid (connection,
- "f");
+ TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
+ TEH_KS_release (key_state);
+ return TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID,
+ "ub_sig");
+ }
+ TALER_amount_ntoh (&deposit.deposit_fee,
+ &dki->issue.properties.fee_deposit);
+ TEH_KS_release (key_state);
+
+ if (0 < TALER_amount_cmp (&deposit.deposit_fee,
+ &deposit.amount_with_fee))
+ {
+ GNUNET_break_op (0);
+ return TEH_RESPONSE_reply_external_error (connection,
+ TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE,
+ "deposited amount smaller than depositing fee");
}
+
res = verify_and_execute_deposit (connection,
&deposit);
GNUNET_JSON_parse_free (spec);
diff --git a/src/exchange/taler-exchange-httpd_parsing.c b/src/exchange/taler-exchange-httpd_parsing.c
index c7118c462..e9c38eb82 100644
--- a/src/exchange/taler-exchange-httpd_parsing.c
+++ b/src/exchange/taler-exchange-httpd_parsing.c
@@ -79,6 +79,7 @@ TEH_PARSE_post_json (struct MHD_Connection *connection,
case GNUNET_JSON_PR_OUT_OF_MEMORY:
return (MHD_NO ==
TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_PARSER_OUT_OF_MEMORY,
"out of memory"))
? GNUNET_SYSERR : GNUNET_NO;
case GNUNET_JSON_PR_CONTINUE:
@@ -144,7 +145,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
if (NULL == str)
{
return (MHD_NO ==
- TEH_RESPONSE_reply_arg_missing (connection, param_name))
+ TEH_RESPONSE_reply_arg_missing (connection,
+ TALER_EC_PARAMETER_MISSING,
+ param_name))
? GNUNET_SYSERR : GNUNET_NO;
}
if (GNUNET_OK !=
@@ -153,7 +156,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
out_data,
out_size))
return (MHD_NO ==
- TEH_RESPONSE_reply_arg_invalid (connection, param_name))
+ TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_PARAMETER_MALFORMED,
+ param_name))
? GNUNET_SYSERR : GNUNET_NO;
return GNUNET_OK;
}
@@ -193,8 +198,9 @@ TEH_PARSE_json_data (struct MHD_Connection *connection,
ret = (MHD_YES ==
TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s, s:I}",
+ "{s:s, s:I, s:s, s:I}",
"error", "parse error",
+ "code", (json_int_t) TALER_EC_JSON_INVALID_WITH_DETAILS,
"field", error_json_name,
"line", (json_int_t) error_line))
? GNUNET_NO : GNUNET_SYSERR;
diff --git a/src/exchange/taler-exchange-httpd_refresh.c b/src/exchange/taler-exchange-httpd_refresh.c
index 0c500920d..3a8875f44 100644
--- a/src/exchange/taler-exchange-httpd_refresh.c
+++ b/src/exchange/taler-exchange-httpd_refresh.c
@@ -69,7 +69,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
struct TALER_Amount total_melt;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "melt request for session %s\n",
+ "/refresh/melt request for session %s\n",
GNUNET_h2s (session_hash));
GNUNET_assert (GNUNET_OK ==
@@ -86,6 +86,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_break_op (0);
TEH_KS_release (key_state);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND,
"new_denoms");
}
dki = &dk->issue;
@@ -105,6 +106,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_break_op (0);
TEH_KS_release (key_state);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW,
"cost calculation failure");
}
}
@@ -115,8 +117,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
if (NULL == dk)
{
GNUNET_break (0);
- return TEH_RESPONSE_reply_arg_invalid (connection,
- "denom_pub");
+ return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
+ "denom_pub");
}
dki = &dk->issue;
TALER_amount_ntoh (&fee_melt,
@@ -129,6 +132,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_break_op (0);
TEH_KS_release (key_state);
return TEH_RESPONSE_reply_external_error (connection,
+ TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION,
"Melt contribution below melting fee");
}
TEH_KS_release (key_state);
@@ -141,8 +145,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
total value of coins being generated to match! */
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error", "value mismatch");
+ "{s:s, s:I}",
+ "error", "value mismatch",
+ "code", (json_int_t) TALER_EC_REFRESH_MELT_FEES_MISSMATCH);
}
return TEH_DB_execute_refresh_melt (connection,
session_hash,
@@ -203,6 +208,7 @@ get_coin_public_info (struct MHD_Connection *connection,
r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
return (MHD_YES ==
TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID,
"denom_sig"))
? GNUNET_NO : GNUNET_SYSERR;
}
@@ -237,6 +243,8 @@ verify_coin_public_info (struct MHD_Connection *connection,
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TALER_Amount fee_refresh;
+ /* FIXME: we lookup the dki twice during /refresh/melt.
+ This should be avoided. */
key_state = TEH_KS_acquire ();
dki = TEH_KS_denomination_key_lookup (key_state,
&melt_detail->coin_info.denom_pub,
@@ -246,6 +254,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
TEH_KS_release (key_state);
TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
"denom_pub");
}
TALER_amount_ntoh (&fee_refresh,
@@ -266,6 +275,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
TEH_KS_release (key_state);
return (MHD_YES ==
TEH_RESPONSE_reply_external_error (connection,
+ TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT,
"melt amount smaller than melting fee"))
? GNUNET_NO : GNUNET_SYSERR;
}
@@ -280,6 +290,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
GNUNET_break_op (0);
if (MHD_YES !=
TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID,
"confirm_sig"))
return GNUNET_SYSERR;
return GNUNET_NO;
@@ -565,6 +576,7 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID,
"coin_evs");
}
if (TALER_CNC_KAPPA != json_array_size (transfer_pubs))
@@ -572,6 +584,7 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID,
"transfer_pubs");
}
res = handle_refresh_melt_json (connection,
@@ -694,6 +707,7 @@ TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh,
GNUNET_JSON_parse_free (spec);
GNUNET_break_op (0);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID,
"transfer_privs");
}
res = handle_refresh_reveal_json (connection,
diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c
index fdb6f8b76..591bb188d 100644
--- a/src/exchange/taler-exchange-httpd_refund.c
+++ b/src/exchange/taler-exchange-httpd_refund.c
@@ -69,14 +69,16 @@ verify_and_execute_refund (struct MHD_Connection *connection,
{
GNUNET_break_op (0);
return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH,
"refund_fee");
}
if (-1 == TALER_amount_cmp (&refund->refund_amount,
&refund->refund_fee) )
{
GNUNET_break_op (0);
- return TEH_RESPONSE_reply_signature_invalid (connection,
- "refund_amount");
+ return TEH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_REFUND_FEE_ABOVE_AMOUNT,
+ "refund_amount");
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
@@ -86,6 +88,7 @@ verify_and_execute_refund (struct MHD_Connection *connection,
{
TALER_LOG_WARNING ("Invalid signature on /refund request\n");
return TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID,
"merchant_sig");
}
return TEH_DB_execute_refund (connection,
diff --git a/src/exchange/taler-exchange-httpd_reserve.c b/src/exchange/taler-exchange-httpd_reserve.c
index 7098e99a2..0abe37c5a 100644
--- a/src/exchange/taler-exchange-httpd_reserve.c
+++ b/src/exchange/taler-exchange-httpd_reserve.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014,2015 GNUnet e.V.
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -138,6 +138,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh,
GNUNET_JSON_parse_free (spec);
TEH_KS_release (ks);
return TEH_RESPONSE_reply_arg_unknown (connection,
+ TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND,
"denom_pub");
}
TALER_amount_ntoh (&amount,
@@ -171,6 +172,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh,
TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n");
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID,
"reserve_sig");
}
res = TEH_DB_execute_reserve_withdraw (connection,
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index cacd933f1..b31f22e10 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -132,17 +132,20 @@ TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
* Send a response indicating an invalid argument.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s}",
+ "{s:s, s:I, s:s}",
"error", "invalid parameter",
+ "code", (json_int_t) ec,
"parameter", param_name);
}
@@ -153,17 +156,20 @@ TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
* denomination key).
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
- "{s:s, s:s}",
+ "{s:s, s:I, s:s}",
"error", "unknown entity referenced",
+ "code", (json_int_t) ec,
"parameter", param_name);
}
@@ -172,17 +178,20 @@ TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
* Send a response indicating an invalid signature.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_UNAUTHORIZED,
- "{s:s, s:s}",
+ "{s:s, s:I, s:s}",
"error", "invalid signature",
+ "code", (json_int_t) ec,
"parameter", param_name);
}
@@ -191,17 +200,20 @@ TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
* Send a response indicating a missing argument.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is missing
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{ s:s, s:s}",
+ "{ s:s, s:I, s:s}",
"error", "missing parameter",
+ "code", (json_int_t) ec,
"parameter", param_name);
}
@@ -210,17 +222,20 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
* Send a response indicating permission denied.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param hint hint about why access was denied
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *hint)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN,
- "{s:s, s:s}",
+ "{s:s, s:I, s:s}",
"error", "permission denied",
+ "code", (json_int_t) ec,
"hint", hint);
}
@@ -229,17 +244,20 @@ TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
* Send a response indicating an internal error.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param hint hint about the internal error's nature
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *hint)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
- "{s:s, s:s}",
+ "{s:s, s:I, s:s}",
"error", "internal error",
+ "code", (json_int_t) ec,
"hint", hint);
}
@@ -248,17 +266,20 @@ TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
* Send a response indicating an external error.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param hint hint about the error's nature
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *hint)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s}",
+ "{s:s, s:I, s:s}",
"error", "client error",
+ "code", (json_int_t) ec,
"hint", hint);
}
@@ -268,15 +289,18 @@ TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
* transaction (concurrent interference).
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @return a MHD result code
*/
int
-TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection)
+TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error", "commit failure");
+ "{s:s, s:I}",
+ "error", "commit failure",
+ "code", (json_int_t) ec);
}
@@ -285,12 +309,15 @@ TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection)
* database.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @return a MHD result code
*/
int
-TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection)
+TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec)
{
return TEH_RESPONSE_reply_internal_error (connection,
+ ec,
"Failed to connect to database");
}
@@ -332,9 +359,9 @@ TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error",
- "invalid json");
+ "{s:s, s:I}",
+ "error", "invalid json",
+ "code", (json_int_t) TALER_EC_JSON_INVALID);
}
@@ -556,11 +583,13 @@ TEH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection
history = compile_transaction_history (tl);
if (NULL == history)
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS);
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN,
- "{s:s, s:o}",
+ "{s:s, s:I, s:o}",
"error", "insufficient funds",
+ "code", (json_int_t) TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
"history", history);
}
@@ -696,8 +725,9 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection,
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_CONFLICT,
- "{s:s, s:o}",
+ "{s:s, s:I, s:o}",
"status", "conflicting refund",
+ "code", (json_int_t) TALER_EC_REFUND_CONFLICT,
"history", compile_transaction_history (tl));
}
@@ -708,17 +738,19 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection,
*
* @param connection connection to the client
* @param response_code response code to generate
+ * @param ec taler error code to include
* @return MHD result code
*/
int
TEH_RESPONSE_reply_refund_failure (struct MHD_Connection *connection,
- unsigned int response_code)
+ unsigned int response_code,
+ enum TALER_ErrorCode ec)
{
return TEH_RESPONSE_reply_json_pack (connection,
response_code,
- "{s:s}",
- "error",
- "no details");
+ "{s:s, s:I}",
+ "status", "refund failure",
+ "code", (json_int_t) ec);
}
@@ -779,6 +811,7 @@ TEH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection,
&balance);
if (NULL == json_history)
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_RESERVE_STATUS_DB_ERROR,
"balance calculation failure");
json_balance = TALER_JSON_from_amount (&balance);
return TEH_RESPONSE_reply_json_pack (connection,
@@ -810,12 +843,14 @@ TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *c
&balance);
if (NULL == json_history)
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS,
"balance calculation failure");
json_balance = TALER_JSON_from_amount (&balance);
return TEH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_PAYMENT_REQUIRED,
- "{s:s, s:o, s:o}",
+ MHD_HTTP_FORBIDDEN,
+ "{s:s, s:I, s:o, s:o}",
"error", "Insufficient funds",
+ "code", (json_int_t) TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS,
"balance", json_balance,
"history", json_history);
}
@@ -830,7 +865,7 @@ TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *c
*/
int
TEH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection,
- const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
+ const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
{
json_t *sig_json;
@@ -869,12 +904,15 @@ TEH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *conne
history = compile_transaction_history (tl);
if (NULL == history)
- return TEH_RESPONSE_reply_internal_db_error (connection);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS);
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN,
- "{s:s, s:o, s:o, s:o, s:o, s:o}",
+ "{s:s, s:I, s:o, s:o, s:o, s:o, s:o}",
"error",
- "insufficient funds",
+ "insufficient funds",
+ "code",
+ (json_int_t) TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS,
"coin_pub",
GNUNET_JSON_from_data_auto (coin_pub),
"original_value",
@@ -1011,8 +1049,9 @@ TEH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
}
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_CONFLICT,
- "{s:s, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:i}",
+ "{s:s, s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:i}",
"error", "commitment violation",
+ "code", (json_int_t) TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION,
"coin_sig", GNUNET_JSON_from_data_auto (&session->melt.coin_sig),
"coin_pub", GNUNET_JSON_from_data_auto (&session->melt.coin.coin_pub),
"melt_amount_with_fee", TALER_JSON_from_amount (&session->melt.amount_with_fee),
@@ -1089,15 +1128,18 @@ TEH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
* 404 reply.
*
* @param connection connection to the client
+ * @param ec Taler error code
* @return MHD result code
*/
int
-TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection)
+TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec)
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error", "Deposit unknown");
+ "{s:s, s:I}",
+ "error", "Deposit unknown",
+ "code", (json_int_t) ec);
}
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
index 742a95b91..70d384fe4 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -29,6 +29,7 @@
#include <jansson.h>
#include <microhttpd.h>
#include <pthread.h>
+#include "taler_error_codes.h"
#include "taler-exchange-httpd.h"
#include "taler-exchange-httpd_db.h"
@@ -78,11 +79,13 @@ TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
* Send a response indicating an invalid signature.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name);
@@ -90,11 +93,13 @@ TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
* Send a response indicating an invalid argument.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid
* @return MHD result code
*/
int
TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name);
@@ -104,11 +109,13 @@ TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
* denomination key).
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name);
@@ -116,11 +123,13 @@ TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
* Send a response indicating a missing argument.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param param_name the parameter that is missing
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *param_name);
@@ -128,11 +137,13 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
* Send a response indicating permission denied.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param hint hint about why access was denied
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *hint);
@@ -140,11 +151,13 @@ TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
* Send a response indicating an internal error.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param hint hint about the internal error's nature
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *hint);
@@ -152,11 +165,13 @@ TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
* Send a response indicating an external error.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @param hint hint about the error's nature
* @return a MHD result code
*/
int
TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
const char *hint);
@@ -165,21 +180,24 @@ TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
* transaction (concurrent interference).
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @return a MHD result code
*/
int
-TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection);
-
+TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec);
/**
* Send a response indicating a failure to talk to the Exchange's
* database.
*
* @param connection the MHD connection to use
+ * @param ec error code uniquely identifying the error
* @return a MHD result code
*/
int
-TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection);
+TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec);
/**
@@ -199,7 +217,7 @@ TEH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection);
* @return a MHD result code
*/
int
-TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection);
+TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connectionx);
/**
@@ -266,11 +284,13 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection,
*
* @param connection connection to the client
* @param response_code response code to generate
+ * @param ec error code uniquely identifying the error
* @return MHD result code
*/
int
TEH_RESPONSE_reply_refund_failure (struct MHD_Connection *connection,
- unsigned int response_code);
+ unsigned int response_code,
+ enum TALER_ErrorCode ec);
/**
@@ -291,10 +311,12 @@ TEH_RESPONSE_reply_refund_success (struct MHD_Connection *connection,
* 404 reply.
*
* @param connection connection to the client
+ * @param ec Taler error code
* @return MHD result code
*/
int
-TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection);
+TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec);
/**
@@ -307,7 +329,7 @@ TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection);
*/
int
TEH_RESPONSE_reply_transfer_pending (struct MHD_Connection *connection,
- struct GNUNET_TIME_Absolute planned_exec_time);
+ struct GNUNET_TIME_Absolute planned_exec_time);
/**
diff --git a/src/exchange/taler-exchange-httpd_test.c b/src/exchange/taler-exchange-httpd_test.c
index 7c3252b10..731da36ce 100644
--- a/src/exchange/taler-exchange-httpd_test.c
+++ b/src/exchange/taler-exchange-httpd_test.c
@@ -295,6 +295,7 @@ TEH_TEST_handler_test_ecdhe (struct TEH_RequestHandler *rh,
{
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TEST_ECDH_ERROR,
"Failed to perform ECDH");
}
GNUNET_JSON_parse_free (spec);
@@ -365,6 +366,7 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh,
{
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_TEST_EDDSA_INVALID,
"eddsa_sig");
}
GNUNET_JSON_parse_free (spec);
@@ -377,6 +379,7 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh,
{
GNUNET_free (pk);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TEST_EDDSA_ERROR,
"Failed to EdDSA-sign");
}
GNUNET_CRYPTO_eddsa_key_get_public (pk,
@@ -419,6 +422,7 @@ TEH_TEST_handler_test_rsa_get (struct TEH_RequestHandler *rh,
{
GNUNET_break (0);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TEST_RSA_GEN_ERROR,
"Failed to create RSA key");
}
pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk);
@@ -426,6 +430,7 @@ TEH_TEST_handler_test_rsa_get (struct TEH_RequestHandler *rh,
{
GNUNET_break (0);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TEST_RSA_PUB_ERROR,
"Failed to get public RSA key");
}
res = TEH_RESPONSE_reply_json_pack (connection,
@@ -489,6 +494,7 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh,
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TEST_RSA_GEN_ERROR,
"Failed to create RSA key");
}
sig = GNUNET_CRYPTO_rsa_sign_blinded (rsa_pk,
@@ -499,6 +505,7 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh,
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TEST_RSA_SIGN_ERROR,
"Failed to RSA-sign");
}
GNUNET_JSON_parse_free (spec);
diff --git a/src/exchange/taler-exchange-httpd_tracking.c b/src/exchange/taler-exchange-httpd_tracking.c
index 1c7c24557..04b50132c 100644
--- a/src/exchange/taler-exchange-httpd_tracking.c
+++ b/src/exchange/taler-exchange-httpd_tracking.c
@@ -88,6 +88,7 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection,
{
GNUNET_break_op (0);
return TEH_RESPONSE_reply_signature_invalid (connection,
+ TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID,
"merchant_sig");
}
return TEH_DB_execute_track_transaction (connection,
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 972d70808..461184c7e 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -20,6 +20,7 @@
* @author Florian Dold
* @author Christian Grothoff
* @author Sree Harsha Totakura
+ * @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_pq_lib.h"
@@ -627,6 +628,23 @@ postgres_prepare (PGconn *db_conn)
"($1, $2, $3, $4, $5, $6, $7);",
7, NULL);
+
+ /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
+ transactions for reserves with serial id '\geq' the given parameter */
+ PREPARE ("audit_reserves_in_get_transactions_incr",
+ "SELECT"
+ " reserve_pub"
+ ",credit_val"
+ ",credit_frac"
+ ",credit_curr"
+ ",execution_date"
+ ",sender_account_details"
+ ",transfer_details"
+ " FROM reserves_in"
+ " WHERE reserve_in_serial_id>=$1"
+ " ORDER BY reserve_in_serial_id",
+ 1, NULL);
+
/* Used in #postgres_get_reserve_history() to obtain inbound transactions
for a reserve */
PREPARE ("reserves_in_get_transactions",
@@ -707,6 +725,23 @@ postgres_prepare (PGconn *db_conn)
" WHERE reserve_pub=$1;",
1, NULL);
+ /* Used in #postgres_select_reserves_out_above_serial_id() */
+ PREPARE ("audit_get_reserves_out_incr",
+ "SELECT"
+ " h_blind_ev"
+ ",denom_pub"
+ ",denom_sig"
+ ",reserve_sig"
+ ",reserve_pub"
+ ",execution_date"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ " FROM reserves_out"
+ " WHERE reserve_out_serial_id>=$1"
+ " ORDER BY reserve_out_serial_id ASC",
+ 1, NULL);
+
/* Used in #postgres_get_refresh_session() to fetch
high-level information about a refresh session */
PREPARE ("get_refresh_session",
@@ -727,6 +762,22 @@ postgres_prepare (PGconn *db_conn)
" WHERE session_hash=$1 ",
1, NULL);
+ /* Used in #postgres_select_refreshs_above_serial_id() to fetch
+ refresh session with id '\geq' the given parameter */
+ PREPARE ("audit_get_refresh_sessions_incr",
+ "SELECT"
+ " old_coin_pub"
+ ",old_coin_sig"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",num_newcoins"
+ ",noreveal_index"
+ " FROM refresh_sessions"
+ " WHERE melt_serial_id>=$1"
+ " ORDER BY melt_serial_id ASC",
+ 1, NULL);
+
/* Used in #postgres_create_refresh_session() to store
high-level information about a refresh session */
PREPARE ("insert_refresh_session",
@@ -802,6 +853,23 @@ postgres_prepare (PGconn *db_conn)
" WHERE old_coin_pub=$1",
1, NULL);
+ /* Fetch refunds with rowid '\geq' the given parameter */
+ PREPARE ("audit_get_refunds_incr",
+ "SELECT"
+ " merchant_pub"
+ ",merchant_sig"
+ ",h_contract"
+ ",transaction_id"
+ ",rtransaction_id"
+ ",coin_pub"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ " FROM refunds"
+ " WHERE refund_serial_id>=$1"
+ " ORDER BY refund_serial_id ASC",
+ 1, NULL);
+
/* Query the 'refunds' by coin public key */
PREPARE ("get_refunds_by_coin",
"SELECT"
@@ -823,6 +891,7 @@ postgres_prepare (PGconn *db_conn)
1, NULL);
+
/* Used in #postgres_insert_transfer_public_key() to
store commitments */
PREPARE ("insert_transfer_public_key",
@@ -921,8 +990,7 @@ postgres_prepare (PGconn *db_conn)
" )",
3, NULL);
- /* Fetch an existing deposit request, used to ensure idempotency
- during /deposit processing. Used in #postgres_have_deposit(). */
+ /* Fetch deposits with rowid '\geq' the given parameter */
PREPARE ("audit_get_deposits_incr",
"SELECT"
" amount_with_fee_val"
@@ -937,11 +1005,12 @@ postgres_prepare (PGconn *db_conn)
",wire_deadline"
",h_contract"
",wire"
+ ",done"
" FROM deposits"
" WHERE ("
" (deposit_serial_id>=$1)"
" )"
- " ORDER BY deposit_serial_id",
+ " ORDER BY deposit_serial_id ASC",
1, NULL);
/* Fetch an existing deposit request.
@@ -1207,6 +1276,18 @@ postgres_prepare (PGconn *db_conn)
" FROM prewire"
" WHERE finished=true",
0, NULL);
+
+ /* Used in #postgres_select_prepare_above_serial_id() */
+ PREPARE ("audit_get_wire_incr",
+ "SELECT"
+ " type"
+ ",buf"
+ ",finished"
+ " FROM prewire"
+ " WHERE prewire_uuid>=$1"
+ " ORDER BY prewire_uuid ASC",
+ 1, NULL);
+
PREPARE ("gc_denominations",
"DELETE"
" FROM denominations"
@@ -4291,9 +4372,9 @@ postgres_select_deposits_above_serial_id (void *cls,
};
PGresult *result;
result = GNUNET_PQ_exec_prepared (session->conn,
- "audit_get_deposits_incr",
- params);
- if (PGRES_COMMAND_OK !=
+ "audit_get_deposits_incr",
+ params);
+ if (PGRES_TUPLES_OK !=
PQresultStatus (result))
{
BREAK_DB_ERR (result);
@@ -4307,20 +4388,62 @@ postgres_select_deposits_above_serial_id (void *cls,
if (0 == nrows)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "audit_get_deposit_incr() returned 0 matching rows\n");
+ "select_deposits_above_serial_id() returned 0 matching rows\n");
PQclear (result);
return GNUNET_NO;
}
for (i=0;i<nrows;i++)
{
+ struct TALER_EXCHANGEDB_Deposit deposit;
+ uint8_t done = 0;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &deposit.amount_with_fee),
+ GNUNET_PQ_result_spec_absolute_time ("timestamp",
+ &deposit.timestamp),
+ GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
+ &deposit.merchant_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &deposit.coin.coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
+ &deposit.csig),
+ GNUNET_PQ_result_spec_uint64 ("transaction_id",
+ &deposit.transaction_id),
+ GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
+ &deposit.refund_deadline),
+ GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
+ &deposit.wire_deadline),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract",
+ &deposit.h_contract),
+ TALER_PQ_result_spec_json ("wire",
+ &deposit.receiver_wire_account),
+ GNUNET_PQ_result_spec_auto_from_type ("done",
+ &done),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ serial_id,
+ &deposit.merchant_pub,
+ &deposit.coin.coin_pub,
+ &deposit.csig,
+ &deposit.amount_with_fee,
+ deposit.transaction_id,
+ &deposit.h_contract,
+ deposit.refund_deadline,
+ deposit.wire_deadline,
+ deposit.receiver_wire_account,
+ done);
}
-
PQclear (result);
return GNUNET_OK;
-
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
}
@@ -4343,8 +4466,72 @@ postgres_select_refreshs_above_serial_id (void *cls,
TALER_EXCHANGEDB_RefreshSessionCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ 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,
+ "audit_get_refresh_sessions_incr",
+ params);
+
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ int nrows;
+ int i;
+
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_refreshs_above_serial_id() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+
+ for (i=0;i<nrows;i++)
+ {
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct TALER_Amount amount_with_fee;
+ uint16_t num_newcoins;
+ uint16_t noreveal_index;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
+ &coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
+ &coin_sig),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &amount_with_fee),
+ GNUNET_PQ_result_spec_uint16 ("num_newcoins",
+ &num_newcoins),
+ GNUNET_PQ_result_spec_uint16 ("noreveal_index",
+ &noreveal_index),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ serial_id,
+ &coin_pub,
+ &coin_sig,
+ &amount_with_fee,
+ num_newcoins,
+ noreveal_index);
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -4367,8 +4554,72 @@ postgres_select_refunds_above_serial_id (void *cls,
TALER_EXCHANGEDB_RefundCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ 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,
+ "audit_get_refunds_incr",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ int nrows;
+ int i;
+
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_refunds_above_serial_id() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (i=0;i<nrows;i++)
+ {
+ struct TALER_EXCHANGEDB_Refund refund;
+
+ 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",
+ &refund.h_contract),
+ GNUNET_PQ_result_spec_uint64 ("transaction_id",
+ &refund.transaction_id),
+ GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
+ &refund.rtransaction_id),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &refund.coin.coin_pub),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &refund.refund_amount),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ serial_id,
+ &refund.coin.coin_pub,
+ &refund.merchant_pub,
+ &refund.merchant_sig,
+ &refund.h_contract,
+ refund.transaction_id,
+ refund.rtransaction_id,
+ &refund.refund_amount);
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -4391,8 +4642,73 @@ postgres_select_reserves_in_above_serial_id (void *cls,
TALER_EXCHANGEDB_ReserveInCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ 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,
+ "audit_reserves_in_get_transactions_incr",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ int nrows;
+ int i;
+
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_reserves_in_above_serial_id() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+
+ for (i=0;i<nrows;i++)
+ {
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_Amount credit;
+ json_t *sender_account_details;
+ json_t *transfer_details;
+ struct GNUNET_TIME_Absolute execution_date;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ &reserve_pub),
+ TALER_PQ_result_spec_amount ("credit",
+ &credit),
+ GNUNET_PQ_result_spec_absolute_time("execution_date",
+ &execution_date),
+ TALER_PQ_result_spec_json ("sender_account_details",
+ &sender_account_details),
+ TALER_PQ_result_spec_json ("transfer_details",
+ &transfer_details),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ serial_id,
+ &reserve_pub,
+ &credit,
+ sender_account_details,
+ transfer_details,
+ execution_date);
+ }
+
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -4415,8 +4731,79 @@ postgres_select_reserves_out_above_serial_id (void *cls,
TALER_EXCHANGEDB_WithdrawCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+ 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,
+ "audit_get_reserves_out_incr",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ int nrows;
+ int i;
+
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "select_reserves_out_above_serial_id() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (i=0;i<nrows;i++)
+ {
+ struct GNUNET_HashCode h_blind_ev;
+ struct TALER_DenominationPublicKey denom_pub;
+ struct TALER_DenominationSignature denom_sig;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_ReserveSignatureP reserve_sig;
+ struct GNUNET_TIME_Absolute execution_date;
+ struct TALER_Amount amount_with_fee;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ 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),
+ GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+ &denom_sig.rsa_signature),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ &reserve_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
+ &reserve_sig),
+ GNUNET_PQ_result_spec_absolute_time ("execution_date",
+ &execution_date),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &amount_with_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ serial_id,
+ &h_blind_ev,
+ &denom_pub,
+ &denom_sig,
+ &reserve_pub,
+ &reserve_sig,
+ execution_date,
+ &amount_with_fee);
+ }
+
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -4440,8 +4827,69 @@ postgres_select_prepare_above_serial_id (void *cls,
TALER_EXCHANGEDB_WirePreparationCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // FIXME: not implemented
- return GNUNET_SYSERR;
+
+ 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,
+ "audit_get_wire_incr",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ int nrows;
+ int i;
+
+ 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 (i=0;i<nrows;i++)
+ {
+ char *wire_method;
+ void *buf;
+ size_t buf_size;
+ uint8_t finished;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("type",
+ &wire_method),
+ GNUNET_PQ_result_spec_variable_size ("buf",
+ &buf,
+ &buf_size),
+ GNUNET_PQ_result_spec_auto_from_type ("finished",
+ &finished),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ cb (cb_cls,
+ serial_id,
+ wire_method,
+ buf,
+ buf_size,
+ finished);
+ }
+
+ PQclear (result);
+ return GNUNET_OK;
}
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 00c7a9ef6..d0ec63f46 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -18,6 +18,7 @@
* @brief test cases for DB interaction functions
* @author Sree Harsha Totakura
* @author Christian Grothoff
+ * @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_exchangedb_lib.h"
@@ -77,6 +78,12 @@ dead_prepare_cb (void *cls,
GNUNET_assert (0);
}
+/**
+ * Counter used in auditor-related db functions. Used to count
+ * expected rows.
+ */
+unsigned int auditor_row_cnt;
+
/**
* Callback that is called with wire prepare data
@@ -103,6 +110,27 @@ mark_prepare_cb (void *cls,
rowid));
}
+/**
+ * Callback with data about a prepared wire transfer.
+ *
+ * @param cls closure
+ * @param rowid row identifier used to mark prepared transaction as done
+ * @param wire_method which wire method is this preparation data for
+ * @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?
+ */
+void
+audit_wire_cb (void *cls,
+ unsigned long long rowid,
+ const char *wire_method,
+ const char *buf,
+ size_t buf_size,
+ int finished)
+{
+ auditor_row_cnt++;
+ return;
+}
/**
* Test API relating to persisting the wire plugins preparation data.
@@ -134,6 +162,14 @@ test_wire_prepare (struct TALER_EXCHANGEDB_Session *session)
session,
&dead_prepare_cb,
NULL));
+ auditor_row_cnt = 0;
+ FAILIF (GNUNET_OK !=
+ plugin->select_prepare_above_serial_id (plugin->cls,
+ session,
+ 0,
+ &audit_wire_cb,
+ NULL));
+ FAILIF (1 != auditor_row_cnt);
return GNUNET_OK;
drop:
return GNUNET_SYSERR;
@@ -465,6 +501,38 @@ check_transfer_data (void *cls,
*ok = GNUNET_SYSERR;
}
+/**
+ * Function called with details about coins that were melted,
+ * with the goal of auditing the refresh's execution.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the refresh session in our DB
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param coin_sig signature from the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param refund_deadline by which the merchant adviced that he might want
+ * to get a refund
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits()
+ * @param done flag set if the deposit was already executed (or not)
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+int
+audit_refresh_session_cb (void *cls,
+ unsigned long long rowid, /* FIXME: decide data type for serial_id! */
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ const struct TALER_Amount *amount_with_fee,
+ uint16_t num_newcoins,
+ uint16_t noreveal_index)
+{
+ auditor_row_cnt++;
+ return GNUNET_OK;
+}
/**
* Function to test melting of coins as part of a refresh session
@@ -538,6 +606,14 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
session,
&session_hash,
&ret_refresh_session));
+
+ auditor_row_cnt = 0;
+ FAILIF (GNUNET_OK != plugin->select_refreshs_above_serial_id (plugin->cls,
+ session,
+ 0,
+ &audit_refresh_session_cb,
+ NULL));
+ FAILIF (1 != auditor_row_cnt);
FAILIF (ret_refresh_session.num_newcoins != refresh_session.num_newcoins);
FAILIF (ret_refresh_session.noreveal_index != refresh_session.noreveal_index);
@@ -874,6 +950,128 @@ deposit_cb (void *cls,
return GNUNET_OK;
}
+/**
+ * Callback for #select_deposits_above_serial_id ()
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the deposit in our DB
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param coin_sig signature from the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param refund_deadline by which the merchant adviced that he might want
+ * to get a refund
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits()
+ * @param done flag set if the deposit was already executed (or not)
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+int
+audit_deposit_cb (void *cls,
+ unsigned long long rowid,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ const struct TALER_Amount *amount_with_fee,
+ uint64_t transaction_id,
+ const struct GNUNET_HashCode *h_contract,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ const json_t *receiver_wire_account,
+ int done)
+{
+ auditor_row_cnt++;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with details about coins that were refunding,
+ * with the goal of auditing the refund's execution.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the refund in our DB
+ * @param coin_pub public key of the coin
+ * @param merchant_pub public key of the merchant
+ * @param merchant_sig signature of the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param transaction_id original transaction ID chosen by the merchant
+ * @param rtransaction_id refund transaction ID chosen by the merchant
+ * @param amount_with_fee amount that was deposited including fee
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+int
+audit_refund_cb (void *cls,
+ unsigned long long rowid, /* FIXME: decide data type for serial_id! */
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_MerchantSignatureP *merchant_sig,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ uint64_t rtransaction_id,
+ const struct TALER_Amount *amount_with_fee)
+{
+ auditor_row_cnt++;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with details about incoming wire transfers.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the refresh session in our DB
+ * @param reserve_pub public key of the reserve (also the WTID)
+ * @param credit amount that was received
+ * @param sender_account_details information about the sender's bank account
+ * @param transfer_details information that uniquely identifies the wire transfer
+ * @param execution_date when did we receive the funds
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+int
+audit_reserve_in_cb (void *cls,
+ unsigned long long rowid, /* FIXME: decide data type for serial_id! */
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *credit,
+ const json_t *sender_account_details,
+ const json_t *transfer_details,
+ struct GNUNET_TIME_Absolute execution_date)
+{
+ auditor_row_cnt++;
+ return GNUNET_OK;
+}
+
+/**
+ * Function called with details about withdraw operations.
+ *
+ * @param cls closure
+ * @param rowid unique serial ID for the refresh session in our DB
+ * @param h_blind_ev blinded hash of the coin's public key
+ * @param denom_pub public denomination key of the deposited coin
+ * @param denom_sig signature over the deposited coin
+ * @param reserve_pub public key of the reserve
+ * @param reserve_sig signature over the withdraw operation
+ * @param execution_date when did the wallet withdraw the coin
+ * @param amount_with_fee amount that was withdrawn
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+int
+audit_reserve_out_cb (void *cls,
+ unsigned long long rowid, /* FIXME: decide data type for serial_id! */
+ const struct GNUNET_HashCode *h_blind_ev,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ const struct TALER_DenominationSignature *denom_sig,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_ReserveSignatureP *reserve_sig,
+ struct GNUNET_TIME_Absolute execution_date,
+ const struct TALER_Amount *amount_with_fee)
+{
+ auditor_row_cnt++;
+ return GNUNET_OK;
+}
/**
* Test garbage collection.
@@ -1121,6 +1319,21 @@ run (void *cls)
}
}
FAILIF (3 != cnt);
+
+ auditor_row_cnt = 0;
+ FAILIF (GNUNET_OK !=
+ plugin->select_reserves_in_above_serial_id (plugin->cls,
+ session,
+ 0,
+ &audit_reserve_in_cb,
+ NULL));
+ FAILIF (GNUNET_OK !=
+ plugin->select_reserves_out_above_serial_id (plugin->cls,
+ session,
+ 0,
+ &audit_reserve_out_cb,
+ NULL));
+ FAILIF (3 != auditor_row_cnt);
/* Tests for deposits */
memset (&deposit, 0, sizeof (deposit));
RND_BLK (&deposit.coin.coin_pub);
@@ -1145,6 +1358,14 @@ run (void *cls)
plugin->have_deposit (plugin->cls,
session,
&deposit));
+ auditor_row_cnt = 0;
+ FAILIF (GNUNET_OK !=
+ plugin->select_deposits_above_serial_id (plugin->cls,
+ session,
+ 0,
+ &audit_deposit_cb,
+ NULL));
+ FAILIF (1 != auditor_row_cnt);
result = 9;
FAILIF (1 !=
plugin->iterate_matching_deposits (plugin->cls,
@@ -1232,7 +1453,15 @@ run (void *cls)
plugin->insert_refund (plugin->cls,
session,
&refund));
+ auditor_row_cnt = 0;
+ FAILIF (GNUNET_OK !=
+ plugin->select_refunds_above_serial_id (plugin->cls,
+ session,
+ 0,
+ &audit_refund_cb,
+ NULL));
+ FAILIF (1 != auditor_row_cnt);
tl = plugin->get_coin_transactions (plugin->cls,
session,
&refund.coin.coin_pub);
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index cc75fb014..c27295a08 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -29,6 +29,90 @@
/**
+ * Function called with the results of select_denomination_info()
+ *
+ * @param cls closure
+ * @param issue issuing information with value, fees and other info about the denomination.
+ *
+ * @return sets the return value of select_denomination_info(),
+ * #GNUNET_OK to continue,
+ * #GNUNET_NO to stop processing further rows
+ * #GNUNET_SYSERR or other values on error.
+ */
+typedef int
+(*TALER_AUDITORDB_DenominationInfoDataCallback)(void *cls,
+ const struct TALER_DenominationKeyValidityPS *issue);
+
+
+/**
+ * Function called with the results of select_historic_denom_revenue()
+ *
+ * @param cls closure
+ * @param denom_pub_hash hash of the denomination key
+ * @param revenue_timestamp when did this profit get realized
+ * @param revenue_balance what was the total profit made from
+ * deposit fees, melting fees, refresh fees
+ * and coins that were never returned?
+ * @param deposit_fee_balance total profits from deposit fees
+ * @param melt_fee_balance total profits from melting fees
+ * @param refund_fee_balance total profits from refund fees
+ *
+ * @return sets the return value of select_denomination_info(),
+ * #GNUNET_OK to continue,
+ * #GNUNET_NO to stop processing further rows
+ * #GNUNET_SYSERR or other values on error.
+ */
+typedef int
+(*TALER_AUDITORDB_HistoricDenominationRevenueDataCallback)(void *cls,
+ const struct GNUNET_HashCode *denom_pub_hash,
+ struct GNUNET_TIME_Absolute revenue_timestamp,
+ const struct TALER_Amount *revenue_balance,
+ const struct TALER_Amount *deposit_fee_balance,
+ const struct TALER_Amount *melt_fee_balance,
+ const struct TALER_Amount *refund_fee_balance);
+
+
+/**
+ * Function called with the results of select_historic_losses()
+ *
+ * @param cls closure
+ * @param denom_pub_hash hash of the denomination key
+ * @param loss_timestamp when did this profit get realized
+ * @param loss_balance what was the total loss
+ *
+ * @return sets the return value of select_denomination_info(),
+ * #GNUNET_OK to continue,
+ * #GNUNET_NO to stop processing further rows
+ * #GNUNET_SYSERR or other values on error.
+ */
+typedef int
+(*TALER_AUDITORDB_HistoricLossesDataCallback)(void *cls,
+ const struct GNUNET_HashCode *denom_pub_hash,
+ struct GNUNET_TIME_Absolute loss_timestamp,
+ const struct TALER_Amount *loss_balance);
+
+
+/**
+ * Function called with the results of select_historic_reserve_revenue()
+ *
+ * @param cls closure
+ * @param start_time beginning of aggregated time interval
+ * @param end_time end of aggregated time interval
+ * @param reserve_profits total profits made
+ *
+ * @return sets the return value of select_denomination_info(),
+ * #GNUNET_OK to continue,
+ * #GNUNET_NO to stop processing further rows
+ * #GNUNET_SYSERR or other values on error.
+ */
+typedef int
+(*TALER_AUDITORDB_HistoricReserveRevenueDataCallback)(void *cls,
+ struct GNUNET_TIME_Absolute start_time,
+ struct GNUNET_TIME_Absolute end_time,
+ const struct TALER_Amount *reserve_profits);
+
+
+/**
* Handle for one session with the database.
*/
struct TALER_AUDITORDB_Session;
@@ -164,11 +248,89 @@ struct TALER_AUDITORDB_Plugin
(*select_denomination_info)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: type! */
+ TALER_AUDITORDB_DenominationInfoDataCallback cb,
void *cb_cls);
/**
+ * Insert information about the auditor's progress with an exchange's
+ * data.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param master_pub master key of the exchange
+ * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed
+ * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
+ * @param last_deposit_serial_id serial ID of the last deposit the auditor processed
+ * @param last_melt_serial_id serial ID of the last refresh the auditor processed
+ * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ */
+ int
+ (*insert_auditor_progress)(void *cls,
+ struct TALER_AUDITORDB_Session *session,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ uint64_t last_reserve_in_serial_id,
+ uint64_t last_reserve_out_serial_id,
+ uint64_t last_deposit_serial_id,
+ uint64_t last_melt_serial_id,
+ uint64_t last_refund_serial_id,
+ uint64_t last_prewire_serial_id);
+
+
+ /**
+ * Update information about the progress of the auditor. There
+ * must be an existing record for the exchange.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param master_pub master key of the exchange
+ * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed
+ * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
+ * @param last_deposit_serial_id serial ID of the last deposit the auditor processed
+ * @param last_melt_serial_id serial ID of the last refresh the auditor processed
+ * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ */
+ int
+ (*update_auditor_progress)(void *cls,
+ struct TALER_AUDITORDB_Session *session,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ uint64_t last_reserve_in_serial_id,
+ uint64_t last_reserve_out_serial_id,
+ uint64_t last_deposit_serial_id,
+ uint64_t last_melt_serial_id,
+ uint64_t last_refund_serial_id,
+ uint64_t last_prewire_serial_id);
+
+
+ /**
+ * Get information about the progress of the auditor.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param master_pub master key of the exchange
+ * @param[out] last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed
+ * @param[out] last_reserve_out_serial_id serial ID of the last withdraw the auditor processed
+ * @param[out] last_deposit_serial_id serial ID of the last deposit the auditor processed
+ * @param[out] last_melt_serial_id serial ID of the last refresh the auditor processed
+ * @param[out] last_prewire_serial_id serial ID of the last prewire transfer the auditor processed
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure;
+ * #GNUNET_NO if we have no records for the @a master_pub
+ */
+ int
+ (*get_auditor_progress)(void *cls,
+ struct TALER_AUDITORDB_Session *session,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ uint64_t *last_reserve_in_serial_id,
+ uint64_t *last_reserve_out_serial_id,
+ uint64_t *last_deposit_serial_id,
+ uint64_t *last_melt_serial_id,
+ uint64_t *last_refund_serial_id,
+ uint64_t *last_prewire_serial_id);
+
+
+ /**
* Insert information about a reserve. There must not be an
* existing record for the reserve.
*
@@ -586,7 +748,7 @@ struct TALER_AUDITORDB_Plugin
(*select_historic_denom_revenue)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: fix type */
+ TALER_AUDITORDB_HistoricDenominationRevenueDataCallback cb,
void *cb_cls);
@@ -628,7 +790,7 @@ struct TALER_AUDITORDB_Plugin
(*select_historic_losses)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: fix type */
+ TALER_AUDITORDB_HistoricLossesDataCallback cb,
void *cb_cls);
@@ -666,7 +828,7 @@ struct TALER_AUDITORDB_Plugin
(*select_historic_reserve_revenue)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
- void *cb, /* FIXME: type */
+ TALER_AUDITORDB_HistoricReserveRevenueDataCallback cb,
void *cb_cls);
@@ -721,6 +883,7 @@ struct TALER_AUDITORDB_Plugin
const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *balance);
+
};
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index bbb300440..6da76a122 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -33,12 +33,1097 @@ enum TALER_ErrorCode
{
/**
- * Special code to indicate no error.
+ * Special code to indicate no error (or no "code" present).
*/
- TALER_EC_NONE = 0
+ TALER_EC_NONE = 0,
+ /**
+ * Special code to indicate that a non-integer error code was
+ * returned in the JSON response.
+ */
+ TALER_EC_INVALID = 1,
+
+ /**
+ * The response we got from the server was not even in JSON format.
+ */
+ TALER_EC_INVALID_RESPONSE = 2,
+
+
+ /* ********** generic error codes ************* */
+
+ /**
+ * The exchange failed to even just initialize its connection to the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DB_SETUP_FAILED = 1001,
+
+ /**
+ * The exchange encountered an error event to just start
+ * the database transaction.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DB_START_FAILED = 1002,
+
+ /**
+ * The exchange encountered an error event to commit
+ * the database transaction (hard, unrecoverable error).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DB_COMMIT_FAILED_HARD = 1003,
+
+ /**
+ * The exchange encountered an error event to commit
+ * the database transaction, even after repeatedly
+ * retrying it there was always a conflicting transaction.
+ * (This indicates a repeated serialization error; should
+ * only happen if some client maliciously tries to create
+ * conflicting concurrent transactions.)
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DB_COMMIT_FAILED_ON_RETRY = 1004,
+ /**
+ * The exchange had insufficient memory to parse the request. This
+ * response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PARSER_OUT_OF_MEMORY = 1005,
+
+ /**
+ * The JSON in the client's request to the exchange was malformed.
+ * (Generic parse error).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_JSON_INVALID = 1006,
+
+ /**
+ * The JSON in the client's request to the exchange was malformed.
+ * Details about the location of the parse error are provided.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_JSON_INVALID_WITH_DETAILS = 1007,
+
+ /**
+ * A required parameter in the request to the exchange was missing.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PARAMETER_MISSING = 1008,
+
+ /**
+ * A parameter in the request to the exchange was malformed.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PARAMETER_MALFORMED = 1009,
+
+ /* ********** request-specific error codes ************* */
+
+ /**
+ * The given reserve does not have sufficient funds to admit the
+ * requested withdraw operation at this time. The response includes
+ * the current "balance" of the reserve as well as the transaction
+ * "history" that lead to this balance. This response is provided
+ * with HTTP status code MHD_HTTP_FORBIDDEN.
+ */
+ TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS = 1100,
+
+ /**
+ * The exchange has no information about the "reserve_pub" that
+ * was given.
+ * This response is provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_WITHDRAW_RESERVE_UNKNOWN = 1101,
+
+ /**
+ * The amount to withdraw together with the fee exceeds the
+ * numeric range for Taler amounts. This is not a client
+ * failure, as the coin value and fees come from the exchange's
+ * configuration.
+ * This response is provided with HTTP status code MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW = 1102,
+
+ /**
+ * All of the deposited amounts into this reserve total up to a
+ * value that is too big for the numeric range for Taler amounts.
+ * This is not a client failure, as the transaction history comes
+ * from the exchange's configuration. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW = 1103,
+
+ /**
+ * For one of the historic withdrawals from this reserve, the
+ * exchange could not find the denomination key.
+ * This is not a client failure, as the transaction history comes
+ * from the exchange's configuration. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND = 1104,
+
+ /**
+ * All of the withdrawals from reserve total up to a
+ * value that is too big for the numeric range for Taler amounts.
+ * This is not a client failure, as the transaction history comes
+ * from the exchange's configuration. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW = 1105,
+
+ /**
+ * The exchange somehow knows about this reserve, but there seem to
+ * have been no wire transfers made. This is not a client failure,
+ * as this is a database consistency issue of the exchange. This
+ * response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER = 1106,
+
+ /**
+ * The exchange failed to create the signature using the
+ * denomination key. This response is provided with HTTP status
+ * code MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_SIGNATURE_FAILED = 1107,
+
+ /**
+ * The exchange failed to store the withdraw operation in its
+ * database. This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_DB_STORE_ERROR = 1108,
+
+ /**
+ * The exchange failed to check against historic withdraw data from
+ * database (as part of ensuring the idempotency of the operation).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_WITHDRAW_DB_FETCH_ERROR = 1109,
+
+ /**
+ * The exchange is not aware of the denomination key
+ * the wallet requested for the withdrawal.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND = 1110,
+
+ /**
+ * The signature of the reserve is not valid. This response is
+ * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID = 1111,
+
+ /**
+ * The exchange failed to obtain the transaction history of the
+ * given reserve from the database while generating an insufficient
+ * funds errors.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1112,
+
+ /**
+ * The exchange failed to obtain the transaction history of the
+ * given reserve from the database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_RESERVE_STATUS_DB_ERROR = 1150,
+
+
+ /**
+ * The respective coin did not have sufficient residual value
+ * for the /deposit operation (i.e. due to double spending).
+ * The "history" in the respose provides the transaction history
+ * of the coin proving this fact. This response is provided
+ * with HTTP status code MHD_HTTP_FORBIDDEN.
+ */
+ TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS = 1200,
+
+ /**
+ * The exchange failed to obtain the transaction history of the
+ * given coin from the database (this does not happen merely because
+ * the coin is seen by the exchange for the first time).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DEPOSIT_HISTORY_DB_ERROR = 1201,
+
+ /**
+ * The exchange failed to store the /depost information in the
+ * database. This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DEPOSIT_STORE_DB_ERROR = 1202,
+
+ /**
+ * The exchange database is unaware of the denomination key that
+ * signed the coin (however, the exchange process is; this is not
+ * supposed to happen; it can happen if someone decides to purge the
+ * DB behind the back of the exchange process). Hence the deposit
+ * is being refused. This response is provided with HTTP status
+ * code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN = 1203,
+
+ /**
+ * The exchange database is unaware of the denomination key that
+ * signed the coin (however, the exchange process is; this is not
+ * supposed to happen; it can happen if someone decides to purge the
+ * DB behind the back of the exchange process). Hence the deposit
+ * is being refused. This response is provided with HTTP status
+ * code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN = 1204,
+
+ /**
+ * The signature of the coin is not valid. This response is
+ * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID = 1205,
+
+ /**
+ * The signature of the denomination key over the coin is not valid.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID = 1206,
+
+ /**
+ * The stated value of the coin after the deposit fee is subtracted
+ * would be negative.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE = 1207,
+
+ /**
+ * The stated refund deadline is after the wire deadline.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE = 1208,
+
+ /**
+ * The exchange does not recognize the validity of or support the
+ * given wire (bank account) address. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT = 1209,
+
+ /**
+ * The exchange failed to canonicalize and hash the given wire format.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON = 1210,
+
+ /**
+ * The hash of the given wire address does not match the hash
+ * specified in the contract.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT = 1211,
+
+ /**
+ * The exchange failed to obtain the transaction history of the
+ * given coin from the database while generating an insufficient
+ * funds errors.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1212,
+
+ /**
+ * The respective coin did not have sufficient residual value
+ * for the /refresh/melt operation. The "history" in this
+ * response provdes the "residual_value" of the coin, which may
+ * be less than its "original_value". This response is provided
+ * with HTTP status code MHD_HTTP_FORBIDDEN.
+ */
+ TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS = 1300,
+
+ /**
+ * The exchange is unaware of the denomination key that was
+ * used to sign the melted coin. This response is provided
+ * with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND = 1301,
+
+ /**
+ * The exchange had an internal error reconstructing the
+ * transaction history of the coin that was being melted.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED = 1302,
+
+ /**
+ * The exchange failed to check against historic melt data from
+ * database (as part of ensuring the idempotency of the operation).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_DB_FETCH_ERROR = 1303,
+
+ /**
+ * The exchange failed to store session data in the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304,
+
+ /**
+ * The exchange failed to store refresh order data in the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR = 1305,
+
+ /**
+ * The exchange failed to store commit data in the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306,
+
+ /**
+ * The exchange failed to store transfer keys in the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR = 1307,
+
+ /**
+ * The exchange is unaware of the denomination key that was
+ * requested for one of the fresh coins. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND = 1308,
+
+ /**
+ * The exchange encountered a numeric overflow totaling up
+ * the cost for the refresh operation. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW = 1309,
+
+ /**
+ * During the transaction phase, the exchange could suddenly
+ * no longer find the denomination key that was
+ * used to sign the melted coin. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND = 1310,
+
+ /**
+ * The exchange encountered melt fees exceeding the melted
+ * coin's contribution. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION = 1311,
+
+ /**
+ * The exchange's cost calculation does not add up to the
+ * melt fees specified in the request. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_FEES_MISSMATCH = 1312,
+
+ /**
+ * The denomination key signature on the melted coin is invalid.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID = 1313,
+
+ /**
+ * The exchange's cost calculation shows that the melt amount
+ * is below the costs of the transaction. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT = 1314,
+
+ /**
+ * The signature made with the coin to be melted is invalid.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID = 1315,
+
+ /**
+ * The size of the cut-and-choose dimension of the
+ * blinded coins request does not match #TALER_CNC_KAPPA.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID = 1316,
+
+ /**
+ * The size of the cut-and-choose dimension of the
+ * transfer keys request does not match #TALER_CNC_KAPPA.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1317,
+
+ /**
+ * The exchange failed to obtain the transaction history of the
+ * given coin from the database while generating an insufficient
+ * funds errors.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1318,
+
+ /**
+ * The provided transfer keys do not match up with the
+ * original commitment. Information about the original
+ * commitment is included in the response. This response is
+ * provided with HTTP status code MHD_HTTP_CONFLICT.
+ */
+ TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION = 1350,
+
+ /**
+ * Failed to blind the envelope to reconstruct the blinded
+ * coins for revealation checks.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_REVEAL_BLINDING_ERROR = 1351,
+
+ /**
+ * Failed to produce the blinded signatures over the coins
+ * to be returned.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_REVEAL_SIGNING_ERROR = 1352,
+
+ /**
+ * The exchange is unaware of the refresh sessino specified in
+ * the request.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN = 1353,
+
+ /**
+ * The exchange failed to retrieve valid session data from the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR = 1354,
+
+ /**
+ * The exchange failed to retrieve order data from the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR = 1355,
+
+ /**
+ * The exchange failed to retrieve transfer keys from the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR = 1356,
+
+ /**
+ * The exchange failed to retrieve commitment data from the
+ * database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_ERROR.
+ */
+ TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR = 1357,
+
+ /**
+ * The size of the cut-and-choose dimension of the
+ * private transfer keys request does not match #TALER_CNC_KAPPA - 1.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1358,
+
+
+ /**
+ * The coin specified in the link request is unknown to the exchange.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_REFRESH_LINK_COIN_UNKNOWN = 1400,
+
+
+ /**
+ * The exchange knows literally nothing about the coin we were asked
+ * to refund. But without a transaction history, we cannot issue a
+ * refund. This is kind-of OK, the owner should just refresh it
+ * directly without executing the refund. This response is provided
+ * with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_REFUND_COIN_NOT_FOUND = 1500,
+
+ /**
+ * We could not process the refund request as the coin's transaction
+ * history does not permit the requested refund at this time. The
+ * "history" in the response proves this. This response is provided
+ * with HTTP status code MHD_HTTP_CONFLICT.
+ */
+ TALER_EC_REFUND_CONFLICT = 1501,
+
+ /**
+ * The exchange knows about the coin we were asked to refund, but
+ * not about the specific /deposit operation. Hence, we cannot
+ * issue a refund (as we do not know if this merchant public key is
+ * authorized to do a refund). This response is provided with HTTP
+ * status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_REFUND_DEPOSIT_NOT_FOUND = 1503,
+
+ /**
+ * The currency specified for the refund is different from
+ * the currency of the coin. This response is provided with HTTP
+ * status code MHD_HTTP_PRECONDITION_FAILED.
+ */
+ TALER_EC_REFUND_CURRENCY_MISSMATCH = 1504,
+
+ /**
+ * When we tried to check if we already paid out the coin, the
+ * exchange's database suddenly disagreed with data it previously
+ * provided (internal inconsistency).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFUND_DB_INCONSISTENT = 1505,
+ /**
+ * The exchange can no longer refund the customer/coin as the
+ * money was already transferred (paid out) to the merchant.
+ * (It should be past the refund deadline.)
+ * This response is provided with HTTP status code
+ * MHD_HTTP_GONE.
+ */
+ TALER_EC_REFUND_MERCHANT_ALREADY_PAID = 1506,
+
+ /**
+ * The amount the exchange was asked to refund exceeds
+ * (with fees) the total amount of the deposit (including fees).
+ * This response is provided with HTTP status code
+ * MHD_HTTP_PRECONDITION_FAILED.
+ */
+ TALER_EC_REFUND_INSUFFICIENT_FUNDS = 1507,
+
+ /**
+ * The exchange failed to recover information about the
+ * denomination key of the refunded coin (even though it
+ * recognizes the key). Hence it could not check the fee
+ * strucutre.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND = 1508,
+
+ /**
+ * The refund fee specified for the request is lower than
+ * the refund fee charged by the exchange for the given
+ * denomination key of the refunded coin.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFUND_FEE_TOO_LOW = 1509,
+
+ /**
+ * The exchange failed to store the refund information to
+ * its database.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_REFUND_STORE_DB_ERROR = 1510,
+
+ /**
+ * The refund fee is specified in a different currency
+ * than the refund amount.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH = 1511,
+
+ /**
+ * The refunded amount is smaller than the refund fee,
+ * which would result in a negative refund.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFUND_FEE_ABOVE_AMOUNT = 1512,
+
+ /**
+ * The signature of the merchant is invalid.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID = 1513,
+
+
+ /**
+ * The wire format specified in the "sender_account_details"
+ * is not understood or not supported by this exchange.
+ * Returned with an HTTP status code of MHD_HTTP_NOT_FOUND.
+ * (As we did not find an interpretation of the wire format.)
+ */
+ TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED = 1600,
+
+ /**
+ * The currency specified in the "amount" parameter is not
+ * supported by this exhange. Returned with an HTTP status
+ * code of MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED = 1601,
+
+ /**
+ * The exchange failed to store information about the incoming
+ * transfer in its database. This response is provided with HTTP
+ * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_ADMIN_ADD_INCOMING_DB_STORE = 1602,
+
+ /**
+ * The exchange encountered an error (that is not about not finding
+ * the wire transfer) trying to lookup a wire transfer identifier
+ * in the database. This response is provided with HTTP
+ * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED = 1700,
+
+ /**
+ * The exchange found internally inconsistent data when resolving a
+ * wire transfer identifier in the database. This response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT = 1701,
+
+ /**
+ * The exchange did not find information about the specified
+ * wire transfer identifier in the database. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND = 1702,
+
+
+ /**
+ * The exchange found internally inconsistent fee data when
+ * resolving a transaction in the database. This
+ * response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT = 1800,
+
+ /**
+ * The exchange encountered an error (that is not about not finding
+ * the transaction) trying to lookup a transaction
+ * in the database. This response is provided with HTTP
+ * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED = 1801,
+
+ /**
+ * The exchange did not find information about the specified
+ * transaction in the database. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_TRACK_TRANSACTION_NOT_FOUND = 1802,
+
+ /**
+ * The exchange failed to identify the wire transfer of the
+ * transaction (or information about the plan that it was supposed
+ * to still happen in the future). This response is provided with
+ * HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR = 1803,
+
+ /**
+ * The signature of the merchant is invalid.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID = 1804,
+
+
+ /* *********** Merchant backend error codes ********* */
+
+ /**
+ * The backend could not find the merchant instance specified
+ * in the request. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_CONTRACT_INSTANCE_UNKNOWN = 2000,
+
+ /**
+ * The exchange failed to provide a meaningful response
+ * to a /deposit request. This response is provided
+ * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE.
+ */
+ TALER_EC_PAY_EXCHANGE_FAILED = 2101,
+
+ /**
+ * The merchant failed to commit the exchanges' response to
+ * a /deposit request to its database. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAY_DB_STORE_PAY_ERROR = 2102,
+
+ /**
+ * The specified exchange is not supported/trusted by
+ * this merchant. This response is provided
+ * with HTTP status code MHD_HTTP_PRECONDITION_FAILED.
+ */
+ TALER_EC_PAY_EXCHANGE_REJECTED = 2103,
+
+ /**
+ * The denomination key used for payment is not listed among the
+ * denomination keys of the exchange. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND = 2104,
+
+ /**
+ * The denomination key used for payment is not audited by an
+ * auditor approved by the merchant. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE = 2105,
+
+ /**
+ * There was an integer overflow totaling up the amounts or
+ * deposit fees in the payment. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_AMOUNT_OVERFLOW = 2106,
+
+ /**
+ * The deposit fees exceed the total value of the payment.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_FEES_EXCEED_PAYMENT = 2107,
+
+ /**
+ * After considering deposit fees, the payment is insufficient
+ * to satisfy the required amount for the contract.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES = 2108,
+
+ /**
+ * While the merchant is happy to cover all applicable deposit fees,
+ * the payment is insufficient to satisfy the required amount for
+ * the contract. This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_PAYMENT_INSUFFICIENT = 2109,
+
+ /**
+ * The signature over the contract of one of the coins
+ * was invalid. This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_COIN_SIGNATURE_INVALID = 2110,
+
+ /**
+ * We failed to contact the exchange for the /pay request.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE.
+ */
+ TALER_EC_PAY_EXCHANGE_TIMEOUT = 2111,
+
+ /**
+ * The backend could not find the merchant instance specified
+ * in the request. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_PAY_INSTANCE_UNKNOWN = 2112,
+
+ /**
+ * The signature over the contract of the merchant
+ * was invalid. This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID = 2113,
+
+ /**
+ * The refund deadline was after the transfer deadline.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE = 2114,
+
+ /**
+ * The request fails to provide coins for the payment.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_COINS_ARRAY_EMPTY = 2115,
+
+ /**
+ * The merchant failed to fetch the merchant's previous state with
+ * respect to a /pay request from its database. This response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAY_DB_FETCH_PAY_ERROR = 2116,
+
+ /**
+ * The merchant failed to fetch the merchant's previous state with
+ * respect to transactions from its database. This response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR = 2117,
+
+ /**
+ * The transaction ID was used for a conflicing transaction before.
+ * This response is
+ * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT = 2118,
+
+ /**
+ * The merchant failed to store the merchant's state with
+ * respect to the transaction in its database. This response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR = 2119,
+
+ /**
+ * The exchange failed to provide a valid response to
+ * the merchant's /keys request.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE.
+ */
+ TALER_EC_PAY_EXCHANGE_KEYS_FAILURE = 2120,
+
+ /**
+ * The payment is too late, the offer has expired.
+ * This response is
+ * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_PAY_OFFER_EXPIRED = 2121,
+
+
+ /**
+ * Integer overflow with sepcified timestamp argument detected.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_HISTORY_TIMESTAMP_OVERFLOW = 2200,
+
+ /**
+ * Failed to retrieve history from merchant database.
+ * This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_HISTORY_DB_FETCH_ERROR = 2201,
+
+
+ /**
+ * We failed to contact the exchange for the /track/transaction
+ * request. This response is provided with HTTP status code
+ * MHD_HTTP_SERVICE_UNAVAILABLE.
+ */
+ TALER_EC_TRACK_TRANSACTION_EXCHANGE_TIMEOUT = 2300,
+
+ /**
+ * The backend could not find the merchant instance specified
+ * in the request. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN = 2301,
+
+ /**
+ * The backend could not find the transaction specified
+ * in the request. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN = 2302,
+
+ /**
+ * The backend had a database access error trying to
+ * retrieve transaction data from its database.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR = 2303,
+
+ /**
+ * The backend had a database access error trying to
+ * retrieve payment data from its database.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSACTION_DB_FETCH_PAYMENT_ERROR = 2304,
+
+ /**
+ * The backend found no applicable deposits in the database.
+ * This is odd, as we know about the transaction, but not
+ * about deposits we made for the transaction. The response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_TRACK_TRANSACTION_DB_NO_DEPOSITS_ERROR = 2305,
+
+ /**
+ * We failed to obtain a wire transfer identifier for one
+ * of the coins in the transaction. The response is
+ * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY if
+ * the exchange had a hard error, or MHD_HTTP_ACCEPTED if the
+ * exchange signaled that the transfer was in progress.
+ */
+ TALER_EC_TRACK_TRANSACTION_COIN_TRACE_ERROR = 2306,
+
+ /**
+ * We failed to obtain the full wire transfer identifier for the
+ * transfer one of the coins was aggregated into.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY.
+ */
+ TALER_EC_TRACK_TRANSACTION_WIRE_TRANSFER_TRACE_ERROR = 2307,
+
+ /**
+ * We got conflicting reports from the exhange with
+ * respect to which transfers are included in which
+ * aggregate.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY.
+ */
+ TALER_EC_TRACK_TRANSACTION_CONFLICTING_REPORTS = 2308,
+
+
+ /**
+ * We failed to contact the exchange for the /track/transfer
+ * request. This response is provided with HTTP status code
+ * MHD_HTTP_SERVICE_UNAVAILABLE.
+ */
+ TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT = 2400,
+
+ /**
+ * The backend could not find the merchant instance specified
+ * in the request. This response is
+ * provided with HTTP status code MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_TRACK_TRANSFER_INSTANCE_UNKNOWN = 2401,
+
+ /**
+ * We failed to persist coin wire transfer information in
+ * our merchant database.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR = 2402,
+
+ /**
+ * We internally failed to execute the /track/transfer request.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_REQUEST_ERROR = 2403,
+
+ /**
+ * We failed to persist wire transfer information in
+ * our merchant database.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR = 2404,
+
+ /**
+ * The exchange returned an error from /track/transfer.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY.
+ */
+ TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR = 2405,
+
+ /**
+ * We failed to fetch deposit information from
+ * our merchant database.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR = 2406,
+
+ /**
+ * We encountered an internal logic error.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR = 2407,
+
+ /**
+ * The exchange gave conflicting information about a coin which has
+ * been wire transferred.
+ * The response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS = 2408,
+
+ /* ********** /test API error codes ************* */
+
+ /**
+ * The exchange failed to compute ECDH. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TEST_ECDH_ERROR = 4000,
+
+ /**
+ * The EdDSA test signature is invalid. This response is provided
+ * with HTTP status code MHD_HTTP_BAD_REQUEST.
+ */
+ TALER_EC_TEST_EDDSA_INVALID = 4001,
+
+ /**
+ * The exchange failed to compute the EdDSA test signature. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TEST_EDDSA_ERROR = 4002,
+
+ /**
+ * The exchange failed to generate an RSA key. This response is provided
+ * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TEST_RSA_GEN_ERROR = 4003,
+
+ /**
+ * The exchange failed to compute the public RSA key. This response
+ * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TEST_RSA_PUB_ERROR = 4004,
+
+ /**
+ * The exchange failed to compute the RSA signature. This response
+ * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TEST_RSA_SIGN_ERROR = 4005,
+
+
+ /**
+ * End of error code range.
+ */
+ TALER_EC_END = 9999
+
};
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 9e3c48c4c..e368f954c 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -24,6 +24,7 @@
#include <jansson.h>
#include "taler_util.h"
+#include "taler_error_codes.h"
#include <gnunet/gnunet_curl_lib.h>
@@ -355,6 +356,7 @@ struct TALER_EXCHANGE_WireHandle;
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param obj the received JSON reply, if successful this should be the wire
* format details as provided by /wire, or NULL if the
* reply was not in JSON format.
@@ -362,6 +364,7 @@ struct TALER_EXCHANGE_WireHandle;
typedef void
(*TALER_EXCHANGE_WireResultCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *obj);
@@ -423,6 +426,7 @@ struct TALER_EXCHANGE_DepositHandle;
typedef void
(*TALER_EXCHANGE_DepositResultCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *obj);
@@ -504,6 +508,7 @@ struct TALER_EXCHANGE_RefundHandle;
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sign_key exchange key used to sign @a obj, or NULL
* @param obj the received JSON reply, should be kept as proof (and, in particular,
* be forwarded to the customer)
@@ -511,6 +516,7 @@ struct TALER_EXCHANGE_RefundHandle;
typedef void
(*TALER_EXCHANGE_RefundResultCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *obj);
@@ -650,6 +656,7 @@ struct TALER_EXCHANGE_ReserveHistory
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param[in] json original response in JSON format (useful only for diagnostics)
* @param balance current balance in the reserve, NULL on error
* @param history_length number of entries in the transaction history, 0 on error
@@ -658,6 +665,7 @@ struct TALER_EXCHANGE_ReserveHistory
typedef void
(*TALER_EXCHANGE_ReserveStatusResultCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *json,
const struct TALER_Amount *balance,
unsigned int history_length,
@@ -713,12 +721,14 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle;
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors)
*/
typedef void
(*TALER_EXCHANGE_ReserveWithdrawResultCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig,
const json_t *full_response);
@@ -835,6 +845,7 @@ struct TALER_EXCHANGE_RefreshMeltHandle;
* @param cls closure
* @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error
* @param sign_key exchange key used to sign @a full_response, or NULL
@@ -843,7 +854,8 @@ struct TALER_EXCHANGE_RefreshMeltHandle;
typedef void
(*TALER_EXCHANGE_RefreshMeltCallback) (void *cls,
unsigned int http_status,
- uint16_t noreveal_index,
+ enum TALER_ErrorCode ec,
+ uint16_t noreveal_index,
const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *full_response);
@@ -900,6 +912,7 @@ TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error
@@ -908,6 +921,7 @@ TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh
typedef void
(*TALER_EXCHANGE_RefreshRevealCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs,
@@ -979,6 +993,7 @@ struct TALER_EXCHANGE_RefreshLinkHandle;
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error
@@ -988,6 +1003,7 @@ struct TALER_EXCHANGE_RefreshLinkHandle;
typedef void
(*TALER_EXCHANGE_RefreshLinkCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs,
@@ -1043,11 +1059,13 @@ struct TALER_EXCHANGE_AdminAddIncomingHandle;
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param full_response full response from the exchange (for logging, in case of errors)
*/
typedef void
(*TALER_EXCHANGE_AdminAddIncomingResultCallback) (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const json_t *full_response);
@@ -1108,6 +1126,7 @@ struct TALER_EXCHANGE_TrackTransferHandle;
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sign_key exchange key used to sign @a json, or NULL
* @param json original json reply (may include signatures, those have then been
* validated already)
@@ -1121,6 +1140,7 @@ struct TALER_EXCHANGE_TrackTransferHandle;
typedef void
(*TALER_EXCHANGE_TrackTransferCallback)(void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *json,
const struct GNUNET_HashCode *h_wire,
@@ -1171,6 +1191,7 @@ struct TALER_EXCHANGE_TrackTransactionHandle;
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sign_key exchange key used to sign @a json, or NULL
* @param json original json reply (may include signatures, those have then been
* validated already)
@@ -1182,6 +1203,7 @@ struct TALER_EXCHANGE_TrackTransactionHandle;
typedef void
(*TALER_EXCHANGE_TrackTransactionCallback)(void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *json,
const struct TALER_WireTransferIdentifierRawP *wtid,
@@ -1240,4 +1262,5 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
json_t *history,
struct TALER_Amount *total);
+
#endif /* _TALER_EXCHANGE_SERVICE_H */
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index b47aea5b6..b247ba1f5 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -25,6 +25,7 @@
#include <jansson.h>
#include <gnunet/gnunet_json_lib.h>
#include "taler_util.h"
+#include "taler_error_codes.h"
/**
* Print JSON parsing related error information
@@ -92,6 +93,17 @@ int
TALER_JSON_hash (const json_t *json,
struct GNUNET_HashCode *hc);
+/**
+ * Extract the Taler error code from the given @a json object.
+ * Note that #TALER_EC_NONE is returned if no "code" is present.
+ *
+ * @param json response to extract the error code from
+ * @return the "code" value from @a json
+ */
+enum TALER_ErrorCode
+TALER_JSON_get_error_code (const json_t *json);
+
+
#endif /* TALER_JSON_LIB_H_ */
/* End of taler_json_lib.h */
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index 613f860cd..c115594f5 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -117,4 +117,6 @@ const struct GNUNET_OS_ProjectData *
TALER_project_data_default (void);
+
+
#endif
diff --git a/src/json/json.c b/src/json/json.c
index 8f21447ec..74559e6c5 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -50,4 +50,33 @@ TALER_JSON_hash (const json_t *json,
}
+
+/**
+ * Extract the Taler error code from the given @a json object.
+ * Note that #TALER_EC_NONE is returned if no "code" is present.
+ *
+ * @param json response to extract the error code from
+ * @return the "code" value from @a json
+ */
+enum TALER_ErrorCode
+TALER_JSON_get_error_code (const json_t *json)
+{
+ const json_t *jc;
+
+ if (NULL == json)
+ {
+ GNUNET_break_op (0);
+ return TALER_EC_INVALID_RESPONSE;
+ }
+ jc = json_object_get (json, "code");
+ if (NULL == jc)
+ return TALER_EC_NONE;
+ if (json_is_integer (jc))
+ return (enum TALER_ErrorCode) json_integer_value (jc);
+ GNUNET_break_op (0);
+ return TALER_EC_INVALID;
+}
+
+
+
/* End of json/json.c */
diff --git a/taler-exchange-dev.nix b/taler-exchange-dev.nix
new file mode 100644
index 000000000..2e5e068e5
--- /dev/null
+++ b/taler-exchange-dev.nix
@@ -0,0 +1,61 @@
+{ stdenv, makeWrapper, pkgconfig, autoconf, automake, libtool, ccache, ccache_dir ? ""
+, gnunet-dev, postgresql, jansson, libgcrypt, libgnurl, libmicrohttpd }:
+
+stdenv.mkDerivation rec {
+ src = ./.;
+ name = "taler-exchange-dev";
+
+ buildInputs = [
+ makeWrapper pkgconfig autoconf automake libtool ccache
+ gnunet-dev postgresql jansson libgcrypt libgnurl libmicrohttpd
+ ];
+
+ patchPhase = ''
+ if [ -e Makefile ]; then
+ make distclean
+ fi
+ '';
+
+ NIX_CFLAGS_COMPILE = "-ggdb -O0";
+
+ configureFlags = [
+ "--enable-gcc-hardening"
+ "--enable-linker-hardening"
+
+ "--enable-logging=verbose"
+ "--enable-poisoning"
+ ];
+
+ preConfigure = ''
+ ./bootstrap
+
+ if [ -n "${ccache_dir}" ]; then
+ export CC='ccache gcc'
+ export CCACHE_COMPRESS=1
+ export CCACHE_DIR="${ccache_dir}"
+ export CCACHE_UMASK=007
+ fi
+ '';
+
+ doCheck = false;
+
+ postInstall = ''
+ # Tests can be run this way
+ #export GNUNET_PREFIX="$out"
+ #export PATH="$out/bin:$PATH"
+ #make -k check
+ '';
+
+ meta = with stdenv.lib; {
+ description = "Exchange for GNU Taler";
+
+ longDescription = ''
+ '';
+
+ homepage = https://taler.net/;
+
+ license = licenses.gpl3Plus;
+ platforms = platforms.gnu;
+ maintainers = with maintainers; [ ];
+ };
+}