resolving merge issue

This commit is contained in:
Christian Grothoff 2016-11-07 14:39:15 +01:00
commit 1d740824fa
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
46 changed files with 5451 additions and 508 deletions

1
.gitignore vendored
View File

@ -30,6 +30,7 @@ GTAGS
src/lib/test_exchange_api src/lib/test_exchange_api
doc/doxygen/doxygen_sqlite3.db doc/doxygen/doxygen_sqlite3.db
src/auditor/taler-auditor src/auditor/taler-auditor
src/auditor/taler-auditor-sign
src/bank-lib/test_bank_api src/bank-lib/test_bank_api
src/bank-lib/test_bank_api_with_fakebank src/bank-lib/test_bank_api_with_fakebank
src/exchange-lib/test_exchange_api src/exchange-lib/test_exchange_api

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "doc/api"] [submodule "doc/api"]
path = doc/api path = doc/api
url = git@git.taler.net:api url = git@git.taler.net:api
[submodule "gnunet"]
path = gnunet
url = git://taler.net/gnunet.git

84
default.nix Normal file
View File

@ -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;
};
};
}

View File

@ -19,6 +19,13 @@
pages = {11-15}, 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, @Misc{greece2015cash,
author = {Reuters}, author = {Reuters},
@ -90,6 +97,13 @@
organization={Springer} 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, @inproceedings{miers2013zerocoin,
title={Zerocoin: Anonymous distributed e-cash from bitcoin}, title={Zerocoin: Anonymous distributed e-cash from bitcoin},
author={Miers, Ian and Garman, Christina and Green, Matthew and Rubin, Aviel D}, 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", author="Bellare, Mihir and Namprempre, Chanathip and Pointcheval, David and Semanko, Michael",
editor="Syverson, Paul", editor="Syverson, Paul",
chapter="The Power of RSA Inversion Oracles and the Security of Chaum's RSA-Based Blind Signature Scheme", 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", year="2002",
publisher="Springer Berlin Heidelberg", publisher="Springer",
address="Berlin, Heidelberg", address="Berlin, Heidelberg",
pages="319--338", pages="319--338",
isbn="978-3-540-46088-6", isbn="978-3-540-46088-6",

View File

@ -63,7 +63,7 @@
% - sharing = coin copying that should not be taxed % - 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} \begin{document}
\mainmatter \mainmatter
@ -77,7 +77,7 @@
\begin{abstract} \begin{abstract}
This paper introduces {\em Taler}, a Chaum-style digital currency that This paper introduces {\em Taler}, a Chaum-style digital currency that
enables anonymous payments while ensuring that entities that receive 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 never defraud anyone, merchants can only fail to deliver the
merchandise to the customer, and payment service providers can be merchandise to the customer, and payment service providers can be
fully audited. All parties receive cryptographic evidence for all 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 The key technical contribution underpinning Taler is a new {\em
refresh protocol} which allows fractional payments and refunds while refresh protocol} which allows fractional payments and refunds while
maintaining anonymity of the customer and unlinkability of maintaining untraceability of the customer and unlinkability of
transactions. The refresh protocol combines an efficient transactions. The refresh protocol combines an
cut-and-choose mechanism with a {\em link} step to ensure that efficient cut-and-choose mechanism with a {\em link} step to ensure
refreshing is not abused for transactional payments. that refreshing is not abused for transactional payments.
We argue that Taler provides a secure digital currency for modern We argue that Taler provides a secure digital currency for modern
liberal societies as it is a flexible, libre and efficient protocol 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 such as the MasterCard and VisaCard credit card schemes and computerized
bank transactions such as SWIFT. These systems enable mass surveillance bank transactions such as SWIFT. These systems enable mass surveillance
by both governments and private companies. Aspects of this 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? crimes like extortion. % TODO : anti-money laundering later?
In particular, bribery and corruption are limited to elites who can In particular, bribery and corruption are limited to elites who can
afford to escape the dragnet. afford to escape the dragnet.
%
At the other extreme, weaker developing nation states have economic At the other extreme, weaker developing nation states have economic
activity based largely on coins, paper money or even barter. Here, activity based largely on coins, paper money or even barter. Here,
the state is often unable to effectively monitor or tax economic 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 society. As bribery is virtually impossible to detect, corruption is
widespread and not limited to social elites. 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. anarchistic economy into the digital realm.
This paper describes Taler, a simple and practical payment system for This paper describes Taler, a simple and practical payment system for
a modern social-liberal society, which is not being served well by a social-liberal society, which is underserved by
current payment systems which enable either an authoritarian state in current payment systems.
total control of the population, or create weak states with almost
anarchistic economies.
The Taler protocol is influenced by ideas from The Taler protocol is influenced by ideas from
Chaum~\cite{chaum1983blind} and also follows Chaum's basic architecture of Chaum~\cite{chaum1983blind} and also follows Chaum's basic
customer, merchant and exchange (Figure~\ref{fig:cmm}). architecture of customer, merchant and exchange
The two designs share the key first step where the {\em customer} (Figure~\ref{fig:cmm}). The two designs share the key first step
withdraws digital {\em coins} from the {\em exchange} with unlinkability where the {\em customer} withdraws digital {\em coins} from the {\em
provided via blind signatures. The coins can then be spent at a exchange} with unlinkability provided via blind signatures. The
{\em merchant} who {\em deposits} them at the exchange. coins can then be spent at a {\em merchant} who {\em deposits} them at
Taler uses online detection of double-spending, thus assuring the merchant the exchange. Taler uses online detection of double-spending and
instantly that a transaction is valid. provides excuplability via cryptographic proofs. Thus merchants are
instantly assured that a transaction is valid.
\begin{figure}[h] \begin{figure}[h]
\centering \centering
@ -159,16 +158,14 @@ instantly that a transaction is valid.
\label{fig:cmm} \label{fig:cmm}
\end{figure} \end{figure}
A key issue for an efficient Chaumian digital payment system is the A key issue for an efficient Chaumian digital payment system is the
need to provide change. For example, a customer may want to pay 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 \EUR{49,99}, but has withdrawn a \EUR{100,00} coin. Withdrawing 10,000
pieces with a denomination of \EUR{0,01} and transferring 4,999 would coins with a denomination of \EUR{0,01} and transferring 4,999 coins would
be too inefficient, even for modern systems. The customer should not be too inefficient. The customer should not
withdraw exact change from her account, as doing so reduces anonymity withdraw exact change from her account, as doing so reduces anonymity
due to the obvious corrolation. A practical payment system must thus due to the obvious correlation. A practical payment system must thus
support giving change in the form of spendable coins, say a \EUR{0,01} support giving change.
coin and a \EUR{50,00} coin.
Taler solves the problem of giving change by introducing a new Taler solves the problem of giving change by introducing a new
{\em refresh protocol}. Using this protocol, a customer can obtain {\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. the same entity which owned the original coin.
\vspace{-0.3cm}
\section{Related Work} \section{Related Work}
\vspace{-0.3cm}
\subsection{Blockchain-based currencies} %\subsection{Blockchain-based currencies}
In recent years, a class of decentralized electronic payment systems, In recent years, a class of decentralized electronic payment systems,
based on collectively recorded and verified append-only public 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 identification of users. In theory, this concern has been addressed
with the Zerocoin extension to the protocol~\cite{miers2013zerocoin}. with the Zerocoin extension to the protocol~\cite{miers2013zerocoin}.
These protocols dispense with the need for a central, trusted The key contribution of blockchain-based protocols is that
authority, while providing a useful measure of pseudonymity. they dispense with the need for a central, trusted
authority.
Yet, there are several major irredeemable problems inherent in their designs: Yet, there are several major irredeemable problems inherent in their designs:
\begin{itemize} \begin{itemize}
\item The computational puzzles solved by Bitcoin nodes with the purpose \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. So Bitcoin is an environmentally irresponsible design.
\item Bitcoin transactions have pseduononymous recipients, making taxation \item Bitcoin transactions have pseduononymous recipients, making taxation
hard to systematically enforce. 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. % currency exchange and exacerbates the problems with currency fluctuations.
\end{itemize} \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 %GreenCoinX\footnote{\url{https://www.greencoinx.com/}} is a more
%recent AltCoin where the company promises to identify the owner of %recent AltCoin where the company promises to identify the owner of
%each coin via e-mail addresses and phone numbers. While it is unclear %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 %would also merely impose a financial panopticon on a BitCoin-style
%money supply and transaction model. %money supply and transaction model.
\subsection{Chaum-style electronic cash} %\subsection{Chaum-style electronic cash}
Chaum~\cite{chaum1983blind} proposed a digital payment system that Chaum~\cite{chaum1983blind} proposed a digital payment system that
would provide some customer anonymity while disclosing the identity of 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 %macropayment. It is therefore unclear how Peppercoin would actually
%reduce the computational burden on the exchange. %reduce the computational burden on the exchange.
%\vspace{-0.3cm}
\section{Design} \section{Design}
%\vspace{-0.3cm}
The Taler system comprises three principal types of actors The Taler system comprises three principal types of actors
(Figure~\ref{fig:cmm}): The \emph{customer} is interested in receiving (Figure~\ref{fig:cmm}): The \emph{customer} is interested in receiving
goods or services from the \emph{merchant} in exchange for payment. goods or services from the \emph{merchant} in exchange for payment.
When making a transaction, both the customer and the merchant use the To pay, the customer {\em spends} digital coins at the merchant. When
same \emph{exchange}, which serves as a payment service provider for making a transaction, both the customer and the merchant use the same
the financial transaction between the two. The exchange is \emph{exchange}, which serves as a payment service provider for the
responsible for allowing the customer to convert financial reserves to financial transaction between the two. The exchange is responsible
the anonymous digital coins, and for enabling the merchant to convert for allowing the customer to withdraw anonymous digital coins from the
spent digital coins back to funds in a financial reserve. In customer's financial reserves, and for enabling the merchant to
addition, we describe an \emph{auditor} who assures customers and deposit digital coins in return for receiving credit at the merchant's
merchants that the exchange operates correctly. 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} \subsection{Security model}
%\vspace{-0.3cm}
Taler's security model assumes that cryptographic primitives are Taler assumes that each participant has full control over their
secure and that each participant is under full control of his system. system. We assume the contact information of the exchange is known to
The contact information of the exchange is known to both customer and both customer and merchant from the start, including that the customer
merchant from the start. We further assume that the customer can can authenticate the merchant, for example by using X.509
authenticate the merchant, e.g. using X.509 certificates~\cite{rfc6818}. A Taler merchant is trusted to deliver
certificates~\cite{rfc5280}. Finally, we assume that customer has an the service or goods to the customer upon receiving payment. The
anonymous bi-directional channel, such as Tor, to communicate with customer can seek legal relief to achieve this, as the customer
both the exchange and the merchant. 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.
The exchange is trusted to hold funds of its customers and to forward A Taler exchange is trusted to hold funds of its customers and to
them when receiving the respective deposit instructions from the forward them when receiving the respective deposit instructions from
merchants. Customer and merchant can have assurances about the the merchants. Customer and merchant can have assurances about the
exchange's liquidity and operation though published audits by exchange's liquidity and operation though published audits by
financial regulators or other trusted third parties. If sufficently financial regulators or other trusted third parties. An exchange's
regular, audits of the exchange's accounts should reveal any possible signing keys expire regularly, allowing the exchange to eventually
fraud. Online signing keys expire regularly, allowing the exchange to destroy the corresponding accumulated cryptographic proofs, and
destroy the corresponding accumulated cryptographic proofs. limiting the exchange's financial liability.
The merchant is trusted to deliver the service or goods to the On the cryptographic side, a Taler exchange demands that coins use a
customer upon receiving payment. The customer can seek legal relief full domain hash (FDH) to make so-called ``one-more forgery'' attacks
to achieve this, as he receives cryptographic proofs of the contract provably hard, assuming the RSA known-target inversion problem is
and has proof that he paid his obligations. 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.
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.
\subsection{Taxability and Entities} \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 effective double-spending detection, this means that either entity has
to constantly fear that the funds might no longer be available to it. 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 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 trust between the two parties.
entity for taxability.
In Taler, making funds available by copying a private key and thus In Taler, making funds available by copying a private key and thus
sharing control is {\bf not} considered a {\em transaction} and thus sharing control is {\bf not} considered a {\em transaction} and thus
{\bf not} recorded for taxation. Taler does, however, ensure {\bf not} recorded for taxation. Taler does, however, ensure
taxability when a merchant entity acquires exclusive control over the taxability when a merchant entity acquires exclusive control over the
value represented by a digital coins. For such transactions, the state 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 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, 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 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 anonymous digital coins to the {\em purchase} performed later at the
merchant. 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 always learn the merchant's identity in order to credit the merchant's
account. This is also necessary for taxation, as Taler deliberately account. This is also necessary for taxation, as Taler deliberately
exposes these events as anchors for tax audits on income. 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 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 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 financial value from an RSA signature over the FDH
(FDH) of the coin's public key. An FDH is used so that ``one-more of the coin's public key. The exchange has multiple RSA {\em
forgery'' is provably hard assuming the RSA known-target inversion denomination key} pairs available for blind-signing coins of
problem is hard~cite[Theorem 12]{RSA-HDF-KTIvCTI}. The exchange has different value.
multiple RSA {\em denomination key} pairs available for blind-signing
coins of different value.
Denomination keys have an expiration date, before which any coins Denomination keys have an expiration date, before which any coins
signed with it must be spent or refreshed. This allows the exchange signed with it must be spent or refreshed. This allows the exchange
to eventually discard records of old transactions, thus limiting the to eventually discard records of old transactions, thus limiting the
records that the exchange must retain and search to detect records that the exchange must retain and search to detect
double-spending attempts. Furthermore, the exchange uses each double-spending attempts. If a private denomination key were to be
denomination key only for a limited number of coins. In this way, if compromised, the exchange can detect this once more coins are redeemed
a private denomination key were to be compromised, the exchange would than the total that was signed into existence using that denomination
detect this once more coins were redeemed than the total that was key. In this case, the exchange can allow authentic customers to
signed into existence using that denomination key. In this case, the redeem their unspent coins that were signed with the compromised
exchange can allow authentic customers to exchange their unspent private key, while refusing further deposits involving coins signed by
coins that were signed with the compromised private key, while the compromised denomination key. As a result, the financial damage
refusing further anonymous transactions involving those coins. As a of losing a private signing key is limited to at most the amount
result, the financial damage of losing a private signing key can be originally signed with that key, and denomination key rotation can be
limited to at most twice the amount originally signed with that key. used to bound that risk.
We also ensure that the exchange cannot deanonymize users by signing We ensure that the exchange cannot deanonymize users by signing
each coin with a fresh denomination key. For this, exchanges are 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 These announcements are expected to be signed with an off-line
long-term private {\em master signing key} of the exchange and the long-term private {\em master signing key} of the exchange and the
auditor. Additionally, customers should obtain these announcements 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 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 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 public key during the withdrawal process. If the private key is
shared with others, they become co-owners of the coin. Knowledge of 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} % \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. are expected to be recorded for tax authorities to ensure taxability.
% FIXME: Auditor? % FIXME: Auditor?
We use RSA for denomination keys and EdDSA over some eliptic curve $S_K$ denotes RSA signing with denomination key $K$ and EdDSA
$\mathbb{E}$ for all other keys. Let $G$ denote the generator of over eliptic curve $\mathbb{E}$ for other types of keys.
our elliptic curve $\mathbb{E}$. $G$ denotes the generator of elliptic curve $\mathbb{E}$.
\subsection{Withdrawal} \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 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. \item blinding factor $b$, and commits $\langle W, C, b \rangle$ to disk.
\end{itemize} \end{itemize}
\item[SEPA Send] \item[Wire transfer send]
The customer transfers an amount of money corresponding to The customer transfers an amount of money corresponding to
at least $K_v$ to the exchange, with $W_p$ in the subject line at least $K_v$ to the exchange, with $W_p$ in the subject line
of the transaction. of the transaction.
\item[SEPA Recieve] \item[Wire transfer recieve]
The exchange receives the transaction and credits the reserve $W_p$ The exchange receives the transaction and credits the reserve $W_p$
with the respective amount in its database. with the respective amount in its database.
\item[POST {\tt /withdraw/sign}] \item[POST {\tt /withdraw/sign}]
The customer sends $S_W(B)$ where $B := B_b(\FDH_K(C_p))$ to 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 the exchange to request withdrawal of $C$; here, $B_b$ denotes
Chaum-style blinding with blinding factor $b$. 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; 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 in this case, it sends a Chaum-style blind signature $S_K(B)$ with
private key $K_s$ to the customer. \\ private key $K_s$ to the customer. \\
If this is a fresh withdrawal request, the exchange performs the following transaction: If this is a fresh withdrawal request, the exchange performs the following transaction:
\begin{enumerate} \begin{enumerate}
\item checks if the reserve $W_p$ has sufficient funds \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 \item stores the withdrawal request and response
$\langle S_W(B), S_K(B) \rangle$ in its database $\langle S_W(B), S_K(B) \rangle$ in its database
for future reference, 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. error back to the customer, with proof that it operated correctly.
Assuming the signature was valid, this would involve showing the transaction Assuming the signature was valid, this would involve showing the transaction
history for the reserve. history for the reserve.
% FIXME: Is it really the whole history?
\item[Done] The customer computes and verifies the unblinded signature \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$ Finally the customer saves the coin $\langle S_K(\FDH_K(C_p)), c_s \rangle$
to their local wallet on disk. to their local wallet on disk.
\end{description} \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 A customer can spend coins at a merchant, under the condition that the
merchant trusts the exchange that issued the coin. merchant trusts the exchange that issued the coin.
% FIXME: Auditor here? % 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 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? % FIXME: Is this correct?
We now describe the protocol between the customer, merchant, and exchange 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] \item[Proposal]
The merchant creates a digitally signed contract The merchant creates a digitally signed contract
$\mathcal{A} := S_M(m, f, a, H(p, r), \vec{X})$ $\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 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 $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$ $r$ is a random nonce. The merchant commits $\langle \mathcal{A} \rangle$
to disk and sends $\mathcal{A}$ to the customer. to disk and sends $\mathcal{A}$ to the customer.
\item[Customer Setup] \item[Customer Setup]
The customer should already possess a coin issued by a exchange that is The customer should already possess a coin $\widetilde{C}$ issued by a exchange that is
accepted by the merchant, meaning $K$ should be publicly signed by 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$. 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} The customer generates a \emph{deposit-permission}
$\mathcal{D} := S_c(\widetilde{C}, m, f, H(a), H(p,r), M_p)$ $\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, and sends $\langle \mathcal{D}, X_j\rangle$ to the merchant.
where $X_j$ is the exchange which signed $K$.
\item[POST {\tt/deposit}] \item[POST {\tt/deposit}]
The merchant gives $(\mathcal{D}, p, r)$ to the exchange, thereby The merchant gives $(\mathcal{D}, p, r)$ to the exchange, thereby
revealing $p$ only to the exchange. 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. The exchange validates $\mathcal{D}$ and checks for double spending.
If the coin has been involved in previous transactions and the new 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. \\ 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 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. and signs a ``200 OK'' message affirming the deposit operation was successful.
\item[200 OK / ???] \item[200 OK / 424 FAILED DEPENDENCY]
The merchant commits and forwards the notification from the exchange to the 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} \end{description}
We have simplified the exposition by assuming that one coin suffices, 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 exchange where the total value adds up to $f$ by running the above
steps for each of the coins. steps for each of the coins.
If a transaction is aborted after Step~\ref{deposit}, If a transaction is aborted after the first POST, subsequent
subsequent transactions with the same coin could be linked to the coin, transactions with the same coin could be linked to this operation.
but not directly to the coin's owner. The same applies to partially The same applies to partially spent coins where $f$ is smaller than
spent coins where $f$ is smaller than the actual value of the coin. the actual value of the coin. To unlink subsequent transactions from
To unlink subsequent transactions from a coin, the customer has to a coin, the customer has to execute the following coin refreshing
execute the coin refreshing protocol with the exchange. protocol with the exchange.
%\begin{figure}[h] %\begin{figure}[h]
%\centering %\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 with the same denomination. In practice, Taler uses a natural
extension where multiple fresh coins are generated a the same time to extension where multiple fresh coins are generated a the same time to
enable giving precise change matching any amount. 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 In the protocol, $\kappa \ge 2$ is a security parameter for the
cases in practice, as the cut-and-choose protocol does not need to cut-and-choose part of the protocol. $\kappa = 3$ is actually
provide cryptographic security: If the maximum applicable tax is less perfectly sufficient in most cases in practice, as the cut-and-choose
than $\frac{2}{3}$, then detecting $\kappa = 3$ ensures that cheating protocol does not need to provide cryptographic security: If the
results in a negative return on average as $\kappa - 1$ out of maximum applicable tax is less than $\frac{2}{3}$, then $\kappa = 3$
$\kappa$ attempts to cheat are detected. This makes the use of ensures that cheating results in a negative financial return on
cut-and-choose practical and efficient in this context. 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 % 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 a transfer private key $t^{(i)}_s$ and computes
\begin{itemize} \begin{itemize}
\item the transfer public key $T^{(i)}_p := t^{(i)}_s G$ and \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} \end{itemize}
We have computed $L_i$ as a Diffie-Hellman shared secret between 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)$ 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)$; 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. 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 Now the customer applies key derivation functions $\KDF_{\textrm{blinding}}$ and $\KDF_{\textrm{Ed25519}}$ to $L^{(i)}$ to generate
\begin{itemize} \begin{itemize}
\item a blinding factor $b^{(i)} = \FDH_K(\KDF_{\textrm{blinding}}(L_i))$. \item a blinding factor $b^{(i)} = \FDH_K(\KDF_{\textrm{blinding}}(L^{(i)}))$.
\item $c_s^{(i)} = \KDF_{\textrm{Ed25519}}(L_i)$ \item $c_s^{(i)} = \KDF_{\textrm{Ed25519}}(L^{(i)})$
\end{itemize} \end{itemize}
Now the customer can compute her new coin key pair Now the customer can compute her new coin key pair
$C^{(i)} := \left(c_s^{(i)}, C_p^{(i)}\right)$ $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. \\ this time to prevent the exchange from assisting tax evasion. \\
% %
The exchange sends $S_{K'}(C'_p, \gamma)$ to the customer where 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}] \item[POST {\tt /refresh/reveal}]
The customer commits $\langle C', S_K(C'_p, \gamma) \rangle$ to disk. The customer commits $\langle C', S_K(C'_p, \gamma) \rangle$ to disk.
Also, the customer assembles Also, the customer assembles
@ -850,16 +871,16 @@ cut-and-choose practical and efficient in this context.
\vspace{-2ex} \vspace{-2ex}
\begin{minipage}{5cm} \begin{minipage}{5cm}
\begin{align*} \begin{align*}
\overline{L}_i :&= H(t_s^{(i)} C_p') \\ \overline{L^{(i)}} :&= H(t_s^{(i)} C_p') \\
\overline{c}_s^{(i)} :&= \KDF_{\textrm{Ed25519}}(\overline{L}_i) \\ \overline{c_s^{(i)}} :&= \KDF_{\textrm{Ed25519}}(\overline{L^{(i)}}) \\
\overline{C^{(i)}_p} :&= \overline{c}_s^{(i)} G \overline{C^{(i)}_p} :&= \overline{c_s^{(i)}} G
\end{align*} \end{align*}
\end{minipage} \end{minipage}
\begin{minipage}{5cm} \begin{minipage}{5cm}
\begin{align*} \begin{align*}
\overline{T_p^{(i)}} :&= t_s^{(i)} G \\ \overline{T_p^{(i)}} :&= t_s^{(i)} G \\
\overline{b}^{(i)} :&= \FDH_K(\KDF_{\textrm{blinding}}(\overline{L}_i)) \\ \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)}} :&= B_{\overline{b^{(i)}}}(\overline{C_p^{(i)}})
\end{align*} \end{align*}
\end{minipage} \end{minipage}
@ -909,7 +930,7 @@ taxation model as with such trust they are assumed to be the same
entity. entity.
The auditor can anonymously check if the exchange correctly implements the 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 this protocol component. Without the link operation, Taler would
devolve into a payment system where both sides can be anonymous, and devolve into a payment system where both sides can be anonymous, and
thus no longer provide taxability. thus no longer provide taxability.
@ -942,13 +963,12 @@ faulty exchange.
The third case are transient failures, such as network failures or The third case are transient failures, such as network failures or
temporary hardware failures at the exchange service provider. Here, the temporary hardware failures at the exchange service provider. Here, the
client may receive an explicit protocol indication, such as an HTTP 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 The appropriate behavior for the client is to automatically retry
after 1s, and twice more at randomized times within 1 minute. after 1s, and twice more at randomized times within 1 minute.
If those three attempts fail, the user should be informed about the If those three attempts fail, the user should be informed about the
delay. The client should then retry another three times within 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 Using this process, short term failures should be effectively obscured
from the user, while malicious behavior is reported to the auditor who from the user, while malicious behavior is reported to the auditor who
can then presumably rectify the situation, using methods such as 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 for executing a transaction is dominated by the network latency, as
local processing virtually always takes less than 10 ms. 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}) %(Figure~\ref{fig:read} vs. Figure~\ref{fig:write})
, as Taler mostly needs to log , as Taler mostly needs to log
transactions and occasionally needs to read to guard against 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 criminals~\cite{sander1999escrow} and where the state could
deanonymize citizens. deanonymize citizens.
\subsection{Offline Payments} %\subsection{Offline Payments}
Chaum's original proposals for anonymous digital cash avoided the need Chaum's original proposals for anonymous digital cash avoided the need
for online interactions with the exchange to detect double spending by 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 %subjected to financial penalties by the state in relation to the
%amount transferred by the traditional currency transfer. %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 In this paper we have use the term ``proof'' in many places as the
protocol provides cryptographic proofs of which parties behave protocol provides cryptographic proofs of which parties behave
@ -1167,11 +1187,11 @@ the participants have to disclose their core secrets.
\bibliographystyle{alpha} \bibliographystyle{alpha}
\bibliography{taler,rfc} \bibliography{taler,rfc}
\vfill %\vfill
\begin{center} %\begin{center}
\Large Demonstration available at \url{https://demo.taler.net/} % \Large Demonstration available at \url{https://demo.taler.net/}
\end{center} %\end{center}
\vfill %\vfill
\newpage \newpage
\appendix \appendix
@ -1241,13 +1261,13 @@ data being committed to disk are represented in between $\langle\rangle$.
\item[$\vec{b}$]{Vector of $b^{(i)}$} \item[$\vec{b}$]{Vector of $b^{(i)}$}
\item[$B^{(i)}$]{Blinding of $C_p^{(i)}$} \item[$B^{(i)}$]{Blinding of $C_p^{(i)}$}
\item[$\vec{B}$]{Vector of $B^{(i)}$} \item[$\vec{B}$]{Vector of $B^{(i)}$}
\item[$L_i$]{Link secret derived from ECDH operation via hashing} \item[$L^{(i)}$]{Link secret derived from ECDH operation via hashing}
% \item[$E_{L_i}()$]{Symmetric encryption using key $L_i$} % \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[$E^{(i)}$]{$i$-th encryption of the private information $(c_s^{(i)}, b_i)$}
% \item[$\vec{E}$]{Vector of $E^{(i)}$} % \item[$\vec{E}$]{Vector of $E^{(i)}$}
\item[$\cal{R}$]{Tuple of revealed vectors in cut-and-choose protocol, \item[$\cal{R}$]{Tuple of revealed vectors in cut-and-choose protocol,
where the vectors exclude the selected index $\gamma$} 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{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{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} \item[$\overline{c_s^{(i)}}$]{Private keys obtained from decryption by the verifier}

1
gnunet Submodule

@ -0,0 +1 @@
Subproject commit 674d59da9956998c0e33ad1a3aa9facc3ba66d10

122
m4/libgcrypt.m4 Normal file
View File

@ -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)
])

