Compare commits
213 Commits
master
...
age-withdr
Author | SHA1 | Date | |
---|---|---|---|
8706a36c95 | |||
2eb3ff1f64 | |||
|
2ca7ce1b89 | ||
|
1e5976a3e9 | ||
|
0698835fed | ||
0a4422f5fa | |||
77f99b6363 | |||
|
3ce29a711b | ||
|
ec03f262b6 | ||
|
942dd73794 | ||
|
cd5fafffe2 | ||
|
5b14fd547e | ||
|
cd45ba408a | ||
|
ea47fb40c0 | ||
|
22ad41a2b4 | ||
|
3976729af1 | ||
c86a169fb5 | |||
3bebbfc2da | |||
7837015692 | |||
a3922302c7 | |||
|
d3607c286d | ||
|
49f8332ef9 | ||
ecea165db7 | |||
63efa1f135 | |||
34f44ccb27 | |||
|
de24415e17 | ||
|
e08fe4eff8 | ||
|
b60b339ee4 | ||
65c861027a | |||
c8250cae25 | |||
fde760aef0 | |||
|
a5451527cb | ||
|
e984dbd8f4 | ||
e0f78bc3c9 | |||
4ebdcc0247 | |||
8a7bfefa38 | |||
88ecba945e | |||
|
43d5e5707c | ||
|
1e572ebcab | ||
|
c6676f1aa5 | ||
|
6c44755458 | ||
|
6a483b51ec | ||
|
66f9a5b5e5 | ||
|
f4abc1c369 | ||
|
c57c3463d1 | ||
8d6b0944da | |||
6107e99559 | |||
3024dc9fa5 | |||
9d706a01a2 | |||
|
c05f832048 | ||
|
1026a32c71 | ||
7e9f5324b7 | |||
|
c02d88c8e3 | ||
|
11ea6fcfce | ||
|
f2c3443860 | ||
|
95c05a8827 | ||
|
40dfb94e0f | ||
|
1db17d43bd | ||
|
999db0fb80 | ||
|
ff8349e6e7 | ||
47620fa81b | |||
|
d3772a834f | ||
|
290268e9af | ||
|
75ea35722b | ||
f969bd3c5b | |||
40629e8992 | |||
|
2d4ebd3fc3 | ||
|
8d6bce26ad | ||
|
2d5f0a87e0 | ||
|
c6e3cba61d | ||
|
a8b3f0eb4e | ||
|
e961b29103 | ||
|
67262173a1 | ||
4d8d6d1222 | |||
|
78ed6228eb | ||
|
57527a5e8d | ||
9c3ddcbc18 | |||
537206e49f | |||
e889179bdd | |||
d3d744a444 | |||
1be14a3416 | |||
2f21fa24e4 | |||
89de1678ef | |||
f8536e8c14 | |||
145310e20e | |||
ddd0e0af13 | |||
ee42b70692 | |||
eeece1c96d | |||
17001e445d | |||
c5c3a44c25 | |||
b87d1112ea | |||
ddedf03a81 | |||
|
421129a32e | ||
|
75733ee00e | ||
|
e2f44ea7b3 | ||
|
fcd3948f3b | ||
|
d25dc8b0ad | ||
|
720783b66a | ||
|
999dae7c5d | ||
|
d4a65faad4 | ||
|
7bb9547599 | ||
|
22d5b9fc3a | ||
|
32d5b90827 | ||
|
ee2471a8c3 | ||
|
ef6496aba5 | ||
|
c512c8b101 | ||
|
f5ce22ddf6 | ||
|
af77a2a178 | ||
|
a37a8d34d5 | ||
|
17789253e9 | ||
|
d6838ed841 | ||
|
35bf856fcb | ||
|
8be960125f | ||
|
9b20c5047e | ||
70bfe0ed1b | |||
|
d8f8c550bd | ||
|
a2dde02b64 | ||
|
015b08b048 | ||
46188ae07e | |||
|
96cbda85e3 | ||
|
4355a08769 | ||
|
4a86d411de | ||
|
27f22ef1d2 | ||
98b51edf49 | |||
|
8cc1edfe0a | ||
|
82fd1a1164 | ||
|
9e7d3f9065 | ||
|
0ad3de938e | ||
|
809300158c | ||
|
9718bc4920 | ||
|
8f2c2766a4 | ||
|
f8fd492e9e | ||
fb5bc18c58 | |||
80a1b8f524 | |||
2ea3ae1008 | |||
|
04885a289a | ||
|
be40886515 | ||
|
ae6e62a0a3 | ||
|
89e2a02380 | ||
|
d36f1b3b6a | ||
|
aa8d44aab3 | ||
|
721cd047ff | ||
|
144b3a50a9 | ||
|
689fd46a60 | ||
|
bac7123763 | ||
|
9f081d28d7 | ||
|
0045eea277 | ||
|
6cc3846f4d | ||
|
b30952ed72 | ||
|
79671bba66 | ||
|
f7dc35e59e | ||
|
755955de28 | ||
|
e371d76cfe | ||
|
30b953ff0f | ||
|
29694be4b1 | ||
4a31a180a4 | |||
|
ef2059c9df | ||
|
4e5a9906c2 | ||
|
89ed38c03c | ||
|
40e45e7f5e | ||
|
bac4932cf5 | ||
|
b7d1ca4cd9 | ||
|
89e21002d6 | ||
|
90ca90b576 | ||
|
92df1cb1da | ||
|
c9ed524bc3 | ||
9f1f069cea | |||
a04425df34 | |||
4833234df6 | |||
|
ff1a28319f | ||
|
bc03a27cba | ||
|
7899bc5621 | ||
|
ec8ad2e3b3 | ||
|
0dd0fff17d | ||
|
b15713f42e | ||
|
4954963405 | ||
|
5259ea0532 | ||
|
cc34502ac1 | ||
|
5f9c3021db | ||
|
09f09a2104 | ||
|
c014acf3c4 | ||
|
3ebd0a70b2 | ||
|
aedd13a778 | ||
|
1cf58e8ff8 | ||
|
4e79967f9b | ||
dc5b0fb0d3 | |||
|
d1379e492d | ||
|
f009e0bd12 | ||
|
85f6c8cdcc | ||
f40932196e | |||
|
fddd06c152 | ||
|
6d363488a1 | ||
|
1639cefa61 | ||
|
404b2b78f1 | ||
|
1f9427e1d9 | ||
|
737b3338ed | ||
|
1e88796045 | ||
|
7c0de44a2b | ||
|
2de2b6e3cf | ||
|
4c1a2c0307 | ||
|
0b8752bb1b | ||
|
82bb911720 | ||
|
8e0f9b40c0 | ||
|
4267f1d762 | ||
|
ffd4057c61 | ||
|
41cb79c685 | ||
|
00021d7e83 | ||
|
8ce9433736 | ||
|
647ae694cc | ||
|
faca037018 | ||
|
75f75c4a51 | ||
9130cda9e7 | |||
3ec14744f0 |
@ -274,11 +274,11 @@ AS_CASE([$with_gnunet],
|
|||||||
CPPFLAGS="-I$with_gnunet/include ${CPPFLAGS}"])
|
CPPFLAGS="-I$with_gnunet/include ${CPPFLAGS}"])
|
||||||
CPPFLAGS="${CPPFLAGS} ${POSTGRESQL_CPPFLAGS}"
|
CPPFLAGS="${CPPFLAGS} ${POSTGRESQL_CPPFLAGS}"
|
||||||
AC_CHECK_HEADERS([gnunet/gnunet_pq_lib.h],
|
AC_CHECK_HEADERS([gnunet/gnunet_pq_lib.h],
|
||||||
[AC_CHECK_LIB([gnunetpq], [GNUNET_PQ_result_spec_string], libgnunetpq=1)])
|
[AC_CHECK_LIB([gnunetpq], [GNUNET_PQ_result_spec_array_string], libgnunetpq=1)])
|
||||||
AS_IF([test $libgnunetpq != 1],
|
AS_IF([test $libgnunetpq != 1],
|
||||||
[AC_MSG_ERROR([[
|
[AC_MSG_ERROR([[
|
||||||
***
|
***
|
||||||
*** You need libgnunetpq to build this program.
|
*** You need libgnunetpq version >= 4.0.0 to build this program.
|
||||||
*** Make sure you have Postgres installed while
|
*** Make sure you have Postgres installed while
|
||||||
*** building GNUnet (and that your GNUnet version
|
*** building GNUnet (and that your GNUnet version
|
||||||
*** is recent!)
|
*** is recent!)
|
||||||
|
@ -70,7 +70,8 @@ EXTRA_DIST = \
|
|||||||
$(rdata_DATA) \
|
$(rdata_DATA) \
|
||||||
coverage.sh \
|
coverage.sh \
|
||||||
gnunet.tag \
|
gnunet.tag \
|
||||||
microhttpd.tag
|
microhttpd.tag \
|
||||||
|
packages
|
||||||
|
|
||||||
# Change the set of supported languages here. You should
|
# Change the set of supported languages here. You should
|
||||||
# also update tos'XX'data and EXTRA_DIST accordingly.
|
# also update tos'XX'data and EXTRA_DIST accordingly.
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit bd4e73b2ed06269fdee42eaad21acb5be8be9302
|
Subproject commit 86b36917a59cc46961a9c9042b1af75a88545558
|
@ -31,7 +31,13 @@
|
|||||||
<member kind="define">
|
<member kind="define">
|
||||||
<type>#define</type>
|
<type>#define</type>
|
||||||
<name>GNUNET_TIME_UNIT_FOREVER_ABS</name>
|
<name>GNUNET_TIME_UNIT_FOREVER_ABS</name>
|
||||||
<anchorfile>gnunet_util_lib.h</anchorfile>
|
<anchorfile>gnunet_time_lib.h</anchorfile>
|
||||||
|
<arglist></arglist>
|
||||||
|
</member>
|
||||||
|
<member kind="define">
|
||||||
|
<type>#define</type>
|
||||||
|
<name>GNUNET_TIME_UNIT_ZERO_ABS</name>
|
||||||
|
<anchorfile>gnunet_time_lib.h</anchorfile>
|
||||||
<arglist></arglist>
|
<arglist></arglist>
|
||||||
</member>
|
</member>
|
||||||
</compound>
|
</compound>
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
# This configuration will be changed by tooling. Do not touch it manually.
|
@ -0,0 +1,49 @@
|
|||||||
|
# Main entry point for the GNU Taler configuration.
|
||||||
|
#
|
||||||
|
# Structure:
|
||||||
|
# - taler.conf is the main configuration entry point
|
||||||
|
# used by all Taler components (the file you are currently
|
||||||
|
# looking at.
|
||||||
|
# - overrides.conf contains configuration overrides that are
|
||||||
|
# set by some tools that help with the configuration,
|
||||||
|
# and should not be edited by humans. Comments in this file
|
||||||
|
# are not preserved.
|
||||||
|
# - conf.d/ contains configuration files for
|
||||||
|
# Taler components, which can be read by all
|
||||||
|
# users of the system and are included by the main
|
||||||
|
# configuration.
|
||||||
|
# - secrets/ contains configuration snippets
|
||||||
|
# with secrets for particular services.
|
||||||
|
# These files should have restrictive permissions
|
||||||
|
# so that only users of the relevant services
|
||||||
|
# can read it. All files in it should end with
|
||||||
|
# ".secret.conf".
|
||||||
|
|
||||||
|
[taler]
|
||||||
|
|
||||||
|
# Currency of the Taler deployment. This setting applies to all Taler
|
||||||
|
# components that only support a single currency.
|
||||||
|
#currency = KUDOS
|
||||||
|
|
||||||
|
# Smallest currency unit handled by the underlying bank system. Taler payments
|
||||||
|
# can make payments smaller than this units, but interactions with external
|
||||||
|
# systems is always rounded to this unit.
|
||||||
|
#currency_round_unit = KUDOS:0.01
|
||||||
|
|
||||||
|
# Monthly amount that mandatorily triggers an AML check
|
||||||
|
#AML_THRESHOLD = KUDOS:10000000
|
||||||
|
|
||||||
|
[paths]
|
||||||
|
|
||||||
|
TALER_HOME = /var/lib/taler
|
||||||
|
TALER_RUNTIME_DIR = /run/taler
|
||||||
|
TALER_CACHE_HOME = /var/cache/taler
|
||||||
|
TALER_CONFIG_HOME = /etc/taler
|
||||||
|
TALER_DATA_HOME = /var/lib/taler
|
||||||
|
|
||||||
|
|
||||||
|
# Inline configurations from all Taler components.
|
||||||
|
@inline-matching@ conf.d/*.conf
|
||||||
|
|
||||||
|
# Overrides from tools that help with configuration.
|
||||||
|
@inline@ overrides.conf
|
@ -0,0 +1,4 @@
|
|||||||
|
<Location "/taler-auditor/">
|
||||||
|
ProxyPass "unix:/var/lib/taler-auditor/auditor.sock|http://example.com/"
|
||||||
|
RequestHeader add "X-Forwarded-Proto" "https"
|
||||||
|
</Location>
|
@ -0,0 +1,18 @@
|
|||||||
|
server {
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/auditor.log;
|
||||||
|
error_log /var/log/nginx/auditor.err;
|
||||||
|
|
||||||
|
location /taler-auditor/ {
|
||||||
|
proxy_pass http://unix:/var/lib/taler-auditor/auditor.sock;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Host "localhost";
|
||||||
|
#proxy_set_header X-Forwarded-Proto "https";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
# Read secret sections into configuration, but only
|
||||||
|
# if we have permission to do so.
|
||||||
|
@inline-secret@ auditordb-postgres ../secrets/auditor-db.secret.conf
|
||||||
|
|
||||||
|
[auditor]
|
||||||
|
# Debian package is configured to use a reverse proxy with a UNIX
|
||||||
|
# domain socket. See nginx/apache configuration files.
|
||||||
|
SERVE = UNIX
|
||||||
|
UNIXPATH = /var/lib/taler-auditor/auditor.sock
|
||||||
|
|
||||||
|
# Only supported database is Postgres right now.
|
||||||
|
DATABASE = postgres
|
@ -0,0 +1,10 @@
|
|||||||
|
# Database configuration for the Taler auditor.
|
||||||
|
|
||||||
|
[auditordb-postgres]
|
||||||
|
|
||||||
|
# Typically, there should only be a single line here, of the form:
|
||||||
|
|
||||||
|
CONFIG=postgres:///DATABASE
|
||||||
|
|
||||||
|
# The details of the URI depend on where the database lives and how
|
||||||
|
# access control was configured.
|
@ -0,0 +1,4 @@
|
|||||||
|
<Location "/taler-exchange/">
|
||||||
|
ProxyPass "unix:/run/taler/exchange-httpd/exchange-http.sock|http://example.com/"
|
||||||
|
RequestHeader add "X-Forwarded-Proto" "https"
|
||||||
|
</Location>
|
@ -0,0 +1,17 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/exchange.log;
|
||||||
|
error_log /var/log/nginx/exchange.err;
|
||||||
|
|
||||||
|
location /taler-exchange/ {
|
||||||
|
proxy_pass http://unix:/run/taler/exchange-httpd/exchange-http.sock:/;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Host "localhost";
|
||||||
|
#proxy_set_header X-Forwarded-Proto "https";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
# Configuration for business-level aspects of the exchange.
|
||||||
|
|
||||||
|
[exchange]
|
||||||
|
|
||||||
|
# Here you MUST add the master public key of the offline system
|
||||||
|
# which you can get using `taler-exchange-offline setup`.
|
||||||
|
# This is just an example, your key will be different!
|
||||||
|
# MASTER_PUBLIC_KEY = YE6Q6TR1EDB7FD0S68TGDZGF1P0GHJD2S0XVV8R2S62MYJ6HJ4ZG
|
||||||
|
# MASTER_PUBLIC_KEY =
|
||||||
|
|
||||||
|
# Publicly visible base URL of the exchange.
|
||||||
|
# BASE_URL = https://example.com/
|
||||||
|
# BASE_URL =
|
||||||
|
|
||||||
|
# Here you MUST configure the amount above which transactions are
|
||||||
|
# always subject to manual AML review.
|
||||||
|
# AML_THRESHOLD =
|
||||||
|
|
||||||
|
# Attribute encryption key for storing attributes encrypted
|
||||||
|
# in the database. Should be a high-entropy nonce.
|
||||||
|
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
||||||
|
|
||||||
|
# For your terms of service and privacy policy, you should specify
|
||||||
|
# an Etag that must be updated whenever there are significant
|
||||||
|
# changes to either document. The format is up to you, what matters
|
||||||
|
# is that the value is updated and never re-used. See the HTTP
|
||||||
|
# specification on Etags.
|
||||||
|
# TERMS_ETAG =
|
||||||
|
# PRIVACY_ETAG =
|
||||||
|
|
||||||
|
SERVE = unix
|
||||||
|
UNIXPATH_MODE = 666
|
||||||
|
|
||||||
|
# Bank accounts used by the exchange should be specified here:
|
||||||
|
[exchange-account-1]
|
||||||
|
|
||||||
|
ENABLE_CREDIT = NO
|
||||||
|
ENABLE_DEBIT = NO
|
||||||
|
|
||||||
|
# Account identifier in the form of an RFC-8905 payto:// URI.
|
||||||
|
# For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
|
||||||
|
# Make sure to URL-encode spaces in $NAME!
|
||||||
|
PAYTO_URI =
|
||||||
|
|
||||||
|
# Credentials to access the account are in a separate
|
||||||
|
# config file with restricted permissions.
|
||||||
|
@inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials-1.secret.conf
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
#
|
||||||
|
# This configuration file specifies the various denominations offered by your
|
||||||
|
# exchange.
|
||||||
|
#
|
||||||
|
# Each denomination must be specified in a sections starting with
|
||||||
|
# "coin_".
|
||||||
|
#
|
||||||
|
# What follows is an example.
|
||||||
|
#
|
||||||
|
|
||||||
|
# [coin_FOO]
|
||||||
|
## Actual value of the coin
|
||||||
|
#VALUE = KUDOS:1
|
||||||
|
|
||||||
|
## How long will one key be used for withdrawals?
|
||||||
|
#DURATION_WITHDRAW = 7 days
|
||||||
|
|
||||||
|
## How long do users have to spend their coins?
|
||||||
|
#DURATION_SPEND = 2 years
|
||||||
|
|
||||||
|
## How long does the exchange keep the proofs around for legal disputes?
|
||||||
|
#DURATION_LEGAL = 6 years
|
||||||
|
|
||||||
|
## Fees charged. Note that for the lowest denomination, the
|
||||||
|
## fee must precisely be the lowest denomination, or zero.
|
||||||
|
#FEE_WITHDRAW = KUDOS:0
|
||||||
|
#FEE_DEPOSIT = KUDOS:0
|
||||||
|
#FEE_REFRESH = KUDOS:0
|
||||||
|
#FEE_REFUND = KUDOS:0
|
||||||
|
|
||||||
|
## How long should the RSA keys be. Do not change unless you really know
|
||||||
|
## what you are doing (consult your local cryptographer first!).
|
||||||
|
#RSA_KEYSIZE = 2048
|
@ -0,0 +1,13 @@
|
|||||||
|
# Configuration settings for system parameters of the exchange.
|
||||||
|
|
||||||
|
# Read secret sections into configuration, but only
|
||||||
|
# if we have permission to do so.
|
||||||
|
@inline-secret@ exchangedb-postgres ../secrets/exchange-db.secret.conf
|
||||||
|
|
||||||
|
[exchange]
|
||||||
|
|
||||||
|
# Only supported database is Postgres right now.
|
||||||
|
DATABASE = postgres
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
# This file contains the secret credentials
|
||||||
|
# to access the Taler Wire Gateway API (usually
|
||||||
|
# provided by LibEuFin) for the exchange accounts.
|
||||||
|
#
|
||||||
|
# Each exchange-account-* section should have a matching
|
||||||
|
# exchange-accountcredentials-* section here.
|
||||||
|
#
|
||||||
|
# Each of those sections must be imported via @inline-secret@,
|
||||||
|
# usually in conf.d/exchange-business.conf.
|
||||||
|
|
||||||
|
[exchange-accountcredentials-1]
|
||||||
|
|
||||||
|
wire_gateway_auth_method = basic
|
||||||
|
password =
|
||||||
|
username =
|
||||||
|
wire_gateway_url =
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
# Database configuration for the Taler exchange.
|
||||||
|
|
||||||
|
[exchangedb-postgres]
|
||||||
|
|
||||||
|
# Typically, there should only be a single line here, of the form:
|
||||||
|
|
||||||
|
# CONFIG=postgres:///DATABASE
|
||||||
|
|
||||||
|
# The details of the URI depend on where the database lives and how
|
||||||
|
# access control was configured.
|
@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system auditor REST API
|
||||||
|
After=postgres.service network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-auditor-httpd
|
||||||
|
Type=simple
|
||||||
|
Restart=on-failure
|
||||||
|
ExecStart=/usr/bin/taler-auditor-httpd -c /etc/taler/taler.conf
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange aggregator service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
After=postgres.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-aggregator
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-aggregator -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange aggregator service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-aggregator
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-aggregator -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange closer service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
After=network.target postgres.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-closer
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-closer -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange expire service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
After=postgres.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-expire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-expire -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,33 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange REST API
|
||||||
|
AssertPathExists=/run/taler/exchange-httpd
|
||||||
|
Requires=taler-exchange-httpd.socket taler-exchange-secmod-cs.service taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
After=postgres.service network.target taler-exchange-secmod-cs.service taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-httpd
|
||||||
|
Type=simple
|
||||||
|
|
||||||
|
# Depending on the configuration, the service process kills itself and then
|
||||||
|
# needs to be restarted. Thus no significant delay on restarts.
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1ms
|
||||||
|
|
||||||
|
# Disable the service if more than 5 restarts are encountered within 5s.
|
||||||
|
# These are usually the systemd defaults, but can be overwritten, thus we set
|
||||||
|
# them here explicitly, as the exchange code assumes StartLimitInterval
|
||||||
|
# to be >=5s.
|
||||||
|
StartLimitBurst=5
|
||||||
|
StartLimitInterval=5s
|
||||||
|
|
||||||
|
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,27 @@
|
|||||||
|
% This is a systemd service template.
|
||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange REST API at %I
|
||||||
|
AssertPathExists=/run/taler/exchange-httpd
|
||||||
|
Requires=taler-exchange-httpd@%i.socket taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
After=postgres.service network.target taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-httpd
|
||||||
|
Type=simple
|
||||||
|
# Depending on the configuration, the service suicides and then
|
||||||
|
# needs to be restarted.
|
||||||
|
Restart=always
|
||||||
|
# Do not dally on restarts.
|
||||||
|
RestartSec=1ms
|
||||||
|
EnvironmentFile=/etc/environment
|
||||||
|
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange CS security module
|
||||||
|
AssertPathExists=/run/taler/exchange-secmod-cs
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-secmod-cs
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=100ms
|
||||||
|
ExecStart=/usr/bin/taler-exchange-secmod-cs -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
IPAddressDeny=any
|
||||||
|
Slice=taler-exchange.slice
|
@ -0,0 +1,19 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange EdDSA security module
|
||||||
|
AssertPathExists=/run/taler/exchange-secmod-eddsa
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-secmod-eddsa
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=100ms
|
||||||
|
ExecStart=/usr/bin/taler-exchange-secmod-eddsa -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
IPAddressDeny=any
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange RSA security module
|
||||||
|
AssertPathExists=/run/taler/exchange-secmod-rsa
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-secmod-rsa
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=100ms
|
||||||
|
ExecStart=/usr/bin/taler-exchange-secmod-rsa -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
IPAddressDeny=any
|
||||||
|
Slice=taler-exchange.slice
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Taler Exchange Transfer Service
|
||||||
|
After=network.target postgres.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-wire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-transfer -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange wirewatch service
|
||||||
|
After=network.target postgres.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-wire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
RuntimeMaxSec=3600s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange wirewatch service
|
||||||
|
After=network.target
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-wire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -4,7 +4,7 @@
|
|||||||
exec 1>&2
|
exec 1>&2
|
||||||
|
|
||||||
RET=0
|
RET=0
|
||||||
changed=$(git diff --cached --name-only | grep -v mustach)
|
changed=$(git diff --cached --name-only | grep -v mustach | grep -v templating/test./)
|
||||||
crustified=""
|
crustified=""
|
||||||
|
|
||||||
for f in $changed;
|
for f in $changed;
|
||||||
@ -28,7 +28,7 @@ done
|
|||||||
if [ $RET = 1 ];
|
if [ $RET = 1 ];
|
||||||
then
|
then
|
||||||
echo "Run"
|
echo "Run"
|
||||||
echo "uncrustify --no-backup -c uncrustify.cfg ${crustified}"
|
echo "uncrustify --replace -c uncrustify.cfg ${crustified}"
|
||||||
echo "before committing."
|
echo "before committing."
|
||||||
fi
|
fi
|
||||||
exit $RET
|
exit $RET
|
||||||
|
@ -12,6 +12,14 @@
|
|||||||
# BASE_URL = https://example.com/
|
# BASE_URL = https://example.com/
|
||||||
# BASE_URL =
|
# BASE_URL =
|
||||||
|
|
||||||
|
# Here you MUST configure the amount above which transactions are
|
||||||
|
# always subject to manual AML review.
|
||||||
|
# AML_THRESHOLD =
|
||||||
|
|
||||||
|
# Attribute encryption key for storing attributes encrypted
|
||||||
|
# in the database. Should be a high-entropy nonce.
|
||||||
|
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
||||||
|
|
||||||
# For your terms of service and privacy policy, you should specify
|
# For your terms of service and privacy policy, you should specify
|
||||||
# an Etag that must be updated whenever there are significant
|
# an Etag that must be updated whenever there are significant
|
||||||
# changes to either document. The format is up to you, what matters
|
# changes to either document. The format is up to you, what matters
|
||||||
@ -26,14 +34,17 @@ UNIXPATH_MODE = 666
|
|||||||
# Bank accounts used by the exchange should be specified here:
|
# Bank accounts used by the exchange should be specified here:
|
||||||
[exchange-account-1]
|
[exchange-account-1]
|
||||||
|
|
||||||
enable_credit = no
|
ENABLE_CREDIT = NO
|
||||||
enable_debit = no
|
ENABLE_DEBIT = NO
|
||||||
|
|
||||||
# Account identifier in the form of an RFC-8905 payto:// URI.
|
# Account identifier in the form of an RFC-8905 payto:// URI.
|
||||||
# For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
|
# For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
|
||||||
# Make sure to URL-encode spaces in $NAME!
|
# Make sure to URL-encode spaces in $NAME!
|
||||||
payto_uri =
|
PAYTO_URI =
|
||||||
|
|
||||||
# Credentials to access the account are in a separate
|
# Credentials to access the account are in a separate
|
||||||
# config file with restricted permissions.
|
# config file with restricted permissions.
|
||||||
@inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials-1.secret.conf
|
@inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials-1.secret.conf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,3 +8,6 @@
|
|||||||
|
|
||||||
# Only supported database is Postgres right now.
|
# Only supported database is Postgres right now.
|
||||||
DATABASE = postgres
|
DATABASE = postgres
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
12
debian/libtalerexchange-dev.install
vendored
12
debian/libtalerexchange-dev.install
vendored
@ -1,17 +1,22 @@
|
|||||||
# Benchmarks, only install them for the dev package.
|
# Benchmarks, only install them for the dev package.
|
||||||
usr/bin/taler-aggregator-benchmark
|
usr/bin/taler-aggregator-benchmark
|
||||||
usr/bin/taler-exchange-benchmark
|
|
||||||
usr/bin/taler-fakebank-run
|
|
||||||
usr/bin/taler-bank-benchmark
|
usr/bin/taler-bank-benchmark
|
||||||
|
usr/bin/taler-exchange-benchmark
|
||||||
usr/bin/taler-exchange-kyc-tester
|
usr/bin/taler-exchange-kyc-tester
|
||||||
|
usr/bin/taler-fakebank-run
|
||||||
|
usr/bin/taler-unified-setup.sh
|
||||||
|
|
||||||
# Only used in test cases. Maybe these
|
# Only used in test cases. Maybe these
|
||||||
# shouldn't even be installed?
|
# shouldn't even be installed?
|
||||||
usr/bin/taler-nexus-prepare
|
|
||||||
usr/bin/taler-bank-manage-testing
|
usr/bin/taler-bank-manage-testing
|
||||||
|
usr/bin/taler-nexus-prepare
|
||||||
|
|
||||||
# Man pages
|
# Man pages
|
||||||
usr/share/man/man1/taler-exchange-kyc-tester*
|
usr/share/man/man1/taler-exchange-kyc-tester*
|
||||||
|
usr/share/man/man1/taler-aggregator-benchmark*
|
||||||
|
usr/share/man/man1/taler-bank-benchmark*
|
||||||
|
usr/share/man/man1/taler-exchange-benchmark*
|
||||||
|
usr/share/man/man1/taler-unified-setup*
|
||||||
|
|
||||||
|
|
||||||
# Headers
|
# Headers
|
||||||
@ -27,5 +32,4 @@ usr/lib/*/libtalertesting.so
|
|||||||
usr/lib/*/libtalerfakebank.so
|
usr/lib/*/libtalerfakebank.so
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
usr/share/man/man1/taler-exchange-benchmark*
|
|
||||||
usr/share/info/taler-developer-manual*
|
usr/share/info/taler-developer-manual*
|
||||||
|
@ -9,6 +9,7 @@ infoimagedir = $(infodir)/images
|
|||||||
man_MANS = \
|
man_MANS = \
|
||||||
prebuilt/man/taler.conf.5 \
|
prebuilt/man/taler.conf.5 \
|
||||||
prebuilt/man/taler-config.1 \
|
prebuilt/man/taler-config.1 \
|
||||||
|
prebuilt/man/taler-aggregator-benchmark.1 \
|
||||||
prebuilt/man/taler-auditor.1 \
|
prebuilt/man/taler-auditor.1 \
|
||||||
prebuilt/man/taler-auditor-dbinit.1 \
|
prebuilt/man/taler-auditor-dbinit.1 \
|
||||||
prebuilt/man/taler-auditor-exchange.1 \
|
prebuilt/man/taler-auditor-exchange.1 \
|
||||||
@ -16,6 +17,7 @@ man_MANS = \
|
|||||||
prebuilt/man/taler-auditor-offline.1 \
|
prebuilt/man/taler-auditor-offline.1 \
|
||||||
prebuilt/man/taler-auditor-sign.1 \
|
prebuilt/man/taler-auditor-sign.1 \
|
||||||
prebuilt/man/taler-auditor-sync.1 \
|
prebuilt/man/taler-auditor-sync.1 \
|
||||||
|
prebuilt/man/taler-bank-benchmark.1 \
|
||||||
prebuilt/man/taler-bank-transfer.1 \
|
prebuilt/man/taler-bank-transfer.1 \
|
||||||
prebuilt/man/taler-exchange-aggregator.1 \
|
prebuilt/man/taler-exchange-aggregator.1 \
|
||||||
prebuilt/man/taler-exchange-benchmark.1 \
|
prebuilt/man/taler-exchange-benchmark.1 \
|
||||||
@ -24,6 +26,7 @@ man_MANS = \
|
|||||||
prebuilt/man/taler-exchange-drain.1 \
|
prebuilt/man/taler-exchange-drain.1 \
|
||||||
prebuilt/man/taler-exchange-expire.1 \
|
prebuilt/man/taler-exchange-expire.1 \
|
||||||
prebuilt/man/taler-exchange-httpd.1 \
|
prebuilt/man/taler-exchange-httpd.1 \
|
||||||
|
prebuilt/man/taler-exchange-kyc-aml-pep-trigger.1 \
|
||||||
prebuilt/man/taler-exchange-kyc-tester.1 \
|
prebuilt/man/taler-exchange-kyc-tester.1 \
|
||||||
prebuilt/man/taler-exchange-offline.1 \
|
prebuilt/man/taler-exchange-offline.1 \
|
||||||
prebuilt/man/taler-exchange-router.1\
|
prebuilt/man/taler-exchange-router.1\
|
||||||
@ -38,7 +41,8 @@ man_MANS = \
|
|||||||
prebuilt/man/taler-helper-auditor-deposits.1\
|
prebuilt/man/taler-helper-auditor-deposits.1\
|
||||||
prebuilt/man/taler-helper-auditor-purses.1\
|
prebuilt/man/taler-helper-auditor-purses.1\
|
||||||
prebuilt/man/taler-helper-auditor-reserves.1\
|
prebuilt/man/taler-helper-auditor-reserves.1\
|
||||||
prebuilt/man/taler-helper-auditor-wire.1
|
prebuilt/man/taler-helper-auditor-wire.1 \
|
||||||
|
prebuilt/man/taler-unified-setup.1
|
||||||
|
|
||||||
info_TEXINFOS = \
|
info_TEXINFOS = \
|
||||||
prebuilt/texinfo/taler-auditor.texi \
|
prebuilt/texinfo/taler-auditor.texi \
|
||||||
|
File diff suppressed because it is too large
Load Diff
3
doc/flows/Makefile
Normal file
3
doc/flows/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
all:
|
||||||
|
pdflatex main.tex
|
||||||
|
pdflatex main.tex
|
39
doc/flows/fees-coins.tex
Normal file
39
doc/flows/fees-coins.tex
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
\section{Fees per coin} \label{sec:fees:coin}
|
||||||
|
|
||||||
|
Payments with Taler are always made using coins. Each coin has a specific
|
||||||
|
denomination, and an exchange will issue coins in different denominations (in
|
||||||
|
the same currency). The fees per coin depend on the operation and the
|
||||||
|
denomination.
|
||||||
|
|
||||||
|
The primary fee to be paid is a {\bf deposit} fee that is
|
||||||
|
charged whenever a coin is fully or partially deposited
|
||||||
|
into a bank account or another wallet.
|
||||||
|
|
||||||
|
A secondary fee to be paid is a {\bf change} fee that is
|
||||||
|
charged whenever a coin partially spent and change must
|
||||||
|
be rendered.
|
||||||
|
|
||||||
|
Coins also have an {\bf expiration} date of approximately {\bf one year}.
|
||||||
|
After the expiration date, coins become worthless. Wallets that are online
|
||||||
|
{\bf three months} {\em before} a coin expires will automatically trade any
|
||||||
|
such coins for one or more fresh coins with a later expiration date. This
|
||||||
|
process is also subject to the {\bf change} fee.
|
||||||
|
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Fees per coin. Coin denomination values are given in units of CHF 0.01.}
|
||||||
|
\label{table:fees:coins}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{l|c|r}
|
||||||
|
{\bf Denomination} & {\bf Fee type} & {\bf Amount} \\ \hline \hline
|
||||||
|
$2^{-4}-2^{ 0}$ & deposit & {\em CHF 0.00125} \\
|
||||||
|
$2^{-4}-2^{ 0}$ & change & {\em CHF 0.00125} \\
|
||||||
|
$2^{ 0}-2^{ 3}$ & deposit & {\em CHF 0.00250} \\
|
||||||
|
$2^{ 0}-2^{ 3}$ & change & {\em CHF 0.00125} \\
|
||||||
|
$2^{ 4}-2^{ 8}$ & deposit & {\em CHF 0.005} \\
|
||||||
|
$2^{ 4}-2^{ 8}$ & change & {\em CHF 0.00125} \\
|
||||||
|
$2^{ 8}-2^{12}$ & deposit & {\em CHF 0.01} \\
|
||||||
|
$2^{ 8}-2^{12}$ & change & {\em CHF 0.00125} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
30
doc/flows/fees-wire.tex
Normal file
30
doc/flows/fees-wire.tex
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
\section{Fees per wire} \label{sec:fees:wire}
|
||||||
|
|
||||||
|
Wire fees apply whenever an exchange needs to initiate a wire transfer to
|
||||||
|
another bank account. Wire fees do not apply to every individual payment to a
|
||||||
|
merchant, as merchants can choose to {\em aggregate} multiple micropayments
|
||||||
|
into one large payment on the wire. Wire fees also do not apply to
|
||||||
|
wallet-to-wallet payments within the Taler system.
|
||||||
|
|
||||||
|
A {\bf wire} fee is applied when a merchant receives
|
||||||
|
an aggregated payment into their bank account.
|
||||||
|
|
||||||
|
A {\bf closing} fee is applied when a wallet fails to
|
||||||
|
withdraw coins and money has to be sent back to the
|
||||||
|
originating bank account.
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Table with wire fees. Wire fees are set annually.}
|
||||||
|
\label{table:fees:wire}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{l|c|r}
|
||||||
|
{\bf Year} & {\bf Fee type} & {\bf Amount} \\ \hline \hline
|
||||||
|
2023 & wire & {\em CHF 0.05} \\
|
||||||
|
2023 & closing & {\em CHF 0.10} \\
|
||||||
|
2024 & wire & {\em CHF 0.05} \\
|
||||||
|
2024 & closing & {\em CHF 0.10} \\
|
||||||
|
2025 & wire & {\em CHF 0.05} \\
|
||||||
|
2025 & closing & {\em CHF 0.10} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
52
doc/flows/int-deposit.tex
Normal file
52
doc/flows/int-deposit.tex
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
\section{Deposit} \label{sec:deposit}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer wallet \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{bank}{\shortstack{Retail bank \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] {Checking \\ Accounts};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\begin{callself}{wallet}{Review deposit fees}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{wallet}{Deposit {(Coins)}}{exchange}
|
||||||
|
\begin{sdblock}{Acceptable account?}{}
|
||||||
|
\mess[0]{exchange}{{Refuse deposit}}{wallet}
|
||||||
|
\end{sdblock}
|
||||||
|
\begin{sdblock}{KYC/AML required?}{}
|
||||||
|
\begin{callself}{exchange}{Figures~\ref{fig:proc:kyc}, \ref{fig:proc:aml}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
% \prelevel
|
||||||
|
% \prelevel
|
||||||
|
% \begin{sdblock}{User abort?}{}
|
||||||
|
% \mess[0]{wallet}{{Request abort}}{exchange}
|
||||||
|
% \mess[0]{exchange}{{Abort confirmation}}{wallet}
|
||||||
|
% \end{sdblock}
|
||||||
|
\mess[0]{exchange}{{Initiate transfer}}{bank}
|
||||||
|
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{A customer deposits the coins issued by a Taler exchange (payment
|
||||||
|
service provider) into a bank account. Even if the
|
||||||
|
bank account is owned by the same customer, the
|
||||||
|
KYC checks from Section~\ref{sec:kyc:deposit} apply.}
|
||||||
|
\label{fig:int:deposit}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
We do {\bf not} permit the customer to regain control over their funds {\em
|
||||||
|
unless} they pass the KYC/AML checks. The technical reason is simply that
|
||||||
|
the KYC/AML checks happen {\em after} the aggregation logic and at this point
|
||||||
|
refunds are no longer permitted. From a compliance perspective, this also
|
||||||
|
prevents malicious customers from risk-free probing of the system.
|
60
doc/flows/int-pay.tex
Normal file
60
doc/flows/int-pay.tex
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
\section{Pay} \label{sec:pay}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer wallet \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[1]{merchant}{\shortstack{Merchant \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[1]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[1]{bank}{\shortstack{Merchant bank \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] {Commercial \\ Accounts};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{wallet}{Browse catalog}{merchant}
|
||||||
|
\mess[0]{merchant}{Commercial offer}{wallet}
|
||||||
|
\begin{callself}{wallet}{Review offer}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{wallet}{Pay {(Coins)}}{merchant}
|
||||||
|
\mess[0]{merchant}{Deposit {(Coins)}}{exchange}
|
||||||
|
\begin{sdblock}{Acceptable account?}{}
|
||||||
|
\mess[0]{exchange}{{Refuse deposit}}{merchant}
|
||||||
|
\mess[0]{merchant}{{Refund purchase}}{wallet}
|
||||||
|
\end{sdblock}
|
||||||
|
\mess[0]{exchange}{{Confirm deposit}}{merchant}
|
||||||
|
\mess[0]{merchant}{Fulfill order}{wallet}
|
||||||
|
\begin{callself}{exchange}{Aggregate transactions}{}
|
||||||
|
\end{callself}
|
||||||
|
\begin{sdblock}{KYC/AML required?}{}
|
||||||
|
\begin{callself}{exchange}{Figures~\ref{fig:proc:kyc}, \ref{fig:proc:aml}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\mess[0]{exchange}{{Initiate transfer}}{bank}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Payments from a customer to merchant result in
|
||||||
|
depositing coins at the Taler exchange (payment service provider)
|
||||||
|
which then credits the merchant's bank account.
|
||||||
|
The KYC/AML checks are described in Section~\ref{sec:kyc:deposit}}
|
||||||
|
\label{fig:int:pay}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
{\bf Internal note:} The exchange refusing a deposit immediately based on
|
||||||
|
unaccaptable merchant accounts may not be fully implemented (this is a very
|
||||||
|
recent feature, after all); especially the merchant then automatically
|
||||||
|
refunding the purchase to the customer is certainly missing. However,
|
||||||
|
the entire situation only arises when a merchant is incorrectly configured
|
||||||
|
and in violation of the terms of service.
|
56
doc/flows/int-pull.tex
Normal file
56
doc/flows/int-pull.tex
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
\section{Pull payment (aka invoicing)} \label{sec:pull}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{payer}{\shortstack{Payer \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] {Pre-funded \\ Wallet};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{payee}{\shortstack{Payee \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\begin{callself}{payee}{Review pull payment fees}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{payee}{{Create invoice (Wallet ID)}}{exchange}
|
||||||
|
|
||||||
|
\mess[0]{exchange}{{Invoice ready}}{payee}
|
||||||
|
\mess[0]{payee}{{Send invoice (e.g. via QR code)}}{payer}
|
||||||
|
|
||||||
|
\begin{callself}{payer}{Review invoice}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{payer}{{Make payment (Coins)}}{exchange}
|
||||||
|
|
||||||
|
\begin{sdblock}{Domestic wallet?}{}
|
||||||
|
\begin{callself}{exchange}{Figure~\ref{fig:proc:domestic}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\begin{sdblock}{KYC/AML required?}{}
|
||||||
|
\begin{callself}{exchange}{Figures~\ref{fig:proc:kyc}, \ref{fig:proc:aml}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
|
||||||
|
\mess[0]{exchange}{{Distribute digital cash}}{payee}
|
||||||
|
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Interactions between wallets and Taler exchange
|
||||||
|
in a pull payment. KYC/AML checks are described in
|
||||||
|
Section~\ref{sec:kyc:pull}.}
|
||||||
|
\label{fig:int:pull}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
We do {\bf not} permit the payer to regain control over their funds, once the
|
||||||
|
payment was made they are locked {\em until} the payee passes the KYC/AML
|
||||||
|
checks. We only do the AML/KYC process once the funds are locked at the
|
||||||
|
exchange. This ensures we know the actual transacted amounts (which may be
|
||||||
|
lower than the total amounts requested) and prevents risk-free probing
|
||||||
|
attacks.
|
48
doc/flows/int-push.tex
Normal file
48
doc/flows/int-push.tex
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
\section{Push payment} \label{sec:push}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{payer}{\shortstack{Payer \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] {Pre-funded \\ Wallet};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{payee}{\shortstack{Payee \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\begin{callself}{payer}{Review push payment fees}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{payer}{{Push funds (Coins)}}{exchange}
|
||||||
|
\mess[0]{payer}{{Offer payment (e.g. via QR code)}}{payee}
|
||||||
|
\begin{callself}{payee}{Review payment offer}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{payee}{{Request funds (Wallet ID)}}{exchange}
|
||||||
|
\begin{sdblock}{Domestic wallet?}{}
|
||||||
|
\begin{callself}{exchange}{Figure~\ref{fig:proc:domestic}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\begin{sdblock}{KYC/AML required?}{}
|
||||||
|
\begin{callself}{exchange}{Figures~\ref{fig:proc:kyc}, \ref{fig:proc:aml}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\mess[0]{exchange}{{Distribute digital cash}}{payee}
|
||||||
|
% \postlevel
|
||||||
|
\begin{sdblock}{Payment offer expired?}{}
|
||||||
|
\mess[0]{exchange}{{Return funds}}{payer}
|
||||||
|
\end{sdblock}
|
||||||
|
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Interactions between wallets and Taler exchange
|
||||||
|
in a push payment. KYC/AML checks are described
|
||||||
|
in Section~\ref{sec:kyc:push}.}
|
||||||
|
\label{fig:int:push}
|
||||||
|
\end{figure}
|
39
doc/flows/int-refund.tex
Normal file
39
doc/flows/int-refund.tex
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
\section{Refund}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer wallet \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{merchant}{\shortstack{Merchant \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\begin{callself}{merchant}{Initiate refund}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{merchant}{{Refund offer (QR code)}}{wallet}
|
||||||
|
\mess[0]{wallet}{Download refund}{merchant}
|
||||||
|
\mess[0]{merchant}{Approve refund}{exchange}
|
||||||
|
\mess[0]{exchange}{Confirm refund}{merchant}
|
||||||
|
\mess[0]{merchant}{Return refund confirmation}{wallet}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Refund processing when a merchant is unable to fulfill
|
||||||
|
a contract. Refunds must happen {\em before} the
|
||||||
|
exchange has aggregated the original transaction for
|
||||||
|
a bank transfer to the merchant. Furthermore, refunds
|
||||||
|
can only go to the customer who made the original payment
|
||||||
|
and the refund cannot exceed the amount of the original
|
||||||
|
payment.}
|
||||||
|
\label{fig:int:refund}
|
||||||
|
\end{figure}
|
48
doc/flows/int-shutdown.tex
Normal file
48
doc/flows/int-shutdown.tex
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
\section{Shutdown}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer wallet \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{bank}{\shortstack{Customer bank \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] {Checking \\ Accounts};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
|
||||||
|
\begin{callself}{exchange}{Operator initiates shutdown}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{exchange}{{Shutdown alert}}{wallet}
|
||||||
|
\begin{sdblock}{Bank account known?}{}
|
||||||
|
\begin{callself}{wallet}{Designate bank account}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\mess[0]{wallet}{{Deposit (Coins)}}{exchange}
|
||||||
|
\begin{sdblock}{Acceptable account?}{}
|
||||||
|
\mess[0]{exchange}{{Refuse deposit}}{wallet}
|
||||||
|
\end{sdblock}
|
||||||
|
\begin{sdblock}{KYC/AML required?}{}
|
||||||
|
\begin{callself}{exchange}{Figures~\ref{fig:proc:kyc}, \ref{fig:proc:aml}}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\mess[0]{exchange}{{Initiate transfer}}{bank}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Shutdown interactions between customer, Taler exchange (payment
|
||||||
|
service provider) and bank.}
|
||||||
|
\label{fig:int:shutdown}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
KYC/AML requirements are relaxed in cases where the customer is able to
|
||||||
|
cryptographically demonstrate that they previously withdrew these coins from
|
||||||
|
the designated checking account. Thus, KYC/AML checks here primarily still
|
||||||
|
apply if the customer received the funds via P2P transfers from other wallets.
|
49
doc/flows/int-withdraw.tex
Normal file
49
doc/flows/int-withdraw.tex
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
\section{Withdraw}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer wallet \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{bank}{\shortstack{Customer bank \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] {Checking \\ Accounts};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{wallet}{Withdraw {(Amount)}}{exchange}
|
||||||
|
\mess[0]{exchange}{{Configuration (ToS, Fees)}}{wallet}
|
||||||
|
\begin{sdblock}{once}{}
|
||||||
|
\begin{callself}{wallet}{Accept ToS}{}
|
||||||
|
\end{callself}
|
||||||
|
\end{sdblock}
|
||||||
|
\begin{callself}{wallet}{Review withdraw fees}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{wallet}{{Initiate transfer (Amount, Credit account, Wallet ID)}}{bank}
|
||||||
|
\mess[0]{bank}{{Credit (Wallet ID)}}{exchange}
|
||||||
|
|
||||||
|
\begin{sdblock}{Acceptable transfer?}{}
|
||||||
|
\mess[0]{exchange}{{Bounce funds}}{bank}
|
||||||
|
\end{sdblock}
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{exchange}{Confirm wire transfer}{wallet}
|
||||||
|
\mess[0]{wallet}{Request digital cash}{exchange}
|
||||||
|
\mess[0]{exchange}{Distribute digital cash}{wallet}
|
||||||
|
\postlevel
|
||||||
|
\begin{sdblock}{Withdraw period expired?}{}
|
||||||
|
\mess[0]{exchange}{{Return remaining funds}}{bank}
|
||||||
|
\end{sdblock}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Withdraw interactions between customer, Taler exchange (payment
|
||||||
|
service provider) and bank. The amount of digital cash distributed is
|
||||||
|
subject to limits per origin account (see Section~\ref{sec:kyc:withdraw}).}
|
||||||
|
\label{fig:int:withdraw}
|
||||||
|
\end{figure}
|
58
doc/flows/kyc-balance.tex
Normal file
58
doc/flows/kyc-balance.tex
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
\section{KYC: Balance}
|
||||||
|
|
||||||
|
Note: this process is not implemented and would require non-trivial extra work
|
||||||
|
if required.
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{center}
|
||||||
|
\begin{tikzpicture}[node distance=1cm,font=\sffamily,
|
||||||
|
start/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=yellow!30},
|
||||||
|
end/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=red!30},
|
||||||
|
process/.style={rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=orange!30},
|
||||||
|
failed/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=red!30},
|
||||||
|
io/.style={trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=blue!30},
|
||||||
|
decision/.style={diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=green!30},
|
||||||
|
arr/.style={very thick,-latex},
|
||||||
|
every edge quotes/.style = {auto, font=\footnotesize, sloped}
|
||||||
|
]
|
||||||
|
\node (start) [start] {Start};
|
||||||
|
\node (balance) [decision,below=of start,text width=3cm] {Transaction leaves wallet balance below AML threshold?};
|
||||||
|
\node (registered) [decision,below=of balance,text width=3cm] {Wallet has been subject to KYC?};
|
||||||
|
\node (kyc) [process, below=of registered] {KYC process};
|
||||||
|
\node (aml) [process, left=of kyc] {AML process};
|
||||||
|
\node (allow) [end, right=of balance] {Allow};
|
||||||
|
\node (deny) [failed, right=of registered] {Deny};
|
||||||
|
\draw[arr] (start) -> (balance) {};
|
||||||
|
\draw[arr] (balance) -> (registered);
|
||||||
|
\draw (balance) edge["No"] (registered);
|
||||||
|
\draw[arr] (balance) -> (allow);
|
||||||
|
\draw (balance) edge["Yes"] (allow);
|
||||||
|
|
||||||
|
\draw[arr] (registered) -> (kyc);
|
||||||
|
\draw (registered) edge["No"] (kyc);
|
||||||
|
\draw[arr] (registered) -> (deny);
|
||||||
|
\draw (registered) edge["Yes"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (deny);
|
||||||
|
\draw (kyc) edge["Failed"] (deny);
|
||||||
|
\draw[arr] (kyc) -> (aml);
|
||||||
|
\draw (kyc) edge["Ok"] (aml);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (balance.west);
|
||||||
|
\draw (aml) edge["New threshold"] (balance.west);
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{center}
|
||||||
|
\caption{Regulatory process when a wallet exceeds its AML threshold.
|
||||||
|
When the transfer is denied the transaction (withdraw, P2P transfer)
|
||||||
|
is refused by the wallet.}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Settings for the balance trigger.}
|
||||||
|
\begin{tabular}{l|l|r}
|
||||||
|
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
|
||||||
|
KYC threshold & Amount & {\em 5000 CHF} \\
|
||||||
|
Default AML threshold & Amount & {\em 5000 CHF} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
80
doc/flows/kyc-deposit.tex
Normal file
80
doc/flows/kyc-deposit.tex
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
\section{KYC: Deposit} \label{sec:kyc:deposit}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{center}
|
||||||
|
\begin{tikzpicture}[node distance=1cm,font=\sffamily,
|
||||||
|
start/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=yellow!30},
|
||||||
|
end/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=red!30},
|
||||||
|
process/.style={rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=orange!30},
|
||||||
|
failed/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=red!30},
|
||||||
|
io/.style={trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=blue!30},
|
||||||
|
decision/.style={diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=green!30},
|
||||||
|
arr/.style={very thick,-latex},
|
||||||
|
every edge quotes/.style = {auto, font=\footnotesize, sloped}
|
||||||
|
]
|
||||||
|
\node (start) [start] {Start};
|
||||||
|
\node (country) [decision,below=of start,text width=2.5cm] {Target account in allowed country?};
|
||||||
|
\node (amount) [decision, below=of country,text width=2.5cm] {Target account received less than KYB threshold?};
|
||||||
|
\node (kyc) [process, right=of amount] {KYB process};
|
||||||
|
\node (high) [decision, below=of amount,text width=2.5cm] {Target account received more than its AML threshold?};
|
||||||
|
\node (aml) [process, right=of high] {AML process};
|
||||||
|
\node (dummy) [below right=of aml] {};
|
||||||
|
\node (allow) [end, below right=of dummy] {Allow};
|
||||||
|
\node (deny) [failed, right=of kyc] {Deny};
|
||||||
|
\draw[arr] (start) -> (country) {};
|
||||||
|
|
||||||
|
\draw[arr] (country) -> (amount);
|
||||||
|
\draw (country) edge["Yes"] (amount);
|
||||||
|
|
||||||
|
\draw[arr] (country.east) -> (deny);
|
||||||
|
\draw (country.east) edge["No"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (amount) -> (high);
|
||||||
|
\draw (amount) edge["Yes"] (high);
|
||||||
|
|
||||||
|
\draw[arr] (amount.east) -> (kyc);
|
||||||
|
\draw (amount.east) edge["No"] (kyc);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (deny);
|
||||||
|
\draw (kyc) edge["Failed"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (high);
|
||||||
|
\draw (kyc) edge["Succeeded"] (high);
|
||||||
|
|
||||||
|
\draw[arr] (high.south) -> (allow);
|
||||||
|
\draw (high.south) edge["Yes"] (allow);
|
||||||
|
|
||||||
|
\draw[arr] (high.east) -> (aml);
|
||||||
|
\draw (high.east) edge["No"] (aml);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (deny);
|
||||||
|
\draw (aml) edge["Violation"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (allow);
|
||||||
|
\draw (aml) edge["Ok"] (allow);
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{center}
|
||||||
|
\caption{Regulatory process when depositing digital cash into a bank
|
||||||
|
account. When the transfer is denied, the money is held in escrow
|
||||||
|
until authorities authorize the transfer.}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Settings for the deposit trigger. Note that the operation
|
||||||
|
must satisfy all of the given rules.}
|
||||||
|
\begin{tabular}{l|l|r}
|
||||||
|
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
|
||||||
|
Allowed bank accounts & RFC 8905 RegEx & {\em CH*} \\ \hline
|
||||||
|
KYB deposit threshold & Amount/month & {\em 5000 CHF} \\
|
||||||
|
KYB deposit threshold & Amount/year & {\em 25000 CHF} \\
|
||||||
|
Default AML deposit threshold & Amount/month & {\em 2500 CHF} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
The KYB deposit threshold of 5'000 \CURRENCY{} per month and than 25'000
|
||||||
|
\CURRENCY{} per year ensure compliance with article 48-1b.
|
||||||
|
|
||||||
|
Additionally, our terms of service will prohibit businesses to receive
|
||||||
|
amounts exceeding 1'000 \CURRENCY{} per transaction (well below the
|
||||||
|
15'000 \CURRENCY{} threshold defined in article 24-1c).
|
86
doc/flows/kyc-pull.tex
Normal file
86
doc/flows/kyc-pull.tex
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
\section{KYC/AML: Pull Payment} \label{sec:kyc:pull}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{center}
|
||||||
|
\begin{tikzpicture}[node distance=0.9cm,font=\sffamily,
|
||||||
|
start/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=yellow!30},
|
||||||
|
end/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=red!30},
|
||||||
|
process/.style={rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=orange!30},
|
||||||
|
failed/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=red!30},
|
||||||
|
io/.style={trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=blue!30},
|
||||||
|
decision/.style={diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=green!30},
|
||||||
|
arr/.style={very thick,-latex},
|
||||||
|
every edge quotes/.style = {auto, font=\footnotesize, sloped}
|
||||||
|
]
|
||||||
|
\node (start) [start] {Start};
|
||||||
|
\node (wallet) [decision,below=of start,text width=2.5cm] {Wallet linked to (domestic) phone number?};
|
||||||
|
\node (domestic) [process, right=of wallet] {Validate phone number};
|
||||||
|
\node (amount) [decision, below=of wallet,text width=2.5cm] {Wallet received less than KYC threshold from other wallets?};
|
||||||
|
\node (kyc) [process, right=of amount] {KYC process};
|
||||||
|
\node (high) [decision, below=of amount,text width=2.5cm] {Wallet received more than its AML threshold?};
|
||||||
|
\node (aml) [process, right=of high] {AML process};
|
||||||
|
\node (dummy) [below right=of aml] {};
|
||||||
|
\node (allow) [end, below right=of dummy] {Allow invoicing};
|
||||||
|
\node (deny) [failed, right=of kyc] {Deny};
|
||||||
|
\draw[arr] (start) -> (wallet) {};
|
||||||
|
|
||||||
|
\draw[arr] (wallet) -> (amount);
|
||||||
|
\draw (wallet) edge["Yes"] (amount);
|
||||||
|
|
||||||
|
\draw[arr] (wallet.east) -> (domestic);
|
||||||
|
\draw (wallet.east) edge["No"] (domestic);
|
||||||
|
|
||||||
|
\draw[arr] (domestic) -> (amount);
|
||||||
|
\draw (domestic) edge["Confirmed"] (amount);
|
||||||
|
|
||||||
|
\draw[arr] (domestic) -> (deny);
|
||||||
|
\draw (domestic) edge["Failed"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (amount) -> (high);
|
||||||
|
\draw (amount) edge["Yes"] (high);
|
||||||
|
|
||||||
|
\draw[arr] (amount.east) -> (kyc);
|
||||||
|
\draw (amount.east) edge["No"] (kyc);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (deny);
|
||||||
|
\draw (kyc) edge["Failed"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (high);
|
||||||
|
\draw (kyc) edge["Succeeded"] (high);
|
||||||
|
|
||||||
|
\draw[arr] (high.south) -> (allow);
|
||||||
|
\draw (high.south) edge["Yes"] (allow);
|
||||||
|
|
||||||
|
\draw[arr] (high.east) -> (aml);
|
||||||
|
\draw (high.east) edge["No"] (aml);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (deny);
|
||||||
|
\draw (aml) edge["Violation"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (allow);
|
||||||
|
\draw (aml) edge["Ok"] (allow);
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{center}
|
||||||
|
\caption{Regulatory process when receiving payments from another wallet.
|
||||||
|
The threshold depends on the risk profile from the KYC process.
|
||||||
|
When KYC thresholds would be passed, the receiving wallet cannot
|
||||||
|
generate a valid invoice until it has provided the KYC data.
|
||||||
|
When a transfer is denied by AML staff, the money is held in escrow
|
||||||
|
until authorities authorize the transfer.}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Settings for the pull payment trigger. Note that the operation
|
||||||
|
must satisfy all of the given rules.}
|
||||||
|
\begin{tabular}{l|l|r}
|
||||||
|
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
|
||||||
|
Permitted phone numbers & Dialing prefix & {\em +41} \\
|
||||||
|
P2P KYC threshold & Amount/month & {\em 1000 CHF} \\
|
||||||
|
P2P KYC threshold & Amount/year & {\em 5000 CHF} \\
|
||||||
|
Default P2P AML threshold & Amount/month & {\em 2500 CHF} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
The P2P KYC thresholds of 1'000 \CURRENCY{} per month and than 5'000
|
||||||
|
\CURRENCY{} per year ensure compliance with article 49-2c.
|
84
doc/flows/kyc-push.tex
Normal file
84
doc/flows/kyc-push.tex
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
\section{KYC/AML: Push Payment} \label{sec:kyc:push}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{center}
|
||||||
|
\begin{tikzpicture}[node distance=0.9cm,font=\sffamily,
|
||||||
|
start/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=yellow!30},
|
||||||
|
end/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=red!30},
|
||||||
|
process/.style={rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=orange!30},
|
||||||
|
failed/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=red!30},
|
||||||
|
io/.style={trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=blue!30},
|
||||||
|
decision/.style={diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=green!30},
|
||||||
|
arr/.style={very thick,-latex},
|
||||||
|
every edge quotes/.style = {auto, font=\footnotesize, sloped}
|
||||||
|
]
|
||||||
|
\node (start) [start] {Start};
|
||||||
|
\node (wallet) [decision,below=of start,text width=2.5cm] {Wallet linked to (domestic) phone number?};
|
||||||
|
\node (domestic) [process, right=of wallet] {Validate phone number};
|
||||||
|
\node (amount) [decision, below=of wallet,text width=2.5cm] {Wallet received less than KYC threshold from other wallets?};
|
||||||
|
\node (kyc) [process, right=of amount] {KYC process};
|
||||||
|
\node (high) [decision, below=of amount,text width=2.5cm] {Wallet received more than its AML threshold?};
|
||||||
|
\node (aml) [process, right=of high] {AML process};
|
||||||
|
\node (dummy) [below right=of aml] {};
|
||||||
|
\node (allow) [end, below right=of dummy] {Allow};
|
||||||
|
\node (deny) [failed, right=of kyc] {Deny};
|
||||||
|
\draw[arr] (start) -> (wallet) {};
|
||||||
|
|
||||||
|
\draw[arr] (wallet) -> (amount);
|
||||||
|
\draw (wallet) edge["Yes"] (amount);
|
||||||
|
|
||||||
|
\draw[arr] (wallet.east) -> (domestic);
|
||||||
|
\draw (wallet.east) edge["No"] (domestic);
|
||||||
|
|
||||||
|
\draw[arr] (domestic) -> (amount);
|
||||||
|
\draw (domestic) edge["Confirmed"] (amount);
|
||||||
|
|
||||||
|
\draw[arr] (domestic) -> (deny);
|
||||||
|
\draw (domestic) edge["Failed"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (amount) -> (high);
|
||||||
|
\draw (amount) edge["Yes"] (high);
|
||||||
|
|
||||||
|
\draw[arr] (amount.east) -> (kyc);
|
||||||
|
\draw (amount.east) edge["No"] (kyc);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (deny);
|
||||||
|
\draw (kyc) edge["Failed"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (kyc) -> (high);
|
||||||
|
\draw (kyc) edge["Succeeded"] (high);
|
||||||
|
|
||||||
|
\draw[arr] (high.south) -> (allow);
|
||||||
|
\draw (high.south) edge["Yes"] (allow);
|
||||||
|
|
||||||
|
\draw[arr] (high.east) -> (aml);
|
||||||
|
\draw (high.east) edge["No"] (aml);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (deny);
|
||||||
|
\draw (aml) edge["Violation"] (deny);
|
||||||
|
|
||||||
|
\draw[arr] (aml) -> (allow);
|
||||||
|
\draw (aml) edge["Ok"] (allow);
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{center}
|
||||||
|
\caption{Regulatory process when receiving payments from another wallet.
|
||||||
|
The threshold depends on the risk profile from the KYC process.
|
||||||
|
When the transfer is denied, the money is held in escrow
|
||||||
|
until authorities authorize the transfer.}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Settings for the push payment trigger. Note that the operation
|
||||||
|
must satisfy all of the given rules.}
|
||||||
|
\begin{tabular}{l|l|r}
|
||||||
|
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
|
||||||
|
Permitted phone numbers & Dialing prefix & {\em +41} \\
|
||||||
|
P2P KYC threshold & Amount/month & {\em 1000 CHF} \\
|
||||||
|
P2P KYC threshold & Amount/year & {\em 5000 CHF} \\
|
||||||
|
Default P2P AML threshold & Amount/month & {\em 2500 CHF} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
The P2P KYC thresholds of 1'000 \CURRENCY{} per month and than 5'000
|
||||||
|
\CURRENCY{} per year ensure compliance with article 49-2c.
|
55
doc/flows/kyc-withdraw.tex
Normal file
55
doc/flows/kyc-withdraw.tex
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
\section{KYC: Withdraw} \label{sec:kyc:withdraw}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{center}
|
||||||
|
\begin{tikzpicture}[node distance=1cm,font=\sffamily,
|
||||||
|
start/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=yellow!30},
|
||||||
|
end/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=red!30},
|
||||||
|
process/.style={rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=orange!30},
|
||||||
|
failed/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=red!30},
|
||||||
|
io/.style={trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=blue!30},
|
||||||
|
decision/.style={diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=green!30},
|
||||||
|
arr/.style={very thick,-latex},
|
||||||
|
every edge quotes/.style = {auto, font=\footnotesize, sloped}
|
||||||
|
]
|
||||||
|
\node (start) [start] {Start};
|
||||||
|
\node (country) [decision,below=of start,text width=3cm] {Wire transfer originates from allowed country?};
|
||||||
|
\node (amount) [decision, below=of country,text width=3cm] {Transferred less than maximum amount from origin account over last month?};
|
||||||
|
\node (allow) [end, below=of amount] {Allow};
|
||||||
|
\node (deny) [failed, right=of allow] {Deny};
|
||||||
|
\draw[arr] (start) -> (country) {};
|
||||||
|
\draw[arr] (country) -> (amount);
|
||||||
|
\draw (country) edge["Yes"] (amount);
|
||||||
|
\draw[arr] (country.east) -> (deny);
|
||||||
|
\draw (country.east) edge["No"] (deny);
|
||||||
|
\draw[arr] (amount) -> (allow);
|
||||||
|
\draw (amount) edge["Yes"] (allow);
|
||||||
|
\draw[arr] (amount.east) -> (deny);
|
||||||
|
\draw (amount.east) edge["No"] (deny);
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{center}
|
||||||
|
\caption{Regulatory process when withdrawing digital cash from a
|
||||||
|
bank account.
|
||||||
|
If the transfer is denied or the user fails to withdraw the
|
||||||
|
funds for any other reason, the money is automatically returned
|
||||||
|
after the bounce period (see Table~\ref{table:kyc:withdraw:settings}) to
|
||||||
|
the originating bank account.}
|
||||||
|
\label{fig:kyc:withdraw}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Settings for the withdraw trigger. Note that the operation
|
||||||
|
must satisfy all of the given rules.} \label{table:kyc:withdraw:settings}
|
||||||
|
\begin{tabular}{l|l|r}
|
||||||
|
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
|
||||||
|
Allowed bank accounts & RFC 8905 RegEx & {\em CH*} \\ \hline
|
||||||
|
SMS-Identification & Amount/month & {\em 200 CHF} \\
|
||||||
|
Withdraw limit & Amount/month & {\em 5000 CHF} \\
|
||||||
|
Withdraw limit & Amount/year & {\em 25000 CHF} \\
|
||||||
|
Bounce period & Delay & 1 month \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
The limit of 200 \CURRENCY{} results from article 48-2. Strictly limiting
|
||||||
|
withdrawals to less than 5'000 \CURRENCY{} per month and less than 25'000
|
||||||
|
\CURRENCY{} per year assures compliance with article 48-1c.
|
239
doc/flows/main.de.tex
Normal file
239
doc/flows/main.de.tex
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
% This is a (partial) translation of main.tex into
|
||||||
|
% German. Please keep the structure as parallel as
|
||||||
|
% possible when improving / expanding the translation!
|
||||||
|
\documentclass[10pt,a4paper,oneside]{book}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage{url}
|
||||||
|
\usepackage{enumitem}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{qrcode}
|
||||||
|
\usepackage{pgf-umlsd}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usetikzlibrary{shapes,arrows}
|
||||||
|
\usetikzlibrary{positioning}
|
||||||
|
\usetikzlibrary{calc}
|
||||||
|
\usetikzlibrary{quotes}
|
||||||
|
\author{Christian Grothoff}
|
||||||
|
\title{Flows in the GNU Taler System}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\newcommand\TALER{TALER OPERATIONS AG}
|
||||||
|
\newcommand\CURRENCY{CHF}
|
||||||
|
\newcommand\LAND{der Schweiz}
|
||||||
|
|
||||||
|
\section{Transaktionen im Taler-Bezahlsystem}\label{sec:Transaktionen}
|
||||||
|
|
||||||
|
Dieser Abschnitt stellt die Transaktionen im Taler-Bezahlsystem
|
||||||
|
vor. Die Grafiken geben wieder, in welcher Reihenfolge die beteiligten
|
||||||
|
Parteien interagieren. \\
|
||||||
|
F\"ur jede einzelne Transaktion ist die automatische Ausl\"osung von
|
||||||
|
Compliance-Prozessen durch den Taler-Exchange einstellbar.
|
||||||
|
Die im Rahmen des jeweiligen Compliance-Prozesses erzwungenen
|
||||||
|
Pr\"ufschritte beschreibt Abschnitt~\ref{sec:triggers}.
|
||||||
|
|
||||||
|
Folgende Transaktionen kommen als Ausl\"oser f\"ur AML- und KYC-Prozesse
|
||||||
|
in Betracht:
|
||||||
|
\begin{description}[noitemsep]
|
||||||
|
\item[withdraw] Ein Nutzer hebt digitales Bargeld (e-money) in Form von
|
||||||
|
Taler-Coins in ein Taler-Wallet ab
|
||||||
|
\item[reimburse] Ein Nutzer l\"asst den Gegenwert von Taler-Coins vom
|
||||||
|
Taler-Exchange an das urspr\"ungliche IBAN-Bankkonto zur\"uck\"uberweisen
|
||||||
|
\item[pay] Ein Nutzer zahlt zugunsten eines IBAN-Bankkontos des Empf\"angers
|
||||||
|
\item[refund] Ein Verk\"aufer erteilt einem Zahlenden die R\"uckerstattung
|
||||||
|
eines Zahlbetrags
|
||||||
|
\item[push] Ein Nutzer sendet einen Zahlbetrag an ein anderes Taler-Wallet
|
||||||
|
\item[pull] Ein Nutzer stellt einem anderen Taler-Wallet eine Rechnung aus
|
||||||
|
und fordert eine Zahlung von diesem Wallet
|
||||||
|
\item[shutdown] Der Betreiber des Taler-Exchange informiert die Inhaber von
|
||||||
|
Coins, die diese von jenem Exchange abgehoben hatten, dass der Exchange
|
||||||
|
geplant eingestellt und die Gegenwerte der Coins restituiert werden
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
Die Nutzer beginnen ein gesch\"aftliches Nutzungsverh\"altnis mit
|
||||||
|
\TALER{}, wenn sie ihre Taler-Wallets anweisen, eine Abhebung durchzuf\"uhren.
|
||||||
|
Das Taler-Bezahlsystem verwendet jedoch keine Konten, sondern wert-basierte
|
||||||
|
Token und explizit keine konten-basierten Geld-\"Aquivalente.
|
||||||
|
Taler soll digitales Bargeld sein und erlaubt technisch bedingt
|
||||||
|
kein Nachvollziehen der Transaktionen seiner Nutzer, wie es Konten mit
|
||||||
|
Eing\"angen und Ausg\"angen von Zahlungen erm\"oglichen w\"urden.
|
||||||
|
Es gibt daher kein ``Er\"offnen'' oder ``Schliessen'' von Konten der Nutzer.
|
||||||
|
Die Begriffe ``opening'' und ``closing'' lassen sich deshalb auch nicht auf
|
||||||
|
das System anwenden oder \"ubertragen. \\
|
||||||
|
|
||||||
|
Die Nutzer k\"onnen
|
||||||
|
\begin{enumerate}[noitemsep]
|
||||||
|
\item die treuh\"andisch verwalteten Einlagen gezielt auf ein bestimmtes
|
||||||
|
Bankkonto auszahlen lassen,
|
||||||
|
%(siehe Abschnitt~\ref{sec:deposit})
|
||||||
|
\item an einen Verk\"aufer zahlen,
|
||||||
|
%(siehe Abschnitt~\ref{sec:deposit})
|
||||||
|
\item einem anderen Empf\"anger mittels peer-to-peer-Verfahren Coins zukommen
|
||||||
|
lassen
|
||||||
|
%(siehe Abschnitte~\ref{sec:push} und~\ref{sec:pull})
|
||||||
|
\item die Coins in ihrem Wallet, das verloren ging oder zerst\"ort wurde,
|
||||||
|
durch Ablauf der G\"ultigkeit entwerten lassen (dies w\"are ebenso der Fall
|
||||||
|
bei einer langen Zeit ohne Internet-Anbindung oder ohne Installation),
|
||||||
|
\item den Wert der Coins im Wallet durch Zahlung von Geb\"uhren f\"ur
|
||||||
|
die Verl\"angerung ihrer G\"ultigkeit langsam verringern lassen.
|
||||||
|
%(siehe Abschnitt~\ref{sec:fees:coin})
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Das Taler-Bezahlsystem verwehrt den Nutzern kategorisch die Abhebung
|
||||||
|
von h\"oheren Betr\"agen als 5.000 \CURRENCY{} pro Monat bzw. von
|
||||||
|
mehr als 15.000 \CURRENCY{} pro Jahr. Damit wird gew\"ahrleistet,
|
||||||
|
dass die Nutzer stets unterhalb der Grenzwerte bleiben, ab denen die
|
||||||
|
meisten Pr\"ufschritte aufgrund regulatorischer Bestimmungen erforderlich
|
||||||
|
werden. \TALER{} stellt dar\"uber hinaus sicher, dass die Nutzer
|
||||||
|
ausschliesslich in \LAND{} ans\"assig sind
|
||||||
|
(siehe Abschnitt~\ref{sec:proc:domestic}), da auf ihrer Seite ein Bankkonto
|
||||||
|
in \LAND{} f\"ur die \"Uberweisungen an den Taler-Exchange und/oder
|
||||||
|
eine Telefonnummer mit entsprechender Vorwahl (++41) ben\"otigt werden.
|
||||||
|
Zus\"atzlich setzt das Taler-Wallet zu jeder Zeit eine Obergrenze
|
||||||
|
von 5.000 \CURRENCY{} auf die Coin-Betr\"age in Summe fest, so dass es
|
||||||
|
keine weitere Abhebung \"uber diesen Grenzwert hinaus bewirken kann.
|
||||||
|
|
||||||
|
F\"ur {\bf Verk\"aufer} beginnt ein gesch\"aftliches Nutzungsverh\"altnis
|
||||||
|
mit \TALER{}, sobald sie Geldeing\"ange auf ihren IBAN-Bankkonten erhalten,
|
||||||
|
die als Zahlungen von Nutzern des Taler-Bezahlsystems ausgel\"ost wurden
|
||||||
|
(siehe Abschnitt~\ref{sec:deposit}). Sollten die Summen der Eing\"ange
|
||||||
|
5.000 \CURRENCY{} pro Monat bzw. 15.000 \CURRENCY{} pro Jahr \"ubersteigen,
|
||||||
|
kommt es zu einer KYB-Pr\"ufung, die dem Begriff ``Er\"offnen'' eines
|
||||||
|
Kontos entspricht und die eine aktualisierte KYB-Information sowie
|
||||||
|
die Pr\"ufung von Sanktionslisten erfordert, sofern der Verk\"aufer
|
||||||
|
innerhalb von 24 Monaten wenigstens einen Geldeingang erhielt.
|
||||||
|
|
||||||
|
Im Gegensatz zu normalen Nutzern k\"onnen Verk\"aufer im Prinzip
|
||||||
|
Zahlungen ohne Limit empfangen. Allerdings m\"ussen diese Transaktionen
|
||||||
|
auch wirklich als Eing\"ange auf dem Bankkonto des Unternehmens verzeichnet
|
||||||
|
werden (im Kontoauszug). In Abh\"angigkeit von den an das Gesch\"aftskonto
|
||||||
|
\"uberwiesenen Betr\"agen wird der Verk\"aufer einer KYB-Pr\"ufung unterzogen
|
||||||
|
(siehe Abschnitt~\ref{sec:KYB}). Dies gilt ebenso f\"ur
|
||||||
|
Geldw\"asche-\"Uberpr\"ufungen (AML checks).
|
||||||
|
|
||||||
|
Das Taler-Bezahlsystem transferiert lediglich Gelder auf die bestehenden
|
||||||
|
Bankkonten der Verk\"aufer, die f\"ur ihre G\"uterleistungen Zahlungen
|
||||||
|
der Nutzer erhalten, f\"ur die bereits bei der \"Uberweisung von deren
|
||||||
|
Kundenkonten eine KYC-Pr\"ufung erfolgte. Daher wird unseres Erachtens
|
||||||
|
der Betreiber eines Taler-Exchange keine Mittelherkunft verlangen bzw.
|
||||||
|
nachweisen m\"ussen
|
||||||
|
\footnote{Wenn Unternehmen das Taler-Bezahlsystem ihrerseits f\"ur
|
||||||
|
Zahlungen nutzen wollen, m\"ussen sie genauso wie alle anderen Nutzer
|
||||||
|
zuerst Geld von ihrem Bankkonto an einen Taler-Exchange \"uberweisen,
|
||||||
|
eine KYC-Pr\"ufung absolvieren und dann ihr Wallet Coins abheben lassen.
|
||||||
|
F\"ur die gesch\"aftlichen K\"aufer gelten ebenfalls die Limits wie
|
||||||
|
f\"ur alle anderen Nutzer.}.
|
||||||
|
|
||||||
|
|
||||||
|
\include{int-withdraw}
|
||||||
|
\include{int-deposit}
|
||||||
|
\include{int-pay}
|
||||||
|
\include{int-refund}
|
||||||
|
\include{int-push}
|
||||||
|
\include{int-pull}
|
||||||
|
\include{int-shutdown}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\chapter{Regulatory Triggers} \label{chap:triggers}
|
||||||
|
|
||||||
|
In this chapter we show decision diagrams for regulatory processes of the
|
||||||
|
various core operations of the GNU Taler payment system. In each case, the
|
||||||
|
{\bf start} state refers to one of the interactions described in the previous
|
||||||
|
chapter. The payment system will then use the process to arrive at an {\bf
|
||||||
|
allow} decision which permits the transaction to go through, or at a {\bf
|
||||||
|
deny} decision which ensures that the funds are not moved.
|
||||||
|
|
||||||
|
The specific {\em decisions} (in green) depend on the risk profile and the
|
||||||
|
regulatory environment. The tables in each section list the specific values
|
||||||
|
that are to be configured.
|
||||||
|
|
||||||
|
There are five types if interactions that can trigger regulatory processes:
|
||||||
|
|
||||||
|
\begin{description}
|
||||||
|
\item[withdraw] a customer withdraws digital cash from their {\bf bank account}
|
||||||
|
\item[deposit] a merchant's {\bf bank account} is designated to receive a payment in digital cash
|
||||||
|
\item[push] a {\bf wallet} accepts a payment from another wallet
|
||||||
|
\item[pull] a {\bf wallet} requests a payment from another wallet
|
||||||
|
\item[balance] a withdraw or P2P payment causes the balance of a {\bf wallet} to exceed a given threshold
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
We note in bold the {\bf anchor} for the regulator process. The anchor is used
|
||||||
|
to link the interaction to an identity. Once an identity has been established
|
||||||
|
for a particular anchor, that link is considered established for all types of
|
||||||
|
activities involving that anchor. A wallet is uniquely identified in the
|
||||||
|
system by its unique cryptographic key. A bank account is uniquely identified
|
||||||
|
in the system by its (RFC 8905) bank routing data (usually including BIC, IBAN
|
||||||
|
and account owner name).
|
||||||
|
|
||||||
|
The KYC and AML processes themselves are described in
|
||||||
|
Chapter~\ref{chap:regproc}.
|
||||||
|
|
||||||
|
\include{kyc-withdraw}
|
||||||
|
\include{kyc-deposit}
|
||||||
|
\include{kyc-push}
|
||||||
|
\include{kyc-pull}
|
||||||
|
\include{kyc-balance}
|
||||||
|
|
||||||
|
\chapter{Regulatory Processes} \label{chap:regproc}
|
||||||
|
|
||||||
|
This chapter describes the interactions between the customer, exchange and
|
||||||
|
organizations or staff assisting with regulatory processes designed to ensure
|
||||||
|
that customers are residents in the area of operation of the payment service
|
||||||
|
provider, are properly identified, and do not engage in money laundering.
|
||||||
|
|
||||||
|
The three main regulatory processes are:
|
||||||
|
|
||||||
|
\begin{description}
|
||||||
|
\item[domestic check] This process establishes that a user is generally
|
||||||
|
eligible to use the payment system. The process checks that the user has an
|
||||||
|
eligible address, but stops short of establishing the user's identity.
|
||||||
|
\item[kyc] This process establishes a user's legal identity, possibly
|
||||||
|
using external providers to review documents and check against blacklists.
|
||||||
|
\item[aml] The AML process reviews suspicious payment activities for
|
||||||
|
money laundering. Here AML staff reviews all collected information.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
\include{proc-domestic}
|
||||||
|
%\include{proc-kyc}
|
||||||
|
\include{proc-kyb}
|
||||||
|
\include{proc-aml}
|
||||||
|
|
||||||
|
\chapter{Fees} \label{chap:fees}
|
||||||
|
|
||||||
|
The business model for operating a Taler exchange is to charge transaction
|
||||||
|
fees. Fees are charged on certain operations by the exchange. There are two
|
||||||
|
types of fees, {\bf wire fees} and {\bf coin fees}. This chapter describes
|
||||||
|
the fee structure.
|
||||||
|
|
||||||
|
Fixed, amount-independent {\bf wire fees} are charged on wire transfers using
|
||||||
|
the core banking system. Details on wire fees are described in
|
||||||
|
Section~\ref{sec:fees:wire}.
|
||||||
|
|
||||||
|
Coin fees are more complex, as they do not exactly follow neither the usual
|
||||||
|
percentage of volume model of other payment systems. Instead, coin fees are
|
||||||
|
applied per coin, resulting in a {\em logarithmic} fee structure. As a
|
||||||
|
result, the effective fee {\em percentage} for tiny transactions is high (for
|
||||||
|
example 50\% for transactions of 0.0025 CHF) while the effective fee
|
||||||
|
percentage for large transactions is nominal (for example $\approx$ 0.05\% for
|
||||||
|
transactions of $\approx$ 40 CHF). Details on coin fees are described in
|
||||||
|
Section~\ref{sec:fees:coin}.
|
||||||
|
|
||||||
|
Fees are configurable (and that fee types beyond those described here are
|
||||||
|
supported by the software). Thus, the specific fees may be adjusted in the
|
||||||
|
future based on business decisions. However, changes to the fees are never
|
||||||
|
retroactively applied to coins already in circulation. Wire fees that have
|
||||||
|
been publicly announced for a particular time period also cannot be changed.
|
||||||
|
Finally, any change to the terms of service must also be explicitly accepted
|
||||||
|
by the users before they withdraw additional funds.
|
||||||
|
|
||||||
|
|
||||||
|
\include{fees-wire}
|
||||||
|
\include{fees-coins}
|
||||||
|
%\include{fees-other}
|
||||||
|
|
||||||
|
|
||||||
|
\end{document}
|
206
doc/flows/main.tex
Normal file
206
doc/flows/main.tex
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
\documentclass[10pt,a4paper,oneside]{book}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage{url}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{qrcode}
|
||||||
|
\usepackage{pgf-umlsd}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usetikzlibrary{shapes,arrows}
|
||||||
|
\usetikzlibrary{positioning}
|
||||||
|
\usetikzlibrary{calc}
|
||||||
|
\usetikzlibrary{quotes}
|
||||||
|
\author{Christian Grothoff}
|
||||||
|
\title{Flows in the GNU Taler System}
|
||||||
|
|
||||||
|
\newcommand\CURRENCY{CHF}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\chapter{Interactions} \label{chap:interactions}
|
||||||
|
|
||||||
|
This chapter introduces the main payment interactions in the GNU Taler payment
|
||||||
|
system. For each interaction, we introduce the parties involved and in which
|
||||||
|
order they interact and how. In each interaction it is possible that the
|
||||||
|
Taler exchange needs to trigger a compliance process. These regulatory
|
||||||
|
riggers are described in more detail in Chapter~\ref{chap:triggers}.
|
||||||
|
|
||||||
|
The main interactions of the system are:
|
||||||
|
|
||||||
|
\begin{description}
|
||||||
|
\item[withdraw] a customer withdraws digital cash to their wallet
|
||||||
|
\item[deposit] a customer returns digital cash into their bank account
|
||||||
|
\item[pay] a customer pays into bank account of a merchant
|
||||||
|
\item[refund] a merchant decides to return funds to a customer
|
||||||
|
\item[push] a customer sends a payment to another wallet
|
||||||
|
\item[pull] a customer requests a payment from another wallet (effectively sending an invoice)
|
||||||
|
\item[shutdown] the Taler payment system operator informs the customers that the system is being shut down for good
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
In the analysis of the legal requirements, it is important to differentiate
|
||||||
|
between transactions between wallets (customer-to-customer) and transactions
|
||||||
|
where money flows from a wallet into a bank account (customer-to-merchant) as
|
||||||
|
these have different limits: When digital coins are used to pay at a business in
|
||||||
|
Taler, the business never actually receives usable digital coins but instead
|
||||||
|
the amount is always directly credited to their bank account. Depending on
|
||||||
|
the transacted amounts, the business will nevertheless be subject to KYB
|
||||||
|
(Section~\ref{sec:proc:kyb}) and AML checks.
|
||||||
|
|
||||||
|
{\bf Customers} begin their business relationship with us when they withdraw
|
||||||
|
digital cash. Taler has no accounts (this is digital cash) and thus there is
|
||||||
|
no ``opening'' or ``closing'' of accounts for consumers. Given digital cash,
|
||||||
|
the customers can either (1) deposit the funds explicitly into a bank account
|
||||||
|
(see Section~\ref{sec:deposit}), (2) pay a merchant (see
|
||||||
|
Section~\ref{sec:pay}), (3) pay another customer using a peer-to-peer
|
||||||
|
transfer (see Sections~\ref{sec:push} and~\ref{sec:pull}), or (4) the coins
|
||||||
|
will expire if the wallet was lost (including offline for a long time or
|
||||||
|
uninstalled). Finally, if a wallet remains (occasionally) online but a user
|
||||||
|
does simply not spend the coins will (5) diminish in value from the change
|
||||||
|
fees (see Section~\ref{sec:fees:coin}) that apply to prevent the coins from
|
||||||
|
expiring outright.
|
||||||
|
|
||||||
|
For customers, we will categorically limit of digital cash withdrawn per month
|
||||||
|
to less than CHF 5'000 per month and less than CHF 25'000 per year, thus
|
||||||
|
ensuring that consumers remain below the thresholds where most regulatory
|
||||||
|
processes become applicable. Payments between users will be limited
|
||||||
|
to receiving less than CHF 1'000 per month and less than CHF 5'000 per year.
|
||||||
|
We will ensure that customers are Swiss
|
||||||
|
(see Section~\ref{sec:proc:domestic}) by requiring them to have a Swiss bank
|
||||||
|
account and/or Swiss phone number (+41-prefix).
|
||||||
|
%Furthermore, the wallet will
|
||||||
|
%impose an upper limit of CHF 5000 on its balance at any point in time.
|
||||||
|
|
||||||
|
For {\bf merchants}, the Taler equivalent of ``opening'' an account and thus
|
||||||
|
establishing an ongoing business relationship is for a business to receive
|
||||||
|
payments (see Section~\ref{sec:pay}) exceeding CHF 5'000/month or CHF
|
||||||
|
25'000/year. We will consider the account ``open'' (and require up-to-date KYB
|
||||||
|
information and check sanction lists) as long as the business has made any
|
||||||
|
transactions within the last 24 months.
|
||||||
|
|
||||||
|
As we will only transfer money into the existing bank accounts of the
|
||||||
|
merchants to compensate them for sales made using the Taler payment system, we
|
||||||
|
do not need to check the origin of funds for those merchants as they will only
|
||||||
|
receive funds from us.\footnote{Should businesses want to use Taler for
|
||||||
|
expenditures, they will need to withdraw digital coins from their bank account
|
||||||
|
just like customers, and the limits for customers will continue to apply.}
|
||||||
|
|
||||||
|
For individual {\bf transactions}, we will impose a limit of CHF
|
||||||
|
1'000/transaction (even though our reading of the regulations would permit
|
||||||
|
individual transactions up to CHF 15'000).
|
||||||
|
|
||||||
|
The following sections describe the respective processes for each of these
|
||||||
|
interactions.
|
||||||
|
|
||||||
|
\include{int-withdraw}
|
||||||
|
\include{int-deposit}
|
||||||
|
\include{int-pay}
|
||||||
|
\include{int-refund}
|
||||||
|
\include{int-push}
|
||||||
|
\include{int-pull}
|
||||||
|
\include{int-shutdown}
|
||||||
|
|
||||||
|
|
||||||
|
\chapter{Regulatory Triggers} \label{chap:triggers}
|
||||||
|
|
||||||
|
In this chapter we show decision diagrams for regulatory processes of the
|
||||||
|
various core operations of the GNU Taler payment system. In each case, the
|
||||||
|
{\bf start} state refers to one of the interactions described in the previous
|
||||||
|
chapter. The payment system will then use the process to arrive at an {\bf
|
||||||
|
allow} decision which permits the transaction to go through, or at a {\bf
|
||||||
|
deny} decision which ensures that the funds are not moved.
|
||||||
|
|
||||||
|
The specific {\em decisions} (in green) depend on the risk profile and the
|
||||||
|
regulatory environment. The tables in each section list the specific values
|
||||||
|
that are to be configured.
|
||||||
|
|
||||||
|
There are five types if interactions that can trigger regulatory processes:
|
||||||
|
|
||||||
|
\begin{description}
|
||||||
|
\item[withdraw] a customer withdraws digital cash from their {\bf bank account}
|
||||||
|
\item[deposit] a customer or merchant's {\bf bank account} is
|
||||||
|
designated to receive a payment due someone paying with or
|
||||||
|
depositing digital cash
|
||||||
|
\item[push] a {\bf wallet} accepts a payment from another wallet
|
||||||
|
\item[pull] a {\bf wallet} requests a payment from another wallet
|
||||||
|
% \item[balance] a withdraw or P2P payment causes the balance of a {\bf wallet} to exceed a given threshold
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
We note in bold the {\bf anchor} for the regulator process. The anchor is used
|
||||||
|
to link the interaction to an identity. Once an identity has been established
|
||||||
|
for a particular anchor, that link is considered established for all types of
|
||||||
|
activities involving that anchor. A wallet is uniquely identified in the
|
||||||
|
system by its unique cryptographic key. A bank account is uniquely identified
|
||||||
|
in the system by its (RFC 8905) bank routing data (usually including BIC, IBAN
|
||||||
|
and account owner name).
|
||||||
|
|
||||||
|
The KYC and AML processes themselves are described in
|
||||||
|
Chapter~\ref{chap:regproc}.
|
||||||
|
|
||||||
|
\include{kyc-withdraw}
|
||||||
|
\include{kyc-deposit}
|
||||||
|
\include{kyc-push}
|
||||||
|
\include{kyc-pull}
|
||||||
|
%\include{kyc-balance}
|
||||||
|
|
||||||
|
\chapter{Regulatory Processes} \label{chap:regproc}
|
||||||
|
|
||||||
|
This chapter describes the interactions between the customer, exchange and
|
||||||
|
organizations or staff assisting with regulatory processes designed to ensure
|
||||||
|
that customers are residents in the area of operation of the payment service
|
||||||
|
provider, are properly identified, and do not engage in money laundering.
|
||||||
|
|
||||||
|
The three main regulatory processes are:
|
||||||
|
|
||||||
|
\begin{description}
|
||||||
|
\item[domestic check] This process establishes that a user is generally
|
||||||
|
eligible to use the payment system. The process checks that the user has an
|
||||||
|
eligible address, but stops short of establishing the user's identity.
|
||||||
|
\item[kyc] This process establishes a user's legal identity, possibly
|
||||||
|
using external providers to review documents and check against blacklists.
|
||||||
|
\item[aml] The AML process reviews suspicious payment activities for
|
||||||
|
money laundering. Here AML staff reviews all collected information.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
\include{proc-domestic}
|
||||||
|
\include{proc-kyc}
|
||||||
|
\include{proc-kyb}
|
||||||
|
\include{proc-aml}
|
||||||
|
|
||||||
|
\chapter{Fees} \label{chap:fees}
|
||||||
|
|
||||||
|
The business model for operating a Taler exchange is to charge transaction
|
||||||
|
fees. Fees are charged on certain operations by the exchange. There are two
|
||||||
|
types of fees, {\bf wire fees} and {\bf coin fees}. This chapter describes
|
||||||
|
the fee structure.
|
||||||
|
|
||||||
|
Fixed, amount-independent {\bf wire fees} are charged on wire transfers using
|
||||||
|
the core banking system. Details on wire fees are described in
|
||||||
|
Section~\ref{sec:fees:wire}.
|
||||||
|
|
||||||
|
Coin fees are more complex, as they do not exactly follow neither the usual
|
||||||
|
percentage of volume model of other payment systems. Instead, coin fees are
|
||||||
|
applied per coin, resulting in a {\em logarithmic} fee structure. As a
|
||||||
|
result, the effective fee {\em percentage} for tiny transactions is high (for
|
||||||
|
example 50\% for transactions of 0.0025 CHF) while the effective fee
|
||||||
|
percentage for large transactions is nominal (for example $\approx$ 0.05\% for
|
||||||
|
transactions of $\approx$ 40 CHF). Details on coin fees are described in
|
||||||
|
Section~\ref{sec:fees:coin}.
|
||||||
|
|
||||||
|
Fees are configurable (and that fee types beyond those described here are
|
||||||
|
supported by the software). Thus, the specific fees may be adjusted in the
|
||||||
|
future based on business decisions. However, changes to the fees are never
|
||||||
|
retroactively applied to coins already in circulation. Wire fees that have
|
||||||
|
been publicly announced for a particular time period also cannot be changed.
|
||||||
|
Finally, any change to the terms of service must also be explicitly accepted
|
||||||
|
by the users before they withdraw additional funds.
|
||||||
|
|
||||||
|
|
||||||
|
\include{fees-wire}
|
||||||
|
\include{fees-coins}
|
||||||
|
%\include{fees-other}
|
||||||
|
|
||||||
|
|
||||||
|
\end{document}
|
47
doc/flows/proc-aml.tex
Normal file
47
doc/flows/proc-aml.tex
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
\section{AML process}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Action};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{staff}{\shortstack{AML staff \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Access \\ Token};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{wallet}{{Initial action}}{exchange}
|
||||||
|
\begin{callself}{exchange}{Establish AML requirement}{}
|
||||||
|
\end{callself}
|
||||||
|
\begin{callself}{exchange}{Queue AML task}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{exchange}{Wait for AML}{wallet}
|
||||||
|
\mess[0]{staff}{Request AML work}{exchange}
|
||||||
|
\mess[0]{exchange}{{Open AML task(s)}}{staff}
|
||||||
|
\mess[0]{staff}{Request details}{exchange}
|
||||||
|
\mess[0]{exchange}{KYC/AML data}{staff}
|
||||||
|
\begin{callself}{staff}{Review and decide}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{staff}{{Decision documentation}}{exchange}
|
||||||
|
\mess[0]{exchange}{AML decision}{wallet}
|
||||||
|
\mess[0]{wallet}{{Retry action}}{exchange}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Deposit interactions between customer, Taler exchange (payment
|
||||||
|
service provider) and the AML staff. The process can be
|
||||||
|
triggered by various {\em actions} described in Chapter~\ref{chap:triggers}.
|
||||||
|
AML staff interactions are cryptographically secured and
|
||||||
|
decisions and the provided reasoning are archived by the exchange.
|
||||||
|
AML staff may interact with the customer (out-of-band)
|
||||||
|
in its decision process.
|
||||||
|
}
|
||||||
|
\label{fig:proc:aml}
|
||||||
|
\end{figure}
|
66
doc/flows/proc-domestic.tex
Normal file
66
doc/flows/proc-domestic.tex
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
\section{Domestic wallet check} \label{sec:proc:domestic}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer wallet \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Wallet ID};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{sms}{\shortstack{Address validator}}
|
||||||
|
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{wallet}{{P2P payment (Wallet ID)}}{exchange}
|
||||||
|
\begin{callself}{exchange}{New wallet?}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{exchange}{Request address validation}{sms}
|
||||||
|
\mess[0]{sms}{Validation process ID}{exchange}
|
||||||
|
\mess[0]{exchange}{Request address validation}{wallet}
|
||||||
|
\mess[0]{wallet}{Send address}{sms}
|
||||||
|
\mess[0]{sms}{{Send confirmation code (to address)}}{wallet}
|
||||||
|
\mess[0]{wallet}{Supply confirmation code}{sms}
|
||||||
|
\mess[0]{sms}{{Confirmed customer address}}{exchange}
|
||||||
|
\mess[0]{exchange}{{Confirm completion}}{wallet}
|
||||||
|
\mess[0]{wallet}{{Retry action}}{exchange}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Deposit interactions between customer, Taler exchange (payment
|
||||||
|
service provider) and external address validation service. The process can be
|
||||||
|
triggered by wallet-to-wallet (P2P) payments described in Chapter~\ref{chap:triggers}.}
|
||||||
|
\label{fig:proc:domestic}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Our users have to accept the terms of service which restrict the use of the
|
||||||
|
service to domestic customers. For interactions with the core banking system,
|
||||||
|
this simply means that we only accept payments from or to domestic bank
|
||||||
|
accounts. For P2P payments between wallets, we require that the wallets are
|
||||||
|
controlled by a domestic entity. We define domestic entities as those that
|
||||||
|
are able to receive messages at a domestic address. Two types of addresses are
|
||||||
|
supported:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Control over a domestic {\bf mobile phone number} is established
|
||||||
|
by sending an SMS message with a confirmation code to the MSIN.
|
||||||
|
\item Control over a domestic {\bf postal address} is established by
|
||||||
|
sending a letter with a confirmation code to the address.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Depending on the type of address, a validation has a limited validity period,
|
||||||
|
as shown in Table~\ref{table:proc:domestic}. When the validity period is
|
||||||
|
over, a wallet has to re-do the address validation before they can receive any
|
||||||
|
further funds through the service.
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\caption{Restrictions on address validations}
|
||||||
|
\label{table:proc:domestic}
|
||||||
|
\begin{tabular}{l|l|r}
|
||||||
|
{\bf Type} & {\bf Validity period} & {\bf Restricted to} \\ \hline \hline
|
||||||
|
Mobile phone number & 12 months & {\em +41} \\
|
||||||
|
Postal address & 36 months & {\em Switzerland} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
97
doc/flows/proc-kyb.tex
Normal file
97
doc/flows/proc-kyb.tex
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
\section{KYB process} \label{sec:proc:kyb}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{merchant}{\shortstack{Merchant \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Action};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{kyb}{\shortstack{KYB provider \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{merchant}{{Initial action}}{exchange}
|
||||||
|
\begin{callself}{exchange}{Establish KYB requirement}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{exchange}{Request new KYB process}{kyb}
|
||||||
|
\mess[0]{kyb}{{Process identifier (PI)}}{exchange}
|
||||||
|
\mess[0]{exchange}{{KYB required (PI)}}{merchant}
|
||||||
|
\mess[0]{merchant}{{KYB start (PI)}}{kyb}
|
||||||
|
\mess[0]{kyb}{{Request identity documentation}}{merchant}
|
||||||
|
\mess[0]{merchant}{{Upload identity documentation}}{kyb}
|
||||||
|
\begin{callself}{kyb}{Validate documentation}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{kyb}{{Share documentation (PI)}}{exchange}
|
||||||
|
\mess[0]{kyb}{{Confirm completion}}{merchant}
|
||||||
|
\mess[0]{merchant}{{Retry action}}{exchange}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Deposit interactions between customer, Taler exchange (payment
|
||||||
|
service provider) and external KYB provider. The process can be
|
||||||
|
triggered by various {\em actions} described in Chapter~\ref{chap:triggers}.}
|
||||||
|
\label{fig:proc:kyb}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
At the beginning of the KYB process, the user needs to specify whether they
|
||||||
|
are an {\bf individual} (not incorporated) or a {\bf business}.\footnote{In
|
||||||
|
practice, we expect most owners of bank accounts crossing the KYB threshold to
|
||||||
|
be businesses, but in principle such a bank account could be owned by an
|
||||||
|
individual operating a business without a separate legal entity.} This then
|
||||||
|
determines which types of attributes are collected in the KYB process
|
||||||
|
(Table~\ref{table:proc:kyb:individual}
|
||||||
|
vs. Table~\ref{table:proc:kyb:business}).
|
||||||
|
|
||||||
|
\begin{table}
|
||||||
|
\caption{Information collected for unincorporated individuals}
|
||||||
|
\label{table:proc:kyb:individual}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{l|c|r}
|
||||||
|
{\bf Type} & {\bf Required} & {\bf Example} \\ \hline \hline
|
||||||
|
Surname & yes & Mustermann \\
|
||||||
|
First name(s) & yes & Max \\
|
||||||
|
Date of birth & yes & 1.1.1980 \\
|
||||||
|
Nationality & yes & Swiss \\
|
||||||
|
Actual address of domicile & yes & Seestrasse 3, 8008 Zuerich \\
|
||||||
|
Phone number & no & +41-123456789 \\
|
||||||
|
E-mail & no & me@example.com \\
|
||||||
|
Identification document & yes & JPG image \\
|
||||||
|
Taxpayer identification & yes & ZPV Nr. 253'123'456 \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{table}
|
||||||
|
\caption{Information collected for businesses. Information on individals is
|
||||||
|
collected for owners with more than 25\% ownership and for those with
|
||||||
|
signature authority for the business.}
|
||||||
|
\label{table:proc:kyb:business}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{l|c|r}
|
||||||
|
{\bf Type} & {\bf Required} & {\bf Example} \\ \hline \hline
|
||||||
|
Company name & yes & Mega AG \\
|
||||||
|
Registered office & yes & Seestrasse 4, 8008 Zuerich \\
|
||||||
|
Company identification document & yes & PDF file \\
|
||||||
|
Power of attorney arrangement & yes & PDF file \\
|
||||||
|
Business registration number & yes & \\
|
||||||
|
Business registration document & yes & PDF file \\
|
||||||
|
Registration authority & yes & \\ \hline
|
||||||
|
Contact person name & yes & Max Mustermann \\
|
||||||
|
Identification document & yes & JPG image \\
|
||||||
|
Date of birth & yes & 1.1.1980 \\
|
||||||
|
Nationality & yes & Swiss \\
|
||||||
|
E-mail & yes & me@example.com \\
|
||||||
|
Phone number & no & +41-123456789 \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
88
doc/flows/proc-kyc.tex
Normal file
88
doc/flows/proc-kyc.tex
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
\section{KYC process}
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{sequencediagram}
|
||||||
|
\newinst{wallet}{\shortstack{Customer \\
|
||||||
|
\\ \begin{tikzpicture}
|
||||||
|
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Action};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
\newinst[2]{kyc}{\shortstack{KYC provider \\
|
||||||
|
\\ \begin{tikzpicture}[shape aspect=.5]
|
||||||
|
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
|
||||||
|
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
|
||||||
|
\end{tikzpicture}
|
||||||
|
}}
|
||||||
|
|
||||||
|
\postlevel
|
||||||
|
\mess[0]{wallet}{{Initial action}}{exchange}
|
||||||
|
\begin{callself}{exchange}{Establish KYC requirement}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{exchange}{Request new KYC process}{kyc}
|
||||||
|
\mess[0]{kyc}{{Process identifier (PI)}}{exchange}
|
||||||
|
\mess[0]{exchange}{{KYC required (PI)}}{wallet}
|
||||||
|
\mess[0]{wallet}{{KYC start (PI)}}{kyc}
|
||||||
|
\mess[0]{kyc}{{Request identity documentation}}{wallet}
|
||||||
|
\mess[0]{wallet}{{Upload identity documentation}}{kyc}
|
||||||
|
\begin{callself}{kyc}{Validate documentation}{}
|
||||||
|
\end{callself}
|
||||||
|
\mess[0]{kyc}{{Share documentation (PI)}}{exchange}
|
||||||
|
\mess[0]{kyc}{{Confirm completion}}{wallet}
|
||||||
|
\mess[0]{wallet}{{Retry action}}{exchange}
|
||||||
|
\end{sequencediagram}
|
||||||
|
\caption{Deposit interactions between customer, Taler exchange (payment
|
||||||
|
service provider) and external KYC provider. The process can be
|
||||||
|
triggered by various {\em actions} described in Chapter~\ref{chap:triggers}.}
|
||||||
|
\label{fig:proc:kyc}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
At the beginning of the KYC process, the user needs to specify whether they
|
||||||
|
are an {\bf individual} or a {\bf business}.\footnote{ In practice, we expect
|
||||||
|
most wallet-users to be individuals, but in principle a wallet could be owned
|
||||||
|
by a business.} This then determines which types of attributes are collected
|
||||||
|
in the KYC process (Table~\ref{table:proc:kyc:individual} vs.
|
||||||
|
Table~\ref{table:proc:kyc:business}).
|
||||||
|
|
||||||
|
\begin{table}
|
||||||
|
\caption{Information collected for individuals}
|
||||||
|
\label{table:proc:kyc:individual}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{l|c|r}
|
||||||
|
{\bf Type} & {\bf Required} & {\bf Example} \\ \hline \hline
|
||||||
|
Surname & yes & Mustermann \\
|
||||||
|
First name(s) & yes & Max \\
|
||||||
|
Date of birth & yes & 1.1.1980 \\
|
||||||
|
Nationality & yes & Swiss \\
|
||||||
|
Actual address of domicile & yes & Seestrasse 3, 8008 Zuerich \\
|
||||||
|
Phone number & no & +41-123456789 \\
|
||||||
|
E-mail & no & me@example.com \\
|
||||||
|
Identification document & yes & JPG image \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
\begin{table}
|
||||||
|
\caption{Information collected for businesses}
|
||||||
|
\label{table:proc:kyc:business}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{l|c|r}
|
||||||
|
{\bf Type} & {\bf Required} & {\bf Example} \\ \hline \hline
|
||||||
|
Company name & yes & Mega AG \\
|
||||||
|
Registered office & yes & Seestrasse 4, 8008 Zuerich \\
|
||||||
|
Company identification document & yes & PDF file \\ \hline
|
||||||
|
Contact person name & yes & Max Mustermann \\
|
||||||
|
Phone number & no & +41-123456789 \\
|
||||||
|
E-mail & yes & me@example.com \\
|
||||||
|
Identification document & yes & JPG image \\
|
||||||
|
Date of birth & yes & 1.1.1980 \\
|
||||||
|
Nationality & yes & Swiss \\ \hline
|
||||||
|
Power of attorney arrangement & yes & PDF file \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
@ -1 +1 @@
|
|||||||
Subproject commit 8452f991dd967328207fab52a99beb19e2cb4dff
|
Subproject commit 6026efb59ef8c41e5b86e68332780d387fdaab0a
|
@ -218,6 +218,7 @@ EXTRA_DIST = \
|
|||||||
taler-auditor.in \
|
taler-auditor.in \
|
||||||
taler-helper-auditor-render.py \
|
taler-helper-auditor-render.py \
|
||||||
auditor.conf \
|
auditor.conf \
|
||||||
|
setup.sh \
|
||||||
test-sync-in.conf \
|
test-sync-in.conf \
|
||||||
test-sync-out.conf \
|
test-sync-out.conf \
|
||||||
generate-auditor-basedb.sh \
|
generate-auditor-basedb.sh \
|
||||||
|
@ -17,7 +17,7 @@ AUDITOR_PRIV_FILE = ${TALER_DATA_HOME}/auditor/offline-keys/auditor.priv
|
|||||||
|
|
||||||
# What is the Web site of the auditor (i.e. to file complaints about
|
# What is the Web site of the auditor (i.e. to file complaints about
|
||||||
# a misbehaving exchange)?
|
# a misbehaving exchange)?
|
||||||
# BASE_URL = https://auditor.taler.net/
|
BASE_URL = http://localhost:8083/
|
||||||
|
|
||||||
|
|
||||||
# Network configuration for the normal API/service HTTP server
|
# Network configuration for the normal API/service HTTP server
|
||||||
|
@ -1,14 +1,27 @@
|
|||||||
[exchange-offline]
|
[PATHS]
|
||||||
MASTER_PRIV_FILE = auditor-basedb.mpriv
|
TALER_CACHE_HOME = $TALER_HOME/.cache/taler/
|
||||||
|
TALER_CONFIG_HOME = $TALER_HOME/.config/taler/
|
||||||
|
TALER_DATA_HOME = $TALER_HOME/.local/share/taler/
|
||||||
|
TALER_HOME = ${PWD}/generate_auditordb_home/
|
||||||
|
|
||||||
[instance-default]
|
[taler]
|
||||||
KEYFILE = ${TALER_DATA_HOME}/merchant/default.priv
|
CURRENCY = TESTKUDOS
|
||||||
NAME = Merchant Inc.
|
CURRENCY_ROUND_UNIT = TESTKUDOS:0.01
|
||||||
|
|
||||||
|
[exchange]
|
||||||
|
MASTER_PUBLIC_KEY = M4FGP18EQFXFGGFQ1AWXHACN2JX0SMVK9CNF6459Z1WG18JSN0BG
|
||||||
|
SIGNKEY_DURATION = 4 weeks
|
||||||
|
LOOKAHEAD_SIGN = 32 weeks 1 day
|
||||||
|
SIGNKEY_LEGAL_DURATION = 4 weeks
|
||||||
|
AML_THRESHOLD = TESTKUDOS:1000000
|
||||||
|
|
||||||
|
[exchangedb-postgres]
|
||||||
|
CONFIG = postgres:///auditor-basedb
|
||||||
|
|
||||||
[exchange-account-1]
|
[exchange-account-1]
|
||||||
PAYTO_URI = payto://iban/SANDBOXX/DE989651?receiver-name=Exchange+Company
|
PAYTO_URI = payto://iban/SANDBOXX/DE989651?receiver-name=Exchange+Company
|
||||||
enable_debit = yes
|
ENABLE_DEBIT = YES
|
||||||
enable_credit = yes
|
ENABLE_CREDIT = YES
|
||||||
|
|
||||||
[exchange-accountcredentials-1]
|
[exchange-accountcredentials-1]
|
||||||
WIRE_GATEWAY_URL = http://localhost:8082/facades/test-facade/taler-wire-gateway/
|
WIRE_GATEWAY_URL = http://localhost:8082/facades/test-facade/taler-wire-gateway/
|
||||||
@ -16,24 +29,38 @@ WIRE_GATEWAY_AUTH_METHOD = basic
|
|||||||
USERNAME = exchange
|
USERNAME = exchange
|
||||||
PASSWORD = x
|
PASSWORD = x
|
||||||
|
|
||||||
[merchant-account-merchant]
|
[merchant]
|
||||||
PAYTO_URI = payto://x-taler-bank/localhost/42
|
WIREFORMAT = default
|
||||||
HONOR_default = YES
|
DEFAULT_MAX_DEPOSIT_FEE = TESTKUDOS:0.1
|
||||||
ACTIVE_default = YES
|
KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
|
||||||
|
DEFAULT_MAX_WIRE_FEE = TESTKUDOS:0.10
|
||||||
|
WIRE_TRANSFER_DELAY = 1 minute
|
||||||
|
FORCE_AUDIT = YES
|
||||||
|
|
||||||
|
[merchantdb-postgres]
|
||||||
|
CONFIG = postgres:///auditor-basedb
|
||||||
|
|
||||||
[merchant-exchange-default]
|
[merchant-exchange-default]
|
||||||
MASTER_KEY = RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470
|
MASTER_KEY = M4FGP18EQFXFGGFQ1AWXHACN2JX0SMVK9CNF6459Z1WG18JSN0BG
|
||||||
EXCHANGE_BASE_URL = http://localhost:8081/
|
EXCHANGE_BASE_URL = http://localhost:8081/
|
||||||
CURRENCY = TESTKUDOS
|
CURRENCY = TESTKUDOS
|
||||||
|
|
||||||
[payments-generator]
|
[bank]
|
||||||
currency = TESTKUDOS
|
HTTP_PORT = 8082
|
||||||
instance = default
|
|
||||||
bank = http://localhost:8082/
|
[libeufin-nexus]
|
||||||
merchant = http://localhost:9966/
|
DB_CONNECTION="jdbc:postgresql://localhost/auditor-basedb?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432"
|
||||||
exchange_admin = http://localhost:18080/
|
|
||||||
exchange-admin = http://localhost:18080/
|
[libeufin-sandbox]
|
||||||
exchange = http://localhost:8081/
|
DB_CONNECTION="jdbc:postgresql://localhost/auditor-basedb?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432"
|
||||||
|
|
||||||
|
[auditor]
|
||||||
|
BASE_URL = http://localhost:8083/
|
||||||
|
TINY_AMOUNT = TESTKUDOS:0.01
|
||||||
|
PUBLIC_KEY = 0EHPW5WEKHXPPN4MPJNGA7Z6D29JP21GKVNV8ARFB1YW7WWJX20G
|
||||||
|
|
||||||
|
[auditordb-postgres]
|
||||||
|
CONFIG = postgres:///auditor-basedb
|
||||||
|
|
||||||
[coin_kudos_ct_1]
|
[coin_kudos_ct_1]
|
||||||
value = TESTKUDOS:0.01
|
value = TESTKUDOS:0.01
|
||||||
@ -130,61 +157,3 @@ fee_refresh = TESTKUDOS:0.03
|
|||||||
fee_refund = TESTKUDOS:0.01
|
fee_refund = TESTKUDOS:0.01
|
||||||
CIPHER = RSA
|
CIPHER = RSA
|
||||||
rsa_keysize = 1024
|
rsa_keysize = 1024
|
||||||
|
|
||||||
[benchmark]
|
|
||||||
BANK_DETAILS = bank_details.json
|
|
||||||
MERCHANT_DETAILS = merchant_details.json
|
|
||||||
|
|
||||||
[arm]
|
|
||||||
CONFIG = /research/taler/exchange/src/auditor/auditor-basedb.conf
|
|
||||||
|
|
||||||
[taler]
|
|
||||||
CURRENCY_ROUND_UNIT = TESTKUDOS:0.01
|
|
||||||
CURRENCY = TESTKUDOS
|
|
||||||
AML_THRESHOLD = TESTKUDOS:1000000
|
|
||||||
|
|
||||||
[merchantdb-postgres]
|
|
||||||
CONFIG = postgres:///auditor-basedb
|
|
||||||
|
|
||||||
[merchant]
|
|
||||||
WIREFORMAT = default
|
|
||||||
DEFAULT_MAX_DEPOSIT_FEE = TESTKUDOS:0.1
|
|
||||||
KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
|
|
||||||
DEFAULT_MAX_WIRE_FEE = TESTKUDOS:0.10
|
|
||||||
WIRE_TRANSFER_DELAY = 1 minute
|
|
||||||
FORCE_AUDIT = YES
|
|
||||||
UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
|
|
||||||
|
|
||||||
[exchangedb-postgres]
|
|
||||||
CONFIG = postgres:///auditor-basedb
|
|
||||||
|
|
||||||
[exchange]
|
|
||||||
MASTER_PUBLIC_KEY = RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470
|
|
||||||
SIGNKEY_DURATION = 4 weeks
|
|
||||||
LOOKAHEAD_SIGN = 32 weeks 1 day
|
|
||||||
SIGNKEY_LEGAL_DURATION = 4 weeks
|
|
||||||
UNIXPATH = ${TALER_RUNTIME_DIR}/exchange.http
|
|
||||||
|
|
||||||
[bank]
|
|
||||||
HTTP_PORT = 8082
|
|
||||||
SUGGESTED_EXCHANGE = http://localhost:8081/
|
|
||||||
SUGGESTED_EXCHANGE_PAYTO = payto://x-taler-bank/localhost/2
|
|
||||||
ALLOW_REGISTRATIONS = YES
|
|
||||||
SERVE = http
|
|
||||||
MAX_DEBT_BANK = TESTKUDOS:100000.0
|
|
||||||
MAX_DEBT = TESTKUDOS:50.0
|
|
||||||
DATABASE = postgres:///auditor-basedb
|
|
||||||
|
|
||||||
[auditordb-postgres]
|
|
||||||
CONFIG = postgres:///auditor-basedb
|
|
||||||
|
|
||||||
[auditor]
|
|
||||||
BASE_URL = http://localhost:8083/
|
|
||||||
TINY_AMOUNT = TESTKUDOS:0.01
|
|
||||||
PUBLIC_KEY = 0EHPW5WEKHXPPN4MPJNGA7Z6D29JP21GKVNV8ARFB1YW7WWJX20G
|
|
||||||
|
|
||||||
[PATHS]
|
|
||||||
TALER_CACHE_HOME = $TALER_HOME/.cache/taler/
|
|
||||||
TALER_CONFIG_HOME = $TALER_HOME/.config/taler/
|
|
||||||
TALER_DATA_HOME = $TALER_HOME/.local/share/taler/
|
|
||||||
TALER_HOME = ${PWD}/generate_auditordb_home/
|
|
||||||
|
@ -1,412 +1,61 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Script to generate the basic database for auditor
|
# This file is in the public domain.
|
||||||
# testing from a 'correct' interaction between exchange,
|
|
||||||
# wallet and merchant.
|
|
||||||
#
|
#
|
||||||
# Creates $BASEDB.sql, $BASEDB.fees,
|
# Script to generate the basic database for auditor testing from a 'correct'
|
||||||
# $BASEDB.{mpub,mpriv}.
|
# interaction between exchange, wallet and merchant.
|
||||||
# Default $BASEDB is "auditor-basedb", override via $1.
|
|
||||||
#
|
#
|
||||||
# Currently must be run online as it interacts with
|
# Creates "$1.sql".
|
||||||
# bank.test.taler.net; also requires the wallet CLI
|
#
|
||||||
# to be installed and in the path. Furthermore, the
|
# Requires the wallet CLI to be installed and in the path. Furthermore, the
|
||||||
# user running this script must be Postgres superuser
|
# user running this script must be Postgres superuser and be allowed to
|
||||||
# and be allowed to create/drop databases.
|
# create/drop databases.
|
||||||
#
|
#
|
||||||
set -eu
|
set -eu
|
||||||
#set -x
|
|
||||||
|
|
||||||
# Cleanup to run whenever we exit
|
|
||||||
function exit_cleanup()
|
|
||||||
{
|
|
||||||
echo "Running generate-auditor-basedb exit cleanup logic..."
|
|
||||||
if test -f ${MY_TMP_DIR:-/}/libeufin-sandbox.pid
|
|
||||||
then
|
|
||||||
PID=`cat ${MY_TMP_DIR}/libeufin-sandbox.pid 2> /dev/null`
|
|
||||||
kill $PID 2> /dev/null || true
|
|
||||||
rm ${MY_TMP_DIR}/libeufin-sandbox.pid
|
|
||||||
echo "Killed libeufin sandbox $PID"
|
|
||||||
wait $PID || true
|
|
||||||
fi
|
|
||||||
if test -f ${MY_TMP_DIR:-/}/libeufin-nexus.pid
|
|
||||||
then
|
|
||||||
PID=`cat ${MY_TMP_DIR}/libeufin-nexus.pid 2> /dev/null`
|
|
||||||
kill $PID 2> /dev/null || true
|
|
||||||
rm ${MY_TMP_DIR}/libeufin-nexus.pid
|
|
||||||
echo "Killed libeufin nexus $PID"
|
|
||||||
wait $PID || true
|
|
||||||
fi
|
|
||||||
echo "killing libeufin DONE"
|
|
||||||
for n in `jobs -p`
|
|
||||||
do
|
|
||||||
kill $n 2> /dev/null || true
|
|
||||||
done
|
|
||||||
wait || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install cleanup handler (except for kill -9)
|
|
||||||
trap exit_cleanup EXIT
|
|
||||||
|
|
||||||
|
|
||||||
# Exit, with status code "skip" (no 'real' failure)
|
|
||||||
function exit_skip() {
|
|
||||||
echo "SKIPPING: $1"
|
|
||||||
exit 77
|
|
||||||
}
|
|
||||||
# Where do we write the result?
|
# Where do we write the result?
|
||||||
BASEDB=${1:-"auditor-basedb"}
|
BASEDB="$1"
|
||||||
# Name of the Postgres database we will use for the script.
|
|
||||||
# Will be dropped, do NOT use anything that might be used
|
|
||||||
# elsewhere
|
|
||||||
export TARGET_DB=`basename ${BASEDB}`
|
|
||||||
|
|
||||||
export WALLET_DB=${BASEDB:-"wallet"}.wdb
|
. setup.sh
|
||||||
|
|
||||||
# delete existing wallet database
|
echo -n "Testing for curl ..."
|
||||||
rm -f $WALLET_DB
|
|
||||||
|
|
||||||
# Configuration file will be edited, so we create one
|
|
||||||
# from the template.
|
|
||||||
export CONF=$1.conf
|
|
||||||
cp generate-auditor-basedb.conf $CONF
|
|
||||||
echo "Created configuration at ${CONF}"
|
|
||||||
DATA_DIR=$1/exchange-data-dir/
|
|
||||||
mkdir -p $DATA_DIR
|
|
||||||
taler-config -c $CONF -s PATHS -o TALER_HOME -V $DATA_DIR
|
|
||||||
|
|
||||||
echo -n "Testing for libeufin"
|
|
||||||
libeufin-cli --help >/dev/null </dev/null || exit_skip " MISSING"
|
|
||||||
echo " FOUND"
|
|
||||||
echo -n "Testing for taler-wallet-cli"
|
|
||||||
taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING"
|
|
||||||
echo " FOUND"
|
|
||||||
echo -n "Testing for curl"
|
|
||||||
curl --help >/dev/null </dev/null || exit_skip " MISSING"
|
curl --help >/dev/null </dev/null || exit_skip " MISSING"
|
||||||
echo " FOUND"
|
echo " FOUND"
|
||||||
|
|
||||||
|
CONF="generate-auditor-basedb.conf"
|
||||||
|
|
||||||
# reset database
|
# reset database
|
||||||
dropdb $TARGET_DB >/dev/null 2>/dev/null || true
|
echo -n "Reset 'auditor-basedb' database ..."
|
||||||
createdb $TARGET_DB || exit_skip "Could not create database $TARGET_DB"
|
dropdb "auditor-basedb" >/dev/null 2>/dev/null || true
|
||||||
ORIGIN=`pwd`
|
createdb "auditor-basedb" || exit_skip "Could not create database '$BASEDB'"
|
||||||
MY_TMP_DIR=`dirname $1`
|
echo " DONE"
|
||||||
|
|
||||||
|
# Launch exchange, merchant and bank.
|
||||||
|
setup -c "$CONF" \
|
||||||
|
-aenmsw \
|
||||||
|
-d "iban"
|
||||||
|
|
||||||
# obtain key configuration data
|
# obtain key configuration data
|
||||||
MASTER_PRIV_FILE=$1.mpriv
|
EXCHANGE_URL=$(taler-config -c "$CONF" -s EXCHANGE -o BASE_URL)
|
||||||
MASTER_PRIV_DIR=`dirname $MASTER_PRIV_FILE`
|
MERCHANT_PORT=$(taler-config -c "$CONF" -s MERCHANT -o PORT)
|
||||||
taler-config -f -c ${CONF} -s exchange-offline -o MASTER_PRIV_FILE -V ${MASTER_PRIV_FILE}
|
MERCHANT_URL="http://localhost:${MERCHANT_PORT}/"
|
||||||
rm -f "${MASTER_PRIV_FILE}"
|
BANK_PORT=$(taler-config -c "$CONF" -s BANK -o HTTP_PORT)
|
||||||
mkdir -p $MASTER_PRIV_DIR
|
|
||||||
gnunet-ecc -l/dev/null -g1 $MASTER_PRIV_FILE > /dev/null
|
|
||||||
export MASTER_PUB=`gnunet-ecc -p $MASTER_PRIV_FILE`
|
|
||||||
export EXCHANGE_URL=`taler-config -c $CONF -s EXCHANGE -o BASE_URL`
|
|
||||||
MERCHANT_PORT=`taler-config -c $CONF -s MERCHANT -o PORT`
|
|
||||||
export MERCHANT_URL=http://localhost:${MERCHANT_PORT}/
|
|
||||||
BANK_PORT=`taler-config -c $CONF -s BANK -o HTTP_PORT`
|
|
||||||
BANK_URL="http://localhost:1${BANK_PORT}"
|
BANK_URL="http://localhost:1${BANK_PORT}"
|
||||||
export AUDITOR_URL=http://localhost:8083/
|
|
||||||
AUDITOR_PRIV_FILE=$1.apriv
|
|
||||||
AUDITOR_PRIV_DIR=`dirname $AUDITOR_PRIV_FILE`
|
|
||||||
taler-config -f -c ${CONF} -s auditor -o AUDITOR_PRIV_FILE -V ${AUDITOR_PRIV_FILE}
|
|
||||||
mkdir -p $AUDITOR_PRIV_DIR
|
|
||||||
gnunet-ecc -l/dev/null -g1 $AUDITOR_PRIV_FILE > /dev/null
|
|
||||||
AUDITOR_PUB=`gnunet-ecc -p $AUDITOR_PRIV_FILE`
|
|
||||||
|
|
||||||
echo "MASTER PUB is ${MASTER_PUB} using file ${MASTER_PRIV_FILE}"
|
|
||||||
echo "AUDITOR PUB is ${AUDITOR_PUB} using file ${AUDITOR_PRIV_FILE}"
|
|
||||||
|
|
||||||
# patch configuration
|
|
||||||
taler-config -c $CONF -s exchange -o MASTER_PUBLIC_KEY -V $MASTER_PUB
|
|
||||||
taler-config -c $CONF -s auditor -o PUBLIC_KEY -V $AUDITOR_PUB
|
|
||||||
taler-config -c $CONF -s merchant-exchange-default -o MASTER_KEY -V $MASTER_PUB
|
|
||||||
|
|
||||||
taler-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s auditordb-postgres -o CONFIG -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s bank -o database -V postgres:///$TARGET_DB
|
|
||||||
|
|
||||||
# setup exchange
|
|
||||||
echo "Setting up exchange"
|
|
||||||
taler-exchange-dbinit -c $CONF
|
|
||||||
|
|
||||||
echo "Setting up merchant"
|
|
||||||
taler-merchant-dbinit -c $CONF
|
|
||||||
|
|
||||||
# setup auditor
|
|
||||||
echo "Setting up auditor"
|
|
||||||
taler-auditor-dbinit -c $CONF || exit_skip "Failed to initialize auditor DB"
|
|
||||||
taler-auditor-exchange -c $CONF -m $MASTER_PUB -u $EXCHANGE_URL || exit_skip "Failed to add exchange to auditor"
|
|
||||||
|
|
||||||
# Launch services
|
|
||||||
echo "Launching services (pre audit DB: $TARGET_DB)"
|
|
||||||
|
|
||||||
rm -rf ${TARGET_DB}-sandbox.sqlite3
|
|
||||||
export LIBEUFIN_SANDBOX_DB_CONNECTION="jdbc:sqlite:${TARGET_DB}-sandbox.sqlite3"
|
|
||||||
# Create the default demobank.
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=secret
|
|
||||||
libeufin-sandbox config --currency "TESTKUDOS" default
|
|
||||||
libeufin-sandbox serve --port "1${BANK_PORT}" \
|
|
||||||
> ${MY_TMP_DIR}/libeufin-sandbox-stdout.log \
|
|
||||||
2> ${MY_TMP_DIR}/libeufin-sandbox-stderr.log &
|
|
||||||
echo $! > ${MY_TMP_DIR}/libeufin-sandbox.pid
|
|
||||||
cd $ORIGIN
|
|
||||||
export LIBEUFIN_SANDBOX_URL="http://localhost:1${BANK_PORT}"
|
|
||||||
set +e
|
|
||||||
echo -n "Waiting for Sandbox..."
|
|
||||||
OK=0
|
|
||||||
for n in `seq 1 100`; do
|
|
||||||
echo -n "."
|
|
||||||
sleep 1
|
|
||||||
if wget --timeout=1 \
|
|
||||||
--user admin --password secret --auth-no-challenge \
|
|
||||||
--tries=3 --waitretry=0 \
|
|
||||||
-o /dev/null -O /dev/null \
|
|
||||||
${LIBEUFIN_SANDBOX_URL};
|
|
||||||
then
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if test $OK != 1
|
|
||||||
then
|
|
||||||
exit_skip " Failed to launch sandbox"
|
|
||||||
fi
|
|
||||||
echo "OK"
|
|
||||||
|
|
||||||
register_sandbox_account() {
|
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=$1
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=$2
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
libeufin-cli sandbox \
|
|
||||||
demobank \
|
|
||||||
register --name "$3"
|
|
||||||
cd $ORIGIN
|
|
||||||
unset LIBEUFIN_SANDBOX_USERNAME
|
|
||||||
unset LIBEUFIN_SANDBOX_PASSWORD
|
|
||||||
}
|
|
||||||
set -e
|
|
||||||
echo -n "Register the 'fortytwo' Sandbox user.."
|
|
||||||
register_sandbox_account fortytwo x "Forty Two"
|
|
||||||
echo OK
|
|
||||||
echo -n "Register the 'fortythree' Sandbox user.."
|
|
||||||
register_sandbox_account fortythree x "Forty Three"
|
|
||||||
echo OK
|
|
||||||
echo -n "Register 'exchange' Sandbox user.."
|
|
||||||
register_sandbox_account exchange x "Exchange Company"
|
|
||||||
echo OK
|
|
||||||
echo -n "Specify exchange's PAYTO_URI in the config ..."
|
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=exchange
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=x
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
PAYTO=`libeufin-cli sandbox demobank info --bank-account exchange | jq --raw-output '.paytoUri'`
|
|
||||||
taler-config -c $CONF -s exchange-account-1 -o PAYTO_URI -V $PAYTO
|
|
||||||
echo " OK"
|
|
||||||
echo -n "Setting this exchange as the bank's default ..."
|
|
||||||
EXCHANGE_PAYTO=`libeufin-cli sandbox demobank info --bank-account exchange | jq --raw-output '.paytoUri'`
|
|
||||||
libeufin-sandbox default-exchange "$EXCHANGE_URL" "$EXCHANGE_PAYTO"
|
|
||||||
echo " OK"
|
|
||||||
# Prepare EBICS: create Ebics host and Exchange subscriber.
|
|
||||||
# Shortly becoming admin to setup Ebics.
|
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=admin
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=secret
|
|
||||||
echo -n "Create EBICS host at Sandbox.."
|
|
||||||
libeufin-cli sandbox \
|
|
||||||
--sandbox-url "http://localhost:1${BANK_PORT}" \
|
|
||||||
ebicshost create --host-id "talerebics"
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Create exchange EBICS subscriber at Sandbox.."
|
|
||||||
libeufin-cli sandbox \
|
|
||||||
demobank new-ebicssubscriber --host-id talerebics \
|
|
||||||
--user-id exchangeebics --partner-id talerpartner \
|
|
||||||
--bank-account exchange # that's a username _and_ a bank account name
|
|
||||||
echo "OK"
|
|
||||||
unset LIBEUFIN_SANDBOX_USERNAME
|
|
||||||
unset LIBEUFIN_SANDBOX_PASSWORD
|
|
||||||
# Prepare Nexus, which is the side actually talking
|
|
||||||
# to the exchange.
|
|
||||||
rm -rf ${TARGET_DB}-nexus.sqlite3
|
|
||||||
export LIBEUFIN_NEXUS_DB_CONNECTION="jdbc:sqlite:${TARGET_DB}-nexus.sqlite3"
|
|
||||||
# For convenience, username and password are
|
|
||||||
# identical to those used at the Sandbox.
|
|
||||||
echo -n "Create exchange Nexus user..."
|
|
||||||
libeufin-nexus superuser exchange --password x
|
|
||||||
echo " OK"
|
|
||||||
libeufin-nexus serve --port ${BANK_PORT} \
|
|
||||||
2> ${MY_TMP_DIR}/libeufin-nexus-stderr.log \
|
|
||||||
> ${MY_TMP_DIR}/libeufin-nexus-stdout.log &
|
|
||||||
echo $! > ${MY_TMP_DIR}/libeufin-nexus.pid
|
|
||||||
export LIBEUFIN_NEXUS_URL="http://localhost:${BANK_PORT}"
|
|
||||||
echo -n "Waiting for Nexus..."
|
|
||||||
set +e
|
|
||||||
OK=0
|
|
||||||
for n in `seq 1 50`; do
|
|
||||||
echo -n "."
|
|
||||||
sleep 1
|
|
||||||
if wget --timeout=1 \
|
|
||||||
--tries=3 --waitretry=0 \
|
|
||||||
-o /dev/null -O /dev/null \
|
|
||||||
$LIBEUFIN_NEXUS_URL;
|
|
||||||
then
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if test $OK != 1
|
|
||||||
then
|
|
||||||
exit_skip " Failed to launch Nexus at $LIBEUFIN_NEXUS_URL"
|
|
||||||
fi
|
|
||||||
set -e
|
|
||||||
echo "OK"
|
|
||||||
export LIBEUFIN_NEXUS_USERNAME=exchange
|
|
||||||
export LIBEUFIN_NEXUS_PASSWORD=x
|
|
||||||
echo -n "Creating an EBICS connection at Nexus..."
|
|
||||||
libeufin-cli connections new-ebics-connection \
|
|
||||||
--ebics-url "http://localhost:1${BANK_PORT}/ebicsweb" \
|
|
||||||
--host-id "talerebics" \
|
|
||||||
--partner-id "talerpartner" \
|
|
||||||
--ebics-user-id "exchangeebics" \
|
|
||||||
talerconn
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Setup EBICS keying..."
|
|
||||||
libeufin-cli connections connect "talerconn" > /dev/null
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Download bank account name from Sandbox..."
|
|
||||||
libeufin-cli connections download-bank-accounts "talerconn"
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Importing bank account info into Nexus..."
|
|
||||||
libeufin-cli connections import-bank-account \
|
|
||||||
--offered-account-id "exchange" \
|
|
||||||
--nexus-bank-account-id "exchange-nexus" \
|
|
||||||
"talerconn"
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Setup payments submission task..."
|
|
||||||
# Tries every second.
|
|
||||||
libeufin-cli accounts task-schedule \
|
|
||||||
--task-type submit \
|
|
||||||
--task-name "exchange-payments" \
|
|
||||||
--task-cronspec "* * *" \
|
|
||||||
"exchange-nexus"
|
|
||||||
echo "OK"
|
|
||||||
# Tries every second. Ask C52
|
|
||||||
echo -n "Setup history fetch task..."
|
|
||||||
libeufin-cli accounts task-schedule \
|
|
||||||
--task-type fetch \
|
|
||||||
--task-name "exchange-history" \
|
|
||||||
--task-cronspec "* * *" \
|
|
||||||
--task-param-level report \
|
|
||||||
--task-param-range-type latest \
|
|
||||||
"exchange-nexus"
|
|
||||||
echo "OK"
|
|
||||||
# create Taler facade.
|
|
||||||
echo -n "Create the Taler facade at Nexus..."
|
|
||||||
libeufin-cli facades \
|
|
||||||
new-taler-wire-gateway-facade \
|
|
||||||
--currency "TESTKUDOS" --facade-name "test-facade" \
|
|
||||||
"talerconn" "exchange-nexus"
|
|
||||||
echo "OK"
|
|
||||||
cd $ORIGIN
|
|
||||||
# Facade schema: http://localhost:$BANK_PORT/facades/test-facade/taler-wire-gateway/
|
|
||||||
|
|
||||||
|
|
||||||
TFN=`which taler-exchange-httpd`
|
|
||||||
TBINPFX=`dirname $TFN`
|
|
||||||
TLIBEXEC=${TBINPFX}/../lib/taler/libexec/
|
|
||||||
taler-exchange-secmod-eddsa -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log &
|
|
||||||
taler-exchange-secmod-rsa -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-rsa.log &
|
|
||||||
taler-exchange-secmod-cs -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-cs.log &
|
|
||||||
taler-exchange-httpd -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-httpd.log &
|
|
||||||
taler-merchant-httpd -c $CONF -L INFO 2> ${MY_TMP_DIR}/taler-merchant-httpd.log &
|
|
||||||
taler-exchange-wirewatch -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-wirewatch.log &
|
|
||||||
taler-auditor-httpd -L INFO -c $CONF 2> ${MY_TMP_DIR}/taler-auditor-httpd.log &
|
|
||||||
export BANK_PORT
|
|
||||||
export EXCHANGE_URL
|
|
||||||
export MERCHANT_URL
|
|
||||||
export AUDITOR_URL
|
|
||||||
|
|
||||||
echo -n "Waiting for services to be available "
|
|
||||||
# Wait for all bank to be available (usually the slowest)
|
|
||||||
for n in `seq 1 50`
|
|
||||||
do
|
|
||||||
echo -n "."
|
|
||||||
sleep 0.2
|
|
||||||
OK=0
|
|
||||||
# bank
|
|
||||||
wget http://localhost:${BANK_PORT}/ -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ 1 != $OK ]
|
|
||||||
then
|
|
||||||
exit_skip "Failed to launch services (bank)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Wait for all services to be available
|
|
||||||
for n in `seq 1 50`
|
|
||||||
do
|
|
||||||
echo -n "."
|
|
||||||
sleep 0.1
|
|
||||||
OK=0
|
|
||||||
# exchange
|
|
||||||
wget ${EXCHANGE_URL}seed -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
# merchant
|
|
||||||
wget ${MERCHANT_URL} -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
# Auditor
|
|
||||||
wget ${AUDITOR_URL} -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ 1 != $OK ]
|
|
||||||
then
|
|
||||||
bash
|
|
||||||
exit_skip "Failed to launch services (Taler)"
|
|
||||||
fi
|
|
||||||
echo -n "Setting up keys"
|
|
||||||
taler-exchange-offline -c $CONF \
|
|
||||||
download sign \
|
|
||||||
enable-account `taler-config -c $CONF -s exchange-account-1 -o PAYTO_URI` \
|
|
||||||
enable-auditor $AUDITOR_PUB $AUDITOR_URL "TESTKUDOS Auditor" \
|
|
||||||
wire-fee now iban TESTKUDOS:0.07 TESTKUDOS:0.01 \
|
|
||||||
global-fee now TESTKUDOS:0.01 TESTKUDOS:0.01 TESTKUDOS:0.01 1h 1year 5 \
|
|
||||||
upload &> ${MY_TMP_DIR}/taler-exchange-offline.log
|
|
||||||
|
|
||||||
echo -n "."
|
|
||||||
|
|
||||||
for n in `seq 1 2`
|
|
||||||
do
|
|
||||||
echo -n "."
|
|
||||||
OK=0
|
|
||||||
wget --timeout=1 http://localhost:8081/keys -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ 1 != $OK ]
|
|
||||||
then
|
|
||||||
exit_skip "Failed to setup keys"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo " DONE"
|
|
||||||
echo -n "Adding auditor signatures ..."
|
|
||||||
|
|
||||||
taler-auditor-offline -c $CONF \
|
|
||||||
download sign upload &> ${MY_TMP_DIR}/taler-auditor-offline.log
|
|
||||||
|
|
||||||
echo " DONE"
|
|
||||||
# Setup merchant
|
|
||||||
|
|
||||||
echo -n "Setting up merchant"
|
|
||||||
|
|
||||||
curl -H "Content-Type: application/json" -X POST -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://iban/SANDBOXX/DE474361?receiver-name=Merchant43"}],"id":"default","name":"default","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' http://localhost:9966/management/instances
|
|
||||||
|
|
||||||
|
|
||||||
|
echo -n "Setting up merchant ..."
|
||||||
|
curl -H "Content-Type: application/json" -X POST -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://iban/SANDBOXX/DE474361?receiver-name=Merchant43"}],"id":"default","name":"default","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' "${MERCHANT_URL}management/instances"
|
||||||
echo " DONE"
|
echo " DONE"
|
||||||
|
|
||||||
# run wallet CLI
|
# delete existing wallet database
|
||||||
echo "Running wallet"
|
export WALLET_DB="wallet.wdb"
|
||||||
|
rm -f "$WALLET_DB"
|
||||||
|
|
||||||
taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api --expect-success 'runIntegrationTest' \
|
echo -n "Running wallet ..."
|
||||||
|
taler-wallet-cli \
|
||||||
|
--no-throttle \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
api \
|
||||||
|
--expect-success \
|
||||||
|
'runIntegrationTest' \
|
||||||
"$(jq -n '
|
"$(jq -n '
|
||||||
{
|
{
|
||||||
amountToSpend: "TESTKUDOS:4",
|
amountToSpend: "TESTKUDOS:4",
|
||||||
@ -418,28 +67,25 @@ taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api --expect-success 'runI
|
|||||||
--arg MERCHANT_URL "$MERCHANT_URL" \
|
--arg MERCHANT_URL "$MERCHANT_URL" \
|
||||||
--arg EXCHANGE_URL "$EXCHANGE_URL" \
|
--arg EXCHANGE_URL "$EXCHANGE_URL" \
|
||||||
--arg BANK_URL "$BANK_URL/demobanks/default/access-api/"
|
--arg BANK_URL "$BANK_URL/demobanks/default/access-api/"
|
||||||
)" &> ${MY_TMP_DIR}/taler-wallet-cli.log
|
)" &> taler-wallet-cli.log
|
||||||
|
echo " DONE"
|
||||||
echo "Shutting down services"
|
|
||||||
exit_cleanup
|
|
||||||
|
|
||||||
# Dump database
|
# Dump database
|
||||||
echo "Dumping database ${BASEDB}(-libeufin).sql"
|
mkdir -p "$(dirname "$BASEDB")"
|
||||||
pg_dump -O $TARGET_DB | sed -e '/AS integer/d' > ${BASEDB}.sql
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
sqlite3 ${TARGET_DB}-nexus.sqlite3 ".dump" > ${BASEDB}-libeufin-nexus.sql
|
|
||||||
sqlite3 ${TARGET_DB}-sandbox.sqlite3 ".dump" > ${BASEDB}-libeufin-sandbox.sql
|
|
||||||
rm ${TARGET_DB}-sandbox.sqlite3 ${TARGET_DB}-nexus.sqlite3 # libeufin DB
|
|
||||||
cd $ORIGIN
|
|
||||||
|
|
||||||
echo $MASTER_PUB > ${BASEDB}.mpub
|
echo "Dumping database ${BASEDB}.sql"
|
||||||
|
pg_dump -O "auditor-basedb" | sed -e '/AS integer/d' > "${BASEDB}.sql"
|
||||||
|
|
||||||
# clean up
|
# clean up
|
||||||
echo "Final clean up"
|
echo -n "Final clean up ..."
|
||||||
dropdb $TARGET_DB
|
kill -TERM "$SETUP_PID"
|
||||||
|
wait
|
||||||
|
unset SETUP_PID
|
||||||
|
dropdb "auditor-basedb"
|
||||||
|
echo " DONE"
|
||||||
|
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
echo " Finished generation of $BASEDB"
|
echo "Finished generation of ${BASEDB}.sql"
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -8,405 +8,50 @@
|
|||||||
set -eu
|
set -eu
|
||||||
# set -x
|
# set -x
|
||||||
|
|
||||||
# Cleanup to run whenever we exit
|
. setup.sh
|
||||||
function exit_cleanup()
|
|
||||||
{
|
|
||||||
echo "Running generate-revoke-basedb exit cleanup logic..."
|
|
||||||
if test -f ${MY_TMP_DIR:-/}/libeufin-sandbox.pid
|
|
||||||
then
|
|
||||||
PID=`cat ${MY_TMP_DIR}/libeufin-sandbox.pid 2> /dev/null`
|
|
||||||
kill $PID 2> /dev/null || true
|
|
||||||
rm ${MY_TMP_DIR}/libeufin-sandbox.pid
|
|
||||||
echo "Killed libeufin sandbox $PID"
|
|
||||||
wait $PID || true
|
|
||||||
fi
|
|
||||||
if test -f ${MY_TMP_DIR}/libeufin-nexus.pid
|
|
||||||
then
|
|
||||||
PID=`cat ${MY_TMP_DIR}/libeufin-nexus.pid 2> /dev/null`
|
|
||||||
kill $PID 2> /dev/null || true
|
|
||||||
rm ${MY_TMP_DIR}/libeufin-nexus.pid
|
|
||||||
echo "Killed libeufin nexus $PID"
|
|
||||||
wait $PID || true
|
|
||||||
fi
|
|
||||||
echo "killing libeufin DONE"
|
|
||||||
for n in `jobs -p`
|
|
||||||
do
|
|
||||||
kill $n 2> /dev/null || true
|
|
||||||
done
|
|
||||||
wait
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_payto_uri() {
|
echo -n "Testing for curl ..."
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=$1
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=$2
|
|
||||||
export LIBEUFIN_SANDBOX_URL=$BANK_URL
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
libeufin-cli sandbox demobank info --bank-account $1 | jq --raw-output '.paytoUri'
|
|
||||||
cd $ORIGIN
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install cleanup handler (except for kill -9)
|
|
||||||
trap exit_cleanup EXIT
|
|
||||||
|
|
||||||
# Exit, with status code "skip" (no 'real' failure)
|
|
||||||
function exit_skip() {
|
|
||||||
echo $1
|
|
||||||
exit 77
|
|
||||||
}
|
|
||||||
|
|
||||||
# Where do we write the result?
|
|
||||||
export BASEDB=${1:-"revoke-basedb"}
|
|
||||||
|
|
||||||
# Name of the Postgres database we will use for the script.
|
|
||||||
# Will be dropped, do NOT use anything that might be used
|
|
||||||
# elsewhere
|
|
||||||
export TARGET_DB=`basename ${BASEDB}`
|
|
||||||
TMP_DIR=`mktemp -d revocation-tmp-XXXXXX`
|
|
||||||
export WALLET_DB=wallet-revocation.json
|
|
||||||
rm -f $WALLET_DB
|
|
||||||
|
|
||||||
# Configuration file will be edited, so we create one
|
|
||||||
# from the template.
|
|
||||||
export CONF=${BASEDB}.conf
|
|
||||||
cp generate-auditor-basedb.conf $CONF
|
|
||||||
echo "Created configuration at ${CONF}"
|
|
||||||
DATA_DIR=$1/exchange-data-dir/
|
|
||||||
mkdir -p $DATA_DIR
|
|
||||||
taler-config -c $CONF -s PATHS -o TALER_HOME -V $DATA_DIR
|
|
||||||
|
|
||||||
echo -n "Testing for libeufin(-cli)"
|
|
||||||
libeufin-cli --help >/dev/null </dev/null || exit_skip " MISSING"
|
|
||||||
echo " FOUND"
|
|
||||||
echo -n "Testing for taler-wallet-cli"
|
|
||||||
taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING"
|
|
||||||
echo " FOUND"
|
|
||||||
echo -n "Testing for curl"
|
|
||||||
curl --help >/dev/null </dev/null || exit_skip " MISSING"
|
curl --help >/dev/null </dev/null || exit_skip " MISSING"
|
||||||
echo " FOUND"
|
echo " FOUND"
|
||||||
|
|
||||||
# reset database
|
CONF="generate-auditor-basedb.conf"
|
||||||
dropdb $TARGET_DB >/dev/null 2>/dev/null || true
|
|
||||||
createdb $TARGET_DB || exit_skip "Could not create database $TARGET_DB"
|
|
||||||
ORIGIN=`pwd`
|
|
||||||
MY_TMP_DIR=`dirname $1`
|
|
||||||
|
|
||||||
|
# reset database
|
||||||
|
echo -n "Reset 'auditor-basedb' database ..."
|
||||||
|
dropdb "auditor-basedb" >/dev/null 2>/dev/null || true
|
||||||
|
createdb "auditor-basedb" || exit_skip "Could not create database '$BASEDB'"
|
||||||
|
echo " DONE"
|
||||||
|
|
||||||
|
# Launch exchange, merchant and bank.
|
||||||
|
setup -c "$CONF" \
|
||||||
|
-aenmsw \
|
||||||
|
-d "iban"
|
||||||
|
|
||||||
# obtain key configuration data
|
# obtain key configuration data
|
||||||
MASTER_PRIV_FILE=$1.mpriv
|
EXCHANGE_URL=$(taler-config -c "$CONF" -s EXCHANGE -o BASE_URL)
|
||||||
MASTER_PRIV_DIR=`dirname $MASTER_PRIV_FILE`
|
MERCHANT_PORT=$(taler-config -c "$CONF" -s MERCHANT -o PORT)
|
||||||
taler-config -f -c $CONF -s exchange-offline -o MASTER_PRIV_FILE -V ${MASTER_PRIV_FILE}
|
MERCHANT_URL="http://localhost:${MERCHANT_PORT}/"
|
||||||
mkdir -p $MASTER_PRIV_DIR
|
BANK_PORT=$(taler-config -c "$CONF" -s BANK -o HTTP_PORT)
|
||||||
rm -f "${MASTER_PRIV_FILE}"
|
BANK_URL="http://localhost:1${BANK_PORT}"
|
||||||
gnunet-ecc -g1 $MASTER_PRIV_FILE > /dev/null
|
|
||||||
export MASTER_PUB=`gnunet-ecc -p $MASTER_PRIV_FILE`
|
|
||||||
export EXCHANGE_URL=`taler-config -c $CONF -s EXCHANGE -o BASE_URL`
|
|
||||||
MERCHANT_PORT=`taler-config -c $CONF -s MERCHANT -o PORT`
|
|
||||||
export MERCHANT_URL=http://localhost:${MERCHANT_PORT}/
|
|
||||||
BANK_PORT=`taler-config -c $CONF -s BANK -o HTTP_PORT`
|
|
||||||
export BANK_URL=http://localhost:1${BANK_PORT}
|
|
||||||
export AUDITOR_URL=http://localhost:8083/
|
|
||||||
AUDITOR_PRIV_FILE=$1.apriv
|
|
||||||
AUDITOR_PRIV_DIR=`dirname $AUDITOR_PRIV_FILE`
|
|
||||||
taler-config -f -c ${CONF} -s auditor -o AUDITOR_PRIV_FILE -V ${AUDITOR_PRIV_FILE}
|
|
||||||
mkdir -p $AUDITOR_PRIV_DIR
|
|
||||||
gnunet-ecc -l /dev/null -g1 $AUDITOR_PRIV_FILE > /dev/null
|
|
||||||
AUDITOR_PUB=`gnunet-ecc -p $AUDITOR_PRIV_FILE`
|
|
||||||
|
|
||||||
echo "MASTER PUB is ${MASTER_PUB} using file ${MASTER_PRIV_FILE}"
|
|
||||||
echo "AUDITOR PUB is ${AUDITOR_PUB} using file ${AUDITOR_PRIV_FILE}"
|
|
||||||
|
|
||||||
|
|
||||||
# patch configuration
|
|
||||||
taler-config -c $CONF -s exchange -o MASTER_PUBLIC_KEY -V $MASTER_PUB
|
|
||||||
taler-config -c $CONF -s auditor -o PUBLIC_KEY -V $AUDITOR_PUB
|
|
||||||
taler-config -c $CONF -s merchant-exchange-default -o MASTER_KEY -V $MASTER_PUB
|
|
||||||
taler-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s auditordb-postgres -o CONFIG -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s bank -o database -V postgres:///$TARGET_DB
|
|
||||||
taler-config -c $CONF -s exchange -o KEYDIR -V "${TMP_DIR}/keydir/"
|
|
||||||
taler-config -c $CONF -s exchange -o REVOCATION_DIR -V "${TMP_DIR}/revdir/"
|
|
||||||
|
|
||||||
# setup exchange
|
|
||||||
echo "Setting up exchange"
|
|
||||||
taler-exchange-dbinit -c $CONF
|
|
||||||
|
|
||||||
echo "Setting up merchant"
|
|
||||||
taler-merchant-dbinit -c $CONF
|
|
||||||
|
|
||||||
# setup auditor
|
|
||||||
echo "Setting up auditor"
|
|
||||||
taler-auditor-dbinit -c $CONF
|
|
||||||
taler-auditor-exchange -c $CONF -m $MASTER_PUB -u $EXCHANGE_URL
|
|
||||||
|
|
||||||
# Launch services
|
|
||||||
echo "Launching services"
|
|
||||||
|
|
||||||
export LIBEUFIN_SANDBOX_DB_CONNECTION="jdbc:sqlite:${TARGET_DB}-sandbox.sqlite3"
|
|
||||||
# Create the default demobank.
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=secret
|
|
||||||
libeufin-sandbox config --currency "TESTKUDOS" default
|
|
||||||
libeufin-sandbox serve --port "1${BANK_PORT}" \
|
|
||||||
> ${MY_TMP_DIR}/libeufin-sandbox-stdout.log \
|
|
||||||
2> ${MY_TMP_DIR}/libeufin-sandbox-stderr.log &
|
|
||||||
echo $! > ${MY_TMP_DIR}/libeufin-sandbox.pid
|
|
||||||
cd $ORIGIN
|
|
||||||
export LIBEUFIN_SANDBOX_URL="http://localhost:1${BANK_PORT}"
|
|
||||||
set +e
|
|
||||||
echo -n "Waiting for Sandbox..."
|
|
||||||
OK=0
|
|
||||||
for n in `seq 1 50`; do
|
|
||||||
echo -n "."
|
|
||||||
sleep 1
|
|
||||||
if wget --timeout=1 \
|
|
||||||
--user admin --password secret --auth-no-challenge \
|
|
||||||
--tries=3 --waitretry=0 \
|
|
||||||
-o /dev/null -O /dev/null \
|
|
||||||
${LIBEUFIN_SANDBOX_URL};
|
|
||||||
then
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if test $OK != 1
|
|
||||||
then
|
|
||||||
exit_skip " Failed to launch sandbox"
|
|
||||||
fi
|
|
||||||
echo "OK"
|
|
||||||
|
|
||||||
register_sandbox_account() {
|
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=$1
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=$2
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
libeufin-cli sandbox \
|
|
||||||
demobank \
|
|
||||||
register --name "$3"
|
|
||||||
cd $ORIGIN
|
|
||||||
unset LIBEUFIN_SANDBOX_USERNAME
|
|
||||||
unset LIBEUFIN_SANDBOX_PASSWORD
|
|
||||||
}
|
|
||||||
set -e
|
|
||||||
echo -n "Register the 'fortytwo' Sandbox user.."
|
|
||||||
register_sandbox_account fortytwo x "Forty Two"
|
|
||||||
echo OK
|
|
||||||
echo -n "Register the 'fortythree' Sandbox user.."
|
|
||||||
register_sandbox_account fortythree x "Forty Three"
|
|
||||||
echo OK
|
|
||||||
echo -n "Register 'exchange' Sandbox user.."
|
|
||||||
register_sandbox_account exchange x "Exchange Company"
|
|
||||||
echo OK
|
|
||||||
echo -n "Specify exchange's PAYTO_URI in the config ..."
|
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=exchange
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=x
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
PAYTO=`libeufin-cli sandbox demobank info --bank-account exchange | jq --raw-output '.paytoUri'`
|
|
||||||
taler-config -c $CONF -s exchange-account-1 -o PAYTO_URI -V $PAYTO
|
|
||||||
echo " OK"
|
|
||||||
echo -n "Setting this exchange as the bank's default ..."
|
|
||||||
EXCHANGE_PAYTO=`libeufin-cli sandbox demobank info --bank-account exchange | jq --raw-output '.paytoUri'`
|
|
||||||
libeufin-sandbox default-exchange "$EXCHANGE_URL" "$EXCHANGE_PAYTO"
|
|
||||||
echo " OK"
|
|
||||||
# Prepare EBICS: create Ebics host and Exchange subscriber.
|
|
||||||
# Shortly becoming admin to setup Ebics.
|
|
||||||
export LIBEUFIN_SANDBOX_USERNAME=admin
|
|
||||||
export LIBEUFIN_SANDBOX_PASSWORD=secret
|
|
||||||
echo -n "Create EBICS host at Sandbox.."
|
|
||||||
libeufin-cli sandbox \
|
|
||||||
--sandbox-url "http://localhost:1${BANK_PORT}" \
|
|
||||||
ebicshost create --host-id "talerebics"
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Create exchange EBICS subscriber at Sandbox.."
|
|
||||||
libeufin-cli sandbox \
|
|
||||||
demobank new-ebicssubscriber --host-id talerebics \
|
|
||||||
--user-id exchangeebics --partner-id talerpartner \
|
|
||||||
--bank-account exchange # that's a username _and_ a bank account name
|
|
||||||
echo "OK"
|
|
||||||
unset LIBEUFIN_SANDBOX_USERNAME
|
|
||||||
unset LIBEUFIN_SANDBOX_PASSWORD
|
|
||||||
# Prepare Nexus, which is the side actually talking
|
|
||||||
# to the exchange.
|
|
||||||
export LIBEUFIN_NEXUS_DB_CONNECTION="jdbc:sqlite:${TARGET_DB}-nexus.sqlite3"
|
|
||||||
# For convenience, username and password are
|
|
||||||
# identical to those used at the Sandbox.
|
|
||||||
echo -n "Create exchange Nexus user..."
|
|
||||||
libeufin-nexus superuser exchange --password x
|
|
||||||
echo " OK"
|
|
||||||
libeufin-nexus serve --port ${BANK_PORT} \
|
|
||||||
2> ${MY_TMP_DIR}/libeufin-nexus-stderr.log \
|
|
||||||
> ${MY_TMP_DIR}/libeufin-nexus-stdout.log &
|
|
||||||
echo $! > ${MY_TMP_DIR}/libeufin-nexus.pid
|
|
||||||
export LIBEUFIN_NEXUS_URL="http://localhost:${BANK_PORT}"
|
|
||||||
echo -n "Waiting for Nexus..."
|
|
||||||
set +e
|
|
||||||
OK=0
|
|
||||||
for n in `seq 1 50`; do
|
|
||||||
echo -n "."
|
|
||||||
sleep 1
|
|
||||||
if wget --timeout=1 \
|
|
||||||
--tries=3 --waitretry=0 \
|
|
||||||
-o /dev/null -O /dev/null \
|
|
||||||
$LIBEUFIN_NEXUS_URL;
|
|
||||||
then
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if test $OK != 1
|
|
||||||
then
|
|
||||||
exit_skip " Failed to launch Nexus at $LIBEUFIN_NEXUS_URL"
|
|
||||||
fi
|
|
||||||
set -e
|
|
||||||
echo "OK"
|
|
||||||
export LIBEUFIN_NEXUS_USERNAME=exchange
|
|
||||||
export LIBEUFIN_NEXUS_PASSWORD=x
|
|
||||||
echo -n "Creating an EBICS connection at Nexus..."
|
|
||||||
libeufin-cli connections new-ebics-connection \
|
|
||||||
--ebics-url "http://localhost:1${BANK_PORT}/ebicsweb" \
|
|
||||||
--host-id "talerebics" \
|
|
||||||
--partner-id "talerpartner" \
|
|
||||||
--ebics-user-id "exchangeebics" \
|
|
||||||
talerconn
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Setup EBICS keying..."
|
|
||||||
libeufin-cli connections connect "talerconn" > /dev/null
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Download bank account name from Sandbox..."
|
|
||||||
libeufin-cli connections download-bank-accounts "talerconn"
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Importing bank account info into Nexus..."
|
|
||||||
libeufin-cli connections import-bank-account \
|
|
||||||
--offered-account-id "exchange" \
|
|
||||||
--nexus-bank-account-id "exchange-nexus" \
|
|
||||||
"talerconn"
|
|
||||||
echo "OK"
|
|
||||||
echo -n "Setup payments submission task..."
|
|
||||||
# Tries every second.
|
|
||||||
libeufin-cli accounts task-schedule \
|
|
||||||
--task-type submit \
|
|
||||||
--task-name "exchange-payments" \
|
|
||||||
--task-cronspec "* * *" \
|
|
||||||
"exchange-nexus"
|
|
||||||
echo "OK"
|
|
||||||
# Tries every second. Ask C52
|
|
||||||
echo -n "Setup history fetch task..."
|
|
||||||
libeufin-cli accounts task-schedule \
|
|
||||||
--task-type fetch \
|
|
||||||
--task-name "exchange-history" \
|
|
||||||
--task-cronspec "* * *" \
|
|
||||||
--task-param-level report \
|
|
||||||
--task-param-range-type latest \
|
|
||||||
"exchange-nexus"
|
|
||||||
echo "OK"
|
|
||||||
# create Taler facade.
|
|
||||||
echo -n "Create the Taler facade at Nexus..."
|
|
||||||
libeufin-cli facades \
|
|
||||||
new-taler-wire-gateway-facade \
|
|
||||||
--currency "TESTKUDOS" --facade-name "test-facade" \
|
|
||||||
"talerconn" "exchange-nexus"
|
|
||||||
echo "OK"
|
|
||||||
cd $ORIGIN
|
|
||||||
# Facade schema: http://localhost:$BANK_PORT/facades/test-facade/taler-wire-gateway/
|
|
||||||
|
|
||||||
TFN=`which taler-exchange-httpd`
|
|
||||||
TBINPFX=`dirname $TFN`
|
|
||||||
TLIBEXEC=${TBINPFX}/../lib/taler/libexec/
|
|
||||||
taler-exchange-secmod-eddsa -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log &
|
|
||||||
SIGNKEY_HELPER_PID=$!
|
|
||||||
taler-exchange-secmod-rsa -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-rsa.log &
|
|
||||||
RSA_DENOM_HELPER_PID=$!
|
|
||||||
taler-exchange-secmod-cs -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-cs.log &
|
|
||||||
CS_DENOM_HELPER_PID=$!
|
|
||||||
taler-exchange-httpd -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-httpd.log &
|
|
||||||
EXCHANGE_PID=$!
|
|
||||||
taler-merchant-httpd -c $CONF -L INFO 2> ${MY_TMP_DIR}/taler-merchant-httpd.log &
|
|
||||||
MERCHANT_PID=$!
|
|
||||||
taler-exchange-wirewatch -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-wirewatch.log &
|
|
||||||
taler-auditor-httpd -c $CONF 2> ${MY_TMP_DIR}/taler-auditor-httpd.log &
|
|
||||||
|
|
||||||
# Wait for all bank to be available (usually the slowest)
|
|
||||||
for n in `seq 1 50`
|
|
||||||
do
|
|
||||||
echo -n "."
|
|
||||||
sleep 0.2
|
|
||||||
OK=0
|
|
||||||
# bank
|
|
||||||
wget http://localhost:8082/ -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ 1 != $OK ]
|
|
||||||
then
|
|
||||||
exit_skip "Failed to launch Bank services"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Wait for all other services to be available
|
|
||||||
for n in `seq 1 50`
|
|
||||||
do
|
|
||||||
echo -n "."
|
|
||||||
sleep 0.1
|
|
||||||
OK=0
|
|
||||||
# exchange
|
|
||||||
wget http://localhost:8081/seed -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
# merchant
|
|
||||||
wget http://localhost:9966/ -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
# Auditor
|
|
||||||
wget http://localhost:8083/ -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ 1 != $OK ]
|
|
||||||
then
|
|
||||||
exit_cleanup
|
|
||||||
exit_skip "Failed to launch Taler services"
|
|
||||||
fi
|
|
||||||
echo " DONE"
|
|
||||||
|
|
||||||
echo -n "Setting up keys"
|
|
||||||
|
|
||||||
taler-exchange-offline -c $CONF \
|
|
||||||
download sign \
|
|
||||||
enable-account `taler-config -c $CONF -s exchange-account-1 -o PAYTO_URI` \
|
|
||||||
enable-auditor $AUDITOR_PUB $AUDITOR_URL "TESTKUDOS Auditor" \
|
|
||||||
wire-fee now iban TESTKUDOS:0.01 TESTKUDOS:0.01 \
|
|
||||||
global-fee now TESTKUDOS:0.01 TESTKUDOS:0.01 TESTKUDOS:0.01 1h 1year 5 \
|
|
||||||
upload &> ${MY_TMP_DIR}/taler-exchange-offline.log
|
|
||||||
|
|
||||||
echo -n "."
|
|
||||||
|
|
||||||
for n in `seq 1 2`
|
|
||||||
do
|
|
||||||
echo -n "."
|
|
||||||
OK=0
|
|
||||||
# bank
|
|
||||||
wget --timeout=1 http://localhost:8081/keys -o /dev/null -O /dev/null >/dev/null || continue
|
|
||||||
OK=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ 1 != $OK ]
|
|
||||||
then
|
|
||||||
exit_skip "Failed to setup keys"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
taler-auditor-offline -c $CONF \
|
|
||||||
download sign upload &> ${MY_TMP_DIR}/taler-auditor-offline.log
|
|
||||||
|
|
||||||
echo " DONE"
|
|
||||||
|
|
||||||
# Setup merchant
|
# Setup merchant
|
||||||
echo -n "Setting up merchant"
|
echo -n "Setting up merchant ..."
|
||||||
|
curl -H "Content-Type: application/json" -X POST -d '{"auth": {"method": "external"}, "accounts":[{"payto_uri":"payto://iban/SANDBOXX/DE474361?receiver-name=Merchant43"}],"id":"default","name":"default","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' "${MERCHANT_URL}management/instances"
|
||||||
curl -H "Content-Type: application/json" -X POST -d '{"auth": {"method": "external"}, "accounts":[{"payto_uri":"payto://iban/SANDBOXX/DE474361?receiver-name=Merchant43"}],"id":"default","name":"default","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' http://localhost:9966/management/instances
|
echo " DONE"
|
||||||
|
|
||||||
|
|
||||||
# run wallet CLI
|
# run wallet CLI
|
||||||
echo "Running wallet"
|
echo "Running wallet"
|
||||||
|
|
||||||
taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api --expect-success 'withdrawTestBalance' \
|
export WALLET_DB="wallet.wdb"
|
||||||
|
rm -f "$WALLET_DB"
|
||||||
|
|
||||||
|
taler-wallet-cli \
|
||||||
|
--no-throttle \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
api \
|
||||||
|
--expect-success 'withdrawTestBalance' \
|
||||||
"$(jq -n '
|
"$(jq -n '
|
||||||
{
|
{
|
||||||
amount: "TESTKUDOS:8",
|
amount: "TESTKUDOS:8",
|
||||||
@ -414,57 +59,85 @@ taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api --expect-success 'with
|
|||||||
exchangeBaseUrl: $EXCHANGE_URL,
|
exchangeBaseUrl: $EXCHANGE_URL,
|
||||||
}' \
|
}' \
|
||||||
--arg BANK_URL "$BANK_URL/demobanks/default/access-api/" \
|
--arg BANK_URL "$BANK_URL/demobanks/default/access-api/" \
|
||||||
--arg EXCHANGE_URL $EXCHANGE_URL
|
--arg EXCHANGE_URL "$EXCHANGE_URL"
|
||||||
)"
|
)" &> taler-wallet-cli-withdraw.log
|
||||||
|
|
||||||
taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB run-until-done
|
taler-wallet-cli \
|
||||||
|
--no-throttle \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
run-until-done \
|
||||||
|
&> taler-wallet-cli-withdraw-finish.log
|
||||||
|
|
||||||
export coins=$(taler-wallet-cli --wallet-db=$WALLET_DB advanced dump-coins)
|
export COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins)
|
||||||
|
|
||||||
echo -n "COINS are:"
|
echo -n "COINS are:"
|
||||||
echo $coins
|
echo "$COINS"
|
||||||
|
|
||||||
# Find coin we want to revoke
|
# Find coin we want to revoke
|
||||||
export rc=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .coin_pub')
|
export rc=$(echo "$COINS" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .coin_pub')
|
||||||
# Find the denom
|
# Find the denom
|
||||||
export rd=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .denom_pub_hash')
|
export rd=$(echo "$COINS" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .denom_pub_hash')
|
||||||
echo "Revoking denomination ${rd} (to affect coin ${rc})"
|
echo -n "Revoking denomination ${rd} (to affect coin ${rc}) ..."
|
||||||
# Find all other coins, which will be suspended
|
# Find all other coins, which will be suspended
|
||||||
export susp=$(echo "$coins" | jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]')
|
export susp=$(echo "$COINS" | jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]')
|
||||||
|
|
||||||
# Do the revocation
|
# Do the revocation
|
||||||
taler-exchange-offline -c $CONF \
|
taler-exchange-offline \
|
||||||
revoke-denomination "${rd}" upload &> ${MY_TMP_DIR}/taler-exchange-offline-revoke.log
|
-c $CONF \
|
||||||
|
revoke-denomination "${rd}" \
|
||||||
|
upload \
|
||||||
|
&> taler-exchange-offline-revoke.log
|
||||||
|
echo "DONE"
|
||||||
|
|
||||||
|
echo -n "Signing replacement keys ..."
|
||||||
sleep 1 # Give exchange time to create replacmenent key
|
sleep 1 # Give exchange time to create replacmenent key
|
||||||
|
|
||||||
# Re-sign replacement keys
|
# Re-sign replacement keys
|
||||||
taler-auditor-offline -c $CONF \
|
taler-auditor-offline \
|
||||||
download sign upload &> ${MY_TMP_DIR}/taler-auditor-offline.log
|
-c $CONF \
|
||||||
|
download \
|
||||||
|
sign \
|
||||||
|
upload \
|
||||||
|
&> taler-auditor-offline-reinit.log
|
||||||
|
echo " DONE"
|
||||||
|
|
||||||
# Now we suspend the other coins, so later we will pay with the recouped coin
|
# Now we suspend the other coins, so later we will pay with the recouped coin
|
||||||
taler-wallet-cli --wallet-db=$WALLET_DB advanced suspend-coins "$susp"
|
taler-wallet-cli \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
advanced \
|
||||||
|
suspend-coins "$susp"
|
||||||
|
|
||||||
# Update exchange /keys so recoup gets scheduled
|
# Update exchange /keys so recoup gets scheduled
|
||||||
taler-wallet-cli --wallet-db=$WALLET_DB exchanges update \
|
taler-wallet-cli \
|
||||||
-f $EXCHANGE_URL
|
--wallet-db="$WALLET_DB" \
|
||||||
|
exchanges \
|
||||||
|
update \
|
||||||
|
-f "$EXCHANGE_URL"
|
||||||
|
|
||||||
# Block until scheduled operations are done
|
# Block until scheduled operations are done
|
||||||
taler-wallet-cli --wallet-db=$WALLET_DB run-until-done
|
taler-wallet-cli \
|
||||||
|
--wallet-db="$WALLET_DB"\
|
||||||
|
run-until-done
|
||||||
|
|
||||||
# Now we buy something, only the coins resulting from recouped will be
|
# Now we buy something, only the coins resulting from recoup will be
|
||||||
# used, as other ones are suspended
|
# used, as other ones are suspended
|
||||||
taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api 'testPay' \
|
taler-wallet-cli \
|
||||||
|
--no-throttle \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
api \
|
||||||
|
'testPay' \
|
||||||
"$(jq -n '
|
"$(jq -n '
|
||||||
{
|
{
|
||||||
amount: "TESTKUDOS:1",
|
amount: "TESTKUDOS:1",
|
||||||
merchantBaseUrl: $MERCHANT_URL,
|
merchantBaseUrl: $MERCHANT_URL,
|
||||||
summary: "foo",
|
summary: "foo",
|
||||||
}' \
|
}' \
|
||||||
--arg MERCHANT_URL $MERCHANT_URL
|
--arg MERCHANT_URL "$MERCHANT_URL"
|
||||||
)"
|
)"
|
||||||
|
|
||||||
taler-wallet-cli --wallet-db=$WALLET_DB run-until-done
|
taler-wallet-cli \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
run-until-done
|
||||||
|
|
||||||
echo "Purchase with recoup'ed coin (via reserve) done"
|
echo "Purchase with recoup'ed coin (via reserve) done"
|
||||||
|
|
||||||
@ -477,9 +150,6 @@ echo "Will refresh coin ${rrc} of denomination ${zombie_denom}"
|
|||||||
# Find all other coins, which will be suspended
|
# Find all other coins, which will be suspended
|
||||||
export susp=$(echo "$coins" | jq --arg rrc "$rrc" '[.coins[] | select(.coin_pub != $rrc) | .coin_pub]')
|
export susp=$(echo "$coins" | jq --arg rrc "$rrc" '[.coins[] | select(.coin_pub != $rrc) | .coin_pub]')
|
||||||
|
|
||||||
export rrc
|
|
||||||
export zombie_denom
|
|
||||||
|
|
||||||
# Travel into the future! (must match DURATION_WITHDRAW option)
|
# Travel into the future! (must match DURATION_WITHDRAW option)
|
||||||
export TIMETRAVEL="--timetravel=604800000000"
|
export TIMETRAVEL="--timetravel=604800000000"
|
||||||
|
|
||||||
@ -510,8 +180,15 @@ do
|
|||||||
done
|
done
|
||||||
|
|
||||||
echo "Refreshing coin $rrc"
|
echo "Refreshing coin $rrc"
|
||||||
taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced force-refresh "$rrc"
|
taler-wallet-cli \
|
||||||
taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
|
"$TIMETRAVEL" \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
advanced force-refresh \
|
||||||
|
"$rrc"
|
||||||
|
taler-wallet-cli \
|
||||||
|
"$TIMETRAVEL" \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
run-until-done
|
||||||
|
|
||||||
# Update our list of the coins
|
# Update our list of the coins
|
||||||
export coins=$(taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced dump-coins)
|
export coins=$(taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced dump-coins)
|
||||||
@ -534,29 +211,49 @@ export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coi
|
|||||||
|
|
||||||
# Do the revocation of freshc
|
# Do the revocation of freshc
|
||||||
echo "Revoking ${fresh_denom} (to affect coin ${freshc})"
|
echo "Revoking ${fresh_denom} (to affect coin ${freshc})"
|
||||||
taler-exchange-offline -c $CONF \
|
taler-exchange-offline \
|
||||||
revoke-denomination "${fresh_denom}" upload &> ${MY_TMP_DIR}/taler-exchange-offline-revoke-2.log
|
-c "$CONF" \
|
||||||
|
revoke-denomination \
|
||||||
|
"${fresh_denom}" \
|
||||||
|
upload &> taler-exchange-offline-revoke-2.log
|
||||||
|
|
||||||
sleep 1 # Give exchange time to create replacmenent key
|
sleep 1 # Give exchange time to create replacmenent key
|
||||||
|
|
||||||
# Re-sign replacement keys
|
# Re-sign replacement keys
|
||||||
taler-auditor-offline -c $CONF \
|
taler-auditor-offline \
|
||||||
download sign upload &> ${MY_TMP_DIR}/taler-auditor-offline.log
|
-c "$CONF" \
|
||||||
|
download \
|
||||||
|
sign \
|
||||||
|
upload &> taler-auditor-offline.log
|
||||||
|
|
||||||
# Now we suspend the other coins, so later we will pay with the recouped coin
|
# Now we suspend the other coins, so later we will pay with the recouped coin
|
||||||
taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced suspend-coins "$susp"
|
taler-wallet-cli \
|
||||||
|
"$TIMETRAVEL" \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
advanced \
|
||||||
|
suspend-coins "$susp"
|
||||||
|
|
||||||
# Update exchange /keys so recoup gets scheduled
|
# Update exchange /keys so recoup gets scheduled
|
||||||
taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB exchanges update \
|
taler-wallet-cli \
|
||||||
-f $EXCHANGE_URL
|
"$TIMETRAVEL"\
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
exchanges update \
|
||||||
|
-f "$EXCHANGE_URL"
|
||||||
|
|
||||||
# Block until scheduled operations are done
|
# Block until scheduled operations are done
|
||||||
taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
|
taler-wallet-cli \
|
||||||
|
"$TIMETRAVEL" \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
run-until-done
|
||||||
|
|
||||||
echo "Restarting merchant (so new keys are known)"
|
echo "Restarting merchant (so new keys are known)"
|
||||||
kill -TERM $MERCHANT_PID
|
kill -TERM $MERCHANT_PID
|
||||||
taler-merchant-httpd -c $CONF -L INFO 2> ${MY_TMP_DIR}/taler-merchant-httpd.log &
|
taler-merchant-httpd \
|
||||||
|
-c "$CONF" \
|
||||||
|
-L INFO \
|
||||||
|
2> ${MY_TMP_DIR}/taler-merchant-httpd.log &
|
||||||
MERCHANT_PID=$!
|
MERCHANT_PID=$!
|
||||||
|
|
||||||
# Wait for merchant to be again available
|
# Wait for merchant to be again available
|
||||||
for n in `seq 1 50`
|
for n in `seq 1 50`
|
||||||
do
|
do
|
||||||
@ -580,7 +277,10 @@ taler-wallet-cli $TIMETRAVEL --no-throttle --wallet-db=$WALLET_DB api 'testPay'
|
|||||||
}' \
|
}' \
|
||||||
--arg MERCHANT_URL $MERCHANT_URL
|
--arg MERCHANT_URL $MERCHANT_URL
|
||||||
)"
|
)"
|
||||||
taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
|
taler-wallet-cli \
|
||||||
|
"$TIMETRAVEL" \
|
||||||
|
--wallet-db="$WALLET_DB" \
|
||||||
|
run-until-done
|
||||||
|
|
||||||
echo "Bought something with refresh-recouped coin"
|
echo "Bought something with refresh-recouped coin"
|
||||||
|
|
||||||
@ -588,26 +288,24 @@ echo "Shutting down services"
|
|||||||
exit_cleanup
|
exit_cleanup
|
||||||
|
|
||||||
|
|
||||||
|
# Where do we write the result?
|
||||||
|
export BASEDB=${1:-"revoke-basedb"}
|
||||||
|
|
||||||
|
|
||||||
# Dump database
|
# Dump database
|
||||||
echo "Dumping database"
|
echo "Dumping database ${BASEDB}.sql"
|
||||||
echo "Dumping PostgreSQL database: ${BASEDB}.sql"
|
pg_dump -O "auditor-basedb" | sed -e '/AS integer/d' > "${BASEDB}.sql"
|
||||||
pg_dump -O $TARGET_DB | sed -e '/AS integer/d' > ${BASEDB}.sql
|
|
||||||
echo "Dumping libeufin database: ${TARGET_DB}-libeufin-*.sql"
|
|
||||||
cd $MY_TMP_DIR
|
|
||||||
sqlite3 ${TARGET_DB}-nexus.sqlite3 ".dump" > ${BASEDB}-libeufin-nexus.sql
|
|
||||||
sqlite3 ${TARGET_DB}-sandbox.sqlite3 ".dump" > ${BASEDB}-libeufin-sandbox.sql
|
|
||||||
|
|
||||||
rm ${TARGET_DB}-sandbox.sqlite3 ${TARGET_DB}-nexus.sqlite3 # libeufin DB
|
# clean up
|
||||||
|
echo -n "Final clean up ..."
|
||||||
cd $ORIGIN
|
kill -TERM "$SETUP_PID"
|
||||||
|
wait
|
||||||
echo $MASTER_PUB > ${BASEDB}.mpub
|
unset SETUP_PID
|
||||||
|
dropdb "auditor-basedb"
|
||||||
echo "Final clean up"
|
echo " DONE"
|
||||||
dropdb $TARGET_DB
|
|
||||||
|
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
echo " Finished generation of $BASEDB "
|
echo "Finished generation of ${BASEDB}.sql"
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
%I7qYÿ®ÜX˜2@–šò%'1†”ÂOàÔæJ³Ô¦‘
|
72
src/auditor/setup.sh
Executable file
72
src/auditor/setup.sh
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# This file is in the public domain
|
||||||
|
|
||||||
|
# Script to be inlined into the main test scripts. Defines function 'setup()'
|
||||||
|
# which wraps around 'taler-unified-setup.sh' to launch GNU Taler services.
|
||||||
|
# Call setup() with the arguments to pass to 'taler-unified-setup'. setup()
|
||||||
|
# will then launch GNU Taler, wait for the process to be complete before
|
||||||
|
# returning. The script will also install an exit handler to ensure the GNU
|
||||||
|
# Taler processes are stopped when the shell exits.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
# Cleanup to run whenever we exit
|
||||||
|
function exit_cleanup()
|
||||||
|
{
|
||||||
|
if [ ! -z ${SETUP_PID+x} ]
|
||||||
|
then
|
||||||
|
echo "Killing taler-unified-setup ($SETUP_PID)" >&2
|
||||||
|
kill -TERM "$SETUP_PID"
|
||||||
|
wait
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install cleanup handler (except for kill -9)
|
||||||
|
trap exit_cleanup EXIT
|
||||||
|
|
||||||
|
function setup()
|
||||||
|
{
|
||||||
|
echo "Starting test system ..." >&2
|
||||||
|
# Create a named pipe in a temp directory we own.
|
||||||
|
FIFO_DIR=$(mktemp -d fifo-XXXXXX)
|
||||||
|
FIFO_OUT=$(echo "$FIFO_DIR/out")
|
||||||
|
mkfifo "$FIFO_OUT"
|
||||||
|
# Open pipe as FD 3 (RW) and FD 4 (RO)
|
||||||
|
exec 3<> "$FIFO_OUT" 4< "$FIFO_OUT"
|
||||||
|
rm -rf "$FIFO_DIR"
|
||||||
|
# We require '-W' for our termination logic to work.
|
||||||
|
taler-unified-setup.sh -W "$@" >&3 &
|
||||||
|
SETUP_PID=$!
|
||||||
|
# Close FD3
|
||||||
|
exec 3>&-
|
||||||
|
sed -u '/<<READY>>/ q' <&4
|
||||||
|
# Close FD4
|
||||||
|
exec 4>&-
|
||||||
|
echo "Test system ready" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Exit, with status code "skip" (no 'real' failure)
|
||||||
|
function exit_fail() {
|
||||||
|
echo "$@" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Exit, with status code "skip" (no 'real' failure)
|
||||||
|
function exit_skip() {
|
||||||
|
echo "SKIPPING: $1"
|
||||||
|
exit 77
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_payto_uri() {
|
||||||
|
export LIBEUFIN_SANDBOX_USERNAME="$1"
|
||||||
|
export LIBEUFIN_SANDBOX_PASSWORD="$2"
|
||||||
|
export LIBEUFIN_SANDBOX_URL="http://localhost:18082"
|
||||||
|
libeufin-cli sandbox demobank info --bank-account "$1" | jq --raw-output '.paytoUri'
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_bankaccount_transactions() {
|
||||||
|
export LIBEUFIN_SANDBOX_USERNAME=$1
|
||||||
|
export LIBEUFIN_SANDBOX_PASSWORD=$2
|
||||||
|
export LIBEUFIN_SANDBOX_URL="http://localhost:18082"
|
||||||
|
libeufin-cli sandbox demobank list-transactions --bank-account $1
|
||||||
|
}
|
@ -213,7 +213,7 @@ main (int argc,
|
|||||||
? "Could not remove exchange from database: entry already absent\n"
|
? "Could not remove exchange from database: entry already absent\n"
|
||||||
: "Could not add exchange to database: entry already exists\n");
|
: "Could not add exchange to database: entry already exists\n");
|
||||||
TALER_AUDITORDB_plugin_unload (adb);
|
TALER_AUDITORDB_plugin_unload (adb);
|
||||||
return EXIT_FAILURE;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TALER_AUDITORDB_plugin_unload (adb);
|
TALER_AUDITORDB_plugin_unload (adb);
|
||||||
|
@ -132,7 +132,7 @@ handle_mhd_completion_callback (void *cls,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a "/version" request.
|
* Handle a "/config" request.
|
||||||
*
|
*
|
||||||
* @param rh context of the handler
|
* @param rh context of the handler
|
||||||
* @param connection the MHD connection to handle
|
* @param connection the MHD connection to handle
|
||||||
@ -142,11 +142,11 @@ handle_mhd_completion_callback (void *cls,
|
|||||||
* @return MHD result code
|
* @return MHD result code
|
||||||
*/
|
*/
|
||||||
static MHD_RESULT
|
static MHD_RESULT
|
||||||
handle_version (struct TAH_RequestHandler *rh,
|
handle_config (struct TAH_RequestHandler *rh,
|
||||||
struct MHD_Connection *connection,
|
struct MHD_Connection *connection,
|
||||||
void **connection_cls,
|
void **connection_cls,
|
||||||
const char *upload_data,
|
const char *upload_data,
|
||||||
size_t *upload_data_size)
|
size_t *upload_data_size)
|
||||||
{
|
{
|
||||||
static json_t *ver; /* we build the response only once, keep around for next query! */
|
static json_t *ver; /* we build the response only once, keep around for next query! */
|
||||||
|
|
||||||
@ -157,6 +157,8 @@ handle_version (struct TAH_RequestHandler *rh,
|
|||||||
if (NULL == ver)
|
if (NULL == ver)
|
||||||
{
|
{
|
||||||
ver = GNUNET_JSON_PACK (
|
ver = GNUNET_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_string ("name",
|
||||||
|
"taler-auditor"),
|
||||||
GNUNET_JSON_pack_string ("version",
|
GNUNET_JSON_pack_string ("version",
|
||||||
AUDITOR_PROTOCOL_VERSION),
|
AUDITOR_PROTOCOL_VERSION),
|
||||||
GNUNET_JSON_pack_string ("currency",
|
GNUNET_JSON_pack_string ("currency",
|
||||||
@ -207,9 +209,9 @@ handle_mhd_request (void *cls,
|
|||||||
{ "/exchanges", MHD_HTTP_METHOD_GET, "application/json",
|
{ "/exchanges", MHD_HTTP_METHOD_GET, "application/json",
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
&TAH_EXCHANGES_handler, MHD_HTTP_OK },
|
&TAH_EXCHANGES_handler, MHD_HTTP_OK },
|
||||||
{ "/version", MHD_HTTP_METHOD_GET, "application/json",
|
{ "/config", MHD_HTTP_METHOD_GET, "application/json",
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
&handle_version, MHD_HTTP_OK },
|
&handle_config, MHD_HTTP_OK },
|
||||||
/* Landing page, for now tells humans to go away
|
/* Landing page, for now tells humans to go away
|
||||||
* (NOTE: ideally, the reverse proxy will respond with a nicer page) */
|
* (NOTE: ideally, the reverse proxy will respond with a nicer page) */
|
||||||
{ "/", MHD_HTTP_METHOD_GET, "text/plain",
|
{ "/", MHD_HTTP_METHOD_GET, "text/plain",
|
||||||
|
@ -605,6 +605,9 @@ main (int argc,
|
|||||||
level,
|
level,
|
||||||
NULL));
|
NULL));
|
||||||
GNUNET_free (level);
|
GNUNET_free (level);
|
||||||
|
/* suppress compiler warnings... */
|
||||||
|
GNUNET_assert (NULL != src_cfgfile);
|
||||||
|
GNUNET_assert (NULL != dst_cfgfile);
|
||||||
if (0 == strcmp (src_cfgfile,
|
if (0 == strcmp (src_cfgfile,
|
||||||
dst_cfgfile))
|
dst_cfgfile))
|
||||||
{
|
{
|
||||||
|
@ -83,7 +83,9 @@ optcheck "$@"
|
|||||||
ARGS=("$@")
|
ARGS=("$@")
|
||||||
ARGS=(${ARGS[@]/$INF})
|
ARGS=(${ARGS[@]/$INF})
|
||||||
|
|
||||||
DIR=`mktemp -d reportXXXXXX`
|
DATE=`date +%F_%H:%M:%S`
|
||||||
|
DIR="report_$DATE"
|
||||||
|
mkdir $DIR
|
||||||
for n in aggregation coins deposits purses reserves
|
for n in aggregation coins deposits purses reserves
|
||||||
do
|
do
|
||||||
taler-helper-auditor-$n ${ARGS[*]} > ${DIR}/$n.json
|
taler-helper-auditor-$n ${ARGS[*]} > ${DIR}/$n.json
|
||||||
|
@ -172,9 +172,9 @@ coin_history_index (const struct TALER_CoinSpendPublicKeyP *coin_pub)
|
|||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
memcpy (&i,
|
GNUNET_memcpy (&i,
|
||||||
coin_pub,
|
coin_pub,
|
||||||
sizeof (i));
|
sizeof (i));
|
||||||
return i % MAX_COIN_HISTORIES;
|
return i % MAX_COIN_HISTORIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,12 +674,12 @@ hash_rc (const char *receiver_account,
|
|||||||
size_t slen = strlen (receiver_account);
|
size_t slen = strlen (receiver_account);
|
||||||
char buf[sizeof (struct TALER_WireTransferIdentifierRawP) + slen];
|
char buf[sizeof (struct TALER_WireTransferIdentifierRawP) + slen];
|
||||||
|
|
||||||
memcpy (buf,
|
GNUNET_memcpy (buf,
|
||||||
wtid,
|
wtid,
|
||||||
sizeof (*wtid));
|
sizeof (*wtid));
|
||||||
memcpy (&buf[sizeof (*wtid)],
|
GNUNET_memcpy (&buf[sizeof (*wtid)],
|
||||||
receiver_account,
|
receiver_account,
|
||||||
slen);
|
slen);
|
||||||
GNUNET_CRYPTO_hash (buf,
|
GNUNET_CRYPTO_hash (buf,
|
||||||
sizeof (buf),
|
sizeof (buf),
|
||||||
key);
|
key);
|
||||||
@ -1483,10 +1483,10 @@ history_debit_cb (void *cls,
|
|||||||
switch (dhr->http_status)
|
switch (dhr->http_status)
|
||||||
{
|
{
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
for (unsigned int i = 0; i<dhr->details.success.details_length; i++)
|
for (unsigned int i = 0; i<dhr->details.ok.details_length; i++)
|
||||||
{
|
{
|
||||||
const struct TALER_BANK_DebitDetails *dd
|
const struct TALER_BANK_DebitDetails *dd
|
||||||
= &dhr->details.success.details[i];
|
= &dhr->details.ok.details[i];
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Analyzing bank DEBIT at %s of %s with WTID %s\n",
|
"Analyzing bank DEBIT at %s of %s with WTID %s\n",
|
||||||
GNUNET_TIME_timestamp2s (dd->execution_date),
|
GNUNET_TIME_timestamp2s (dd->execution_date),
|
||||||
@ -1504,9 +1504,9 @@ history_debit_cb (void *cls,
|
|||||||
roi->details.execution_date = dd->execution_date;
|
roi->details.execution_date = dd->execution_date;
|
||||||
roi->details.wtid = dd->wtid;
|
roi->details.wtid = dd->wtid;
|
||||||
roi->details.credit_account_uri = (const char *) &roi[1];
|
roi->details.credit_account_uri = (const char *) &roi[1];
|
||||||
memcpy (&roi[1],
|
GNUNET_memcpy (&roi[1],
|
||||||
dd->credit_account_uri,
|
dd->credit_account_uri,
|
||||||
slen);
|
slen);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONTAINER_multihashmap_put (out_map,
|
GNUNET_CONTAINER_multihashmap_put (out_map,
|
||||||
&roi->subject_hash,
|
&roi->subject_hash,
|
||||||
@ -1678,9 +1678,9 @@ reserve_in_cb (void *cls,
|
|||||||
rii->details.execution_date = execution_date;
|
rii->details.execution_date = execution_date;
|
||||||
rii->details.reserve_pub = *reserve_pub;
|
rii->details.reserve_pub = *reserve_pub;
|
||||||
rii->details.debit_account_uri = (const char *) &rii[1];
|
rii->details.debit_account_uri = (const char *) &rii[1];
|
||||||
memcpy (&rii[1],
|
GNUNET_memcpy (&rii[1],
|
||||||
sender_account_details,
|
sender_account_details,
|
||||||
slen);
|
slen);
|
||||||
GNUNET_CRYPTO_hash (&wire_reference,
|
GNUNET_CRYPTO_hash (&wire_reference,
|
||||||
sizeof (uint64_t),
|
sizeof (uint64_t),
|
||||||
&rii->row_off_hash);
|
&rii->row_off_hash);
|
||||||
@ -1978,10 +1978,10 @@ history_credit_cb (void *cls,
|
|||||||
switch (chr->http_status)
|
switch (chr->http_status)
|
||||||
{
|
{
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
for (unsigned int i = 0; i<chr->details.success.details_length; i++)
|
for (unsigned int i = 0; i<chr->details.ok.details_length; i++)
|
||||||
{
|
{
|
||||||
const struct TALER_BANK_CreditDetails *cd
|
const struct TALER_BANK_CreditDetails *cd
|
||||||
= &chr->details.success.details[i];
|
= &chr->details.ok.details[i];
|
||||||
|
|
||||||
if (! analyze_credit (wa,
|
if (! analyze_credit (wa,
|
||||||
cd))
|
cd))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# This file is part of TALER
|
# This file is part of TALER
|
||||||
# Copyright (C) 2014-2022 Taler Systems SA
|
# Copyright (C) 2014-2023 Taler Systems SA
|
||||||
#
|
#
|
||||||
# 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
|
||||||
@ -49,17 +49,7 @@ VALGRIND=""
|
|||||||
# history request.
|
# history request.
|
||||||
LIBEUFIN_SETTLE_TIME=1
|
LIBEUFIN_SETTLE_TIME=1
|
||||||
|
|
||||||
# Exit, with status code "skip" (no 'real' failure)
|
. setup.sh
|
||||||
function exit_skip() {
|
|
||||||
echo "SKIPPING test: $1"
|
|
||||||
exit 77
|
|
||||||
}
|
|
||||||
|
|
||||||
# Exit, with error message (hard failure)
|
|
||||||
function exit_fail() {
|
|
||||||
echo "FAILING test: $1"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Stop libeufin sandbox and nexus (if running)
|
# Stop libeufin sandbox and nexus (if running)
|
||||||
function stop_libeufin()
|
function stop_libeufin()
|
||||||
@ -2002,12 +1992,12 @@ function check_with_database()
|
|||||||
{
|
{
|
||||||
BASEDB=$1
|
BASEDB=$1
|
||||||
CONF=$1.conf
|
CONF=$1.conf
|
||||||
ORIGIN=`pwd`
|
ORIGIN=$(pwd)
|
||||||
MY_TMP_DIR=`dirname $1`
|
MY_TMP_DIR=$(dirname $1)
|
||||||
echo "Running test suite with database $BASEDB using configuration $CONF"
|
echo "Running test suite with database $BASEDB using configuration $CONF"
|
||||||
MASTER_PRIV_FILE=${BASEDB}.mpriv
|
MASTER_PRIV_FILE=${BASEDB}.mpriv
|
||||||
taler-config -f -c ${CONF} -s exchange-offline -o MASTER_PRIV_FILE -V ${MASTER_PRIV_FILE}
|
taler-config -f -c ${CONF} -s exchange-offline -o MASTER_PRIV_FILE -V ${MASTER_PRIV_FILE}
|
||||||
MASTER_PUB=`gnunet-ecc -p $MASTER_PRIV_FILE`
|
MASTER_PUB=$(gnunet-ecc -p $MASTER_PRIV_FILE)
|
||||||
|
|
||||||
echo "MASTER PUB is ${MASTER_PUB} using file ${MASTER_PRIV_FILE}"
|
echo "MASTER PUB is ${MASTER_PUB} using file ${MASTER_PRIV_FILE}"
|
||||||
|
|
||||||
@ -2037,7 +2027,7 @@ function check_with_database()
|
|||||||
|
|
||||||
# ####### Setup globals ######
|
# ####### Setup globals ######
|
||||||
# Postgres database to use
|
# Postgres database to use
|
||||||
export DB=auditor-basedb
|
export DB="auditor-basedb"
|
||||||
|
|
||||||
# test required commands exist
|
# test required commands exist
|
||||||
echo "Testing for jq"
|
echo "Testing for jq"
|
||||||
@ -2059,12 +2049,12 @@ INITDB_BIN=$(command -v initdb) || true
|
|||||||
if [[ ! -z "$INITDB_BIN" ]]; then
|
if [[ ! -z "$INITDB_BIN" ]]; then
|
||||||
echo " FOUND (in path) at" $INITDB_BIN
|
echo " FOUND (in path) at" $INITDB_BIN
|
||||||
else
|
else
|
||||||
HAVE_INITDB=`find /usr -name "initdb" | head -1 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
HAVE_INITDB=$(find /usr -name "initdb" | head -1 2> /dev/null | grep postgres) || exit_skip " MISSING"
|
||||||
echo " FOUND at" `dirname $HAVE_INITDB`
|
echo " FOUND at" $(dirname $HAVE_INITDB)
|
||||||
INITDB_BIN=`echo $HAVE_INITDB | grep bin/initdb | grep postgres | sort -n | tail -n1`
|
INITDB_BIN=$(echo $HAVE_INITDB | grep bin/initdb | grep postgres | sort -n | tail -n1)
|
||||||
fi
|
fi
|
||||||
POSTGRES_PATH=`dirname $INITDB_BIN`
|
POSTGRES_PATH=$(dirname $INITDB_BIN)
|
||||||
MYDIR=`mktemp -d /tmp/taler-auditor-basedbXXXXXX`
|
MYDIR=$(mktemp -d /tmp/taler-auditor-basedbXXXXXX)
|
||||||
echo "Using $MYDIR for logging and temporary data"
|
echo "Using $MYDIR for logging and temporary data"
|
||||||
TMPDIR="$MYDIR/postgres/"
|
TMPDIR="$MYDIR/postgres/"
|
||||||
mkdir -p $TMPDIR
|
mkdir -p $TMPDIR
|
||||||
@ -2089,9 +2079,9 @@ PGHOST="$TMPDIR/sockets"
|
|||||||
export PGHOST
|
export PGHOST
|
||||||
|
|
||||||
echo "Generating fresh database at $MYDIR"
|
echo "Generating fresh database at $MYDIR"
|
||||||
if faketime -f '-1 d' ./generate-auditor-basedb.sh $MYDIR/$DB
|
if faketime -f '-1 d' ./generate-auditor-basedb.sh "$MYDIR/$DB"
|
||||||
then
|
then
|
||||||
check_with_database $MYDIR/$DB
|
check_with_database "$MYDIR/$DB"
|
||||||
if test x$fail != x0
|
if test x$fail != x0
|
||||||
then
|
then
|
||||||
exit $fail
|
exit $fail
|
||||||
|
@ -74,25 +74,25 @@ handle_admin_add_incoming_finished (void *cls,
|
|||||||
const void *response)
|
const void *response)
|
||||||
{
|
{
|
||||||
struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
|
struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
|
||||||
uint64_t row_id = UINT64_MAX;
|
|
||||||
struct GNUNET_TIME_Timestamp timestamp;
|
|
||||||
enum TALER_ErrorCode ec;
|
|
||||||
const json_t *j = response;
|
const json_t *j = response;
|
||||||
|
struct TALER_BANK_AdminAddIncomingResponse ir = {
|
||||||
|
.http_status = response_code,
|
||||||
|
.response = response
|
||||||
|
};
|
||||||
|
|
||||||
aai->job = NULL;
|
aai->job = NULL;
|
||||||
timestamp = GNUNET_TIME_UNIT_FOREVER_TS;
|
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
{
|
{
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_uint64 ("row_id",
|
GNUNET_JSON_spec_uint64 ("row_id",
|
||||||
&row_id),
|
&ir.details.ok.serial_id),
|
||||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||||
×tamp),
|
&ir.details.ok.timestamp),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,42 +102,41 @@ handle_admin_add_incoming_finished (void *cls,
|
|||||||
NULL, NULL))
|
NULL, NULL))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
response_code = 0;
|
ir.http_status = 0;
|
||||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ec = TALER_EC_NONE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_BAD_REQUEST:
|
case MHD_HTTP_BAD_REQUEST:
|
||||||
/* This should never happen, either us or the bank is buggy
|
/* This should never happen, either us or the bank is buggy
|
||||||
(or API version conflict); just pass JSON reply to the application */
|
(or API version conflict); just pass JSON reply to the application */
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_FORBIDDEN:
|
case MHD_HTTP_FORBIDDEN:
|
||||||
/* Access denied */
|
/* Access denied */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_UNAUTHORIZED:
|
case MHD_HTTP_UNAUTHORIZED:
|
||||||
/* Nothing really to verify, bank says the password is invalid; we should
|
/* Nothing really to verify, bank says the password is invalid; we should
|
||||||
pass the JSON reply to the application */
|
pass the JSON reply to the application */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_NOT_FOUND:
|
case MHD_HTTP_NOT_FOUND:
|
||||||
/* Nothing really to verify, maybe account really does not exist.
|
/* Nothing really to verify, maybe account really does not exist.
|
||||||
We should pass the JSON reply to the application */
|
We should pass the JSON reply to the application */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
/* Nothing to verify, we used the same wire subject
|
/* Nothing to verify, we used the same wire subject
|
||||||
twice? */
|
twice? */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||||
/* Server had an internal issue; we should retry, but this API
|
/* Server had an internal issue; we should retry, but this API
|
||||||
leaves this to the application */
|
leaves this to the application */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* unexpected response code */
|
/* unexpected response code */
|
||||||
@ -145,15 +144,11 @@ handle_admin_add_incoming_finished (void *cls,
|
|||||||
"Unexpected response code %u\n",
|
"Unexpected response code %u\n",
|
||||||
(unsigned int) response_code);
|
(unsigned int) response_code);
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
ec = TALER_JSON_get_error_code (j);
|
ir.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
aai->cb (aai->cb_cls,
|
aai->cb (aai->cb_cls,
|
||||||
response_code,
|
&ir);
|
||||||
ec,
|
|
||||||
row_id,
|
|
||||||
timestamp,
|
|
||||||
j);
|
|
||||||
TALER_BANK_admin_add_incoming_cancel (aai);
|
TALER_BANK_admin_add_incoming_cancel (aai);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,8 +131,8 @@ parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chr.details.success.details_length = len;
|
chr.details.ok.details_length = len;
|
||||||
chr.details.success.details = cd;
|
chr.details.ok.details = cd;
|
||||||
hh->hcb (hh->hcb_cls,
|
hh->hcb (hh->hcb_cls,
|
||||||
&chr);
|
&chr);
|
||||||
}
|
}
|
||||||
|
@ -133,8 +133,8 @@ parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dhr.details.success.details_length = len;
|
dhr.details.ok.details_length = len;
|
||||||
dhr.details.success.details = dd;
|
dhr.details.ok.details = dd;
|
||||||
hh->hcb (hh->hcb_cls,
|
hh->hcb (hh->hcb_cls,
|
||||||
&dhr);
|
&dhr);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2015--2020 Taler Systems SA
|
Copyright (C) 2015--2023 Taler Systems SA
|
||||||
|
|
||||||
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
|
||||||
@ -99,12 +99,12 @@ TALER_BANK_prepare_transfer (
|
|||||||
wp->account_len = htonl ((uint32_t) d_len);
|
wp->account_len = htonl ((uint32_t) d_len);
|
||||||
wp->exchange_url_len = htonl ((uint32_t) u_len);
|
wp->exchange_url_len = htonl ((uint32_t) u_len);
|
||||||
end = (char *) &wp[1];
|
end = (char *) &wp[1];
|
||||||
memcpy (end,
|
GNUNET_memcpy (end,
|
||||||
destination_account_payto_uri,
|
destination_account_payto_uri,
|
||||||
d_len);
|
d_len);
|
||||||
memcpy (end + d_len,
|
GNUNET_memcpy (end + d_len,
|
||||||
exchange_base_url,
|
exchange_base_url,
|
||||||
u_len);
|
u_len);
|
||||||
*buf = (char *) wp;
|
*buf = (char *) wp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,23 +158,24 @@ handle_transfer_finished (void *cls,
|
|||||||
{
|
{
|
||||||
struct TALER_BANK_TransferHandle *th = cls;
|
struct TALER_BANK_TransferHandle *th = cls;
|
||||||
const json_t *j = response;
|
const json_t *j = response;
|
||||||
uint64_t row_id = UINT64_MAX;
|
struct TALER_BANK_TransferResponse tr = {
|
||||||
struct GNUNET_TIME_Timestamp timestamp = GNUNET_TIME_UNIT_FOREVER_TS;
|
.http_status = response_code,
|
||||||
enum TALER_ErrorCode ec;
|
.response = j
|
||||||
|
};
|
||||||
|
|
||||||
th->job = NULL;
|
th->job = NULL;
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
tr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
{
|
{
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_uint64 ("row_id",
|
GNUNET_JSON_spec_uint64 ("row_id",
|
||||||
&row_id),
|
&tr.details.ok.row_id),
|
||||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||||
×tamp),
|
&tr.details.ok.timestamp),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -184,39 +185,38 @@ handle_transfer_finished (void *cls,
|
|||||||
NULL, NULL))
|
NULL, NULL))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
response_code = 0;
|
tr.http_status = 0;
|
||||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
tr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ec = TALER_EC_NONE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_BAD_REQUEST:
|
case MHD_HTTP_BAD_REQUEST:
|
||||||
/* This should never happen, either us or the bank is buggy
|
/* This should never happen, either us or the bank is buggy
|
||||||
(or API version conflict); just pass JSON reply to the application */
|
(or API version conflict); just pass JSON reply to the application */
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
ec = TALER_JSON_get_error_code (j);
|
tr.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_UNAUTHORIZED:
|
case MHD_HTTP_UNAUTHORIZED:
|
||||||
/* Nothing really to verify, bank says our credentials are
|
/* Nothing really to verify, bank says our credentials are
|
||||||
invalid. We should pass the JSON reply to the application. */
|
invalid. We should pass the JSON reply to the application. */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
tr.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_NOT_FOUND:
|
case MHD_HTTP_NOT_FOUND:
|
||||||
/* Nothing really to verify, endpoint wrong -- could be user unknown */
|
/* Nothing really to verify, endpoint wrong -- could be user unknown */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
tr.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
/* Nothing really to verify. Server says we used the same transfer request
|
/* Nothing really to verify. Server says we used the same transfer request
|
||||||
UID before, but with different details. Should not happen if the user
|
UID before, but with different details. Should not happen if the user
|
||||||
properly used #TALER_BANK_prepare_transfer() and our PRNG is not
|
properly used #TALER_BANK_prepare_transfer() and our PRNG is not
|
||||||
broken... */
|
broken... */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
tr.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||||
/* Server had an internal issue; we should retry, but this API
|
/* Server had an internal issue; we should retry, but this API
|
||||||
leaves this to the application */
|
leaves this to the application */
|
||||||
ec = TALER_JSON_get_error_code (j);
|
tr.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* unexpected response code */
|
/* unexpected response code */
|
||||||
@ -224,14 +224,11 @@ handle_transfer_finished (void *cls,
|
|||||||
"Unexpected response code %u\n",
|
"Unexpected response code %u\n",
|
||||||
(unsigned int) response_code);
|
(unsigned int) response_code);
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
ec = TALER_JSON_get_error_code (j);
|
tr.ec = TALER_JSON_get_error_code (j);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
th->cb (th->cb_cls,
|
th->cb (th->cb_cls,
|
||||||
response_code,
|
&tr);
|
||||||
ec,
|
|
||||||
row_id,
|
|
||||||
timestamp);
|
|
||||||
TALER_BANK_transfer_cancel (th);
|
TALER_BANK_transfer_cancel (th);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1389,9 +1389,9 @@ make_transfer (
|
|||||||
if (NULL != timestamp)
|
if (NULL != timestamp)
|
||||||
*timestamp = t->date;
|
*timestamp = t->date;
|
||||||
t->type = T_DEBIT;
|
t->type = T_DEBIT;
|
||||||
memcpy (t->subject.debit.exchange_base_url,
|
GNUNET_memcpy (t->subject.debit.exchange_base_url,
|
||||||
exchange_base_url,
|
exchange_base_url,
|
||||||
url_len);
|
url_len);
|
||||||
t->subject.debit.wtid = *subject;
|
t->subject.debit.wtid = *subject;
|
||||||
if (NULL == request_uid)
|
if (NULL == request_uid)
|
||||||
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
|
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
|
||||||
|
@ -179,10 +179,10 @@ credit_history_cb (void *cls,
|
|||||||
global_ret = 0;
|
global_ret = 0;
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
for (unsigned int i = 0; i<reply->details.success.details_length; i++)
|
for (unsigned int i = 0; i<reply->details.ok.details_length; i++)
|
||||||
{
|
{
|
||||||
const struct TALER_BANK_CreditDetails *cd =
|
const struct TALER_BANK_CreditDetails *cd =
|
||||||
&reply->details.success.details[i];
|
&reply->details.ok.details[i];
|
||||||
|
|
||||||
/* If credit/debit accounts were specified, use as a filter */
|
/* If credit/debit accounts were specified, use as a filter */
|
||||||
if ( (NULL != credit_account) &&
|
if ( (NULL != credit_account) &&
|
||||||
@ -279,10 +279,10 @@ debit_history_cb (void *cls,
|
|||||||
global_ret = 0;
|
global_ret = 0;
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
for (unsigned int i = 0; i<reply->details.success.details_length; i++)
|
for (unsigned int i = 0; i<reply->details.ok.details_length; i++)
|
||||||
{
|
{
|
||||||
const struct TALER_BANK_DebitDetails *dd =
|
const struct TALER_BANK_DebitDetails *dd =
|
||||||
&reply->details.success.details[i];
|
&reply->details.ok.details[i];
|
||||||
|
|
||||||
/* If credit/debit accounts were specified, use as a filter */
|
/* If credit/debit accounts were specified, use as a filter */
|
||||||
if ( (NULL != credit_account) &&
|
if ( (NULL != credit_account) &&
|
||||||
@ -357,34 +357,28 @@ execute_debit_history (void)
|
|||||||
* execution.
|
* execution.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
* @param response_code HTTP status code
|
* @param tr response details
|
||||||
* @param ec taler error code
|
|
||||||
* @param row_id unique ID of the wire transfer in the bank's records
|
|
||||||
* @param timestamp when did the transaction go into effect
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
confirmation_cb (void *cls,
|
confirmation_cb (void *cls,
|
||||||
unsigned int response_code,
|
const struct TALER_BANK_TransferResponse *tr)
|
||||||
enum TALER_ErrorCode ec,
|
|
||||||
uint64_t row_id,
|
|
||||||
struct GNUNET_TIME_Timestamp timestamp)
|
|
||||||
{
|
{
|
||||||
(void) cls;
|
(void) cls;
|
||||||
eh = NULL;
|
eh = NULL;
|
||||||
if (MHD_HTTP_OK != response_code)
|
if (MHD_HTTP_OK != tr->http_status)
|
||||||
{
|
{
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"The wire transfer didn't execute correctly (%u/%d).\n",
|
"The wire transfer didn't execute correctly (%u/%d).\n",
|
||||||
response_code,
|
tr->http_status,
|
||||||
ec);
|
tr->ec);
|
||||||
GNUNET_SCHEDULER_shutdown ();
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stdout,
|
fprintf (stdout,
|
||||||
"Wire transfer #%llu executed successfully at %s.\n",
|
"Wire transfer #%llu executed successfully at %s.\n",
|
||||||
(unsigned long long) row_id,
|
(unsigned long long) tr->details.ok.row_id,
|
||||||
GNUNET_TIME_timestamp2s (timestamp));
|
GNUNET_TIME_timestamp2s (tr->details.ok.timestamp));
|
||||||
global_ret = 0;
|
global_ret = 0;
|
||||||
GNUNET_SCHEDULER_shutdown ();
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
}
|
}
|
||||||
@ -464,39 +458,29 @@ execute_wire_transfer (void)
|
|||||||
* Function called with the result of the operation.
|
* Function called with the result of the operation.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
* @param air response details
|
||||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
|
||||||
* @param ec detailed error code
|
|
||||||
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
|
|
||||||
* @param timestamp timestamp when the transaction got settled at the bank.
|
|
||||||
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
res_cb (void *cls,
|
res_cb (void *cls,
|
||||||
unsigned int http_status,
|
const struct TALER_BANK_AdminAddIncomingResponse *air)
|
||||||
enum TALER_ErrorCode ec,
|
|
||||||
uint64_t serial_id,
|
|
||||||
struct GNUNET_TIME_Timestamp timestamp,
|
|
||||||
const json_t *json)
|
|
||||||
{
|
{
|
||||||
(void) cls;
|
(void) cls;
|
||||||
(void) timestamp;
|
|
||||||
op = NULL;
|
op = NULL;
|
||||||
switch (ec)
|
switch (air->http_status)
|
||||||
{
|
{
|
||||||
case TALER_EC_NONE:
|
case MHD_HTTP_OK:
|
||||||
global_ret = 0;
|
global_ret = 0;
|
||||||
fprintf (stdout,
|
fprintf (stdout,
|
||||||
"%llu\n",
|
"%llu\n",
|
||||||
(unsigned long long) serial_id);
|
(unsigned long long) air->details.ok.serial_id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"Operation failed with status code %u/%u\n",
|
"Operation failed with status code %u/%u\n",
|
||||||
(unsigned int) ec,
|
(unsigned int) air->ec,
|
||||||
http_status);
|
air->http_status);
|
||||||
if (NULL != json)
|
if (NULL != air->response)
|
||||||
json_dumpf (json,
|
json_dumpf (air->response,
|
||||||
stderr,
|
stderr,
|
||||||
JSON_INDENT (2));
|
JSON_INDENT (2));
|
||||||
break;
|
break;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# This file is in the public domain.
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
1
src/benchmark/.gitignore
vendored
1
src/benchmark/.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
taler-bank-benchmark
|
taler-bank-benchmark
|
||||||
taler-aggregator-benchmark
|
taler-aggregator-benchmark
|
||||||
|
*.edited
|
||||||
|
@ -15,6 +15,7 @@ bin_PROGRAMS = \
|
|||||||
taler-bank-benchmark \
|
taler-bank-benchmark \
|
||||||
taler-exchange-benchmark
|
taler-exchange-benchmark
|
||||||
|
|
||||||
|
|
||||||
taler_aggregator_benchmark_SOURCES = \
|
taler_aggregator_benchmark_SOURCES = \
|
||||||
taler-aggregator-benchmark.c
|
taler-aggregator-benchmark.c
|
||||||
taler_aggregator_benchmark_LDADD = \
|
taler_aggregator_benchmark_LDADD = \
|
||||||
@ -64,6 +65,11 @@ taler_exchange_benchmark_LDADD = \
|
|||||||
$(XLIB)
|
$(XLIB)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
benchmark-common.conf \
|
||||||
benchmark-cs.conf \
|
benchmark-cs.conf \
|
||||||
benchmark-rsa.conf \
|
benchmark-rsa.conf \
|
||||||
|
bank-benchmark-cs.conf \
|
||||||
|
bank-benchmark-rsa.conf \
|
||||||
|
coins-cs.conf \
|
||||||
|
coins-rsa.conf \
|
||||||
exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv
|
exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv
|
||||||
|
@ -1,128 +1,17 @@
|
|||||||
# This file is in the public domain.
|
# This file is in the public domain.
|
||||||
#
|
@INLINE@ benchmark-common.conf
|
||||||
[paths]
|
@INLINE@ coins-cs.conf
|
||||||
# Persistent data storage for the testcase
|
|
||||||
# This value is a default for `taler_config_home'
|
|
||||||
taler_test_home = exchange_benchmark_home/
|
|
||||||
|
|
||||||
[taler]
|
|
||||||
# Currency supported by the exchange (can only be one)
|
|
||||||
currency = EUR
|
|
||||||
CURRENCY_ROUND_UNIT = EUR:0.01
|
|
||||||
|
|
||||||
[exchange]
|
|
||||||
# how long is one signkey valid?
|
|
||||||
signkey_duration = 4 weeks
|
|
||||||
signkey_legal_duration = 2 years
|
|
||||||
# how long do we provide to clients denomination and signing keys
|
|
||||||
# ahead of time?
|
|
||||||
# Keep it short so the test runs fast.
|
|
||||||
lookahead_sign = 12h
|
|
||||||
# HTTP port the exchange listens to
|
|
||||||
port = 8081
|
|
||||||
# Master public key used to sign the exchange's various keys
|
|
||||||
master_public_key = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
|
||||||
# How to access our database
|
|
||||||
DB = postgres
|
|
||||||
# Base URL of the exchange. Must be set to a URL where the
|
|
||||||
# exchange (or the twister) is actually listening.
|
|
||||||
base_url = "http://localhost:8081/"
|
|
||||||
|
|
||||||
WIREWATCH_IDLE_SLEEP_INTERVAL = 500 ms
|
|
||||||
|
|
||||||
[exchange-offline]
|
|
||||||
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
|
|
||||||
|
|
||||||
[auditor]
|
|
||||||
BASE_URL = "http://localhost:8083/"
|
|
||||||
|
|
||||||
[exchangedb-postgres]
|
|
||||||
config = "postgres:///talercheck"
|
|
||||||
|
|
||||||
[benchmark-remote-exchange]
|
|
||||||
host = localhost
|
|
||||||
# Adjust $HOME to match remote target!
|
|
||||||
dir = $HOME/repos/taler/exchange/src/benchmark
|
|
||||||
|
|
||||||
[bank]
|
|
||||||
HTTP_PORT = 8082
|
|
||||||
SERVE = http
|
|
||||||
MAX_DEBT = EUR:100000000000.0
|
|
||||||
MAX_DEBT_BANK = EUR:1000000000000000.0
|
|
||||||
|
|
||||||
[benchmark]
|
|
||||||
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42?receiver-name=user42
|
|
||||||
|
|
||||||
[exchange-account-2]
|
[exchange-account-2]
|
||||||
# What is the payto://-URL of the exchange (to generate wire response)
|
# What is the payto://-URL of the exchange (to generate wire response)
|
||||||
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange?receiver-name=Exchange"
|
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange?receiver-name=Exchange"
|
||||||
enable_debit = YES
|
ENABLE_DEBIT = YES
|
||||||
enable_credit = YES
|
ENABLE_CREDIT = YES
|
||||||
|
|
||||||
[exchange-accountcredentials-2]
|
[exchange-accountcredentials-2]
|
||||||
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
||||||
WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
|
WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
|
||||||
# Authentication information for basic authentication
|
# Authentication information for basic authentication
|
||||||
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
||||||
username = Exchange
|
USERNAME = Exchange
|
||||||
password = x
|
PASSWORD = x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Sections starting with "coin_" specify which denominations
|
|
||||||
# the exchange should support (and their respective fee structure)
|
|
||||||
[coin_eur_ct_1]
|
|
||||||
value = EUR:0.01
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.00
|
|
||||||
fee_deposit = EUR:0.00
|
|
||||||
fee_refresh = EUR:0.01
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_ct_10]
|
|
||||||
value = EUR:0.10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_1]
|
|
||||||
value = EUR:1
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_5]
|
|
||||||
value = EUR:5
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_10]
|
|
||||||
value = EUR:10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
@ -1,133 +1,17 @@
|
|||||||
# This file is in the public domain.
|
# This file is in the public domain.
|
||||||
#
|
@INLINE@ benchmark-common.conf
|
||||||
[paths]
|
@INLINE@ coins-cs.conf
|
||||||
# Persistent data storage for the testcase
|
|
||||||
# This value is a default for `taler_config_home'
|
|
||||||
taler_test_home = exchange_benchmark_home/
|
|
||||||
|
|
||||||
[taler]
|
|
||||||
# Currency supported by the exchange (can only be one)
|
|
||||||
currency = EUR
|
|
||||||
CURRENCY_ROUND_UNIT = EUR:0.01
|
|
||||||
|
|
||||||
[exchange]
|
|
||||||
# how long is one signkey valid?
|
|
||||||
signkey_duration = 4 weeks
|
|
||||||
signkey_legal_duration = 2 years
|
|
||||||
# how long do we provide to clients denomination and signing keys
|
|
||||||
# ahead of time?
|
|
||||||
# Keep it short so the test runs fast.
|
|
||||||
lookahead_sign = 12h
|
|
||||||
# HTTP port the exchange listens to
|
|
||||||
port = 8081
|
|
||||||
# Master public key used to sign the exchange's various keys
|
|
||||||
master_public_key = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
|
||||||
# How to access our database
|
|
||||||
DB = postgres
|
|
||||||
# Base URL of the exchange. Must be set to a URL where the
|
|
||||||
# exchange (or the twister) is actually listening.
|
|
||||||
base_url = "http://localhost:8081/"
|
|
||||||
|
|
||||||
WIREWATCH_IDLE_SLEEP_INTERVAL = 1500 ms
|
|
||||||
|
|
||||||
[exchange-offline]
|
|
||||||
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
|
|
||||||
|
|
||||||
[auditor]
|
|
||||||
BASE_URL = "http://localhost:8083/"
|
|
||||||
|
|
||||||
[exchangedb-postgres]
|
|
||||||
config = "postgres://exchange:taler@192.168.42.42/exchange"
|
|
||||||
|
|
||||||
[benchmark-remote-exchange]
|
|
||||||
host = localhost
|
|
||||||
# Adjust $HOME to match remote target!
|
|
||||||
dir = $HOME/repos/taler/exchange/src/benchmark
|
|
||||||
|
|
||||||
[bank]
|
|
||||||
HTTP_PORT = 8082
|
|
||||||
SERVE = http
|
|
||||||
MAX_DEBT = EUR:100000000000.0
|
|
||||||
MAX_DEBT_BANK = EUR:1000000000000000.0
|
|
||||||
|
|
||||||
[benchmark]
|
|
||||||
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
|
||||||
|
|
||||||
[exchange-account-2]
|
[exchange-account-2]
|
||||||
# What is the payto://-URL of the exchange (to generate wire response)
|
# What is the payto://-URL of the exchange (to generate wire response)
|
||||||
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange"
|
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange?receiver-name=Exchange"
|
||||||
enable_debit = YES
|
ENABLE_DEBIT = YES
|
||||||
enable_credit = YES
|
ENABLE_CREDIT = YES
|
||||||
|
|
||||||
[exchange-accountcredentials-2]
|
[exchange-accountcredentials-2]
|
||||||
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
||||||
WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
|
WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
|
||||||
# Authentication information for basic authentication
|
# Authentication information for basic authentication
|
||||||
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
||||||
username = Exchange
|
USERNAME = Exchange
|
||||||
password = x
|
PASSWORD = x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Sections starting with "coin_" specify which denominations
|
|
||||||
# the exchange should support (and their respective fee structure)
|
|
||||||
[coin_eur_ct_1]
|
|
||||||
value = EUR:0.01
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.00
|
|
||||||
fee_deposit = EUR:0.00
|
|
||||||
fee_refresh = EUR:0.01
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_ct_10]
|
|
||||||
value = EUR:0.10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_1]
|
|
||||||
value = EUR:1
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_5]
|
|
||||||
value = EUR:5
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_10]
|
|
||||||
value = EUR:10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
89
src/benchmark/benchmark-common.conf
Normal file
89
src/benchmark/benchmark-common.conf
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# This file is in the public domain.
|
||||||
|
[paths]
|
||||||
|
TALER_TEST_HOME=exchange_benchmark_home/
|
||||||
|
|
||||||
|
[taler]
|
||||||
|
CURRENCY=EUR
|
||||||
|
CURRENCY_ROUND_UNIT=EUR:0.01
|
||||||
|
|
||||||
|
[exchange]
|
||||||
|
AML_THRESHOLD=EUR:99999999
|
||||||
|
SIGNKEY_LEGAL_DURATION=2 years
|
||||||
|
PORT=8081
|
||||||
|
MASTER_PUBLIC_KEY=98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
||||||
|
DB=postgres
|
||||||
|
BASE_URL="http://localhost:8081/"
|
||||||
|
# Only set this option if you are actually running
|
||||||
|
# multiple aggregators!
|
||||||
|
# AGGREGATOR_SHARD_SIZE=67108864
|
||||||
|
WIREWATCH_IDLE_SLEEP_INTERVAL=5 ms
|
||||||
|
|
||||||
|
[exchangedb-postgres]
|
||||||
|
CONFIG="postgres:///talercheck"
|
||||||
|
|
||||||
|
[exchange-offline]
|
||||||
|
MASTER_PRIV_FILE=${TALER_DATA_HOME}/exchange/offline-keys/master.priv
|
||||||
|
|
||||||
|
[taler-exchange-secmod-rsa]
|
||||||
|
LOOKAHEAD_SIGN="1 d"
|
||||||
|
|
||||||
|
[taler-exchange-secmod-cs]
|
||||||
|
LOOKAHEAD_SIGN="1 d"
|
||||||
|
|
||||||
|
[taler-exchange-secmod-eddsa]
|
||||||
|
DURATION="2 d"
|
||||||
|
LOOKAHEAD_SIGN="1 d"
|
||||||
|
|
||||||
|
# account-2 is suitable for fakebank
|
||||||
|
[exchange-account-1]
|
||||||
|
PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42"
|
||||||
|
ENABLE_DEBIT = YES
|
||||||
|
ENABLE_CREDIT = YES
|
||||||
|
|
||||||
|
[exchange-accountcredentials-1]
|
||||||
|
WIRE_GATEWAY_AUTH_METHOD = none
|
||||||
|
WIRE_GATEWAY_URL = "http://localhost:8082/42/"
|
||||||
|
|
||||||
|
# account-2 is suitable for libeufin
|
||||||
|
[exchange-account-2]
|
||||||
|
ENABLE_DEBIT = YES
|
||||||
|
ENABLE_CREDIT = YES
|
||||||
|
PAYTO_URI = payto://iban/SANDBOXX/DE033310?receiver-name=Exchange+Company
|
||||||
|
|
||||||
|
[exchange-accountcredentials-2]
|
||||||
|
WIRE_GATEWAY_AUTH_METHOD = basic
|
||||||
|
USERNAME = exchange
|
||||||
|
PASSWORD = x
|
||||||
|
WIRE_GATEWAY_URL = "http://localhost:8082/facades/test-facade/taler-wire-gateway/"
|
||||||
|
|
||||||
|
|
||||||
|
# Trust local exchange for "EUR" currency
|
||||||
|
[merchant-exchange-benchmark]
|
||||||
|
EXCHANGE_BASE_URL = http://localhost:8081/
|
||||||
|
MASTER_KEY=98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
||||||
|
# If currency does not match [TALER] section, the exchange
|
||||||
|
# will be ignored!
|
||||||
|
CURRENCY = EUR
|
||||||
|
|
||||||
|
|
||||||
|
[merchantdb-postgres]
|
||||||
|
CONFIG="postgres:///talercheck"
|
||||||
|
|
||||||
|
[auditordb-postgres]
|
||||||
|
CONFIG="postgres:///talercheck"
|
||||||
|
|
||||||
|
[syncdb-postgres]
|
||||||
|
CONFIG="postgres:///talercheck"
|
||||||
|
|
||||||
|
[bank]
|
||||||
|
HTTP_PORT=8082
|
||||||
|
SERVE=http
|
||||||
|
|
||||||
|
[libeufin-nexus]
|
||||||
|
DB_CONNECTION="jdbc:postgresql://localhost/talercheck?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432"
|
||||||
|
|
||||||
|
[libeufin-sandbox]
|
||||||
|
DB_CONNECTION="jdbc:postgresql://localhost/talercheck?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432"
|
||||||
|
|
||||||
|
[auditor]
|
||||||
|
BASE_URL="http://localhost:8083/"
|
@ -1,58 +1,6 @@
|
|||||||
# This file is in the public domain.
|
# This file is in the public domain.
|
||||||
#
|
@INLINE@ benchmark-common.conf
|
||||||
[paths]
|
@INLINE@ coins-cs.conf
|
||||||
# Persistent data storage for the testcase
|
|
||||||
# This value is a default for `taler_config_home'
|
|
||||||
TALER_TEST_HOME = exchange_benchmark_home/
|
|
||||||
|
|
||||||
[taler]
|
|
||||||
# Currency supported by the exchange (can only be one)
|
|
||||||
CURRENCY = EUR
|
|
||||||
CURRENCY_ROUND_UNIT = EUR:0.01
|
|
||||||
|
|
||||||
[exchange]
|
|
||||||
|
|
||||||
SIGNKEY_LEGAL_DURATION = 2 years
|
|
||||||
|
|
||||||
# HTTP port the exchange listens to
|
|
||||||
PORT = 8081
|
|
||||||
# Master public key used to sign the exchange's various keys
|
|
||||||
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
|
||||||
# How to access our database
|
|
||||||
DB = postgres
|
|
||||||
# Base URL of the exchange. Must be set to a URL where the
|
|
||||||
# exchange (or the twister) is actually listening.
|
|
||||||
BASE_URL = "http://localhost:8081/"
|
|
||||||
|
|
||||||
AGGREGATOR_SHARD_SIZE = 67108864
|
|
||||||
#AGGREGATOR_SHARD_SIZE = 2147483648
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WIREWATCH_IDLE_SLEEP_INTERVAL = 5 ms
|
|
||||||
|
|
||||||
[exchange-offline]
|
|
||||||
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
|
|
||||||
|
|
||||||
[auditor]
|
|
||||||
BASE_URL = "http://localhost:8083/"
|
|
||||||
|
|
||||||
[exchangedb-postgres]
|
|
||||||
CONFIG = "postgres:///talercheck"
|
|
||||||
|
|
||||||
[benchmark-remote-exchange]
|
|
||||||
HOST = localhost
|
|
||||||
# Adjust $HOME to match remote target!
|
|
||||||
DIR = $HOME/repos/taler/exchange/src/benchmark
|
|
||||||
|
|
||||||
[bank]
|
|
||||||
HTTP_PORT = 8082
|
|
||||||
SERVE = http
|
|
||||||
MAX_DEBT = EUR:100000000000.0
|
|
||||||
MAX_DEBT_BANK = EUR:1000000000000000.0
|
|
||||||
|
|
||||||
[benchmark]
|
|
||||||
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
|
||||||
|
|
||||||
[exchange-account-test]
|
[exchange-account-test]
|
||||||
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
||||||
@ -66,61 +14,3 @@ WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
|
|||||||
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
||||||
USERNAME = Exchange
|
USERNAME = Exchange
|
||||||
PASSWORD = x
|
PASSWORD = x
|
||||||
|
|
||||||
|
|
||||||
# Sections starting with "coin_" specify which denominations
|
|
||||||
# the exchange should support (and their respective fee structure)
|
|
||||||
[coin_eur_ct_1]
|
|
||||||
value = EUR:0.01
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.00
|
|
||||||
fee_deposit = EUR:0.00
|
|
||||||
fee_refresh = EUR:0.01
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_ct_10]
|
|
||||||
value = EUR:0.10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_1]
|
|
||||||
value = EUR:1
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_5]
|
|
||||||
value = EUR:5
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
|
||||||
[coin_eur_10]
|
|
||||||
value = EUR:10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = CS
|
|
||||||
|
@ -1,58 +1,6 @@
|
|||||||
# This file is in the public domain.
|
# This file is in the public domain.
|
||||||
#
|
@INLINE@ benchmark-common.conf
|
||||||
[paths]
|
@INLINE@ coins-rsa.conf
|
||||||
# Persistent data storage for the testcase
|
|
||||||
# This value is a default for `taler_config_home'
|
|
||||||
TALER_TEST_HOME = exchange_benchmark_home/
|
|
||||||
|
|
||||||
[taler]
|
|
||||||
# Currency supported by the exchange (can only be one)
|
|
||||||
CURRENCY = EUR
|
|
||||||
CURRENCY_ROUND_UNIT = EUR:0.01
|
|
||||||
|
|
||||||
[exchange]
|
|
||||||
|
|
||||||
SIGNKEY_LEGAL_DURATION = 2 years
|
|
||||||
|
|
||||||
# HTTP port the exchange listens to
|
|
||||||
PORT = 8081
|
|
||||||
# Master public key used to sign the exchange's various keys
|
|
||||||
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
|
||||||
# How to access our database
|
|
||||||
DB = postgres
|
|
||||||
# Base URL of the exchange. Must be set to a URL where the
|
|
||||||
# exchange (or the twister) is actually listening.
|
|
||||||
BASE_URL = "http://localhost:8081/"
|
|
||||||
|
|
||||||
AGGREGATOR_SHARD_SIZE = 67108864
|
|
||||||
#AGGREGATOR_SHARD_SIZE = 2147483648
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WIREWATCH_IDLE_SLEEP_INTERVAL = 5 ms
|
|
||||||
|
|
||||||
[exchange-offline]
|
|
||||||
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
|
|
||||||
|
|
||||||
[auditor]
|
|
||||||
BASE_URL = "http://localhost:8083/"
|
|
||||||
|
|
||||||
[exchangedb-postgres]
|
|
||||||
CONFIG = "postgres:///talercheck"
|
|
||||||
|
|
||||||
[benchmark-remote-exchange]
|
|
||||||
HOST = localhost
|
|
||||||
# Adjust $HOME to match remote target!
|
|
||||||
DIR = $HOME/repos/taler/exchange/src/benchmark
|
|
||||||
|
|
||||||
[bank]
|
|
||||||
HTTP_PORT = 8082
|
|
||||||
SERVE = http
|
|
||||||
MAX_DEBT = EUR:100000000000.0
|
|
||||||
MAX_DEBT_BANK = EUR:1000000000000000.0
|
|
||||||
|
|
||||||
[benchmark]
|
|
||||||
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
|
||||||
|
|
||||||
[exchange-account-test]
|
[exchange-account-test]
|
||||||
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
|
||||||
@ -66,66 +14,3 @@ WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
|
|||||||
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
WIRE_GATEWAY_AUTH_METHOD = "basic"
|
||||||
USERNAME = Exchange
|
USERNAME = Exchange
|
||||||
PASSWORD = x
|
PASSWORD = x
|
||||||
|
|
||||||
|
|
||||||
# Sections starting with "coin_" specify which denominations
|
|
||||||
# the exchange should support (and their respective fee structure)
|
|
||||||
[coin_eur_ct_1]
|
|
||||||
value = EUR:0.01
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.00
|
|
||||||
fee_deposit = EUR:0.00
|
|
||||||
fee_refresh = EUR:0.01
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_ct_10]
|
|
||||||
value = EUR:0.10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_1]
|
|
||||||
value = EUR:1
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_5]
|
|
||||||
value = EUR:5
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
|
||||||
[coin_eur_10]
|
|
||||||
value = EUR:10
|
|
||||||
duration_withdraw = 7 days
|
|
||||||
duration_spend = 2 years
|
|
||||||
duration_legal = 3 years
|
|
||||||
fee_withdraw = EUR:0.01
|
|
||||||
fee_deposit = EUR:0.01
|
|
||||||
fee_refresh = EUR:0.03
|
|
||||||
fee_refund = EUR:0.01
|
|
||||||
CIPHER = RSA
|
|
||||||
rsa_keysize = 2048
|
|
||||||
|
58
src/benchmark/coins-cs.conf
Normal file
58
src/benchmark/coins-cs.conf
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# This file is in the public domain.
|
||||||
|
#
|
||||||
|
# Sections starting with "coin_" specify which denominations
|
||||||
|
# the exchange should support (and their respective fee structure)
|
||||||
|
[coin_eur_ct_1]
|
||||||
|
value = EUR:0.01
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.00
|
||||||
|
fee_deposit = EUR:0.00
|
||||||
|
fee_refresh = EUR:0.01
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = CS
|
||||||
|
|
||||||
|
[coin_eur_ct_10]
|
||||||
|
value = EUR:0.10
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = CS
|
||||||
|
|
||||||
|
[coin_eur_1]
|
||||||
|
value = EUR:1
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = CS
|
||||||
|
|
||||||
|
[coin_eur_5]
|
||||||
|
value = EUR:5
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = CS
|
||||||
|
|
||||||
|
[coin_eur_10]
|
||||||
|
value = EUR:10
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = CS
|
63
src/benchmark/coins-rsa.conf
Normal file
63
src/benchmark/coins-rsa.conf
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# This file is in the public domain.
|
||||||
|
#
|
||||||
|
# Sections starting with "coin_" specify which denominations
|
||||||
|
# the exchange should support (and their respective fee structure)
|
||||||
|
[coin_eur_ct_1]
|
||||||
|
value = EUR:0.01
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.00
|
||||||
|
fee_deposit = EUR:0.00
|
||||||
|
fee_refresh = EUR:0.01
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = RSA
|
||||||
|
rsa_keysize = 2048
|
||||||
|
|
||||||
|
[coin_eur_ct_10]
|
||||||
|
value = EUR:0.10
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = RSA
|
||||||
|
rsa_keysize = 2048
|
||||||
|
|
||||||
|
[coin_eur_1]
|
||||||
|
value = EUR:1
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = RSA
|
||||||
|
rsa_keysize = 2048
|
||||||
|
|
||||||
|
[coin_eur_5]
|
||||||
|
value = EUR:5
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = RSA
|
||||||
|
rsa_keysize = 2048
|
||||||
|
|
||||||
|
[coin_eur_10]
|
||||||
|
value = EUR:10
|
||||||
|
duration_withdraw = 7 days
|
||||||
|
duration_spend = 2 years
|
||||||
|
duration_legal = 3 years
|
||||||
|
fee_withdraw = EUR:0.01
|
||||||
|
fee_deposit = EUR:0.01
|
||||||
|
fee_refresh = EUR:0.03
|
||||||
|
fee_refund = EUR:0.01
|
||||||
|
CIPHER = RSA
|
||||||
|
rsa_keysize = 2048
|
@ -251,7 +251,7 @@ add_refund (const struct Merchant *m,
|
|||||||
r.details.rtransaction_id = 42;
|
r.details.rtransaction_id = 42;
|
||||||
make_amount (0, 5000000, &r.details.refund_amount);
|
make_amount (0, 5000000, &r.details.refund_amount);
|
||||||
make_amount (0, 5, &r.details.refund_fee);
|
make_amount (0, 5, &r.details.refund_fee);
|
||||||
if (0 <=
|
if (0 >=
|
||||||
plugin->insert_refund (plugin->cls,
|
plugin->insert_refund (plugin->cls,
|
||||||
&r))
|
&r))
|
||||||
{
|
{
|
||||||
@ -307,8 +307,13 @@ add_deposit (const struct Merchant *m)
|
|||||||
deposit.wire_salt = m->wire_salt;
|
deposit.wire_salt = m->wire_salt;
|
||||||
deposit.receiver_wire_account = m->payto_uri;
|
deposit.receiver_wire_account = m->payto_uri;
|
||||||
deposit.timestamp = random_time ();
|
deposit.timestamp = random_time ();
|
||||||
deposit.refund_deadline = random_time ();
|
do {
|
||||||
deposit.wire_deadline = random_time ();
|
deposit.refund_deadline = random_time ();
|
||||||
|
deposit.wire_deadline = random_time ();
|
||||||
|
} while (GNUNET_TIME_timestamp_cmp (deposit.wire_deadline,
|
||||||
|
<,
|
||||||
|
deposit.refund_deadline));
|
||||||
|
|
||||||
make_amount (1, 0, &deposit.amount_with_fee);
|
make_amount (1, 0, &deposit.amount_with_fee);
|
||||||
make_amount (0, 5, &deposit.deposit_fee);
|
make_amount (0, 5, &deposit.deposit_fee);
|
||||||
if (0 >=
|
if (0 >=
|
||||||
@ -446,6 +451,9 @@ run (void *cls,
|
|||||||
}
|
}
|
||||||
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
|
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
|
||||||
NULL);
|
NULL);
|
||||||
|
memset (&issue,
|
||||||
|
0,
|
||||||
|
sizeof (issue));
|
||||||
RANDOMIZE (&issue.signature);
|
RANDOMIZE (&issue.signature);
|
||||||
issue.start
|
issue.start
|
||||||
= start;
|
= start;
|
||||||
@ -478,6 +486,7 @@ run (void *cls,
|
|||||||
TALER_DENOMINATION_RSA,
|
TALER_DENOMINATION_RSA,
|
||||||
1024));
|
1024));
|
||||||
alg_values.cipher = TALER_DENOMINATION_RSA;
|
alg_values.cipher = TALER_DENOMINATION_RSA;
|
||||||
|
denom_pub.age_mask = issue.age_mask;
|
||||||
TALER_denom_pub_hash (&denom_pub,
|
TALER_denom_pub_hash (&denom_pub,
|
||||||
&h_denom_pub);
|
&h_denom_pub);
|
||||||
make_amount (2, 0, &issue.value);
|
make_amount (2, 0, &issue.value);
|
||||||
@ -497,7 +506,6 @@ run (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TALER_planchet_blinding_secret_create (&ps,
|
TALER_planchet_blinding_secret_create (&ps,
|
||||||
&alg_values,
|
&alg_values,
|
||||||
&bks);
|
&bks);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
(C) 2014-2021 Taler Systems SA
|
(C) 2014-2023 Taler Systems SA
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it
|
TALER is free software; you can redistribute it and/or modify it
|
||||||
under the terms of the GNU Affero General Public License as
|
under the terms of the GNU Affero General Public License as
|
||||||
@ -39,65 +39,16 @@
|
|||||||
#include "taler_error_codes.h"
|
#include "taler_error_codes.h"
|
||||||
|
|
||||||
|
|
||||||
/* Error codes. */
|
|
||||||
enum BenchmarkError
|
|
||||||
{
|
|
||||||
MISSING_BANK_URL,
|
|
||||||
FAILED_TO_LAUNCH_BANK,
|
|
||||||
BAD_CLI_ARG,
|
|
||||||
BAD_CONFIG_FILE,
|
|
||||||
NO_CONFIG_FILE_GIVEN
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What mode should the benchmark run in?
|
* Credentials to use for the benchmark.
|
||||||
*/
|
*/
|
||||||
enum BenchmarkMode
|
static struct TALER_TESTING_Credentials cred;
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run as client against the bank.
|
|
||||||
*/
|
|
||||||
MODE_CLIENT = 1,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the bank.
|
|
||||||
*/
|
|
||||||
MODE_BANK = 2,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run both, for a local benchmark.
|
|
||||||
*/
|
|
||||||
MODE_BOTH = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hold information regarding which bank has the exchange account.
|
|
||||||
*/
|
|
||||||
static const struct TALER_EXCHANGEDB_AccountInfo *exchange_bank_account;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Time snapshot taken right before executing the CMDs.
|
|
||||||
*/
|
|
||||||
static struct GNUNET_TIME_Absolute start_time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Benchmark duration time taken right after the CMD interpreter
|
|
||||||
* returns.
|
|
||||||
*/
|
|
||||||
static struct GNUNET_TIME_Relative duration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of all the commands the benchmark is running.
|
* Array of all the commands the benchmark is running.
|
||||||
*/
|
*/
|
||||||
static struct TALER_TESTING_Command *all_commands;
|
static struct TALER_TESTING_Command *all_commands;
|
||||||
|
|
||||||
/**
|
|
||||||
* Dummy keepalive task.
|
|
||||||
*/
|
|
||||||
static struct GNUNET_SCHEDULER_Task *keepalive;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of our configuration file.
|
* Name of our configuration file.
|
||||||
*/
|
*/
|
||||||
@ -105,27 +56,14 @@ static char *cfg_filename;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the fakebank instead of LibEuFin.
|
* Use the fakebank instead of LibEuFin.
|
||||||
* NOTE: LibEuFin not yet supported! Set
|
|
||||||
* to 0 once we do support it!
|
|
||||||
*/
|
*/
|
||||||
static int use_fakebank = 1;
|
static int use_fakebank;
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of taler-exchange-wirewatchers to launch.
|
|
||||||
*/
|
|
||||||
static unsigned int start_wirewatch;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verbosity level.
|
* Verbosity level.
|
||||||
*/
|
*/
|
||||||
static unsigned int verbose;
|
static unsigned int verbose;
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of the transaction history the fakebank
|
|
||||||
* should keep in RAM.
|
|
||||||
*/
|
|
||||||
static unsigned long long history_size = 65536;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many reserves we want to create per client.
|
* How many reserves we want to create per client.
|
||||||
*/
|
*/
|
||||||
@ -141,6 +79,11 @@ static unsigned int howmany_clients = 1;
|
|||||||
*/
|
*/
|
||||||
static unsigned int howmany_threads;
|
static unsigned int howmany_threads;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many wirewatch processes do we want to create.
|
||||||
|
*/
|
||||||
|
static unsigned int start_wirewatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log level used during the run.
|
* Log level used during the run.
|
||||||
*/
|
*/
|
||||||
@ -151,32 +94,17 @@ static char *loglev;
|
|||||||
*/
|
*/
|
||||||
static char *logfile;
|
static char *logfile;
|
||||||
|
|
||||||
/**
|
|
||||||
* Benchmarking mode (run as client, exchange, both) as string.
|
|
||||||
*/
|
|
||||||
static char *mode_str;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Benchmarking mode (run as client, bank, both).
|
|
||||||
*/
|
|
||||||
static enum BenchmarkMode mode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't kill exchange/fakebank/wirewatch until
|
|
||||||
* requested by the user explicitly.
|
|
||||||
*/
|
|
||||||
static int linger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not initialize or reset the database.
|
|
||||||
*/
|
|
||||||
static int incremental;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration.
|
* Configuration.
|
||||||
*/
|
*/
|
||||||
static struct GNUNET_CONFIGURATION_Handle *cfg;
|
static struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Section with the configuration data for the exchange
|
||||||
|
* bank account.
|
||||||
|
*/
|
||||||
|
static char *exchange_bank_section;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currency used.
|
* Currency used.
|
||||||
*/
|
*/
|
||||||
@ -237,10 +165,10 @@ print_stats (void)
|
|||||||
|
|
||||||
total = GNUNET_strdup (
|
total = GNUNET_strdup (
|
||||||
GNUNET_STRINGS_relative_time_to_string (timings[i].total_duration,
|
GNUNET_STRINGS_relative_time_to_string (timings[i].total_duration,
|
||||||
GNUNET_YES));
|
true));
|
||||||
latency = GNUNET_strdup (
|
latency = GNUNET_strdup (
|
||||||
GNUNET_STRINGS_relative_time_to_string (timings[i].success_latency,
|
GNUNET_STRINGS_relative_time_to_string (timings[i].success_latency,
|
||||||
GNUNET_YES));
|
true));
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"%s-%d took %s in total with %s for latency for %u executions (%u repeats)\n",
|
"%s-%d took %s in total with %s for latency for %u executions (%u repeats)\n",
|
||||||
timings[i].prefix,
|
timings[i].prefix,
|
||||||
@ -270,38 +198,39 @@ run (void *cls,
|
|||||||
|
|
||||||
(void) cls;
|
(void) cls;
|
||||||
len = howmany_reserves + 2;
|
len = howmany_reserves + 2;
|
||||||
all_commands = GNUNET_malloc_large (len
|
all_commands = GNUNET_malloc_large ((1 + len)
|
||||||
* sizeof (struct TALER_TESTING_Command));
|
* sizeof (struct TALER_TESTING_Command));
|
||||||
GNUNET_assert (NULL != all_commands);
|
GNUNET_assert (NULL != all_commands);
|
||||||
|
all_commands[0]
|
||||||
|
= TALER_TESTING_cmd_get_exchange ("get-exchange",
|
||||||
|
cred.cfg,
|
||||||
|
NULL,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
|
||||||
GNUNET_asprintf (&total_reserve_amount,
|
GNUNET_asprintf (&total_reserve_amount,
|
||||||
"%s:5",
|
"%s:5",
|
||||||
currency);
|
currency);
|
||||||
for (unsigned int j = 0; j < howmany_reserves; j++)
|
for (unsigned int j = 0; j < howmany_reserves; j++)
|
||||||
{
|
{
|
||||||
char *create_reserve_label;
|
char *create_reserve_label;
|
||||||
char *user_payto_uri;
|
|
||||||
|
|
||||||
// FIXME: vary user accounts more...
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
|
||||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
|
||||||
"benchmark",
|
|
||||||
"USER_PAYTO_URI",
|
|
||||||
&user_payto_uri));
|
|
||||||
GNUNET_asprintf (&create_reserve_label,
|
GNUNET_asprintf (&create_reserve_label,
|
||||||
"createreserve-%u",
|
"createreserve-%u",
|
||||||
j);
|
j);
|
||||||
all_commands[j]
|
// TODO: vary user accounts more...
|
||||||
|
all_commands[1 + j]
|
||||||
= TALER_TESTING_cmd_admin_add_incoming_retry (
|
= TALER_TESTING_cmd_admin_add_incoming_retry (
|
||||||
TALER_TESTING_cmd_admin_add_incoming (add_label (
|
TALER_TESTING_cmd_admin_add_incoming (add_label (
|
||||||
create_reserve_label),
|
create_reserve_label),
|
||||||
total_reserve_amount,
|
total_reserve_amount,
|
||||||
exchange_bank_account->auth,
|
&cred.ba,
|
||||||
add_label (user_payto_uri)));
|
cred.user42_payto));
|
||||||
}
|
}
|
||||||
GNUNET_free (total_reserve_amount);
|
GNUNET_free (total_reserve_amount);
|
||||||
all_commands[howmany_reserves]
|
all_commands[1 + howmany_reserves]
|
||||||
= TALER_TESTING_cmd_stat (timings);
|
= TALER_TESTING_cmd_stat (timings);
|
||||||
all_commands[howmany_reserves + 1]
|
all_commands[1 + howmany_reserves + 1]
|
||||||
= TALER_TESTING_cmd_end ();
|
= TALER_TESTING_cmd_end ();
|
||||||
TALER_TESTING_run2 (is,
|
TALER_TESTING_run2 (is,
|
||||||
all_commands,
|
all_commands,
|
||||||
@ -318,15 +247,11 @@ launch_clients (void)
|
|||||||
enum GNUNET_GenericReturnValue result = GNUNET_OK;
|
enum GNUNET_GenericReturnValue result = GNUNET_OK;
|
||||||
pid_t cpids[howmany_clients];
|
pid_t cpids[howmany_clients];
|
||||||
|
|
||||||
start_time = GNUNET_TIME_absolute_get ();
|
|
||||||
if (1 == howmany_clients)
|
if (1 == howmany_clients)
|
||||||
{
|
{
|
||||||
/* do everything in this process */
|
/* do everything in this process */
|
||||||
result = TALER_TESTING_setup (&run,
|
result = TALER_TESTING_loop (&run,
|
||||||
NULL,
|
NULL);
|
||||||
cfg,
|
|
||||||
NULL,
|
|
||||||
GNUNET_NO);
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
print_stats ();
|
print_stats ();
|
||||||
return result;
|
return result;
|
||||||
@ -340,11 +265,8 @@ launch_clients (void)
|
|||||||
GNUNET_log_setup ("benchmark-worker",
|
GNUNET_log_setup ("benchmark-worker",
|
||||||
NULL == loglev ? "INFO" : loglev,
|
NULL == loglev ? "INFO" : loglev,
|
||||||
logfile);
|
logfile);
|
||||||
result = TALER_TESTING_setup (&run,
|
result = TALER_TESTING_loop (&run,
|
||||||
NULL,
|
NULL);
|
||||||
cfg,
|
|
||||||
NULL,
|
|
||||||
GNUNET_NO);
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
print_stats ();
|
print_stats ();
|
||||||
if (GNUNET_OK != result)
|
if (GNUNET_OK != result)
|
||||||
@ -393,78 +315,6 @@ again:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the fakebank.
|
|
||||||
*
|
|
||||||
* @param cls fakebank handle
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
stop_fakebank (void *cls)
|
|
||||||
{
|
|
||||||
struct TALER_FAKEBANK_Handle *fakebank = cls;
|
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Stopping fakebank\n");
|
|
||||||
TALER_FAKEBANK_stop (fakebank);
|
|
||||||
GNUNET_SCHEDULER_cancel (keepalive);
|
|
||||||
keepalive = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dummy task that is never run.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
never_task (void *cls)
|
|
||||||
{
|
|
||||||
(void) cls;
|
|
||||||
GNUNET_assert (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the fakebank.
|
|
||||||
*
|
|
||||||
* @param cls NULL
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
launch_fakebank (void *cls)
|
|
||||||
{
|
|
||||||
struct TALER_FAKEBANK_Handle *fakebank;
|
|
||||||
unsigned long long pnum;
|
|
||||||
|
|
||||||
(void) cls;
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
|
||||||
"bank",
|
|
||||||
"HTTP_PORT",
|
|
||||||
&pnum))
|
|
||||||
{
|
|
||||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"bank",
|
|
||||||
"HTTP_PORT",
|
|
||||||
"must be valid port number");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fakebank
|
|
||||||
= TALER_FAKEBANK_start2 ((uint16_t) pnum,
|
|
||||||
currency,
|
|
||||||
history_size,
|
|
||||||
howmany_threads);
|
|
||||||
if (NULL == fakebank)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
keepalive
|
|
||||||
= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
|
|
||||||
&never_task,
|
|
||||||
NULL);
|
|
||||||
GNUNET_SCHEDULER_add_shutdown (&stop_fakebank,
|
|
||||||
fakebank);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the benchmark in parallel in many (client) processes
|
* Run the benchmark in parallel in many (client) processes
|
||||||
* and summarize result.
|
* and summarize result.
|
||||||
@ -475,278 +325,94 @@ static enum GNUNET_GenericReturnValue
|
|||||||
parallel_benchmark (void)
|
parallel_benchmark (void)
|
||||||
{
|
{
|
||||||
enum GNUNET_GenericReturnValue result = GNUNET_OK;
|
enum GNUNET_GenericReturnValue result = GNUNET_OK;
|
||||||
pid_t fakebank = -1;
|
|
||||||
struct GNUNET_OS_Process *bankd = NULL;
|
|
||||||
struct GNUNET_OS_Process *wirewatch[GNUNET_NZL (start_wirewatch)];
|
struct GNUNET_OS_Process *wirewatch[GNUNET_NZL (start_wirewatch)];
|
||||||
|
|
||||||
memset (wirewatch,
|
memset (wirewatch,
|
||||||
0,
|
0,
|
||||||
sizeof (wirewatch));
|
sizeof (wirewatch));
|
||||||
if ( (MODE_BANK == mode) ||
|
/* start exchange wirewatch */
|
||||||
(MODE_BOTH == mode) )
|
for (unsigned int w = 0; w<start_wirewatch; w++)
|
||||||
{
|
{
|
||||||
if (use_fakebank)
|
wirewatch[w] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
||||||
{
|
NULL, NULL, NULL,
|
||||||
unsigned long long pnum;
|
"taler-exchange-wirewatch",
|
||||||
|
"taler-exchange-wirewatch",
|
||||||
if (GNUNET_OK !=
|
"-c", cfg_filename,
|
||||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
(NULL != loglev) ? "-L" : NULL,
|
||||||
"bank",
|
loglev,
|
||||||
"HTTP_PORT",
|
NULL);
|
||||||
&pnum))
|
if (NULL == wirewatch[w])
|
||||||
{
|
|
||||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"bank",
|
|
||||||
"HTTP_PORT",
|
|
||||||
"must be valid port number");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
/* start fakebank */
|
|
||||||
fakebank = fork ();
|
|
||||||
if (0 == fakebank)
|
|
||||||
{
|
|
||||||
GNUNET_log_setup ("benchmark-fakebank",
|
|
||||||
NULL == loglev ? "INFO" : loglev,
|
|
||||||
logfile);
|
|
||||||
GNUNET_SCHEDULER_run (&launch_fakebank,
|
|
||||||
NULL);
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
if (-1 == fakebank)
|
|
||||||
{
|
|
||||||
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"fork");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
/* wait for fakebank to be ready */
|
|
||||||
{
|
|
||||||
char *bank_url;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
GNUNET_asprintf (&bank_url,
|
|
||||||
"http://localhost:%u/",
|
|
||||||
(unsigned int) (uint16_t) pnum);
|
|
||||||
ret = TALER_TESTING_wait_httpd_ready (bank_url);
|
|
||||||
GNUNET_free (bank_url);
|
|
||||||
if (0 != ret)
|
|
||||||
{
|
|
||||||
int wstatus;
|
|
||||||
|
|
||||||
kill (fakebank,
|
|
||||||
SIGTERM);
|
|
||||||
if (fakebank !=
|
|
||||||
waitpid (fakebank,
|
|
||||||
&wstatus,
|
|
||||||
0))
|
|
||||||
{
|
|
||||||
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"waitpid");
|
|
||||||
}
|
|
||||||
fakebank = -1;
|
|
||||||
exit (ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"FIXME #7273: launching LibEuFin not yet supported\n");
|
"Failed to launch wirewatch, aborting benchmark\n");
|
||||||
bankd = NULL; // FIXME #7273
|
for (unsigned int x = 0; x<w; x++)
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == incremental)
|
|
||||||
{
|
|
||||||
struct GNUNET_OS_Process *dbinit;
|
|
||||||
|
|
||||||
dbinit = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
|
||||||
NULL, NULL, NULL,
|
|
||||||
"taler-exchange-dbinit",
|
|
||||||
"taler-exchange-dbinit",
|
|
||||||
"-c", cfg_filename,
|
|
||||||
"-r",
|
|
||||||
(NULL != loglev) ? "-L" : NULL,
|
|
||||||
loglev,
|
|
||||||
NULL);
|
|
||||||
if (NULL == dbinit)
|
|
||||||
{
|
|
||||||
if (NULL != bankd)
|
|
||||||
{
|
|
||||||
GNUNET_OS_process_kill (bankd,
|
|
||||||
SIGTERM);
|
|
||||||
GNUNET_OS_process_destroy (bankd);
|
|
||||||
bankd = NULL;
|
|
||||||
}
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
GNUNET_break (GNUNET_OK ==
|
|
||||||
GNUNET_OS_process_wait (dbinit));
|
|
||||||
GNUNET_OS_process_destroy (dbinit);
|
|
||||||
}
|
|
||||||
/* start exchange wirewatch */
|
|
||||||
for (unsigned int w = 0; w<start_wirewatch; w++)
|
|
||||||
{
|
|
||||||
wirewatch[w] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
|
||||||
NULL, NULL, NULL,
|
|
||||||
"taler-exchange-wirewatch",
|
|
||||||
"taler-exchange-wirewatch",
|
|
||||||
"-c", cfg_filename,
|
|
||||||
(NULL != loglev) ? "-L" : NULL,
|
|
||||||
loglev,
|
|
||||||
NULL);
|
|
||||||
if (NULL == wirewatch[w])
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"Failed to launch wirewatch, aborting benchmark\n");
|
|
||||||
for (unsigned int x = 0; x<w; x++)
|
|
||||||
{
|
|
||||||
GNUNET_break (0 ==
|
|
||||||
GNUNET_OS_process_kill (wirewatch[x],
|
|
||||||
SIGTERM));
|
|
||||||
GNUNET_break (GNUNET_OK ==
|
|
||||||
GNUNET_OS_process_wait (wirewatch[x]));
|
|
||||||
GNUNET_OS_process_destroy (wirewatch[x]);
|
|
||||||
wirewatch[x] = NULL;
|
|
||||||
}
|
|
||||||
if (-1 != fakebank)
|
|
||||||
{
|
|
||||||
int wstatus;
|
|
||||||
|
|
||||||
kill (fakebank,
|
|
||||||
SIGTERM);
|
|
||||||
if (fakebank !=
|
|
||||||
waitpid (fakebank,
|
|
||||||
&wstatus,
|
|
||||||
0))
|
|
||||||
{
|
|
||||||
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"waitpid");
|
|
||||||
}
|
|
||||||
fakebank = -1;
|
|
||||||
}
|
|
||||||
if (NULL != bankd)
|
|
||||||
{
|
|
||||||
GNUNET_OS_process_kill (bankd,
|
|
||||||
SIGTERM);
|
|
||||||
GNUNET_OS_process_destroy (bankd);
|
|
||||||
bankd = NULL;
|
|
||||||
}
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (MODE_CLIENT == mode) ||
|
|
||||||
(MODE_BOTH == mode) )
|
|
||||||
result = launch_clients ();
|
|
||||||
if ( (GNUNET_YES == linger) ||
|
|
||||||
(MODE_BANK == mode) )
|
|
||||||
{
|
|
||||||
printf ("Press ENTER to stop!\n");
|
|
||||||
if (MODE_BANK != mode)
|
|
||||||
duration = GNUNET_TIME_absolute_get_duration (start_time);
|
|
||||||
(void) getchar ();
|
|
||||||
if (MODE_BANK == mode)
|
|
||||||
duration = GNUNET_TIME_absolute_get_duration (start_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (MODE_BANK == mode) ||
|
|
||||||
(MODE_BOTH == mode) )
|
|
||||||
{
|
|
||||||
/* Ensure wirewatch runs to completion! */
|
|
||||||
if (0 != start_wirewatch)
|
|
||||||
{
|
|
||||||
/* replace ONE of the wirewatchers with one that is in test-mode */
|
|
||||||
GNUNET_break (0 ==
|
|
||||||
GNUNET_OS_process_kill (wirewatch[0],
|
|
||||||
SIGTERM));
|
|
||||||
GNUNET_break (GNUNET_OK ==
|
|
||||||
GNUNET_OS_process_wait (wirewatch[0]));
|
|
||||||
GNUNET_OS_process_destroy (wirewatch[0]);
|
|
||||||
wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
|
||||||
NULL, NULL, NULL,
|
|
||||||
"taler-exchange-wirewatch",
|
|
||||||
"taler-exchange-wirewatch",
|
|
||||||
"-c", cfg_filename,
|
|
||||||
"-t",
|
|
||||||
(NULL != loglev) ? "-L" : NULL,
|
|
||||||
loglev,
|
|
||||||
NULL);
|
|
||||||
/* wait for it to finish! */
|
|
||||||
GNUNET_break (GNUNET_OK ==
|
|
||||||
GNUNET_OS_process_wait (wirewatch[0]));
|
|
||||||
GNUNET_OS_process_destroy (wirewatch[0]);
|
|
||||||
wirewatch[0] = NULL;
|
|
||||||
/* Then stop the rest, which should basically also be finished */
|
|
||||||
for (unsigned int w = 1; w<start_wirewatch; w++)
|
|
||||||
{
|
{
|
||||||
GNUNET_break (0 ==
|
GNUNET_break (0 ==
|
||||||
GNUNET_OS_process_kill (wirewatch[w],
|
GNUNET_OS_process_kill (wirewatch[x],
|
||||||
SIGTERM));
|
SIGTERM));
|
||||||
GNUNET_break (GNUNET_OK ==
|
GNUNET_break (GNUNET_OK ==
|
||||||
GNUNET_OS_process_wait (wirewatch[w]));
|
GNUNET_OS_process_wait (wirewatch[x]));
|
||||||
GNUNET_OS_process_destroy (wirewatch[w]);
|
GNUNET_OS_process_destroy (wirewatch[x]);
|
||||||
|
wirewatch[x] = NULL;
|
||||||
}
|
}
|
||||||
|
return GNUNET_SYSERR;
|
||||||
/* But be extra sure we did finish all shards by doing one more */
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
|
|
||||||
"Shard check phase\n");
|
|
||||||
wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
|
||||||
NULL, NULL, NULL,
|
|
||||||
"taler-exchange-wirewatch",
|
|
||||||
"taler-exchange-wirewatch",
|
|
||||||
"-c", cfg_filename,
|
|
||||||
"-t",
|
|
||||||
(NULL != loglev) ? "-L" : NULL,
|
|
||||||
loglev,
|
|
||||||
NULL);
|
|
||||||
/* wait for it to finish! */
|
|
||||||
GNUNET_break (GNUNET_OK ==
|
|
||||||
GNUNET_OS_process_wait (wirewatch[0]));
|
|
||||||
GNUNET_OS_process_destroy (wirewatch[0]);
|
|
||||||
wirewatch[0] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now stop the time, if this was the right mode */
|
|
||||||
if ( (GNUNET_YES != linger) &&
|
|
||||||
(MODE_BANK != mode) )
|
|
||||||
duration = GNUNET_TIME_absolute_get_duration (start_time);
|
|
||||||
|
|
||||||
/* stop fakebank */
|
|
||||||
if (-1 != fakebank)
|
|
||||||
{
|
|
||||||
int wstatus;
|
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Telling fakebank to shut down\n");
|
|
||||||
kill (fakebank,
|
|
||||||
SIGTERM);
|
|
||||||
if (fakebank !=
|
|
||||||
waitpid (fakebank,
|
|
||||||
&wstatus,
|
|
||||||
0))
|
|
||||||
{
|
|
||||||
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"waitpid");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( (! WIFEXITED (wstatus)) ||
|
|
||||||
(0 != WEXITSTATUS (wstatus)) )
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
result = GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fakebank = -1;
|
|
||||||
}
|
|
||||||
if (NULL != bankd)
|
|
||||||
{
|
|
||||||
GNUNET_OS_process_kill (bankd,
|
|
||||||
SIGTERM);
|
|
||||||
GNUNET_OS_process_destroy (bankd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result = launch_clients ();
|
||||||
|
/* Ensure wirewatch runs to completion! */
|
||||||
|
if (0 != start_wirewatch)
|
||||||
|
{
|
||||||
|
/* replace ONE of the wirewatchers with one that is in test-mode */
|
||||||
|
GNUNET_break (0 ==
|
||||||
|
GNUNET_OS_process_kill (wirewatch[0],
|
||||||
|
SIGTERM));
|
||||||
|
GNUNET_break (GNUNET_OK ==
|
||||||
|
GNUNET_OS_process_wait (wirewatch[0]));
|
||||||
|
GNUNET_OS_process_destroy (wirewatch[0]);
|
||||||
|
wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
"taler-exchange-wirewatch",
|
||||||
|
"taler-exchange-wirewatch",
|
||||||
|
"-c", cfg_filename,
|
||||||
|
"-t",
|
||||||
|
(NULL != loglev) ? "-L" : NULL,
|
||||||
|
loglev,
|
||||||
|
NULL);
|
||||||
|
/* wait for it to finish! */
|
||||||
|
GNUNET_break (GNUNET_OK ==
|
||||||
|
GNUNET_OS_process_wait (wirewatch[0]));
|
||||||
|
GNUNET_OS_process_destroy (wirewatch[0]);
|
||||||
|
wirewatch[0] = NULL;
|
||||||
|
/* Then stop the rest, which should basically also be finished */
|
||||||
|
for (unsigned int w = 1; w<start_wirewatch; w++)
|
||||||
|
{
|
||||||
|
GNUNET_break (0 ==
|
||||||
|
GNUNET_OS_process_kill (wirewatch[w],
|
||||||
|
SIGTERM));
|
||||||
|
GNUNET_break (GNUNET_OK ==
|
||||||
|
GNUNET_OS_process_wait (wirewatch[w]));
|
||||||
|
GNUNET_OS_process_destroy (wirewatch[w]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* But be extra sure we did finish all shards by doing one more */
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
|
||||||
|
"Shard check phase\n");
|
||||||
|
wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
"taler-exchange-wirewatch",
|
||||||
|
"taler-exchange-wirewatch",
|
||||||
|
"-c", cfg_filename,
|
||||||
|
"-t",
|
||||||
|
(NULL != loglev) ? "-L" : NULL,
|
||||||
|
loglev,
|
||||||
|
NULL);
|
||||||
|
/* wait for it to finish! */
|
||||||
|
GNUNET_break (GNUNET_OK ==
|
||||||
|
GNUNET_OS_process_wait (wirewatch[0]));
|
||||||
|
GNUNET_OS_process_destroy (wirewatch[0]);
|
||||||
|
wirewatch[0] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,32 +432,17 @@ main (int argc,
|
|||||||
struct GNUNET_GETOPT_CommandLineOption options[] = {
|
struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||||
GNUNET_GETOPT_option_mandatory (
|
GNUNET_GETOPT_option_mandatory (
|
||||||
GNUNET_GETOPT_option_cfgfile (&cfg_filename)),
|
GNUNET_GETOPT_option_cfgfile (&cfg_filename)),
|
||||||
#if FIXME_SUPPORT_LIBEUFIN
|
|
||||||
GNUNET_GETOPT_option_flag ('f',
|
GNUNET_GETOPT_option_flag ('f',
|
||||||
"fakebank",
|
"fakebank",
|
||||||
"start a fakebank instead of the Python bank",
|
"we are using fakebank",
|
||||||
&use_fakebank),
|
&use_fakebank),
|
||||||
#endif
|
|
||||||
GNUNET_GETOPT_option_help ("taler-bank benchmark"),
|
GNUNET_GETOPT_option_help ("taler-bank benchmark"),
|
||||||
GNUNET_GETOPT_option_flag ('K',
|
|
||||||
"linger",
|
|
||||||
"linger around until key press",
|
|
||||||
&linger),
|
|
||||||
GNUNET_GETOPT_option_flag ('i',
|
|
||||||
"incremental",
|
|
||||||
"skip initializing and resetting the database",
|
|
||||||
&incremental),
|
|
||||||
GNUNET_GETOPT_option_string ('l',
|
GNUNET_GETOPT_option_string ('l',
|
||||||
"logfile",
|
"logfile",
|
||||||
"LF",
|
"LF",
|
||||||
"will log to file LF",
|
"will log to file LF",
|
||||||
&logfile),
|
&logfile),
|
||||||
GNUNET_GETOPT_option_loglevel (&loglev),
|
GNUNET_GETOPT_option_loglevel (&loglev),
|
||||||
GNUNET_GETOPT_option_string ('m',
|
|
||||||
"mode",
|
|
||||||
"MODE",
|
|
||||||
"run as bank, client or both",
|
|
||||||
&mode_str),
|
|
||||||
GNUNET_GETOPT_option_uint ('p',
|
GNUNET_GETOPT_option_uint ('p',
|
||||||
"worker-parallelism",
|
"worker-parallelism",
|
||||||
"NPROCS",
|
"NPROCS",
|
||||||
@ -807,11 +458,12 @@ main (int argc,
|
|||||||
"NRESERVES",
|
"NRESERVES",
|
||||||
"How many reserves per client we should create",
|
"How many reserves per client we should create",
|
||||||
&howmany_reserves),
|
&howmany_reserves),
|
||||||
GNUNET_GETOPT_option_ulong ('s',
|
GNUNET_GETOPT_option_string (
|
||||||
"size",
|
'u',
|
||||||
"HISTORY_SIZE",
|
"exchange-account-section",
|
||||||
"Maximum history size kept in memory by the fakebank",
|
"SECTION",
|
||||||
&history_size),
|
"use exchange bank account configuration from the given SECTION",
|
||||||
|
&exchange_bank_section),
|
||||||
GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
|
GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
|
||||||
GNUNET_GETOPT_option_verbose (&verbose),
|
GNUNET_GETOPT_option_verbose (&verbose),
|
||||||
GNUNET_GETOPT_option_uint ('w',
|
GNUNET_GETOPT_option_uint ('w',
|
||||||
@ -821,6 +473,7 @@ main (int argc,
|
|||||||
&start_wirewatch),
|
&start_wirewatch),
|
||||||
GNUNET_GETOPT_OPTION_END
|
GNUNET_GETOPT_OPTION_END
|
||||||
};
|
};
|
||||||
|
struct GNUNET_TIME_Relative duration;
|
||||||
|
|
||||||
unsetenv ("XDG_DATA_HOME");
|
unsetenv ("XDG_DATA_HOME");
|
||||||
unsetenv ("XDG_CONFIG_HOME");
|
unsetenv ("XDG_CONFIG_HOME");
|
||||||
@ -833,35 +486,15 @@ main (int argc,
|
|||||||
GNUNET_free (cfg_filename);
|
GNUNET_free (cfg_filename);
|
||||||
if (GNUNET_NO == result)
|
if (GNUNET_NO == result)
|
||||||
return 0;
|
return 0;
|
||||||
return BAD_CLI_ARG;
|
return EXIT_INVALIDARGUMENT;
|
||||||
}
|
}
|
||||||
|
if (NULL == exchange_bank_section)
|
||||||
|
exchange_bank_section = "exchange-account-1";
|
||||||
|
if (NULL == loglev)
|
||||||
|
loglev = "INFO";
|
||||||
GNUNET_log_setup ("taler-bank-benchmark",
|
GNUNET_log_setup ("taler-bank-benchmark",
|
||||||
NULL == loglev ? "INFO" : loglev,
|
loglev,
|
||||||
logfile);
|
logfile);
|
||||||
if (history_size < 10)
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"History size too small, this can hardly work\n");
|
|
||||||
return BAD_CLI_ARG;
|
|
||||||
}
|
|
||||||
if (NULL == mode_str)
|
|
||||||
mode = MODE_BOTH;
|
|
||||||
else if (0 == strcasecmp (mode_str,
|
|
||||||
"bank"))
|
|
||||||
mode = MODE_BANK;
|
|
||||||
else if (0 == strcasecmp (mode_str,
|
|
||||||
"client"))
|
|
||||||
mode = MODE_CLIENT;
|
|
||||||
else if (0 == strcasecmp (mode_str,
|
|
||||||
"both"))
|
|
||||||
mode = MODE_BOTH;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TALER_LOG_ERROR ("Unknown mode given: '%s'\n",
|
|
||||||
mode_str);
|
|
||||||
GNUNET_free (cfg_filename);
|
|
||||||
return BAD_CONFIG_FILE;
|
|
||||||
}
|
|
||||||
if (NULL == cfg_filename)
|
if (NULL == cfg_filename)
|
||||||
cfg_filename = GNUNET_CONFIGURATION_default_filename ();
|
cfg_filename = GNUNET_CONFIGURATION_default_filename ();
|
||||||
if (NULL == cfg_filename)
|
if (NULL == cfg_filename)
|
||||||
@ -877,7 +510,7 @@ main (int argc,
|
|||||||
{
|
{
|
||||||
TALER_LOG_ERROR ("Could not parse configuration\n");
|
TALER_LOG_ERROR ("Could not parse configuration\n");
|
||||||
GNUNET_free (cfg_filename);
|
GNUNET_free (cfg_filename);
|
||||||
return BAD_CONFIG_FILE;
|
return EXIT_NOTCONFIGURED;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_currency (cfg,
|
TALER_config_get_currency (cfg,
|
||||||
@ -885,52 +518,30 @@ main (int argc,
|
|||||||
{
|
{
|
||||||
GNUNET_CONFIGURATION_destroy (cfg);
|
GNUNET_CONFIGURATION_destroy (cfg);
|
||||||
GNUNET_free (cfg_filename);
|
GNUNET_free (cfg_filename);
|
||||||
return BAD_CONFIG_FILE;
|
return EXIT_NOTCONFIGURED;
|
||||||
}
|
|
||||||
if (MODE_BANK != mode)
|
|
||||||
{
|
|
||||||
if (howmany_clients > 10240)
|
|
||||||
{
|
|
||||||
TALER_LOG_ERROR ("-p option value given is too large\n");
|
|
||||||
return BAD_CLI_ARG;
|
|
||||||
}
|
|
||||||
if (0 == howmany_clients)
|
|
||||||
{
|
|
||||||
TALER_LOG_ERROR ("-p option value must not be zero\n");
|
|
||||||
GNUNET_free (cfg_filename);
|
|
||||||
return BAD_CLI_ARG;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_EXCHANGEDB_load_accounts (cfg,
|
TALER_TESTING_get_credentials (
|
||||||
TALER_EXCHANGEDB_ALO_AUTHDATA
|
cfg_filename,
|
||||||
| TALER_EXCHANGEDB_ALO_CREDIT))
|
exchange_bank_section,
|
||||||
|
use_fakebank
|
||||||
|
? TALER_TESTING_BS_FAKEBANK
|
||||||
|
: TALER_TESTING_BS_IBAN,
|
||||||
|
&cred))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Configuration fails to provide exchange bank details\n");
|
"Required bank credentials not given in configuration\n");
|
||||||
GNUNET_free (cfg_filename);
|
GNUNET_free (cfg_filename);
|
||||||
return BAD_CONFIG_FILE;
|
return EXIT_NOTCONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
exchange_bank_account
|
|
||||||
= TALER_EXCHANGEDB_find_account_by_method ("x-taler-bank");
|
|
||||||
if (NULL == exchange_bank_account)
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
struct GNUNET_TIME_Absolute start_time;
|
||||||
"No bank account for `x-taler-bank` given in configuration\n");
|
|
||||||
GNUNET_free (cfg_filename);
|
|
||||||
return BAD_CONFIG_FILE;
|
|
||||||
}
|
|
||||||
result = parallel_benchmark ();
|
|
||||||
TALER_EXCHANGEDB_unload_accounts ();
|
|
||||||
GNUNET_CONFIGURATION_destroy (cfg);
|
|
||||||
GNUNET_free (cfg_filename);
|
|
||||||
|
|
||||||
if (MODE_BANK == mode)
|
start_time = GNUNET_TIME_absolute_get ();
|
||||||
{
|
result = parallel_benchmark ();
|
||||||
/* If we're the bank, we're done now. No need to print results. */
|
duration = GNUNET_TIME_absolute_get_duration (start_time);
|
||||||
return (GNUNET_OK == result) ? 0 : result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK == result)
|
if (GNUNET_OK == result)
|
||||||
@ -958,7 +569,7 @@ main (int argc,
|
|||||||
tps);
|
tps);
|
||||||
}
|
}
|
||||||
fprintf (stdout,
|
fprintf (stdout,
|
||||||
"CPU time: sys %llu user %llu\n", \
|
"CPU time: sys %llu user %llu\n",
|
||||||
(unsigned long long) (usage.ru_stime.tv_sec * 1000 * 1000
|
(unsigned long long) (usage.ru_stime.tv_sec * 1000 * 1000
|
||||||
+ usage.ru_stime.tv_usec),
|
+ usage.ru_stime.tv_usec),
|
||||||
(unsigned long long) (usage.ru_utime.tv_sec * 1000 * 1000
|
(unsigned long long) (usage.ru_utime.tv_sec * 1000 * 1000
|
||||||
@ -969,5 +580,7 @@ main (int argc,
|
|||||||
GNUNET_array_grow (labels,
|
GNUNET_array_grow (labels,
|
||||||
label_len,
|
label_len,
|
||||||
0);
|
0);
|
||||||
|
GNUNET_CONFIGURATION_destroy (cfg);
|
||||||
|
GNUNET_free (cfg_filename);
|
||||||
return (GNUNET_OK == result) ? 0 : result;
|
return (GNUNET_OK == result) ? 0 : result;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,10 +3,10 @@
|
|||||||
[exchange-offline]
|
[exchange-offline]
|
||||||
|
|
||||||
# Where do we store the offline master private key of the exchange?
|
# Where do we store the offline master private key of the exchange?
|
||||||
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange-offline/master.priv
|
MASTER_PRIV_FILE = ${TALER_DATA_HOME}exchange-offline/master.priv
|
||||||
|
|
||||||
# Where do we store the TOFU key material?
|
# Where do we store the TOFU key material?
|
||||||
SECM_TOFU_FILE = ${TALER_DATA_HOME}/exchange-offline/secm_tofus.pub
|
SECM_TOFU_FILE = ${TALER_DATA_HOME}exchange-offline/secm_tofus.pub
|
||||||
|
|
||||||
# Base32-encoded public key of the RSA helper.
|
# Base32-encoded public key of the RSA helper.
|
||||||
# SECM_DENOM_PUBKEY =
|
# SECM_DENOM_PUBKEY =
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2020-2021 Taler Systems SA
|
Copyright (C) 2020-2023 Taler Systems SA
|
||||||
|
|
||||||
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
|
||||||
@ -174,7 +174,7 @@ static struct DenominationAddRequest *dar_tail;
|
|||||||
/**
|
/**
|
||||||
* Handle to the exchange, used to request /keys.
|
* Handle to the exchange, used to request /keys.
|
||||||
*/
|
*/
|
||||||
static struct TALER_EXCHANGE_Handle *exchange;
|
static struct TALER_EXCHANGE_GetKeysHandle *exchange;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,7 +219,7 @@ do_shutdown (void *cls)
|
|||||||
}
|
}
|
||||||
if (NULL != exchange)
|
if (NULL != exchange)
|
||||||
{
|
{
|
||||||
TALER_EXCHANGE_disconnect (exchange);
|
TALER_EXCHANGE_get_keys_cancel (exchange);
|
||||||
exchange = NULL;
|
exchange = NULL;
|
||||||
}
|
}
|
||||||
if (NULL != nxt)
|
if (NULL != nxt)
|
||||||
@ -388,14 +388,15 @@ load_offline_key (int do_create)
|
|||||||
* add operation result.
|
* add operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct DenominationAddRequest`
|
* @param cls closure with a `struct DenominationAddRequest`
|
||||||
* @param hr HTTP response data
|
* @param adr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
denomination_add_cb (
|
denomination_add_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_AuditorAddDenominationResponse *adr)
|
||||||
{
|
{
|
||||||
struct DenominationAddRequest *dar = cls;
|
struct DenominationAddRequest *dar = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -644,30 +645,24 @@ do_upload (char *const *args)
|
|||||||
* a particular exchange and what keys the exchange is using.
|
* a particular exchange and what keys the exchange is using.
|
||||||
*
|
*
|
||||||
* @param cls closure with the `char **` remaining args
|
* @param cls closure with the `char **` remaining args
|
||||||
* @param hr HTTP response data
|
* @param kr response data
|
||||||
* @param keys information about the various keys used
|
* @param keys key data from the exchange
|
||||||
* by the exchange, NULL if /keys failed
|
|
||||||
* @param compat protocol compatibility information
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
keys_cb (
|
keys_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
const struct TALER_EXCHANGE_KeysResponse *kr,
|
||||||
const struct TALER_EXCHANGE_Keys *keys,
|
struct TALER_EXCHANGE_Keys *keys)
|
||||||
enum TALER_EXCHANGE_VersionCompatibility compat)
|
|
||||||
{
|
{
|
||||||
char *const *args = cls;
|
char *const *args = cls;
|
||||||
|
|
||||||
(void) keys;
|
exchange = NULL;
|
||||||
(void) compat;
|
switch (kr->hr.http_status)
|
||||||
switch (hr->http_status)
|
|
||||||
{
|
{
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
if (! json_is_object (hr->reply))
|
if (NULL == kr->hr.reply)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
TALER_EXCHANGE_disconnect (exchange);
|
|
||||||
exchange = NULL;
|
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
return;
|
return;
|
||||||
@ -676,11 +671,9 @@ keys_cb (
|
|||||||
default:
|
default:
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"Failed to download keys: %s (HTTP status: %u/%u)\n",
|
"Failed to download keys: %s (HTTP status: %u/%u)\n",
|
||||||
hr->hint,
|
kr->hr.hint,
|
||||||
hr->http_status,
|
kr->hr.http_status,
|
||||||
(unsigned int) hr->ec);
|
(unsigned int) kr->hr.ec);
|
||||||
TALER_EXCHANGE_disconnect (exchange);
|
|
||||||
exchange = NULL;
|
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
return;
|
return;
|
||||||
@ -689,7 +682,7 @@ keys_cb (
|
|||||||
GNUNET_JSON_pack_string ("operation",
|
GNUNET_JSON_pack_string ("operation",
|
||||||
OP_INPUT_KEYS),
|
OP_INPUT_KEYS),
|
||||||
GNUNET_JSON_pack_object_incref ("arguments",
|
GNUNET_JSON_pack_object_incref ("arguments",
|
||||||
(json_t *) hr->reply));
|
(json_t *) kr->hr.reply));
|
||||||
if (NULL == args[0])
|
if (NULL == args[0])
|
||||||
{
|
{
|
||||||
json_dumpf (in,
|
json_dumpf (in,
|
||||||
@ -698,9 +691,8 @@ keys_cb (
|
|||||||
json_decref (in);
|
json_decref (in);
|
||||||
in = NULL;
|
in = NULL;
|
||||||
}
|
}
|
||||||
TALER_EXCHANGE_disconnect (exchange);
|
|
||||||
exchange = NULL;
|
|
||||||
next (args);
|
next (args);
|
||||||
|
TALER_EXCHANGE_keys_decref (keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -727,11 +719,11 @@ do_download (char *const *args)
|
|||||||
global_ret = EXIT_NOTCONFIGURED;
|
global_ret = EXIT_NOTCONFIGURED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exchange = TALER_EXCHANGE_connect (ctx,
|
exchange = TALER_EXCHANGE_get_keys (ctx,
|
||||||
exchange_url,
|
exchange_url,
|
||||||
&keys_cb,
|
NULL,
|
||||||
(void *) args,
|
&keys_cb,
|
||||||
TALER_EXCHANGE_OPTION_END);
|
(void *) args);
|
||||||
GNUNET_free (exchange_url);
|
GNUNET_free (exchange_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,11 +948,11 @@ do_show (char *const *args)
|
|||||||
json_t *keys;
|
json_t *keys;
|
||||||
const char *err_name;
|
const char *err_name;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
json_t *denomkeys;
|
const json_t *denomkeys;
|
||||||
struct TALER_MasterPublicKeyP mpub;
|
struct TALER_MasterPublicKeyP mpub;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("denoms",
|
GNUNET_JSON_spec_array_const ("denoms",
|
||||||
&denomkeys),
|
&denomkeys),
|
||||||
GNUNET_JSON_spec_fixed_auto ("master_public_key",
|
GNUNET_JSON_spec_fixed_auto ("master_public_key",
|
||||||
&mpub),
|
&mpub),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
@ -1004,11 +996,9 @@ do_show (char *const *args)
|
|||||||
{
|
{
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
/* do NOT consume input if next argument is '-' */
|
/* do NOT consume input if next argument is '-' */
|
||||||
if ( (NULL != args[0]) &&
|
if ( (NULL != args[0]) &&
|
||||||
@ -1145,10 +1135,10 @@ do_sign (char *const *args)
|
|||||||
const char *err_name;
|
const char *err_name;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
struct TALER_MasterPublicKeyP mpub;
|
struct TALER_MasterPublicKeyP mpub;
|
||||||
json_t *denomkeys;
|
const json_t *denomkeys;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("denoms",
|
GNUNET_JSON_spec_array_const ("denoms",
|
||||||
&denomkeys),
|
&denomkeys),
|
||||||
GNUNET_JSON_spec_fixed_auto ("master_public_key",
|
GNUNET_JSON_spec_fixed_auto ("master_public_key",
|
||||||
&mpub),
|
&mpub),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
@ -1203,11 +1193,9 @@ do_sign (char *const *args)
|
|||||||
{
|
{
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
next (args);
|
next (args);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_exchange_service.h"
|
#include "taler_exchange_service.h"
|
||||||
#include "taler_extensions.h"
|
#include "taler_extensions.h"
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the input for the 'sign' and 'show' operation.
|
* Name of the input for the 'sign' and 'show' operation.
|
||||||
@ -1119,14 +1121,15 @@ load_offline_key (int do_create)
|
|||||||
* Function called with information about the post revocation operation result.
|
* Function called with information about the post revocation operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct DenomRevocationRequest`
|
* @param cls closure with a `struct DenomRevocationRequest`
|
||||||
* @param hr HTTP response data
|
* @param dr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
denom_revocation_cb (
|
denom_revocation_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *dr)
|
||||||
{
|
{
|
||||||
struct DenomRevocationRequest *drr = cls;
|
struct DenomRevocationRequest *drr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &dr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1208,14 +1211,15 @@ upload_denom_revocation (const char *exchange_url,
|
|||||||
* Function called with information about the post revocation operation result.
|
* Function called with information about the post revocation operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct SignkeyRevocationRequest`
|
* @param cls closure with a `struct SignkeyRevocationRequest`
|
||||||
* @param hr HTTP response data
|
* @param sr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
signkey_revocation_cb (
|
signkey_revocation_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *sr)
|
||||||
{
|
{
|
||||||
struct SignkeyRevocationRequest *srr = cls;
|
struct SignkeyRevocationRequest *srr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &sr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1297,13 +1301,15 @@ upload_signkey_revocation (const char *exchange_url,
|
|||||||
* Function called with information about the post auditor add operation result.
|
* Function called with information about the post auditor add operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct AuditorAddRequest`
|
* @param cls closure with a `struct AuditorAddRequest`
|
||||||
* @param hr HTTP response data
|
* @param mer response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
auditor_add_cb (void *cls,
|
auditor_add_cb (
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
void *cls,
|
||||||
|
const struct TALER_EXCHANGE_ManagementAuditorEnableResponse *mer)
|
||||||
{
|
{
|
||||||
struct AuditorAddRequest *aar = cls;
|
struct AuditorAddRequest *aar = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &mer->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1397,13 +1403,15 @@ upload_auditor_add (const char *exchange_url,
|
|||||||
* Function called with information about the post auditor del operation result.
|
* Function called with information about the post auditor del operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct AuditorDelRequest`
|
* @param cls closure with a `struct AuditorDelRequest`
|
||||||
* @param hr HTTP response data
|
* @param mdr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
auditor_del_cb (void *cls,
|
auditor_del_cb (void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct
|
||||||
|
TALER_EXCHANGE_ManagementAuditorDisableResponse *mdr)
|
||||||
{
|
{
|
||||||
struct AuditorDelRequest *adr = cls;
|
struct AuditorDelRequest *adr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &mdr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1489,13 +1497,14 @@ upload_auditor_del (const char *exchange_url,
|
|||||||
* Function called with information about the post wire add operation result.
|
* Function called with information about the post wire add operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct WireAddRequest`
|
* @param cls closure with a `struct WireAddRequest`
|
||||||
* @param hr HTTP response data
|
* @param wer response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
wire_add_cb (void *cls,
|
wire_add_cb (void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer)
|
||||||
{
|
{
|
||||||
struct WireAddRequest *war = cls;
|
struct WireAddRequest *war = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1533,10 +1542,21 @@ upload_wire_add (const char *exchange_url,
|
|||||||
struct GNUNET_TIME_Timestamp start_time;
|
struct GNUNET_TIME_Timestamp start_time;
|
||||||
struct WireAddRequest *war;
|
struct WireAddRequest *war;
|
||||||
const char *err_name;
|
const char *err_name;
|
||||||
|
const char *conversion_url = NULL;
|
||||||
|
const json_t *debit_restrictions;
|
||||||
|
const json_t *credit_restrictions;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_string ("payto_uri",
|
GNUNET_JSON_spec_string ("payto_uri",
|
||||||
&payto_uri),
|
&payto_uri),
|
||||||
|
GNUNET_JSON_spec_mark_optional (
|
||||||
|
GNUNET_JSON_spec_string ("conversion_url",
|
||||||
|
&conversion_url),
|
||||||
|
NULL),
|
||||||
|
GNUNET_JSON_spec_array_const ("debit_restrictions",
|
||||||
|
&debit_restrictions),
|
||||||
|
GNUNET_JSON_spec_array_const ("credit_restrictions",
|
||||||
|
&credit_restrictions),
|
||||||
GNUNET_JSON_spec_timestamp ("validity_start",
|
GNUNET_JSON_spec_timestamp ("validity_start",
|
||||||
&start_time),
|
&start_time),
|
||||||
GNUNET_JSON_spec_fixed_auto ("master_sig_add",
|
GNUNET_JSON_spec_fixed_auto ("master_sig_add",
|
||||||
@ -1599,6 +1619,9 @@ upload_wire_add (const char *exchange_url,
|
|||||||
TALER_EXCHANGE_management_enable_wire (ctx,
|
TALER_EXCHANGE_management_enable_wire (ctx,
|
||||||
exchange_url,
|
exchange_url,
|
||||||
payto_uri,
|
payto_uri,
|
||||||
|
conversion_url,
|
||||||
|
debit_restrictions,
|
||||||
|
credit_restrictions,
|
||||||
start_time,
|
start_time,
|
||||||
&master_sig_add,
|
&master_sig_add,
|
||||||
&master_sig_wire,
|
&master_sig_wire,
|
||||||
@ -1614,13 +1637,14 @@ upload_wire_add (const char *exchange_url,
|
|||||||
* Function called with information about the post wire del operation result.
|
* Function called with information about the post wire del operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct WireDelRequest`
|
* @param cls closure with a `struct WireDelRequest`
|
||||||
* @param hr HTTP response data
|
* @param wdres response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
wire_del_cb (void *cls,
|
wire_del_cb (void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdres)
|
||||||
{
|
{
|
||||||
struct WireDelRequest *wdr = cls;
|
struct WireDelRequest *wdr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &wdres->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1706,14 +1730,15 @@ upload_wire_del (const char *exchange_url,
|
|||||||
* Function called with information about the post wire fee operation result.
|
* Function called with information about the post wire fee operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct WireFeeRequest`
|
* @param cls closure with a `struct WireFeeRequest`
|
||||||
* @param hr HTTP response data
|
* @param swr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
wire_fee_cb (
|
wire_fee_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementSetWireFeeResponse *swr)
|
||||||
{
|
{
|
||||||
struct WireFeeRequest *wfr = cls;
|
struct WireFeeRequest *wfr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &swr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1811,14 +1836,15 @@ upload_wire_fee (const char *exchange_url,
|
|||||||
* Function called with information about the post global fee operation result.
|
* Function called with information about the post global fee operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct WireFeeRequest`
|
* @param cls closure with a `struct WireFeeRequest`
|
||||||
* @param hr HTTP response data
|
* @param gr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
global_fee_cb (
|
global_fee_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementSetGlobalFeeResponse *gr)
|
||||||
{
|
{
|
||||||
struct GlobalFeeRequest *gfr = cls;
|
struct GlobalFeeRequest *gfr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &gr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -1927,14 +1953,15 @@ upload_global_fee (const char *exchange_url,
|
|||||||
* Function called with information about the drain profits operation.
|
* Function called with information about the drain profits operation.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct DrainProfitsRequest`
|
* @param cls closure with a `struct DrainProfitsRequest`
|
||||||
* @param hr HTTP response data
|
* @param mdr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
drain_profits_cb (
|
drain_profits_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementDrainResponse *mdr)
|
||||||
{
|
{
|
||||||
struct DrainProfitsRequest *dpr = cls;
|
struct DrainProfitsRequest *dpr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &mdr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -2033,14 +2060,15 @@ upload_drain (const char *exchange_url,
|
|||||||
* Function called with information about the post upload keys operation result.
|
* Function called with information about the post upload keys operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct UploadKeysRequest`
|
* @param cls closure with a `struct UploadKeysRequest`
|
||||||
* @param hr HTTP response data
|
* @param mr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
keys_cb (
|
keys_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementPostKeysResponse *mr)
|
||||||
{
|
{
|
||||||
struct UploadKeysRequest *ukr = cls;
|
struct UploadKeysRequest *ukr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -2076,13 +2104,13 @@ upload_keys (const char *exchange_url,
|
|||||||
struct UploadKeysRequest *ukr;
|
struct UploadKeysRequest *ukr;
|
||||||
const char *err_name;
|
const char *err_name;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
json_t *denom_sigs;
|
const json_t *denom_sigs;
|
||||||
json_t *signkey_sigs;
|
const json_t *signkey_sigs;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("denom_sigs",
|
GNUNET_JSON_spec_array_const ("denom_sigs",
|
||||||
&denom_sigs),
|
&denom_sigs),
|
||||||
GNUNET_JSON_spec_json ("signkey_sigs",
|
GNUNET_JSON_spec_array_const ("signkey_sigs",
|
||||||
&signkey_sigs),
|
&signkey_sigs),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
@ -2198,7 +2226,6 @@ upload_keys (const char *exchange_url,
|
|||||||
}
|
}
|
||||||
GNUNET_free (pkd.sign_sigs);
|
GNUNET_free (pkd.sign_sigs);
|
||||||
GNUNET_free (pkd.denom_sigs);
|
GNUNET_free (pkd.denom_sigs);
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2206,14 +2233,15 @@ upload_keys (const char *exchange_url,
|
|||||||
* Function called with information about the post upload extensions operation result.
|
* Function called with information about the post upload extensions operation result.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct UploadExtensionsRequest`
|
* @param cls closure with a `struct UploadExtensionsRequest`
|
||||||
* @param hr HTTP response data
|
* @param er response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
extensions_cb (
|
extensions_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementPostExtensionsResponse *er)
|
||||||
{
|
{
|
||||||
struct UploadExtensionsRequest *uer = cls;
|
struct UploadExtensionsRequest *uer = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &er->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -2245,13 +2273,13 @@ upload_extensions (const char *exchange_url,
|
|||||||
size_t idx,
|
size_t idx,
|
||||||
const json_t *value)
|
const json_t *value)
|
||||||
{
|
{
|
||||||
json_t *extensions;
|
const json_t *extensions;
|
||||||
struct TALER_MasterSignatureP sig;
|
struct TALER_MasterSignatureP sig;
|
||||||
const char *err_name;
|
const char *err_name;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("extensions",
|
GNUNET_JSON_spec_object_const ("extensions",
|
||||||
&extensions),
|
&extensions),
|
||||||
GNUNET_JSON_spec_fixed_auto ("extensions_sig",
|
GNUNET_JSON_spec_fixed_auto ("extensions_sig",
|
||||||
&sig),
|
&sig),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
@ -2282,9 +2310,9 @@ upload_extensions (const char *exchange_url,
|
|||||||
struct TALER_ExtensionManifestsHashP h_manifests;
|
struct TALER_ExtensionManifestsHashP h_manifests;
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_JSON_extensions_manifests_hash (extensions, &h_manifests))
|
TALER_JSON_extensions_manifests_hash (extensions,
|
||||||
|
&h_manifests))
|
||||||
{
|
{
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"couldn't hash extensions' manifests\n");
|
"couldn't hash extensions' manifests\n");
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
@ -2301,7 +2329,6 @@ upload_extensions (const char *exchange_url,
|
|||||||
&master_pub,
|
&master_pub,
|
||||||
&sig))
|
&sig))
|
||||||
{
|
{
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"invalid signature for extensions\n");
|
"invalid signature for extensions\n");
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
@ -2316,8 +2343,9 @@ upload_extensions (const char *exchange_url,
|
|||||||
.extensions = extensions,
|
.extensions = extensions,
|
||||||
.extensions_sig = sig,
|
.extensions_sig = sig,
|
||||||
};
|
};
|
||||||
struct UploadExtensionsRequest *uer = GNUNET_new (struct
|
struct UploadExtensionsRequest *uer
|
||||||
UploadExtensionsRequest);
|
= GNUNET_new (struct UploadExtensionsRequest);
|
||||||
|
|
||||||
uer->idx = idx;
|
uer->idx = idx;
|
||||||
uer->h = TALER_EXCHANGE_management_post_extensions (
|
uer->h = TALER_EXCHANGE_management_post_extensions (
|
||||||
ctx,
|
ctx,
|
||||||
@ -2329,7 +2357,6 @@ upload_extensions (const char *exchange_url,
|
|||||||
uer_tail,
|
uer_tail,
|
||||||
uer);
|
uer);
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2337,14 +2364,15 @@ upload_extensions (const char *exchange_url,
|
|||||||
* Function called with information about the add partner operation.
|
* Function called with information about the add partner operation.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct PartnerAddRequest`
|
* @param cls closure with a `struct PartnerAddRequest`
|
||||||
* @param hr HTTP response data
|
* @param apr response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
add_partner_cb (
|
add_partner_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementAddPartnerResponse *apr)
|
||||||
{
|
{
|
||||||
struct PartnerAddRequest *par = cls;
|
struct PartnerAddRequest *par = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &apr->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -2447,14 +2475,15 @@ add_partner (const char *exchange_url,
|
|||||||
* Function called with information about the AML officer update operation.
|
* Function called with information about the AML officer update operation.
|
||||||
*
|
*
|
||||||
* @param cls closure with a `struct AmlStaffRequest`
|
* @param cls closure with a `struct AmlStaffRequest`
|
||||||
* @param hr HTTP response data
|
* @param ar response data
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
update_aml_officer_cb (
|
update_aml_officer_cb (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr)
|
const struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar)
|
||||||
{
|
{
|
||||||
struct AmlStaffRequest *asr = cls;
|
struct AmlStaffRequest *asr = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr;
|
||||||
|
|
||||||
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
if (MHD_HTTP_NO_CONTENT != hr->http_status)
|
||||||
{
|
{
|
||||||
@ -2949,6 +2978,96 @@ do_del_auditor (char *const *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse account restriction.
|
||||||
|
*
|
||||||
|
* @param args the array of command-line arguments to process next
|
||||||
|
* @param[in,out] restrictions JSON array to update
|
||||||
|
* @return -1 on error, otherwise number of arguments from @a args that were used
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_restriction (char *const *args,
|
||||||
|
json_t *restrictions)
|
||||||
|
{
|
||||||
|
if (NULL == args[0])
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Restriction TYPE argument missing\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (0 == strcmp (args[0],
|
||||||
|
"deny"))
|
||||||
|
{
|
||||||
|
GNUNET_assert (0 ==
|
||||||
|
json_array_append_new (
|
||||||
|
restrictions,
|
||||||
|
GNUNET_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_string ("type",
|
||||||
|
"deny"))));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (0 == strcmp (args[0],
|
||||||
|
"regex"))
|
||||||
|
{
|
||||||
|
json_t *i18n;
|
||||||
|
json_error_t err;
|
||||||
|
|
||||||
|
if ( (NULL == args[1]) ||
|
||||||
|
(NULL == args[2]) ||
|
||||||
|
(NULL == args[3]) )
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Mandatory arguments for restriction of type `regex' missing (REGEX, HINT, HINT-I18 required)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
regex_t ex;
|
||||||
|
|
||||||
|
if (0 != regcomp (&ex,
|
||||||
|
args[1],
|
||||||
|
REG_NOSUB | REG_EXTENDED))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid regular expression `%s'\n",
|
||||||
|
args[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
regfree (&ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
i18n = json_loads (args[3],
|
||||||
|
JSON_REJECT_DUPLICATES,
|
||||||
|
&err);
|
||||||
|
if (NULL == i18n)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid JSON for restriction of type `regex': `%s` at %d\n",
|
||||||
|
args[3],
|
||||||
|
err.position);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
GNUNET_assert (0 ==
|
||||||
|
json_array_append_new (
|
||||||
|
restrictions,
|
||||||
|
GNUNET_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_string ("type",
|
||||||
|
"regex"),
|
||||||
|
GNUNET_JSON_pack_string ("regex",
|
||||||
|
args[1]),
|
||||||
|
GNUNET_JSON_pack_string ("human_hint",
|
||||||
|
args[2]),
|
||||||
|
GNUNET_JSON_pack_object_steal ("human_hint_i18n",
|
||||||
|
i18n)
|
||||||
|
)));
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Restriction TYPE `%s' unsupported\n",
|
||||||
|
args[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add wire account.
|
* Add wire account.
|
||||||
*
|
*
|
||||||
@ -2961,6 +3080,10 @@ do_add_wire (char *const *args)
|
|||||||
struct TALER_MasterSignatureP master_sig_add;
|
struct TALER_MasterSignatureP master_sig_add;
|
||||||
struct TALER_MasterSignatureP master_sig_wire;
|
struct TALER_MasterSignatureP master_sig_wire;
|
||||||
struct GNUNET_TIME_Timestamp now;
|
struct GNUNET_TIME_Timestamp now;
|
||||||
|
const char *conversion_url = NULL;
|
||||||
|
json_t *debit_restrictions;
|
||||||
|
json_t *credit_restrictions;
|
||||||
|
unsigned int num_args = 1;
|
||||||
|
|
||||||
if (NULL != in)
|
if (NULL != in)
|
||||||
{
|
{
|
||||||
@ -3011,24 +3134,101 @@ do_add_wire (char *const *args)
|
|||||||
}
|
}
|
||||||
GNUNET_free (wire_method);
|
GNUNET_free (wire_method);
|
||||||
}
|
}
|
||||||
|
debit_restrictions = json_array ();
|
||||||
|
GNUNET_assert (NULL != debit_restrictions);
|
||||||
|
credit_restrictions = json_array ();
|
||||||
|
GNUNET_assert (NULL != credit_restrictions);
|
||||||
|
while (NULL != args[num_args])
|
||||||
|
{
|
||||||
|
if (0 == strcmp (args[num_args],
|
||||||
|
"conversion-url"))
|
||||||
|
{
|
||||||
|
num_args++;
|
||||||
|
conversion_url = args[num_args];
|
||||||
|
if (NULL == conversion_url)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"'conversion-url' requires an argument\n");
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
test_shutdown ();
|
||||||
|
json_decref (debit_restrictions);
|
||||||
|
json_decref (credit_restrictions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
num_args++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 == strcmp (args[num_args],
|
||||||
|
"credit-restriction"))
|
||||||
|
{
|
||||||
|
int iret;
|
||||||
|
|
||||||
|
num_args++;
|
||||||
|
iret = parse_restriction (&args[num_args],
|
||||||
|
credit_restrictions);
|
||||||
|
if (iret <= 0)
|
||||||
|
{
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
test_shutdown ();
|
||||||
|
json_decref (debit_restrictions);
|
||||||
|
json_decref (credit_restrictions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
num_args += iret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 == strcmp (args[num_args],
|
||||||
|
"debit-restriction"))
|
||||||
|
{
|
||||||
|
int iret;
|
||||||
|
|
||||||
|
num_args++;
|
||||||
|
iret = parse_restriction (&args[num_args],
|
||||||
|
debit_restrictions);
|
||||||
|
if (iret <= 0)
|
||||||
|
{
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
test_shutdown ();
|
||||||
|
json_decref (debit_restrictions);
|
||||||
|
json_decref (credit_restrictions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
num_args += iret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
TALER_exchange_offline_wire_add_sign (args[0],
|
TALER_exchange_offline_wire_add_sign (args[0],
|
||||||
|
conversion_url,
|
||||||
|
debit_restrictions,
|
||||||
|
credit_restrictions,
|
||||||
now,
|
now,
|
||||||
&master_priv,
|
&master_priv,
|
||||||
&master_sig_add);
|
&master_sig_add);
|
||||||
TALER_exchange_wire_signature_make (args[0],
|
TALER_exchange_wire_signature_make (args[0],
|
||||||
|
conversion_url,
|
||||||
|
debit_restrictions,
|
||||||
|
credit_restrictions,
|
||||||
&master_priv,
|
&master_priv,
|
||||||
&master_sig_wire);
|
&master_sig_wire);
|
||||||
output_operation (OP_ENABLE_WIRE,
|
output_operation (OP_ENABLE_WIRE,
|
||||||
GNUNET_JSON_PACK (
|
GNUNET_JSON_PACK (
|
||||||
GNUNET_JSON_pack_string ("payto_uri",
|
GNUNET_JSON_pack_string ("payto_uri",
|
||||||
args[0]),
|
args[0]),
|
||||||
|
GNUNET_JSON_pack_array_steal ("debit_restrictions",
|
||||||
|
debit_restrictions),
|
||||||
|
GNUNET_JSON_pack_array_steal ("credit_restrictions",
|
||||||
|
credit_restrictions),
|
||||||
|
GNUNET_JSON_pack_allow_null (
|
||||||
|
GNUNET_JSON_pack_string ("conversion_url",
|
||||||
|
conversion_url)),
|
||||||
GNUNET_JSON_pack_timestamp ("validity_start",
|
GNUNET_JSON_pack_timestamp ("validity_start",
|
||||||
now),
|
now),
|
||||||
GNUNET_JSON_pack_data_auto ("master_sig_add",
|
GNUNET_JSON_pack_data_auto ("master_sig_add",
|
||||||
&master_sig_add),
|
&master_sig_add),
|
||||||
GNUNET_JSON_pack_data_auto ("master_sig_wire",
|
GNUNET_JSON_pack_data_auto ("master_sig_wire",
|
||||||
&master_sig_wire)));
|
&master_sig_wire)));
|
||||||
next (args + 1);
|
next (args + num_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3198,14 +3398,28 @@ do_set_global_fee (char *const *args)
|
|||||||
(NULL == args[3]) ||
|
(NULL == args[3]) ||
|
||||||
(NULL == args[4]) ||
|
(NULL == args[4]) ||
|
||||||
(NULL == args[5]) ||
|
(NULL == args[5]) ||
|
||||||
(NULL == args[6]) ||
|
(NULL == args[6]) )
|
||||||
( (1 != sscanf (args[0],
|
{
|
||||||
"%u%c",
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
&year,
|
"You must use YEAR, HISTORY-FEE, ACCOUNT-FEE, PURSE-FEE, PURSE-TIMEOUT, HISTORY-EXPIRATION and PURSE-ACCOUNT-LIMIT as arguments for this subcommand\n");
|
||||||
&dummy)) &&
|
test_shutdown ();
|
||||||
(0 != strcasecmp ("now",
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
args[0])) ) ||
|
return;
|
||||||
(GNUNET_OK !=
|
}
|
||||||
|
if ( (1 != sscanf (args[0],
|
||||||
|
"%u%c",
|
||||||
|
&year,
|
||||||
|
&dummy)) &&
|
||||||
|
(0 != strcasecmp ("now",
|
||||||
|
args[0])) )
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid YEAR given for 'global-fee' subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( (GNUNET_OK !=
|
||||||
TALER_string_to_amount (args[1],
|
TALER_string_to_amount (args[1],
|
||||||
&fees.history)) ||
|
&fees.history)) ||
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
@ -3213,20 +3427,34 @@ do_set_global_fee (char *const *args)
|
|||||||
&fees.account)) ||
|
&fees.account)) ||
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
TALER_string_to_amount (args[3],
|
TALER_string_to_amount (args[3],
|
||||||
&fees.purse)) ||
|
&fees.purse)) )
|
||||||
(GNUNET_OK !=
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid amount given for 'global-fee' subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( (GNUNET_OK !=
|
||||||
GNUNET_STRINGS_fancy_time_to_relative (args[4],
|
GNUNET_STRINGS_fancy_time_to_relative (args[4],
|
||||||
&purse_timeout)) ||
|
&purse_timeout)) ||
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
GNUNET_STRINGS_fancy_time_to_relative (args[5],
|
GNUNET_STRINGS_fancy_time_to_relative (args[5],
|
||||||
&history_expiration)) ||
|
&history_expiration)) )
|
||||||
(1 != sscanf (args[6],
|
|
||||||
"%u%c",
|
|
||||||
&purse_account_limit,
|
|
||||||
&dummy)) )
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"You must use YEAR, HISTORY-FEE, ACCOUNT-FEE, PURSE-FEE, PURSE-TIMEOUT, HISTORY-EXPIRATION and PURSE-ACCOUNT-LIMIT as arguments for this subcommand\n");
|
"Invalid delay given for 'global-fee' subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (1 != sscanf (args[6],
|
||||||
|
"%u%c",
|
||||||
|
&purse_account_limit,
|
||||||
|
&dummy))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid purse account limit given for 'global-fee' subcommand\n");
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
global_ret = EXIT_INVALIDARGUMENT;
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
return;
|
return;
|
||||||
@ -3643,18 +3871,15 @@ enable_aml_staff (char *const *args)
|
|||||||
* whether there are subsequent commands).
|
* whether there are subsequent commands).
|
||||||
*
|
*
|
||||||
* @param cls closure with the `char **` remaining args
|
* @param cls closure with the `char **` remaining args
|
||||||
* @param hr HTTP response data
|
* @param mgr response data
|
||||||
* @param keys information about the various keys used
|
|
||||||
* by the exchange, NULL if /management/keys failed
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
download_cb (void *cls,
|
download_cb (void *cls,
|
||||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
const struct TALER_EXCHANGE_ManagementGetKeysResponse *mgr)
|
||||||
const struct TALER_EXCHANGE_FutureKeys *keys)
|
|
||||||
{
|
{
|
||||||
char *const *args = cls;
|
char *const *args = cls;
|
||||||
|
const struct TALER_EXCHANGE_HttpResponse *hr = &mgr->hr;
|
||||||
|
|
||||||
(void) keys;
|
|
||||||
mgkh = NULL;
|
mgkh = NULL;
|
||||||
switch (hr->http_status)
|
switch (hr->http_status)
|
||||||
{
|
{
|
||||||
@ -4258,15 +4483,15 @@ do_show (char *const *args)
|
|||||||
json_t *keys;
|
json_t *keys;
|
||||||
const char *err_name;
|
const char *err_name;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
json_t *denomkeys;
|
const json_t *denomkeys;
|
||||||
json_t *signkeys;
|
const json_t *signkeys;
|
||||||
struct TALER_MasterPublicKeyP mpub;
|
struct TALER_MasterPublicKeyP mpub;
|
||||||
struct TALER_SecurityModulePublicKeySetP secmset;
|
struct TALER_SecurityModulePublicKeySetP secmset;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("future_denoms",
|
GNUNET_JSON_spec_array_const ("future_denoms",
|
||||||
&denomkeys),
|
&denomkeys),
|
||||||
GNUNET_JSON_spec_json ("future_signkeys",
|
GNUNET_JSON_spec_array_const ("future_signkeys",
|
||||||
&signkeys),
|
&signkeys),
|
||||||
GNUNET_JSON_spec_fixed_auto ("master_pub",
|
GNUNET_JSON_spec_fixed_auto ("master_pub",
|
||||||
&mpub),
|
&mpub),
|
||||||
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
|
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
|
||||||
@ -4311,7 +4536,6 @@ do_show (char *const *args)
|
|||||||
"Fatal: exchange uses different master key!\n");
|
"Fatal: exchange uses different master key!\n");
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4320,7 +4544,6 @@ do_show (char *const *args)
|
|||||||
{
|
{
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4334,12 +4557,10 @@ do_show (char *const *args)
|
|||||||
{
|
{
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
next (args);
|
next (args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4659,15 +4880,15 @@ do_sign (char *const *args)
|
|||||||
json_t *keys;
|
json_t *keys;
|
||||||
const char *err_name;
|
const char *err_name;
|
||||||
unsigned int err_line;
|
unsigned int err_line;
|
||||||
json_t *denomkeys;
|
const json_t *denomkeys;
|
||||||
json_t *signkeys;
|
const json_t *signkeys;
|
||||||
struct TALER_MasterPublicKeyP mpub;
|
struct TALER_MasterPublicKeyP mpub;
|
||||||
struct TALER_SecurityModulePublicKeySetP secmset;
|
struct TALER_SecurityModulePublicKeySetP secmset;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("future_denoms",
|
GNUNET_JSON_spec_array_const ("future_denoms",
|
||||||
&denomkeys),
|
&denomkeys),
|
||||||
GNUNET_JSON_spec_json ("future_signkeys",
|
GNUNET_JSON_spec_array_const ("future_signkeys",
|
||||||
&signkeys),
|
&signkeys),
|
||||||
GNUNET_JSON_spec_fixed_auto ("master_pub",
|
GNUNET_JSON_spec_fixed_auto ("master_pub",
|
||||||
&mpub),
|
&mpub),
|
||||||
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
|
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
|
||||||
@ -4714,7 +4935,6 @@ do_sign (char *const *args)
|
|||||||
"Fatal: exchange uses different master key!\n");
|
"Fatal: exchange uses different master key!\n");
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4725,7 +4945,6 @@ do_sign (char *const *args)
|
|||||||
"Fatal: security module keys changed!\n");
|
"Fatal: security module keys changed!\n");
|
||||||
global_ret = EXIT_FAILURE;
|
global_ret = EXIT_FAILURE;
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4749,7 +4968,6 @@ do_sign (char *const *args)
|
|||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
json_decref (signkey_sig_array);
|
json_decref (signkey_sig_array);
|
||||||
json_decref (denomkey_sig_array);
|
json_decref (denomkey_sig_array);
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4761,7 +4979,6 @@ do_sign (char *const *args)
|
|||||||
GNUNET_JSON_pack_array_steal ("signkey_sigs",
|
GNUNET_JSON_pack_array_steal ("signkey_sigs",
|
||||||
signkey_sig_array)));
|
signkey_sig_array)));
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
json_decref (keys);
|
json_decref (keys);
|
||||||
next (args);
|
next (args);
|
||||||
}
|
}
|
||||||
@ -5045,7 +5262,7 @@ work (void *cls)
|
|||||||
{
|
{
|
||||||
.name = "enable-account",
|
.name = "enable-account",
|
||||||
.help =
|
.help =
|
||||||
"enable wire account of the exchange (payto-URI must be given as argument)",
|
"enable wire account of the exchange (payto-URI must be given as argument; for optional argument see man page)",
|
||||||
.cb = &do_add_wire
|
.cb = &do_add_wire
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,8 @@ pkgcfg_DATA = \
|
|||||||
exchange.conf
|
exchange.conf
|
||||||
|
|
||||||
# Programs
|
# Programs
|
||||||
|
bin_SCRIPTS = \
|
||||||
|
taler-exchange-kyc-aml-pep-trigger.sh
|
||||||
|
|
||||||
bin_PROGRAMS = \
|
bin_PROGRAMS = \
|
||||||
taler-exchange-aggregator \
|
taler-exchange-aggregator \
|
||||||
@ -131,6 +133,7 @@ taler_exchange_httpd_SOURCES = \
|
|||||||
taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
|
taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
|
||||||
taler-exchange-httpd_age-withdraw_reveal.c taler-exchange-httpd_age-withdraw_reveal.h \
|
taler-exchange-httpd_age-withdraw_reveal.c taler-exchange-httpd_age-withdraw_reveal.h \
|
||||||
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
|
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
|
||||||
|
taler-exchange-httpd_common_kyc.c taler-exchange-httpd_common_kyc.h \
|
||||||
taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
|
taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
|
||||||
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
|
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
|
||||||
taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
|
taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
|
||||||
@ -181,7 +184,6 @@ taler_exchange_httpd_SOURCES = \
|
|||||||
taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
|
taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
|
||||||
taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
|
taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
|
||||||
taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \
|
taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \
|
||||||
taler-exchange-httpd_wire.c taler-exchange-httpd_wire.h \
|
|
||||||
taler-exchange-httpd_withdraw.c taler-exchange-httpd_withdraw.h
|
taler-exchange-httpd_withdraw.c taler-exchange-httpd_withdraw.h
|
||||||
|
|
||||||
taler_exchange_httpd_LDADD = \
|
taler_exchange_httpd_LDADD = \
|
||||||
@ -227,4 +229,5 @@ EXTRA_DIST = \
|
|||||||
test_taler_exchange_httpd.get \
|
test_taler_exchange_httpd.get \
|
||||||
test_taler_exchange_httpd.post \
|
test_taler_exchange_httpd.post \
|
||||||
exchange.conf \
|
exchange.conf \
|
||||||
|
$(bin_SCRIPTS) \
|
||||||
$(check_SCRIPTS)
|
$(check_SCRIPTS)
|
||||||
|
@ -6,10 +6,23 @@
|
|||||||
# This must be adjusted to your actual installation.
|
# This must be adjusted to your actual installation.
|
||||||
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
||||||
|
|
||||||
|
# Must be set to the threshold above which transactions
|
||||||
|
# are flagged for AML review.
|
||||||
|
# AML_THRESHOLD =
|
||||||
|
|
||||||
|
# Specifies a program (binary) to run on KYC attribute data to decide
|
||||||
|
# whether we should immediately flag an account for AML review.
|
||||||
|
# The KYC attribute data will be passed on standard-input.
|
||||||
|
# Return non-zero to trigger AML review of the new user.
|
||||||
|
KYC_AML_TRIGGER = true
|
||||||
|
|
||||||
# Attribute encryption key for storing attributes encrypted
|
# Attribute encryption key for storing attributes encrypted
|
||||||
# in the database. Should be a high-entropy nonce.
|
# in the database. Should be a high-entropy nonce.
|
||||||
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
||||||
|
|
||||||
|
# Set to NO to disable rewards.
|
||||||
|
ENABLE_REWARDS = YES
|
||||||
|
|
||||||
# How long do we allow /keys to be cached at most? The actual
|
# How long do we allow /keys to be cached at most? The actual
|
||||||
# limit is the minimum of this value and the first expected
|
# limit is the minimum of this value and the first expected
|
||||||
# significant change in /keys based on the expiration times.
|
# significant change in /keys based on the expiration times.
|
||||||
|
@ -303,17 +303,17 @@ parse_aggregator_config (void)
|
|||||||
(TALER_amount_is_zero (¤cy_round_unit)) )
|
(TALER_amount_is_zero (¤cy_round_unit)) )
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Need non-zero amount in section `TALER' under `CURRENCY_ROUND_UNIT'\n");
|
"Need non-zero amount in section `taler' under `CURRENCY_ROUND_UNIT'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_amount (cfg,
|
TALER_config_get_amount (cfg,
|
||||||
"taler",
|
"exchange",
|
||||||
"AML_THRESHOLD",
|
"AML_THRESHOLD",
|
||||||
&aml_threshold))
|
&aml_threshold))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Need amount in section `TALER' under `AML_THRESHOLD'\n");
|
"Need amount in section `exchange' under `AML_THRESHOLD'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,10 +312,10 @@ expired_reserve_cb (void *cls,
|
|||||||
memset (&wtid,
|
memset (&wtid,
|
||||||
0,
|
0,
|
||||||
sizeof (wtid));
|
sizeof (wtid));
|
||||||
memcpy (&wtid,
|
GNUNET_memcpy (&wtid,
|
||||||
reserve_pub,
|
reserve_pub,
|
||||||
GNUNET_MIN (sizeof (wtid),
|
GNUNET_MIN (sizeof (wtid),
|
||||||
sizeof (*reserve_pub)));
|
sizeof (*reserve_pub)));
|
||||||
qs = db_plugin->insert_reserve_closed (db_plugin->cls,
|
qs = db_plugin->insert_reserve_closed (db_plugin->cls,
|
||||||
reserve_pub,
|
reserve_pub,
|
||||||
now,
|
now,
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include "taler_kyclogic_lib.h"
|
#include "taler_kyclogic_lib.h"
|
||||||
#include "taler_templating_lib.h"
|
#include "taler_templating_lib.h"
|
||||||
#include "taler_mhd_lib.h"
|
#include "taler_mhd_lib.h"
|
||||||
|
#include "taler-exchange-httpd_age-withdraw.h"
|
||||||
|
#include "taler-exchange-httpd_age-withdraw_reveal.h"
|
||||||
#include "taler-exchange-httpd_aml-decision.h"
|
#include "taler-exchange-httpd_aml-decision.h"
|
||||||
#include "taler-exchange-httpd_auditors.h"
|
#include "taler-exchange-httpd_auditors.h"
|
||||||
#include "taler-exchange-httpd_batch-deposit.h"
|
#include "taler-exchange-httpd_batch-deposit.h"
|
||||||
@ -68,7 +70,6 @@
|
|||||||
#include "taler-exchange-httpd_reserves_status.h"
|
#include "taler-exchange-httpd_reserves_status.h"
|
||||||
#include "taler-exchange-httpd_terms.h"
|
#include "taler-exchange-httpd_terms.h"
|
||||||
#include "taler-exchange-httpd_transfers_get.h"
|
#include "taler-exchange-httpd_transfers_get.h"
|
||||||
#include "taler-exchange-httpd_wire.h"
|
|
||||||
#include "taler-exchange-httpd_withdraw.h"
|
#include "taler-exchange-httpd_withdraw.h"
|
||||||
#include "taler_exchangedb_lib.h"
|
#include "taler_exchangedb_lib.h"
|
||||||
#include "taler_exchangedb_plugin.h"
|
#include "taler_exchangedb_plugin.h"
|
||||||
@ -153,6 +154,16 @@ struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
|
|||||||
*/
|
*/
|
||||||
char *TEH_currency;
|
char *TEH_currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the KYC-AML-trigger evaluation binary.
|
||||||
|
*/
|
||||||
|
char *TEH_kyc_aml_trigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option set to #GNUNET_YES if rewards are enabled.
|
||||||
|
*/
|
||||||
|
int TEH_enable_rewards;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What is the largest amount we allow a peer to
|
* What is the largest amount we allow a peer to
|
||||||
* merge into a reserve before always triggering
|
* merge into a reserve before always triggering
|
||||||
@ -542,7 +553,6 @@ handle_get_aml (struct TEH_RequestContext *rc,
|
|||||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||||
NULL);
|
NULL);
|
||||||
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
||||||
GNUNET_break_op (0);
|
|
||||||
return TALER_MHD_reply_with_error (rc->connection,
|
return TALER_MHD_reply_with_error (rc->connection,
|
||||||
MHD_HTTP_FORBIDDEN,
|
MHD_HTTP_FORBIDDEN,
|
||||||
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_ACCESS_DENIED,
|
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_ACCESS_DENIED,
|
||||||
@ -562,6 +572,46 @@ handle_get_aml (struct TEH_RequestContext *rc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a "/age-withdraw/$ACH/reveal" POST request. Parses the "ACH"
|
||||||
|
* hash of the commitment from a previous call to
|
||||||
|
* /reserves/$reserve_pub/age-withdraw
|
||||||
|
*
|
||||||
|
* @param rc request context
|
||||||
|
* @param root uploaded JSON data
|
||||||
|
* @param args array of additional options
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
static MHD_RESULT
|
||||||
|
handle_post_age_withdraw (struct TEH_RequestContext *rc,
|
||||||
|
const json_t *root,
|
||||||
|
const char *const args[2])
|
||||||
|
{
|
||||||
|
struct TALER_AgeWithdrawCommitmentHashP ach;
|
||||||
|
|
||||||
|
if (0 != strcmp ("reveal", args[1]))
|
||||||
|
return r404 (rc->connection,
|
||||||
|
args[1]);
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_STRINGS_string_to_data (args[0],
|
||||||
|
strlen (args[0]),
|
||||||
|
&ach,
|
||||||
|
sizeof (ach)))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return TALER_MHD_reply_with_error (rc->connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
|
||||||
|
args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TEH_handler_age_withdraw_reveal (rc,
|
||||||
|
&ach,
|
||||||
|
root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature of functions that handle operations on reserves.
|
* Signature of functions that handle operations on reserves.
|
||||||
*
|
*
|
||||||
@ -608,6 +658,10 @@ handle_post_reserves (struct TEH_RequestContext *rc,
|
|||||||
.op = "batch-withdraw",
|
.op = "batch-withdraw",
|
||||||
.handler = &TEH_handler_batch_withdraw
|
.handler = &TEH_handler_batch_withdraw
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.op = "age-withdraw",
|
||||||
|
.handler = &TEH_handler_age_withdraw
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.op = "withdraw",
|
.op = "withdraw",
|
||||||
.handler = &TEH_handler_withdraw
|
.handler = &TEH_handler_withdraw
|
||||||
@ -932,9 +986,9 @@ proceed_with_handler (struct TEH_RequestContext *rc,
|
|||||||
|
|
||||||
/* Parse command-line arguments */
|
/* Parse command-line arguments */
|
||||||
/* make a copy of 'url' because 'strtok_r()' will modify */
|
/* make a copy of 'url' because 'strtok_r()' will modify */
|
||||||
memcpy (d,
|
GNUNET_memcpy (d,
|
||||||
url,
|
url,
|
||||||
ulen);
|
ulen);
|
||||||
i = 0;
|
i = 0;
|
||||||
args[i++] = strtok_r (d, "/", &sp);
|
args[i++] = strtok_r (d, "/", &sp);
|
||||||
while ( (NULL != args[i - 1]) &&
|
while ( (NULL != args[i - 1]) &&
|
||||||
@ -1445,6 +1499,12 @@ handle_mhd_request (void *cls,
|
|||||||
.handler.post = &handle_post_reserves,
|
.handler.post = &handle_post_reserves,
|
||||||
.nargs = 2
|
.nargs = 2
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.url = "age-withdraw",
|
||||||
|
.method = MHD_HTTP_METHOD_POST,
|
||||||
|
.handler.post = &handle_post_age_withdraw,
|
||||||
|
.nargs = 2
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.url = "reserves-attest",
|
.url = "reserves-attest",
|
||||||
.method = MHD_HTTP_METHOD_GET,
|
.method = MHD_HTTP_METHOD_GET,
|
||||||
@ -1617,33 +1677,8 @@ handle_mhd_request (void *cls,
|
|||||||
if (0 == strcasecmp (method,
|
if (0 == strcasecmp (method,
|
||||||
MHD_HTTP_METHOD_POST))
|
MHD_HTTP_METHOD_POST))
|
||||||
{
|
{
|
||||||
const char *cl;
|
TALER_MHD_check_content_length (connection,
|
||||||
|
TALER_MHD_REQUEST_BUFFER_MAX);
|
||||||
/* Maybe check for maximum upload size
|
|
||||||
and refuse requests if they are just too big. */
|
|
||||||
cl = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_HEADER_KIND,
|
|
||||||
MHD_HTTP_HEADER_CONTENT_LENGTH);
|
|
||||||
if (NULL != cl)
|
|
||||||
{
|
|
||||||
unsigned long long cv;
|
|
||||||
char dummy;
|
|
||||||
|
|
||||||
if (1 != sscanf (cl,
|
|
||||||
"%llu%c",
|
|
||||||
&cv,
|
|
||||||
&dummy))
|
|
||||||
{
|
|
||||||
/* Not valid HTTP request, just close connection. */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
if (cv > TALER_MHD_REQUEST_BUFFER_MAX)
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return TALER_MHD_reply_request_too_large (connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1870,6 +1905,17 @@ exchange_serve_process_config (void)
|
|||||||
"valid relative time expected");
|
"valid relative time expected");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
|
||||||
|
"exchange",
|
||||||
|
"KYC_AML_TRIGGER",
|
||||||
|
&TEH_kyc_aml_trigger))
|
||||||
|
{
|
||||||
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"exchange",
|
||||||
|
"KYC_AML_TRIGGER");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_currency (TEH_cfg,
|
TALER_config_get_currency (TEH_cfg,
|
||||||
&TEH_currency))
|
&TEH_currency))
|
||||||
@ -1881,19 +1927,30 @@ exchange_serve_process_config (void)
|
|||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_amount (TEH_cfg,
|
TALER_config_get_amount (TEH_cfg,
|
||||||
"taler",
|
"exchange",
|
||||||
"AML_THRESHOLD",
|
"AML_THRESHOLD",
|
||||||
&TEH_aml_threshold))
|
&TEH_aml_threshold))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Need amount in section `TALER' under `AML_THRESHOLD'\n");
|
"Need amount in section `exchange' under `AML_THRESHOLD'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (0 != strcmp (TEH_currency,
|
if (0 != strcmp (TEH_currency,
|
||||||
TEH_aml_threshold.currency))
|
TEH_aml_threshold.currency))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Amount in section `TALER' under `AML_THRESHOLD' uses the wrong currency!\n");
|
"Amount in section `exchange' under `AML_THRESHOLD' uses the wrong currency!\n");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
TEH_enable_rewards
|
||||||
|
= GNUNET_CONFIGURATION_get_value_yesno (
|
||||||
|
TEH_cfg,
|
||||||
|
"exchange",
|
||||||
|
"ENABLE_REWARDS");
|
||||||
|
if (GNUNET_SYSERR == TEH_enable_rewards)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Need YES or NO in section `exchange' under `ENABLE_REWARDS'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
@ -2215,6 +2272,7 @@ do_shutdown (void *cls)
|
|||||||
|
|
||||||
mhd = TALER_MHD_daemon_stop ();
|
mhd = TALER_MHD_daemon_stop ();
|
||||||
TEH_resume_keys_requests (true);
|
TEH_resume_keys_requests (true);
|
||||||
|
TEH_deposits_get_cleanup ();
|
||||||
TEH_reserves_get_cleanup ();
|
TEH_reserves_get_cleanup ();
|
||||||
TEH_purses_get_cleanup ();
|
TEH_purses_get_cleanup ();
|
||||||
TEH_kyc_check_cleanup ();
|
TEH_kyc_check_cleanup ();
|
||||||
|
@ -64,6 +64,11 @@ extern int TEH_check_invariants_flag;
|
|||||||
*/
|
*/
|
||||||
extern int TEH_allow_keys_timetravel;
|
extern int TEH_allow_keys_timetravel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option set to #GNUNET_YES if rewards are allowed.
|
||||||
|
*/
|
||||||
|
extern int TEH_enable_rewards;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main directory with revocation data.
|
* Main directory with revocation data.
|
||||||
*/
|
*/
|
||||||
@ -97,6 +102,11 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
|
|||||||
*/
|
*/
|
||||||
extern char *TEH_currency;
|
extern char *TEH_currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the KYC-AML-trigger evaluation binary.
|
||||||
|
*/
|
||||||
|
extern char *TEH_kyc_aml_trigger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What is the largest amount we allow a peer to
|
* What is the largest amount we allow a peer to
|
||||||
* merge into a reserve before always triggering
|
* merge into a reserve before always triggering
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user