View File

@ -12,7 +12,8 @@ pkgcfg_DATA = \
auditordb-postgres.conf auditordb-postgres.conf
EXTRA_DIST = \ EXTRA_DIST = \
auditordb-postgres.conf auditordb-postgres.conf \
test-auditor-db-postgres.conf
plugindir = $(libdir)/taler plugindir = $(libdir)/taler
@ -49,5 +50,21 @@ libtalerauditordb_la_LDFLAGS = \
-no-undefined -no-undefined
EXTRA_test_auditordb_postgres_DEPENDENCIES = \ #EXTRA_test_auditordb_postgres_DEPENDENCIES = \
libtaler_plugin_auditordb_postgres.la # 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

File diff suppressed because it is too large Load Diff

View File

@ -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"

View File

@ -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;
}

View File

@ -67,22 +67,35 @@ main (int argc,
char * const *argv) char * const *argv)
{ {
struct GNUNET_OS_Process *bankd; struct GNUNET_OS_Process *bankd;
struct GNUNET_OS_Process *bankd_admin;
unsigned int cnt; unsigned int cnt;
int result; int result;
GNUNET_log_setup ("test-bank-api", GNUNET_log_setup ("test-bank-api",
"WARNING", "WARNING",
NULL); 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, bankd = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL, GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-bank-manage", "taler-bank-manage",
"taler-bank-manage", "taler-bank-manage",
"serve-http", "serve-http",
"--port", "8081", "--port", "8080",
NULL); NULL);
if (NULL == bankd)
if ((NULL == bankd_admin) || (NULL == bankd))
{ {
/*FIXME: More accurate error message?*/
fprintf (stderr, fprintf (stderr,
"taler-bank-manage not found, skipping test\n"); "taler-bank-manage not found, skipping test\n");
return 77; /* report 'skip' */ return 77; /* report 'skip' */
@ -99,13 +112,26 @@ main (int argc,
if (cnt > 30) if (cnt > 30)
break; 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"); fprintf (stderr, "\n");
result = GNUNET_SYSERR; result = GNUNET_SYSERR;
if (cnt <= 30) if (cnt <= 30)
GNUNET_SCHEDULER_run (&run, &result); GNUNET_SCHEDULER_run (&run, &result);
GNUNET_OS_process_kill (bankd, GNUNET_OS_process_kill (bankd,
SIGTERM); SIGTERM);
GNUNET_OS_process_kill (bankd_admin,
SIGTERM);
GNUNET_OS_process_wait (bankd); GNUNET_OS_process_wait (bankd);
GNUNET_OS_process_destroy (bankd); GNUNET_OS_process_destroy (bankd);
if (cnt > 30) if (cnt > 30)

View File

@ -541,6 +541,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
* @param cls closure with the `struct Coin *` * @param cls closure with the `struct Coin *`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 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 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 * @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 static void
reveal_cb (void *cls, reveal_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
unsigned int num_coins, unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs, const struct TALER_DenominationSignature *sigs,
@ -617,6 +619,7 @@ reveal_cb (void *cls,
* @param cls closure with the `struct Coin *` * @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. * @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) * 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, * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error * UINT16_MAX on error
* @param exchange_pub public key the exchange used for signing * @param exchange_pub public key the exchange used for signing
@ -625,6 +628,7 @@ reveal_cb (void *cls,
static void static void
melt_cb (void *cls, melt_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
uint16_t noreveal_index, uint16_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *full_response) 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 cls closure with the `struct Coin` that we are processing
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * @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) * 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 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, * @param obj the received JSON reply, should be kept as proof (and, in case of errors,
* be forwarded to the customer) * be forwarded to the customer)
@ -783,6 +788,7 @@ refresh_coin (struct Coin *coin)
static void static void
deposit_cb (void *cls, deposit_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj) const json_t *obj)
{ {
@ -935,12 +941,14 @@ spend_coin (struct Coin *coin,
* @param cls closure with our `struct Coin` * @param cls closure with our `struct Coin`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors) * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
static void static void
reserve_withdraw_cb (void *cls, reserve_withdraw_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig, const struct TALER_DenominationSignature *sig,
const json_t *full_response) const json_t *full_response)
{ {
@ -1027,11 +1035,13 @@ withdraw_coin (struct Coin *coin)
* @param cls closure with the `struct Reserve *` * @param cls closure with the `struct Reserve *`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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) * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
static void static void
add_incoming_cb (void *cls, add_incoming_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *full_response) const json_t *full_response)
{ {
struct Reserve *r = cls; struct Reserve *r = cls;

View File

@ -14,7 +14,7 @@ libtalerexchange_la_LDFLAGS = \
-no-undefined -no-undefined
libtalerexchange_la_SOURCES = \ 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_handle.c exchange_api_handle.h \
exchange_api_admin.c \ exchange_api_admin.c \
exchange_api_deposit.c \ exchange_api_deposit.c \

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 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, aai->cb (aai->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
json); json);
TALER_EXCHANGE_admin_add_incoming_cancel (aai); TALER_EXCHANGE_admin_add_incoming_cancel (aai);
} }

View File

@ -20,7 +20,6 @@
* @author Christian Grothoff * @author Christian Grothoff
*/ */
#include "platform.h" #include "platform.h"
#include "exchange_api_common.h"
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
@ -38,8 +37,8 @@
*/ */
int int
TALER_EXCHANGE_verify_coin_history (const char *currency, TALER_EXCHANGE_verify_coin_history (const char *currency,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
json_t *history, json_t *history,
struct TALER_Amount *total) struct TALER_Amount *total)
{ {
size_t len; size_t len;

View File

@ -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 */

View File

@ -29,7 +29,6 @@
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_exchange_service.h" #include "taler_exchange_service.h"
#include "exchange_api_common.h"
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -262,6 +261,7 @@ handle_deposit_finished (void *cls,
} }
dh->cb (dh->cb_cls, dh->cb (dh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
ep, ep,
json); json);
TALER_EXCHANGE_deposit_cancel (dh); TALER_EXCHANGE_deposit_cancel (dh);

View File

@ -28,7 +28,6 @@
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_exchange_service.h" #include "taler_exchange_service.h"
#include "exchange_api_common.h"
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -1115,6 +1114,7 @@ handle_refresh_melt_finished (void *cls,
{ {
rmh->melt_cb (rmh->melt_cb_cls, rmh->melt_cb (rmh->melt_cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
noreveal_index, noreveal_index,
(0 == response_code) ? NULL : &exchange_pub, (0 == response_code) ? NULL : &exchange_pub,
json); json);
@ -1160,6 +1160,7 @@ handle_refresh_melt_finished (void *cls,
if (NULL != rmh->melt_cb) if (NULL != rmh->melt_cb)
rmh->melt_cb (rmh->melt_cb_cls, rmh->melt_cb (rmh->melt_cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
UINT16_MAX, UINT16_MAX,
NULL, NULL,
json); json);
@ -1598,6 +1599,7 @@ handle_refresh_reveal_finished (void *cls,
{ {
rrh->reveal_cb (rrh->reveal_cb_cls, rrh->reveal_cb (rrh->reveal_cb_cls,
MHD_HTTP_OK, MHD_HTTP_OK,
TALER_EC_NONE,
rrh->md->num_fresh_coins, rrh->md->num_fresh_coins,
coin_privs, coin_privs,
sigs, sigs,
@ -1634,7 +1636,10 @@ handle_refresh_reveal_finished (void *cls,
if (NULL != rrh->reveal_cb) if (NULL != rrh->reveal_cb)
rrh->reveal_cb (rrh->reveal_cb_cls, rrh->reveal_cb (rrh->reveal_cb_cls,
response_code, response_code,
0, NULL, NULL, TALER_JSON_get_error_code (json),
0,
NULL,
NULL,
json); json);
TALER_EXCHANGE_refresh_reveal_cancel (rrh); TALER_EXCHANGE_refresh_reveal_cancel (rrh);
} }

View File

@ -265,6 +265,7 @@ parse_refresh_link_ok (struct TALER_EXCHANGE_RefreshLinkHandle *rlh,
{ {
rlh->link_cb (rlh->link_cb_cls, rlh->link_cb (rlh->link_cb_cls,
MHD_HTTP_OK, MHD_HTTP_OK,
TALER_EC_NONE,
num_coins, num_coins,
coin_privs, coin_privs,
sigs, sigs,
@ -345,7 +346,11 @@ handle_refresh_link_finished (void *cls,
if (NULL != rlh->link_cb) if (NULL != rlh->link_cb)
rlh->link_cb (rlh->link_cb_cls, rlh->link_cb (rlh->link_cb_cls,
response_code, response_code,
0, NULL, NULL, NULL, TALER_JSON_get_error_code (json),
0,
NULL,
NULL,
NULL,
json); json);
TALER_EXCHANGE_refresh_link_cancel (rlh); TALER_EXCHANGE_refresh_link_cancel (rlh);
} }

View File

@ -28,7 +28,6 @@
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_exchange_service.h" #include "taler_exchange_service.h"
#include "exchange_api_common.h"
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -196,6 +195,7 @@ handle_refund_finished (void *cls,
} }
rh->cb (rh->cb_cls, rh->cb (rh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
ep, ep,
json); json);
TALER_EXCHANGE_refund_cancel (rh); TALER_EXCHANGE_refund_cancel (rh);

View File

@ -314,7 +314,8 @@ handle_reserve_status_finished (void *cls,
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (json, GNUNET_JSON_parse (json,
spec, spec,
NULL, NULL)) NULL,
NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
response_code = 0; response_code = 0;
@ -355,6 +356,7 @@ handle_reserve_status_finished (void *cls,
} }
wsh->cb (wsh->cb_cls, wsh->cb (wsh->cb_cls,
response_code, response_code,
TALER_EC_NONE,
json, json,
&balance, &balance,
len, len,
@ -387,6 +389,7 @@ handle_reserve_status_finished (void *cls,
if (NULL != wsh->cb) if (NULL != wsh->cb)
wsh->cb (wsh->cb_cls, wsh->cb (wsh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
json, json,
NULL, NULL,
0, NULL); 0, NULL);
@ -589,6 +592,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
dsig.rsa_signature = sig; dsig.rsa_signature = sig;
wsh->cb (wsh->cb_cls, wsh->cb (wsh->cb_cls,
MHD_HTTP_OK, MHD_HTTP_OK,
TALER_EC_NONE,
&dsig, &dsig,
json); json);
/* make sure callback isn't called again after return */ /* 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 * Check the signatures on the withdraw transactions in the provided
* history and that the balances add up. We don't do anything directly * 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. * 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 /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
break; break;
case MHD_HTTP_PAYMENT_REQUIRED: case MHD_HTTP_FORBIDDEN:
/* The exchange says that the reserve has insufficient funds; /* The exchange says that the reserve has insufficient funds;
check the signatures in the history... */ check the signatures in the history... */
if (GNUNET_OK != if (GNUNET_OK !=
@ -762,6 +766,7 @@ handle_reserve_withdraw_finished (void *cls,
if (NULL != wsh->cb) if (NULL != wsh->cb)
wsh->cb (wsh->cb_cls, wsh->cb (wsh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
NULL, NULL,
json); json);
TALER_EXCHANGE_reserve_withdraw_cancel (wsh); TALER_EXCHANGE_reserve_withdraw_cancel (wsh);

View File

@ -28,7 +28,6 @@
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_exchange_service.h" #include "taler_exchange_service.h"
#include "exchange_api_common.h"
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -239,6 +238,7 @@ handle_deposit_wtid_finished (void *cls,
} }
dwh->cb (dwh->cb_cls, dwh->cb (dwh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
ep, ep,
json, json,
wtid, wtid,

View File

@ -26,7 +26,6 @@
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h" #include "taler_exchange_service.h"
#include "exchange_api_common.h"
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -183,6 +182,7 @@ check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh
} }
wdh->cb (wdh->cb_cls, wdh->cb (wdh->cb_cls,
MHD_HTTP_OK, MHD_HTTP_OK,
TALER_EC_NONE,
&exchange_pub, &exchange_pub,
json, json,
&h_wire, &h_wire,
@ -253,6 +253,7 @@ handle_track_transfer_finished (void *cls,
} }
wdh->cb (wdh->cb_cls, wdh->cb (wdh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
NULL, NULL,
json, json,
NULL, NULL,

View File

@ -28,7 +28,6 @@
#include "taler_exchange_service.h" #include "taler_exchange_service.h"
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_wire_plugin.h" #include "taler_wire_plugin.h"
#include "exchange_api_common.h"
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
@ -210,6 +209,7 @@ handle_wire_finished (void *cls,
} }
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json),
(NULL != keep) ? keep : json); (NULL != keep) ? keep : json);
if (NULL != keep) if (NULL != keep)
json_decref (keep); json_decref (keep);

View File

@ -761,11 +761,13 @@ next_command (struct InterpreterState *is)
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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) * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
static void static void
add_incoming_cb (void *cls, add_incoming_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *full_response) const json_t *full_response)
{ {
struct InterpreterState *is = cls; 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 cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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[in] json original response in JSON format (useful only for diagnostics)
* @param balance current balance in the reserve, NULL on error * @param balance current balance in the reserve, NULL on error
* @param history_length number of entries in the transaction history, 0 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 static void
reserve_status_cb (void *cls, reserve_status_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *json, const json_t *json,
const struct TALER_Amount *balance, const struct TALER_Amount *balance,
unsigned int history_length, unsigned int history_length,
@ -924,7 +928,7 @@ reserve_status_cb (void *cls,
{ {
if (GNUNET_OK != if (GNUNET_OK !=
compare_reserve_withdraw_history (&history[j], compare_reserve_withdraw_history (&history[j],
rel)) rel))
{ {
GNUNET_break (0); GNUNET_break (0);
fail (is); fail (is);
@ -973,12 +977,14 @@ reserve_status_cb (void *cls,
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors) * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
static void static void
reserve_withdraw_cb (void *cls, reserve_withdraw_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig, const struct TALER_DenominationSignature *sig,
const json_t *full_response) const json_t *full_response)
{ {
@ -1009,7 +1015,7 @@ reserve_withdraw_cb (void *cls,
cmd->details.reserve_withdraw.sig.rsa_signature cmd->details.reserve_withdraw.sig.rsa_signature
= GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
break; break;
case MHD_HTTP_PAYMENT_REQUIRED: case MHD_HTTP_FORBIDDEN:
/* nothing to check */ /* nothing to check */
break; break;
default: default:
@ -1027,6 +1033,7 @@ reserve_withdraw_cb (void *cls,
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * @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) * 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 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, * @param obj the received JSON reply, should be kept as proof (and, in case of errors,
* be forwarded to the customer) * be forwarded to the customer)
@ -1034,6 +1041,7 @@ reserve_withdraw_cb (void *cls,
static void static void
deposit_cb (void *cls, deposit_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj) const json_t *obj)
{ {
@ -1061,6 +1069,7 @@ deposit_cb (void *cls,
* @param cls closure with the interpreter state * @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. * @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) * 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, * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error * UINT16_MAX on error
* @param exchange_pub public key the exchange used for signing * @param exchange_pub public key the exchange used for signing
@ -1069,6 +1078,7 @@ deposit_cb (void *cls,
static void static void
melt_cb (void *cls, melt_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
uint16_t noreveal_index, uint16_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *full_response) const json_t *full_response)
@ -1098,6 +1108,7 @@ melt_cb (void *cls,
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 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 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 * @param sigs array of signature over @a num_coins coins, NULL on error
@ -1106,6 +1117,7 @@ melt_cb (void *cls,
static void static void
reveal_cb (void *cls, reveal_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
unsigned int num_coins, unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs, const struct TALER_DenominationSignature *sigs,
@ -1160,6 +1172,7 @@ reveal_cb (void *cls,
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 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 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 * @param sigs array of signature over @a num_coins coins, NULL on error
@ -1169,6 +1182,7 @@ reveal_cb (void *cls,
static void static void
link_cb (void *cls, link_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
unsigned int num_coins, unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs, 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 cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; * @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) * 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 * @param obj the received JSON reply, if successful this should be the wire
* format details as provided by /wire. * format details as provided by /wire.
*/ */
static void static void
wire_cb (void *cls, wire_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *obj) const json_t *obj)
{ {
struct InterpreterState *is = cls; struct InterpreterState *is = cls;
@ -1391,6 +1407,7 @@ wire_cb (void *cls,
* *
* @param cls closure * @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation * @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 exchange_pub public key the exchange used for signing
* @param json original json reply (may include signatures, those have then been * @param json original json reply (may include signatures, those have then been
* validated already) * validated already)
@ -1404,6 +1421,7 @@ wire_cb (void *cls,
static void static void
wire_deposits_cb (void *cls, wire_deposits_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *json, const json_t *json,
const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_wire,
@ -1521,6 +1539,7 @@ wire_deposits_cb (void *cls,
* *
* @param cls closure * @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation * @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 exchange_pub public key the exchange used for signing
* @param json original json reply (may include signatures, those have then been * @param json original json reply (may include signatures, those have then been
* validated already) * validated already)
@ -1534,6 +1553,7 @@ wire_deposits_cb (void *cls,
static void static void
deposit_wtid_cb (void *cls, deposit_wtid_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *json, const json_t *json,
const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_WireTransferIdentifierRawP *wtid,
@ -1588,6 +1608,7 @@ deposit_wtid_cb (void *cls,
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * @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) * 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 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, * @param obj the received JSON reply, should be kept as proof (and, in particular,
* be forwarded to the customer) * be forwarded to the customer)
@ -1595,6 +1616,7 @@ deposit_wtid_cb (void *cls,
static void static void
refund_cb (void *cls, refund_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj) const json_t *obj)
{ {
@ -1782,9 +1804,9 @@ interpreter_run (void *cls)
&reserve_pub.eddsa_pub); &reserve_pub.eddsa_pub);
cmd->details.reserve_status.wsh cmd->details.reserve_status.wsh
= TALER_EXCHANGE_reserve_status (exchange, = TALER_EXCHANGE_reserve_status (exchange,
&reserve_pub, &reserve_pub,
&reserve_status_cb, &reserve_status_cb,
is); is);
return; return;
case OC_WITHDRAW_SIGN: case OC_WITHDRAW_SIGN:
GNUNET_assert (NULL != GNUNET_assert (NULL !=
@ -2737,7 +2759,7 @@ run (void *cls)
/* Try to overdraw funds ... */ /* Try to overdraw funds ... */
{ .oc = OC_WITHDRAW_SIGN, { .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-2", .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.reserve_reference = "create-reserve-1",
.details.reserve_withdraw.amount = "EUR:5" }, .details.reserve_withdraw.amount = "EUR:5" },
@ -3051,8 +3073,11 @@ main (int argc,
unsigned long code; unsigned long code;
GNUNET_log_setup ("test-exchange-api", GNUNET_log_setup ("test-exchange-api",
"WARNING", "DEBUG",
NULL); "/tmp/logs");
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test log\n");
return 0;
/* These might get in the way... */ /* These might get in the way... */
unsetenv ("XDG_DATA_HOME"); unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME"); unsetenv ("XDG_CONFIG_HOME");

View File

@ -89,6 +89,7 @@ TEH_ADMIN_handler_admin_add_incoming (struct TEH_RequestHandler *rh,
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED,
"sender_account_details"); "sender_account_details");
} }
if (0 != strcasecmp (amount.currency, if (0 != strcasecmp (amount.currency,
@ -100,6 +101,7 @@ TEH_ADMIN_handler_admin_add_incoming (struct TEH_RequestHandler *rh,
amount.currency); amount.currency);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED,
"amount:currency"); "amount:currency");
} }
res = TEH_DB_execute_admin_add_incoming (connection, res = TEH_DB_execute_admin_add_incoming (connection,

View File

@ -53,7 +53,8 @@ transaction_start_label: /* we will use goto for retries */ \
session)) \ session)) \
{ \ { \
GNUNET_break (0); \ 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) \ if (GNUNET_SYSERR == transaction_commit_result) \
{ \ { \
TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ 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) \ if (GNUNET_NO == transaction_commit_result) \
{ \ { \
TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ 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", \ TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \
transaction_retries, \ transaction_retries, \
__FUNCTION__); \ __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 */ } /* 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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 == if (GNUNET_YES ==
TEH_plugin->have_deposit (TEH_plugin->cls, TEH_plugin->have_deposit (TEH_plugin->cls,
@ -225,8 +229,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
if (NULL == dki) if (NULL == dki)
{ {
TEH_KS_release (mks); TEH_KS_release (mks);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_internal_db_error (connection,
"denom_pub"); TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN);
} }
TALER_amount_ntoh (&value, TALER_amount_ntoh (&value,
&dki->issue.properties.value); &dki->issue.properties.value);
@ -249,7 +253,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
session); session);
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); 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 /* Check that cost of all transactions is smaller than
the value of the coin. */ 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"); TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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); 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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; dep = NULL;
ref = NULL; ref = NULL;
@ -337,7 +344,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); session);
return TEH_RESPONSE_reply_refund_failure (connection, 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; deposit_found = GNUNET_NO;
refund_found = GNUNET_NO; refund_found = GNUNET_NO;
@ -411,7 +419,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
session); session);
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); 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 */ /* handle if conflicting refund found */
if (GNUNET_SYSERR == 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, TEH_plugin->rollback (TEH_plugin->cls,
session); session);
return TEH_RESPONSE_reply_refund_failure (connection, 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 */ /* 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, TEH_plugin->rollback (TEH_plugin->cls,
session); session);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_REFUND_DB_INCONSISTENT,
"database inconsistent"); "database inconsistent");
} }
if (GNUNET_YES == done) 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, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); tl);
return TEH_RESPONSE_reply_refund_failure (connection, 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 */ /* 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, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); tl);
return TEH_RESPONSE_reply_refund_failure (connection, 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! */ /* 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, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); tl);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND,
"denomination key not found"); "denomination key not found");
} }
TALER_amount_ntoh (&expect_fee, 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, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); tl);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFUND_FEE_TOO_LOW,
"refund_fee"); "refund_fee");
} }
if (1 == fee_cmp) 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"); TALER_LOG_WARNING ("Failed to store /refund information in database\n");
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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); 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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, rh = TEH_plugin->get_reserve_history (TEH_plugin->cls,
session, session,
@ -637,6 +654,7 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); session);
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_WITHDRAW_RESERVE_UNKNOWN,
"reserve_pub"); "reserve_pub");
} }
@ -653,7 +671,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
{ {
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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 */ /* calculate balance of the reserve */
@ -673,7 +692,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
{ {
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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; res |= 1;
break; break;
@ -686,7 +706,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
GNUNET_break (0); GNUNET_break (0);
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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, TALER_amount_ntoh (&value,
&tdki->issue.properties.value); &tdki->issue.properties.value);
@ -700,7 +721,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
{ {
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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; res |= 2;
break; break;
@ -708,9 +730,10 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
} }
if (0 == (res & 1)) 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); 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)) if (0 == (res & 2))
{ {
@ -748,6 +771,7 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); session);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_WITHDRAW_SIGNATURE_FAILED,
"Internal error"); "Internal error");
} }
collectable.sig = *denom_sig; collectable.sig = *denom_sig;
@ -765,7 +789,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
GNUNET_break (0); GNUNET_break (0);
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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); 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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, res = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
session, session,
@ -820,7 +846,8 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
if (GNUNET_SYSERR == res) if (GNUNET_SYSERR == res)
{ {
GNUNET_break (0); 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 */ /* 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); GNUNET_assert (GNUNET_NO == res);
/* FIXME: do we have to do this a second time here? */
key_state = TEH_KS_acquire (); key_state = TEH_KS_acquire ();
dki = TEH_KS_denomination_key_lookup (key_state, dki = TEH_KS_denomination_key_lookup (key_state,
denomination_pub, denomination_pub,
@ -843,9 +871,11 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
TEH_KS_release (key_state); TEH_KS_release (key_state);
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
"{s:s}", "{s:s, s:I}",
"error", "error",
"Denomination not found"); "Denomination not found",
"code",
(json_int_t) TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND);
} }
denom_sig.rsa_signature = NULL; denom_sig.rsa_signature = NULL;
res = execute_reserve_withdraw_transaction (connection, res = execute_reserve_withdraw_transaction (connection,
@ -901,8 +931,9 @@ refresh_check_melt (struct MHD_Connection *connection,
TEH_KS_DKU_DEPOSIT); TEH_KS_DKU_DEPOSIT);
if (NULL == dk) if (NULL == dk)
return (MHD_YES == return (MHD_YES ==
TEH_RESPONSE_reply_arg_unknown (connection, TEH_RESPONSE_reply_internal_error (connection,
"denom_pub")) TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND,
"denomination key no longer available while executing transaction"))
? GNUNET_NO : GNUNET_SYSERR; ? GNUNET_NO : GNUNET_SYSERR;
dki = &dk->issue; dki = &dk->issue;
TALER_amount_ntoh (&coin_value, 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, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl); tl);
return (MHD_YES == 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; ? GNUNET_NO : GNUNET_SYSERR;
} }
/* Refuse to refresh when the coin's value is insufficient /* 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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); START_TRANSACTION (session, connection);
res = TEH_plugin->get_refresh_session (TEH_plugin->cls, 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, TEH_plugin->rollback (TEH_plugin->cls,
session); 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 */ /* store 'global' session data */
refresh_session.num_newcoins = num_new_denoms; refresh_session.num_newcoins = num_new_denoms;
refresh_session.noreveal_index refresh_session.noreveal_index
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
TALER_CNC_KAPPA); TALER_CNC_KAPPA);
key_state = TEH_KS_acquire (); key_state = TEH_KS_acquire ();
if (GNUNET_OK != if (GNUNET_OK !=
(res = refresh_check_melt (connection, (res = refresh_check_melt (connection,
@ -1047,7 +1081,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{ {
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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 */ /* store requested new denominations */
@ -1060,7 +1095,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{ {
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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 != if (GNUNET_OK !=
@ -1072,7 +1108,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection,
{ {
TEH_plugin->rollback (TEH_plugin->cls, TEH_plugin->rollback (TEH_plugin->cls,
session); 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 != if (GNUNET_OK !=
TEH_plugin->insert_refresh_transfer_public_key (TEH_plugin->cls, 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, TEH_plugin->rollback (TEH_plugin->cls,
session); 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); COMMIT_TRANSACTION (session, connection);
@ -1126,8 +1164,6 @@ check_commitment (struct MHD_Connection *connection,
struct TALER_TransferSecretP transfer_secret; struct TALER_TransferSecretP transfer_secret;
unsigned int j; unsigned int j;
/* FIXME: instead of consulting DB, reconstruct everything
from transfer_priv here! */
TALER_link_reveal_transfer_secret (transfer_priv, TALER_link_reveal_transfer_secret (transfer_priv,
&melt->coin.coin_pub, &melt->coin.coin_pub,
&transfer_secret); &transfer_secret);
@ -1158,8 +1194,10 @@ check_commitment (struct MHD_Connection *connection,
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Blind failed (bad denomination key!?)\n"); "Blind failed (bad denomination key!?)\n");
return (MHD_YES == TEH_RESPONSE_reply_internal_error (connection, return (MHD_YES ==
"Blinding error")) TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_REFRESH_REVEAL_BLINDING_ERROR,
"Blinding error"))
? GNUNET_NO : GNUNET_SYSERR; ? GNUNET_NO : GNUNET_SYSERR;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, GNUNET_CRYPTO_hash_context_read (hash_context,
@ -1274,7 +1312,8 @@ execute_refresh_reveal_transaction (struct MHD_Connection *connection,
j); j);
if (NULL == ev_sigs[j].rsa_signature) 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; 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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, res = TEH_plugin->get_refresh_session (TEH_plugin->cls,
@ -1332,10 +1372,12 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
&refresh_session); &refresh_session);
if (GNUNET_NO == res) if (GNUNET_NO == res)
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN,
"session_hash"); "session_hash");
if ( (GNUNET_SYSERR == res) || if ( (GNUNET_SYSERR == res) ||
(refresh_session.noreveal_index >= TALER_CNC_KAPPA) ) (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, denom_pubs = GNUNET_new_array (refresh_session.num_newcoins,
struct TALER_DenominationPublicKey); struct TALER_DenominationPublicKey);
if (GNUNET_OK != if (GNUNET_OK !=
@ -1349,7 +1391,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
GNUNET_free (denom_pubs); GNUNET_free (denom_pubs);
GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); 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_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; ? 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_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_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
GNUNET_CRYPTO_hash_context_abort (hash_context); 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_NO : GNUNET_SYSERR;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, 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_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_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
GNUNET_CRYPTO_hash_context_abort (hash_context); 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; ? GNUNET_NO : GNUNET_SYSERR;
} }
for (i=0;i<refresh_session.num_newcoins;i++) 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_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_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key);
GNUNET_CRYPTO_hash_context_abort (hash_context); 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 */ /* add envelopes to hash_context */
for (j=0;j<refresh_session.num_newcoins;j++) 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))) if (NULL == (ctx.session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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.connection = connection;
ctx.num_sessions = 0; ctx.num_sessions = 0;
@ -1680,6 +1727,7 @@ TEH_DB_execute_refresh_link (struct MHD_Connection *connection,
GNUNET_assert (GNUNET_OK == ctx.status); GNUNET_assert (GNUNET_OK == ctx.status);
if (0 == ctx.num_sessions) if (0 == ctx.num_sessions)
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_REFRESH_LINK_COIN_UNKNOWN,
"coin_pub"); "coin_pub");
res = TEH_RESPONSE_reply_refresh_link_success (connection, res = TEH_RESPONSE_reply_refresh_link_success (connection,
ctx.num_sessions, 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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, ret = TEH_plugin->reserves_in_insert (TEH_plugin->cls,
session, session,
@ -1732,7 +1781,8 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
if (GNUNET_SYSERR == ret) if (GNUNET_SYSERR == ret)
{ {
GNUNET_break (0); 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, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK, 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))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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.is_valid = GNUNET_NO;
ctx.wdd_head = NULL; ctx.wdd_head = NULL;
@ -1926,18 +1977,21 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
if (GNUNET_SYSERR == ret) if (GNUNET_SYSERR == ret)
{ {
GNUNET_break (0); 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; goto cleanup;
} }
if (GNUNET_SYSERR == ctx.is_valid) if (GNUNET_SYSERR == ctx.is_valid)
{ {
GNUNET_break (0); 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; goto cleanup;
} }
if (GNUNET_NO == ctx.is_valid) if (GNUNET_NO == ctx.is_valid)
{ {
ret = TEH_RESPONSE_reply_arg_unknown (connection, ret = TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND,
"wtid"); "wtid");
goto cleanup; goto cleanup;
} }
@ -2035,7 +2089,8 @@ handle_wtid_data (void *cls,
coin_fee)) coin_fee))
{ {
GNUNET_break (0); 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 else
{ {
@ -2079,7 +2134,8 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection,
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{ {
GNUNET_break (0); 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.connection = connection;
ctx.h_contract = *h_contract; ctx.h_contract = *h_contract;
@ -2100,17 +2156,20 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection,
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_break (GNUNET_SYSERR == ctx.res); 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) if (GNUNET_NO == ret)
{ {
GNUNET_break (GNUNET_SYSERR == ctx.res); 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) if (GNUNET_SYSERR == ctx.res)
{ {
GNUNET_break (0); GNUNET_break (0);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR,
"bug resolving deposit wtid"); "bug resolving deposit wtid");
} }
return ctx.res; return ctx.res;

View File

@ -48,12 +48,9 @@
*/ */
static int static int
verify_and_execute_deposit (struct MHD_Connection *connection, 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_DepositRequestPS dr;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TALER_Amount fee_deposit;
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); 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"); TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
return TEH_RESPONSE_reply_signature_invalid (connection, return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID,
"coin_sig"); "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, return TEH_DB_execute_deposit (connection,
deposit); deposit);
@ -141,12 +108,11 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
json_t *wire; json_t *wire;
struct TALER_EXCHANGEDB_Deposit deposit; struct TALER_EXCHANGEDB_Deposit deposit;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TEH_KS_StateHandle *ks; struct TEH_KS_StateHandle *key_state;
struct GNUNET_HashCode my_h_wire; struct GNUNET_HashCode my_h_wire;
struct TALER_Amount amount;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("wire", &wire), 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_public_key ("denom_pub", &deposit.coin.denom_pub),
TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig), TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub), 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) if (GNUNET_NO == res)
return MHD_YES; /* failure */ return MHD_YES; /* failure */
deposit.receiver_wire_account = wire;
if (deposit.refund_deadline.abs_value_us > deposit.wire_deadline.abs_value_us) if (deposit.refund_deadline.abs_value_us > deposit.wire_deadline.abs_value_us)
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
"refund_deadline"); "refund_deadline");
} }
@ -194,6 +162,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT,
"wire"); "wire");
} }
if (GNUNET_OK != 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"); TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON,
"wire"); "wire");
} }
if (0 != memcmp (&deposit.h_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 */ /* Client hashed contract differently than we did, reject */
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT,
"H_wire"); "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, &deposit.coin.denom_pub,
TEH_KS_DKU_DEPOSIT); TEH_KS_DKU_DEPOSIT);
if (NULL == dki) if (NULL == dki)
{ {
TEH_KS_release (ks); TEH_KS_release (key_state);
GNUNET_JSON_parse_free (spec); TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n");
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN,
"denom_pub"); "denom_pub");
} }
TALER_amount_ntoh (&deposit.deposit_fee, TALER_amount_ntoh (&deposit.deposit_fee,
&dki->issue.properties.fee_deposit); &dki->issue.properties.fee_deposit);
TEH_KS_release (ks); /* check coin signature */
deposit.receiver_wire_account = wire; if (GNUNET_YES !=
deposit.amount_with_fee = amount; TALER_test_coin_valid (&deposit.coin))
if (-1 == TALER_amount_cmp (&deposit.amount_with_fee,
&deposit.deposit_fee))
{ {
/* Total amount smaller than fee, invalid */ TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
GNUNET_JSON_parse_free (spec); TEH_KS_release (key_state);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_signature_invalid (connection,
"f"); 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, res = verify_and_execute_deposit (connection,
&deposit); &deposit);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);

View File

@ -79,6 +79,7 @@ TEH_PARSE_post_json (struct MHD_Connection *connection,
case GNUNET_JSON_PR_OUT_OF_MEMORY: case GNUNET_JSON_PR_OUT_OF_MEMORY:
return (MHD_NO == return (MHD_NO ==
TEH_RESPONSE_reply_internal_error (connection, TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_PARSER_OUT_OF_MEMORY,
"out of memory")) "out of memory"))
? GNUNET_SYSERR : GNUNET_NO; ? GNUNET_SYSERR : GNUNET_NO;
case GNUNET_JSON_PR_CONTINUE: case GNUNET_JSON_PR_CONTINUE:
@ -144,7 +145,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
if (NULL == str) if (NULL == str)
{ {
return (MHD_NO == 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; ? GNUNET_SYSERR : GNUNET_NO;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -153,7 +156,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
out_data, out_data,
out_size)) out_size))
return (MHD_NO == 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; ? GNUNET_SYSERR : GNUNET_NO;
return GNUNET_OK; return GNUNET_OK;
} }
@ -193,8 +198,9 @@ TEH_PARSE_json_data (struct MHD_Connection *connection,
ret = (MHD_YES == ret = (MHD_YES ==
TEH_RESPONSE_reply_json_pack (connection, TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{s:s, s:s, s:I}", "{s:s, s:I, s:s, s:I}",
"error", "parse error", "error", "parse error",
"code", (json_int_t) TALER_EC_JSON_INVALID_WITH_DETAILS,
"field", error_json_name, "field", error_json_name,
"line", (json_int_t) error_line)) "line", (json_int_t) error_line))
? GNUNET_NO : GNUNET_SYSERR; ? GNUNET_NO : GNUNET_SYSERR;

View File

@ -69,7 +69,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
struct TALER_Amount total_melt; struct TALER_Amount total_melt;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"melt request for session %s\n", "/refresh/melt request for session %s\n",
GNUNET_h2s (session_hash)); GNUNET_h2s (session_hash));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
@ -86,6 +86,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_break_op (0); GNUNET_break_op (0);
TEH_KS_release (key_state); TEH_KS_release (key_state);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND,
"new_denoms"); "new_denoms");
} }
dki = &dk->issue; dki = &dk->issue;
@ -105,6 +106,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_break_op (0); GNUNET_break_op (0);
TEH_KS_release (key_state); TEH_KS_release (key_state);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW,
"cost calculation failure"); "cost calculation failure");
} }
} }
@ -115,8 +117,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
if (NULL == dk) if (NULL == dk)
{ {
GNUNET_break (0); GNUNET_break (0);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
"denom_pub"); TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
"denom_pub");
} }
dki = &dk->issue; dki = &dk->issue;
TALER_amount_ntoh (&fee_melt, TALER_amount_ntoh (&fee_melt,
@ -129,6 +132,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_break_op (0); GNUNET_break_op (0);
TEH_KS_release (key_state); TEH_KS_release (key_state);
return TEH_RESPONSE_reply_external_error (connection, return TEH_RESPONSE_reply_external_error (connection,
TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION,
"Melt contribution below melting fee"); "Melt contribution below melting fee");
} }
TEH_KS_release (key_state); 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! */ total value of coins being generated to match! */
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{s:s}", "{s:s, s:I}",
"error", "value mismatch"); "error", "value mismatch",
"code", (json_int_t) TALER_EC_REFRESH_MELT_FEES_MISSMATCH);
} }
return TEH_DB_execute_refresh_melt (connection, return TEH_DB_execute_refresh_melt (connection,
session_hash, 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; r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
return (MHD_YES == return (MHD_YES ==
TEH_RESPONSE_reply_signature_invalid (connection, TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID,
"denom_sig")) "denom_sig"))
? GNUNET_NO : GNUNET_SYSERR; ? GNUNET_NO : GNUNET_SYSERR;
} }
@ -237,6 +243,8 @@ verify_coin_public_info (struct MHD_Connection *connection,
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TALER_Amount fee_refresh; struct TALER_Amount fee_refresh;
/* FIXME: we lookup the dki twice during /refresh/melt.
This should be avoided. */
key_state = TEH_KS_acquire (); key_state = TEH_KS_acquire ();
dki = TEH_KS_denomination_key_lookup (key_state, dki = TEH_KS_denomination_key_lookup (key_state,
&melt_detail->coin_info.denom_pub, &melt_detail->coin_info.denom_pub,
@ -246,6 +254,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
TEH_KS_release (key_state); TEH_KS_release (key_state);
TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND,
"denom_pub"); "denom_pub");
} }
TALER_amount_ntoh (&fee_refresh, TALER_amount_ntoh (&fee_refresh,
@ -266,6 +275,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
TEH_KS_release (key_state); TEH_KS_release (key_state);
return (MHD_YES == return (MHD_YES ==
TEH_RESPONSE_reply_external_error (connection, TEH_RESPONSE_reply_external_error (connection,
TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT,
"melt amount smaller than melting fee")) "melt amount smaller than melting fee"))
? GNUNET_NO : GNUNET_SYSERR; ? GNUNET_NO : GNUNET_SYSERR;
} }
@ -280,6 +290,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
GNUNET_break_op (0); GNUNET_break_op (0);
if (MHD_YES != if (MHD_YES !=
TEH_RESPONSE_reply_signature_invalid (connection, TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID,
"confirm_sig")) "confirm_sig"))
return GNUNET_SYSERR; return GNUNET_SYSERR;
return GNUNET_NO; return GNUNET_NO;
@ -565,6 +576,7 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID,
"coin_evs"); "coin_evs");
} }
if (TALER_CNC_KAPPA != json_array_size (transfer_pubs)) 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_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID,
"transfer_pubs"); "transfer_pubs");
} }
res = handle_refresh_melt_json (connection, 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_JSON_parse_free (spec);
GNUNET_break_op (0); GNUNET_break_op (0);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID,
"transfer_privs"); "transfer_privs");
} }
res = handle_refresh_reveal_json (connection, res = handle_refresh_reveal_json (connection,

View File

@ -69,14 +69,16 @@ verify_and_execute_refund (struct MHD_Connection *connection,
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TEH_RESPONSE_reply_arg_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH,
"refund_fee"); "refund_fee");
} }
if (-1 == TALER_amount_cmp (&refund->refund_amount, if (-1 == TALER_amount_cmp (&refund->refund_amount,
&refund->refund_fee) ) &refund->refund_fee) )
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TEH_RESPONSE_reply_signature_invalid (connection, return TEH_RESPONSE_reply_arg_invalid (connection,
"refund_amount"); TALER_EC_REFUND_FEE_ABOVE_AMOUNT,
"refund_amount");
} }
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, 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"); TALER_LOG_WARNING ("Invalid signature on /refund request\n");
return TEH_RESPONSE_reply_signature_invalid (connection, return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID,
"merchant_sig"); "merchant_sig");
} }
return TEH_DB_execute_refund (connection, return TEH_DB_execute_refund (connection,

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 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); GNUNET_JSON_parse_free (spec);
TEH_KS_release (ks); TEH_KS_release (ks);
return TEH_RESPONSE_reply_arg_unknown (connection, return TEH_RESPONSE_reply_arg_unknown (connection,
TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND,
"denom_pub"); "denom_pub");
} }
TALER_amount_ntoh (&amount, 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"); TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n");
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_signature_invalid (connection, return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID,
"reserve_sig"); "reserve_sig");
} }
res = TEH_DB_execute_reserve_withdraw (connection, res = TEH_DB_execute_reserve_withdraw (connection,

View File

@ -132,17 +132,20 @@ TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
* Send a response indicating an invalid argument. * Send a response indicating an invalid argument.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid * @param param_name the parameter that is invalid
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name) const char *param_name)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{s:s, s:s}", "{s:s, s:I, s:s}",
"error", "invalid parameter", "error", "invalid parameter",
"code", (json_int_t) ec,
"parameter", param_name); "parameter", param_name);
} }
@ -153,17 +156,20 @@ TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
* denomination key). * denomination key).
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid * @param param_name the parameter that is invalid
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name) const char *param_name)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
"{s:s, s:s}", "{s:s, s:I, s:s}",
"error", "unknown entity referenced", "error", "unknown entity referenced",
"code", (json_int_t) ec,
"parameter", param_name); "parameter", param_name);
} }
@ -172,17 +178,20 @@ TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
* Send a response indicating an invalid signature. * Send a response indicating an invalid signature.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid * @param param_name the parameter that is invalid
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name) const char *param_name)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_UNAUTHORIZED, MHD_HTTP_UNAUTHORIZED,
"{s:s, s:s}", "{s:s, s:I, s:s}",
"error", "invalid signature", "error", "invalid signature",
"code", (json_int_t) ec,
"parameter", param_name); "parameter", param_name);
} }
@ -191,17 +200,20 @@ TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
* Send a response indicating a missing argument. * Send a response indicating a missing argument.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is missing * @param param_name the parameter that is missing
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name) const char *param_name)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{ s:s, s:s}", "{ s:s, s:I, s:s}",
"error", "missing parameter", "error", "missing parameter",
"code", (json_int_t) ec,
"parameter", param_name); "parameter", param_name);
} }
@ -210,17 +222,20 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
* Send a response indicating permission denied. * Send a response indicating permission denied.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param hint hint about why access was denied * @param hint hint about why access was denied
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *hint) const char *hint)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN, MHD_HTTP_FORBIDDEN,
"{s:s, s:s}", "{s:s, s:I, s:s}",
"error", "permission denied", "error", "permission denied",
"code", (json_int_t) ec,
"hint", hint); "hint", hint);
} }
@ -229,17 +244,20 @@ TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
* Send a response indicating an internal error. * Send a response indicating an internal error.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param hint hint about the internal error's nature * @param hint hint about the internal error's nature
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *hint) const char *hint)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,
"{s:s, s:s}", "{s:s, s:I, s:s}",
"error", "internal error", "error", "internal error",
"code", (json_int_t) ec,
"hint", hint); "hint", hint);
} }
@ -248,17 +266,20 @@ TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
* Send a response indicating an external error. * Send a response indicating an external error.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param hint hint about the error's nature * @param hint hint about the error's nature
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *hint) const char *hint)
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{s:s, s:s}", "{s:s, s:I, s:s}",
"error", "client error", "error", "client error",
"code", (json_int_t) ec,
"hint", hint); "hint", hint);
} }
@ -268,15 +289,18 @@ TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
* transaction (concurrent interference). * transaction (concurrent interference).
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @return a MHD result code * @return a MHD result code
*/ */
int 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, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{s:s}", "{s:s, s:I}",
"error", "commit failure"); "error", "commit failure",
"code", (json_int_t) ec);
} }
@ -285,12 +309,15 @@ TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection)
* database. * database.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @return a MHD result code * @return a MHD result code
*/ */
int 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, return TEH_RESPONSE_reply_internal_error (connection,
ec,
"Failed to connect to database"); "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, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
"{s:s}", "{s:s, s:I}",
"error", "error", "invalid json",
"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); history = compile_transaction_history (tl);
if (NULL == history) 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, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN, MHD_HTTP_FORBIDDEN,
"{s:s, s:o}", "{s:s, s:I, s:o}",
"error", "insufficient funds", "error", "insufficient funds",
"code", (json_int_t) TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
"history", history); "history", history);
} }
@ -696,8 +725,9 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection,
{ {
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_CONFLICT, MHD_HTTP_CONFLICT,
"{s:s, s:o}", "{s:s, s:I, s:o}",
"status", "conflicting refund", "status", "conflicting refund",
"code", (json_int_t) TALER_EC_REFUND_CONFLICT,
"history", compile_transaction_history (tl)); "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 connection connection to the client
* @param response_code response code to generate * @param response_code response code to generate
* @param ec taler error code to include
* @return MHD result code * @return MHD result code
*/ */
int int
TEH_RESPONSE_reply_refund_failure (struct MHD_Connection *connection, 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, return TEH_RESPONSE_reply_json_pack (connection,
response_code, response_code,
"{s:s}", "{s:s, s:I}",
"error", "status", "refund failure",
"no details"); "code", (json_int_t) ec);
} }
@ -779,6 +811,7 @@ TEH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection,
&balance); &balance);
if (NULL == json_history) if (NULL == json_history)
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_RESERVE_STATUS_DB_ERROR,
"balance calculation failure"); "balance calculation failure");
json_balance = TALER_JSON_from_amount (&balance); json_balance = TALER_JSON_from_amount (&balance);
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
@ -810,12 +843,14 @@ TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *c
&balance); &balance);
if (NULL == json_history) if (NULL == json_history)
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS,
"balance calculation failure"); "balance calculation failure");
json_balance = TALER_JSON_from_amount (&balance); json_balance = TALER_JSON_from_amount (&balance);
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_PAYMENT_REQUIRED, MHD_HTTP_FORBIDDEN,
"{s:s, s:o, s:o}", "{s:s, s:I, s:o, s:o}",
"error", "Insufficient funds", "error", "Insufficient funds",
"code", (json_int_t) TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS,
"balance", json_balance, "balance", json_balance,
"history", json_history); "history", json_history);
} }
@ -830,7 +865,7 @@ TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *c
*/ */
int int
TEH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, 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; json_t *sig_json;
@ -869,12 +904,15 @@ TEH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *conne
history = compile_transaction_history (tl); history = compile_transaction_history (tl);
if (NULL == history) 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, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN, 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", "error",
"insufficient funds", "insufficient funds",
"code",
(json_int_t) TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS,
"coin_pub", "coin_pub",
GNUNET_JSON_from_data_auto (coin_pub), GNUNET_JSON_from_data_auto (coin_pub),
"original_value", "original_value",
@ -1011,8 +1049,9 @@ TEH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
} }
return TEH_RESPONSE_reply_json_pack (connection, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_CONFLICT, 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", "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_sig", GNUNET_JSON_from_data_auto (&session->melt.coin_sig),
"coin_pub", GNUNET_JSON_from_data_auto (&session->melt.coin.coin_pub), "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), "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. * 404 reply.
* *
* @param connection connection to the client * @param connection connection to the client
* @param ec Taler error code
* @return MHD result code * @return MHD result code
*/ */
int 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, return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
"{s:s}", "{s:s, s:I}",
"error", "Deposit unknown"); "error", "Deposit unknown",
"code", (json_int_t) ec);
} }

View File

@ -29,6 +29,7 @@
#include <jansson.h> #include <jansson.h>
#include <microhttpd.h> #include <microhttpd.h>
#include <pthread.h> #include <pthread.h>
#include "taler_error_codes.h"
#include "taler-exchange-httpd.h" #include "taler-exchange-httpd.h"
#include "taler-exchange-httpd_db.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. * Send a response indicating an invalid signature.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid * @param param_name the parameter that is invalid
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name); const char *param_name);
@ -90,11 +93,13 @@ TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
* Send a response indicating an invalid argument. * Send a response indicating an invalid argument.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid * @param param_name the parameter that is invalid
* @return MHD result code * @return MHD result code
*/ */
int int
TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name); const char *param_name);
@ -104,11 +109,13 @@ TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
* denomination key). * denomination key).
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is invalid * @param param_name the parameter that is invalid
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name); const char *param_name);
@ -116,11 +123,13 @@ TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
* Send a response indicating a missing argument. * Send a response indicating a missing argument.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param param_name the parameter that is missing * @param param_name the parameter that is missing
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *param_name); const char *param_name);
@ -128,11 +137,13 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
* Send a response indicating permission denied. * Send a response indicating permission denied.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param hint hint about why access was denied * @param hint hint about why access was denied
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *hint); const char *hint);
@ -140,11 +151,13 @@ TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
* Send a response indicating an internal error. * Send a response indicating an internal error.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param hint hint about the internal error's nature * @param hint hint about the internal error's nature
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *hint); const char *hint);
@ -152,11 +165,13 @@ TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
* Send a response indicating an external error. * Send a response indicating an external error.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param hint hint about the error's nature * @param hint hint about the error's nature
* @return a MHD result code * @return a MHD result code
*/ */
int int
TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *hint); const char *hint);
@ -165,21 +180,24 @@ TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
* transaction (concurrent interference). * transaction (concurrent interference).
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @return a MHD result code * @return a MHD result code
*/ */
int 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 * Send a response indicating a failure to talk to the Exchange's
* database. * database.
* *
* @param connection the MHD connection to use * @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @return a MHD result code * @return a MHD result code
*/ */
int 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 * @return a MHD result code
*/ */
int 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 connection connection to the client
* @param response_code response code to generate * @param response_code response code to generate
* @param ec error code uniquely identifying the error
* @return MHD result code * @return MHD result code
*/ */
int int
TEH_RESPONSE_reply_refund_failure (struct MHD_Connection *connection, 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. * 404 reply.
* *
* @param connection connection to the client * @param connection connection to the client
* @param ec Taler error code
* @return MHD result code * @return MHD result code
*/ */
int 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 int
TEH_RESPONSE_reply_transfer_pending (struct MHD_Connection *connection, TEH_RESPONSE_reply_transfer_pending (struct MHD_Connection *connection,
struct GNUNET_TIME_Absolute planned_exec_time); struct GNUNET_TIME_Absolute planned_exec_time);
/** /**

View File

@ -295,6 +295,7 @@ TEH_TEST_handler_test_ecdhe (struct TEH_RequestHandler *rh,
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TEST_ECDH_ERROR,
"Failed to perform ECDH"); "Failed to perform ECDH");
} }
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -365,6 +366,7 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh,
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_signature_invalid (connection, return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_TEST_EDDSA_INVALID,
"eddsa_sig"); "eddsa_sig");
} }
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -377,6 +379,7 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh,
{ {
GNUNET_free (pk); GNUNET_free (pk);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TEST_EDDSA_ERROR,
"Failed to EdDSA-sign"); "Failed to EdDSA-sign");
} }
GNUNET_CRYPTO_eddsa_key_get_public (pk, GNUNET_CRYPTO_eddsa_key_get_public (pk,
@ -419,6 +422,7 @@ TEH_TEST_handler_test_rsa_get (struct TEH_RequestHandler *rh,
{ {
GNUNET_break (0); GNUNET_break (0);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TEST_RSA_GEN_ERROR,
"Failed to create RSA key"); "Failed to create RSA key");
} }
pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk); 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); GNUNET_break (0);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TEST_RSA_PUB_ERROR,
"Failed to get public RSA key"); "Failed to get public RSA key");
} }
res = TEH_RESPONSE_reply_json_pack (connection, 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_break (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TEST_RSA_GEN_ERROR,
"Failed to create RSA key"); "Failed to create RSA key");
} }
sig = GNUNET_CRYPTO_rsa_sign_blinded (rsa_pk, 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_break (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_internal_error (connection, return TEH_RESPONSE_reply_internal_error (connection,
TALER_EC_TEST_RSA_SIGN_ERROR,
"Failed to RSA-sign"); "Failed to RSA-sign");
} }
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);

View File

@ -88,6 +88,7 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection,
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TEH_RESPONSE_reply_signature_invalid (connection, return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID,
"merchant_sig"); "merchant_sig");
} }
return TEH_DB_execute_track_transaction (connection, return TEH_DB_execute_track_transaction (connection,

View File

@ -20,6 +20,7 @@
* @author Florian Dold * @author Florian Dold
* @author Christian Grothoff * @author Christian Grothoff
* @author Sree Harsha Totakura * @author Sree Harsha Totakura
* @author Marcello Stanisci
*/ */
#include "platform.h" #include "platform.h"
#include "taler_pq_lib.h" #include "taler_pq_lib.h"
@ -627,6 +628,23 @@ postgres_prepare (PGconn *db_conn)
"($1, $2, $3, $4, $5, $6, $7);", "($1, $2, $3, $4, $5, $6, $7);",
7, NULL); 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 /* Used in #postgres_get_reserve_history() to obtain inbound transactions
for a reserve */ for a reserve */
PREPARE ("reserves_in_get_transactions", PREPARE ("reserves_in_get_transactions",
@ -707,6 +725,23 @@ postgres_prepare (PGconn *db_conn)
" WHERE reserve_pub=$1;", " WHERE reserve_pub=$1;",
1, NULL); 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 /* Used in #postgres_get_refresh_session() to fetch
high-level information about a refresh session */ high-level information about a refresh session */
PREPARE ("get_refresh_session", PREPARE ("get_refresh_session",
@ -727,6 +762,22 @@ postgres_prepare (PGconn *db_conn)
" WHERE session_hash=$1 ", " WHERE session_hash=$1 ",
1, NULL); 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 /* Used in #postgres_create_refresh_session() to store
high-level information about a refresh session */ high-level information about a refresh session */
PREPARE ("insert_refresh_session", PREPARE ("insert_refresh_session",
@ -802,6 +853,23 @@ postgres_prepare (PGconn *db_conn)
" WHERE old_coin_pub=$1", " WHERE old_coin_pub=$1",
1, NULL); 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 */ /* Query the 'refunds' by coin public key */
PREPARE ("get_refunds_by_coin", PREPARE ("get_refunds_by_coin",
"SELECT" "SELECT"
@ -823,6 +891,7 @@ postgres_prepare (PGconn *db_conn)
1, NULL); 1, NULL);
/* Used in #postgres_insert_transfer_public_key() to /* Used in #postgres_insert_transfer_public_key() to
store commitments */ store commitments */
PREPARE ("insert_transfer_public_key", PREPARE ("insert_transfer_public_key",
@ -921,8 +990,7 @@ postgres_prepare (PGconn *db_conn)
" )", " )",
3, NULL); 3, NULL);
/* Fetch an existing deposit request, used to ensure idempotency /* Fetch deposits with rowid '\geq' the given parameter */
during /deposit processing. Used in #postgres_have_deposit(). */
PREPARE ("audit_get_deposits_incr", PREPARE ("audit_get_deposits_incr",
"SELECT" "SELECT"
" amount_with_fee_val" " amount_with_fee_val"
@ -937,11 +1005,12 @@ postgres_prepare (PGconn *db_conn)
",wire_deadline" ",wire_deadline"
",h_contract" ",h_contract"
",wire" ",wire"
",done"
" FROM deposits" " FROM deposits"
" WHERE (" " WHERE ("
" (deposit_serial_id>=$1)" " (deposit_serial_id>=$1)"
" )" " )"
" ORDER BY deposit_serial_id", " ORDER BY deposit_serial_id ASC",
1, NULL); 1, NULL);
/* Fetch an existing deposit request. /* Fetch an existing deposit request.
@ -1207,6 +1276,18 @@ postgres_prepare (PGconn *db_conn)
" FROM prewire" " FROM prewire"
" WHERE finished=true", " WHERE finished=true",
0, NULL); 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", PREPARE ("gc_denominations",
"DELETE" "DELETE"
" FROM denominations" " FROM denominations"
@ -4291,9 +4372,9 @@ postgres_select_deposits_above_serial_id (void *cls,
}; };
PGresult *result; PGresult *result;
result = GNUNET_PQ_exec_prepared (session->conn, result = GNUNET_PQ_exec_prepared (session->conn,
"audit_get_deposits_incr", "audit_get_deposits_incr",
params); params);
if (PGRES_COMMAND_OK != if (PGRES_TUPLES_OK !=
PQresultStatus (result)) PQresultStatus (result))
{ {
BREAK_DB_ERR (result); BREAK_DB_ERR (result);
@ -4307,20 +4388,62 @@ postgres_select_deposits_above_serial_id (void *cls,
if (0 == nrows) if (0 == nrows)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 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); PQclear (result);
return GNUNET_NO; return GNUNET_NO;
} }
for (i=0;i<nrows;i++) 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); PQclear (result);
return GNUNET_OK; 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, TALER_EXCHANGEDB_RefreshSessionCallback cb,
void *cb_cls) void *cb_cls)
{ {
GNUNET_break (0); // FIXME: not implemented struct GNUNET_PQ_QueryParam params[] = {
return GNUNET_SYSERR; 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, TALER_EXCHANGEDB_RefundCallback cb,
void *cb_cls) void *cb_cls)
{ {
GNUNET_break (0); // FIXME: not implemented struct GNUNET_PQ_QueryParam params[] = {
return GNUNET_SYSERR; 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, TALER_EXCHANGEDB_ReserveInCallback cb,
void *cb_cls) void *cb_cls)
{ {
GNUNET_break (0); // FIXME: not implemented struct GNUNET_PQ_QueryParam params[] = {
return GNUNET_SYSERR; 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, TALER_EXCHANGEDB_WithdrawCallback cb,
void *cb_cls) void *cb_cls)
{ {
GNUNET_break (0); // FIXME: not implemented struct GNUNET_PQ_QueryParam params[] = {
return GNUNET_SYSERR; 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, TALER_EXCHANGEDB_WirePreparationCallback cb,
void *cb_cls) 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;
} }

View File

@ -18,6 +18,7 @@
* @brief test cases for DB interaction functions * @brief test cases for DB interaction functions
* @author Sree Harsha Totakura * @author Sree Harsha Totakura
* @author Christian Grothoff * @author Christian Grothoff
* @author Marcello Stanisci
*/ */
#include "platform.h" #include "platform.h"
#include "taler_exchangedb_lib.h" #include "taler_exchangedb_lib.h"
@ -77,6 +78,12 @@ dead_prepare_cb (void *cls,
GNUNET_assert (0); 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 * Callback that is called with wire prepare data
@ -103,6 +110,27 @@ mark_prepare_cb (void *cls,
rowid)); 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. * Test API relating to persisting the wire plugins preparation data.
@ -134,6 +162,14 @@ test_wire_prepare (struct TALER_EXCHANGEDB_Session *session)
session, session,
&dead_prepare_cb, &dead_prepare_cb,
NULL)); 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; return GNUNET_OK;
drop: drop:
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -465,6 +501,38 @@ check_transfer_data (void *cls,
*ok = GNUNET_SYSERR; *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 * 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,
&session_hash, &session_hash,
&ret_refresh_session)); &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.num_newcoins != refresh_session.num_newcoins);
FAILIF (ret_refresh_session.noreveal_index != refresh_session.noreveal_index); FAILIF (ret_refresh_session.noreveal_index != refresh_session.noreveal_index);
@ -874,6 +950,128 @@ deposit_cb (void *cls,
return GNUNET_OK; 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. * Test garbage collection.
@ -1121,6 +1319,21 @@ run (void *cls)
} }
} }
FAILIF (3 != cnt); 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 */ /* Tests for deposits */
memset (&deposit, 0, sizeof (deposit)); memset (&deposit, 0, sizeof (deposit));
RND_BLK (&deposit.coin.coin_pub); RND_BLK (&deposit.coin.coin_pub);
@ -1145,6 +1358,14 @@ run (void *cls)
plugin->have_deposit (plugin->cls, plugin->have_deposit (plugin->cls,
session, session,
&deposit)); &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; result = 9;
FAILIF (1 != FAILIF (1 !=
plugin->iterate_matching_deposits (plugin->cls, plugin->iterate_matching_deposits (plugin->cls,
@ -1232,7 +1453,15 @@ run (void *cls)
plugin->insert_refund (plugin->cls, plugin->insert_refund (plugin->cls,
session, session,
&refund)); &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, tl = plugin->get_coin_transactions (plugin->cls,
session, session,
&refund.coin.coin_pub); &refund.coin.coin_pub);

View File

@ -28,6 +28,90 @@
#include "taler_signatures.h" #include "taler_signatures.h"
/**
* 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. * Handle for one session with the database.
*/ */
@ -164,10 +248,88 @@ struct TALER_AUDITORDB_Plugin
(*select_denomination_info)(void *cls, (*select_denomination_info)(void *cls,
struct TALER_AUDITORDB_Session *session, struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
void *cb, /* FIXME: type! */ TALER_AUDITORDB_DenominationInfoDataCallback cb,
void *cb_cls); 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 * Insert information about a reserve. There must not be an
* existing record for the reserve. * existing record for the reserve.
@ -586,7 +748,7 @@ struct TALER_AUDITORDB_Plugin
(*select_historic_denom_revenue)(void *cls, (*select_historic_denom_revenue)(void *cls,
struct TALER_AUDITORDB_Session *session, struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
void *cb, /* FIXME: fix type */ TALER_AUDITORDB_HistoricDenominationRevenueDataCallback cb,
void *cb_cls); void *cb_cls);
@ -628,7 +790,7 @@ struct TALER_AUDITORDB_Plugin
(*select_historic_losses)(void *cls, (*select_historic_losses)(void *cls,
struct TALER_AUDITORDB_Session *session, struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
void *cb, /* FIXME: fix type */ TALER_AUDITORDB_HistoricLossesDataCallback cb,
void *cb_cls); void *cb_cls);
@ -666,7 +828,7 @@ struct TALER_AUDITORDB_Plugin
(*select_historic_reserve_revenue)(void *cls, (*select_historic_reserve_revenue)(void *cls,
struct TALER_AUDITORDB_Session *session, struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
void *cb, /* FIXME: type */ TALER_AUDITORDB_HistoricReserveRevenueDataCallback cb,
void *cb_cls); void *cb_cls);
@ -721,6 +883,7 @@ struct TALER_AUDITORDB_Plugin
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
struct TALER_Amount *balance); struct TALER_Amount *balance);
}; };

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include <jansson.h> #include <jansson.h>
#include "taler_util.h" #include "taler_util.h"
#include "taler_error_codes.h"
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
@ -355,6 +356,7 @@ struct TALER_EXCHANGE_WireHandle;
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; * @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) * 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 * @param obj the received JSON reply, if successful this should be the wire
* format details as provided by /wire, or NULL if the * format details as provided by /wire, or NULL if the
* reply was not in JSON format. * reply was not in JSON format.
@ -362,6 +364,7 @@ struct TALER_EXCHANGE_WireHandle;
typedef void typedef void
(*TALER_EXCHANGE_WireResultCallback) (void *cls, (*TALER_EXCHANGE_WireResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *obj); const json_t *obj);
@ -423,6 +426,7 @@ struct TALER_EXCHANGE_DepositHandle;
typedef void typedef void
(*TALER_EXCHANGE_DepositResultCallback) (void *cls, (*TALER_EXCHANGE_DepositResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key, const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *obj); const json_t *obj);
@ -504,6 +508,7 @@ struct TALER_EXCHANGE_RefundHandle;
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * @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) * 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 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, * @param obj the received JSON reply, should be kept as proof (and, in particular,
* be forwarded to the customer) * be forwarded to the customer)
@ -511,6 +516,7 @@ struct TALER_EXCHANGE_RefundHandle;
typedef void typedef void
(*TALER_EXCHANGE_RefundResultCallback) (void *cls, (*TALER_EXCHANGE_RefundResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key, const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *obj); const json_t *obj);
@ -650,6 +656,7 @@ struct TALER_EXCHANGE_ReserveHistory
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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[in] json original response in JSON format (useful only for diagnostics)
* @param balance current balance in the reserve, NULL on error * @param balance current balance in the reserve, NULL on error
* @param history_length number of entries in the transaction history, 0 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 typedef void
(*TALER_EXCHANGE_ReserveStatusResultCallback) (void *cls, (*TALER_EXCHANGE_ReserveStatusResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *json, const json_t *json,
const struct TALER_Amount *balance, const struct TALER_Amount *balance,
unsigned int history_length, unsigned int history_length,
@ -713,12 +721,14 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle;
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors) * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
typedef void typedef void
(*TALER_EXCHANGE_ReserveWithdrawResultCallback) (void *cls, (*TALER_EXCHANGE_ReserveWithdrawResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig, const struct TALER_DenominationSignature *sig,
const json_t *full_response); const json_t *full_response);
@ -835,6 +845,7 @@ struct TALER_EXCHANGE_RefreshMeltHandle;
* @param cls closure * @param cls closure
* @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. * @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) * 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, * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT16_MAX on error * UINT16_MAX on error
* @param sign_key exchange key used to sign @a full_response, or NULL * @param sign_key exchange key used to sign @a full_response, or NULL
@ -843,7 +854,8 @@ struct TALER_EXCHANGE_RefreshMeltHandle;
typedef void typedef void
(*TALER_EXCHANGE_RefreshMeltCallback) (void *cls, (*TALER_EXCHANGE_RefreshMeltCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
uint16_t noreveal_index, enum TALER_ErrorCode ec,
uint16_t noreveal_index,
const struct TALER_ExchangePublicKeyP *sign_key, const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *full_response); const json_t *full_response);
@ -900,6 +912,7 @@ TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 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 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 * @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 typedef void
(*TALER_EXCHANGE_RefreshRevealCallback) (void *cls, (*TALER_EXCHANGE_RefreshRevealCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
unsigned int num_coins, unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs, const struct TALER_DenominationSignature *sigs,
@ -979,6 +993,7 @@ struct TALER_EXCHANGE_RefreshLinkHandle;
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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 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 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 * @param sigs array of signature over @a num_coins coins, NULL on error
@ -988,6 +1003,7 @@ struct TALER_EXCHANGE_RefreshLinkHandle;
typedef void typedef void
(*TALER_EXCHANGE_RefreshLinkCallback) (void *cls, (*TALER_EXCHANGE_RefreshLinkCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
unsigned int num_coins, unsigned int num_coins,
const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs, const struct TALER_DenominationSignature *sigs,
@ -1043,11 +1059,13 @@ struct TALER_EXCHANGE_AdminAddIncomingHandle;
* @param cls closure * @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @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) * 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) * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
typedef void typedef void
(*TALER_EXCHANGE_AdminAddIncomingResultCallback) (void *cls, (*TALER_EXCHANGE_AdminAddIncomingResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *full_response); const json_t *full_response);
@ -1108,6 +1126,7 @@ struct TALER_EXCHANGE_TrackTransferHandle;
* *
* @param cls closure * @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation * @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 sign_key exchange key used to sign @a json, or NULL
* @param json original json reply (may include signatures, those have then been * @param json original json reply (may include signatures, those have then been
* validated already) * validated already)
@ -1121,6 +1140,7 @@ struct TALER_EXCHANGE_TrackTransferHandle;
typedef void typedef void
(*TALER_EXCHANGE_TrackTransferCallback)(void *cls, (*TALER_EXCHANGE_TrackTransferCallback)(void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key, const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *json, const json_t *json,
const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_wire,
@ -1171,6 +1191,7 @@ struct TALER_EXCHANGE_TrackTransactionHandle;
* *
* @param cls closure * @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation * @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 sign_key exchange key used to sign @a json, or NULL
* @param json original json reply (may include signatures, those have then been * @param json original json reply (may include signatures, those have then been
* validated already) * validated already)
@ -1182,6 +1203,7 @@ struct TALER_EXCHANGE_TrackTransactionHandle;
typedef void typedef void
(*TALER_EXCHANGE_TrackTransactionCallback)(void *cls, (*TALER_EXCHANGE_TrackTransactionCallback)(void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *sign_key, const struct TALER_ExchangePublicKeyP *sign_key,
const json_t *json, const json_t *json,
const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_WireTransferIdentifierRawP *wtid,
@ -1240,4 +1262,5 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
json_t *history, json_t *history,
struct TALER_Amount *total); struct TALER_Amount *total);
#endif /* _TALER_EXCHANGE_SERVICE_H */ #endif /* _TALER_EXCHANGE_SERVICE_H */

View File

@ -25,6 +25,7 @@
#include <jansson.h> #include <jansson.h>
#include <gnunet/gnunet_json_lib.h> #include <gnunet/gnunet_json_lib.h>
#include "taler_util.h" #include "taler_util.h"
#include "taler_error_codes.h"
/** /**
* Print JSON parsing related error information * Print JSON parsing related error information
@ -92,6 +93,17 @@ int
TALER_JSON_hash (const json_t *json, TALER_JSON_hash (const json_t *json,
struct GNUNET_HashCode *hc); 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_ */ #endif /* TALER_JSON_LIB_H_ */
/* End of taler_json_lib.h */ /* End of taler_json_lib.h */

View File

@ -117,4 +117,6 @@ const struct GNUNET_OS_ProjectData *
TALER_project_data_default (void); TALER_project_data_default (void);
#endif #endif

View File

@ -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 */ /* End of json/json.c */

61
taler-exchange-dev.nix Normal file
View File

@ -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; [ ];
};
}