aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore20
-rw-r--r--README48
-rw-r--r--configure.ac10
-rw-r--r--[-rwxr-xr-x]contrib/coverage.sh2
-rw-r--r--contrib/exchange-template/README1
-rw-r--r--contrib/exchange-template/config/exchange-common.conf30
-rw-r--r--contrib/exchange-template/config/exchange-keyup.conf64
-rw-r--r--contrib/mint-template/README1
-rw-r--r--contrib/mint-template/config/mint-common.conf28
-rw-r--r--contrib/mint-template/config/mint-keyup.conf64
-rw-r--r--doc/Makefile.am10
-rw-r--r--doc/coding-style.txt12
-rw-r--r--doc/doxygen/Makefile.am6
-rw-r--r--doc/doxygen/taler-mint.doxy2
-rw-r--r--[-rwxr-xr-x]doc/logos/fonts/OldNewspaperTypes.ttfbin85804 -> 85804 bytes
-rw-r--r--doc/paper/rfc.bib111
-rw-r--r--doc/paper/taler.tex424
-rw-r--r--doc/taler-auditor-sign.114
-rw-r--r--doc/taler-exchange-dbinit.129
-rw-r--r--doc/taler-exchange-httpd.139
-rw-r--r--doc/taler-exchange-keycheck.129
-rw-r--r--doc/taler-exchange-keyup.138
-rw-r--r--doc/taler-exchange-reservemod.135
-rw-r--r--doc/taler-exchange-sepa.141
-rw-r--r--doc/taler-mint-dbinit.129
-rw-r--r--doc/taler-mint-httpd.139
-rw-r--r--doc/taler-mint-keycheck.129
-rw-r--r--doc/taler-mint-keyup.138
-rw-r--r--doc/taler-mint-reservemod.135
-rw-r--r--doc/taler-mint-sepa.141
-rw-r--r--doc/taler.conf.520
-rw-r--r--src/Makefile.am14
-rw-r--r--src/bank-lib/bank_api_context.c2
-rw-r--r--src/bank-lib/bank_api_json.h4
-rw-r--r--src/exchange-lib/Makefile.am62
-rw-r--r--src/exchange-lib/afl-generate.sh34
-rw-r--r--src/exchange-lib/baseline/admin_add_incoming.req (renamed from src/mint-lib/baseline/admin_add_incoming.req)0
-rw-r--r--src/exchange-lib/baseline/deposit.req (renamed from src/mint-lib/baseline/deposit.req)0
-rw-r--r--src/exchange-lib/baseline/keys.req (renamed from src/mint-lib/baseline/keys.req)0
-rw-r--r--src/exchange-lib/baseline/refresh_link.req (renamed from src/mint-lib/baseline/refresh_link.req)0
-rw-r--r--src/exchange-lib/baseline/refresh_melt.req (renamed from src/mint-lib/baseline/refresh_melt.req)0
-rw-r--r--src/exchange-lib/baseline/refresh_reveal.req (renamed from src/mint-lib/baseline/refresh_reveal.req)0
-rw-r--r--src/exchange-lib/baseline/reserve_status.req (renamed from src/mint-lib/baseline/reserve_status.req)0
-rw-r--r--src/exchange-lib/baseline/reserve_withdraw.req (renamed from src/mint-lib/baseline/reserve_withdraw.req)0
-rw-r--r--src/exchange-lib/baseline/wire.req (renamed from src/mint-lib/baseline/wire.req)0
-rw-r--r--src/exchange-lib/baseline/wire_sepa.req (renamed from src/mint-lib/baseline/wire_sepa.req)0
-rw-r--r--src/exchange-lib/baseline/wire_test.req (renamed from src/mint-lib/baseline/wire_test.req)0
-rw-r--r--src/exchange-lib/exchange_api_admin.c254
-rw-r--r--src/exchange-lib/exchange_api_common.c194
-rw-r--r--src/exchange-lib/exchange_api_common.h41
-rw-r--r--src/exchange-lib/exchange_api_context.c537
-rw-r--r--src/exchange-lib/exchange_api_context.h169
-rw-r--r--src/exchange-lib/exchange_api_deposit.c569
-rw-r--r--src/exchange-lib/exchange_api_deposit_wtid.c379
-rw-r--r--src/exchange-lib/exchange_api_handle.c902
-rw-r--r--src/exchange-lib/exchange_api_handle.h59
-rw-r--r--src/exchange-lib/exchange_api_json.c525
-rw-r--r--src/exchange-lib/exchange_api_json.h352
-rw-r--r--src/exchange-lib/exchange_api_refresh.c2061
-rw-r--r--src/exchange-lib/exchange_api_refresh_link.c482
-rw-r--r--src/exchange-lib/exchange_api_reserve.c930
-rw-r--r--src/exchange-lib/exchange_api_wire.c620
-rw-r--r--src/exchange-lib/exchange_api_wire_deposits.c284
-rw-r--r--src/exchange-lib/test-exchange-home/config/exchange-common.conf31
-rw-r--r--src/exchange-lib/test-exchange-home/config/exchange-keyup.conf86
-rw-r--r--src/exchange-lib/test-exchange-home/master.priv (renamed from src/mint-lib/test-mint-home/master.priv)0
-rw-r--r--src/exchange-lib/test-exchange-home/sepa.json (renamed from src/mint-lib/test-mint-home/sepa.json)0
-rw-r--r--src/exchange-lib/test_exchange_api.c2599
-rw-r--r--src/exchange-tools/Makefile.am81
-rw-r--r--src/exchange-tools/taler-auditor-sign.c321
-rw-r--r--src/exchange-tools/taler-exchange-dbinit.c105
-rw-r--r--src/exchange-tools/taler-exchange-keycheck.c247
-rw-r--r--src/exchange-tools/taler-exchange-keyup.c1039
-rw-r--r--src/exchange-tools/taler-exchange-reservemod.c206
-rw-r--r--src/exchange-tools/taler-exchange-sepa.c163
-rw-r--r--src/exchange/.gitignore6
-rw-r--r--src/exchange/Makefile.am59
-rw-r--r--src/exchange/afl-tests/id:000000,orig:admin_add_incoming.req (renamed from src/mint/afl-tests/id:000000,orig:admin_add_incoming.req)0
-rw-r--r--src/exchange/afl-tests/id:000001,orig:deposit.req (renamed from src/mint/afl-tests/id:000001,orig:deposit.req)0
-rw-r--r--src/exchange/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060 (renamed from src/mint/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060)0
-rw-r--r--src/exchange/afl-tests/id:000002,orig:keys.req (renamed from src/mint/afl-tests/id:000002,orig:keys.req)0
-rw-r--r--src/exchange/afl-tests/id:000003,orig:refresh_link.req (renamed from src/mint/afl-tests/id:000003,orig:refresh_link.req)0
-rw-r--r--src/exchange/afl-tests/id:000004,orig:refresh_melt.req (renamed from src/mint/afl-tests/id:000004,orig:refresh_melt.req)0
-rw-r--r--src/exchange/afl-tests/id:000005,orig:refresh_reveal.req (renamed from src/mint/afl-tests/id:000005,orig:refresh_reveal.req)0
-rw-r--r--src/exchange/afl-tests/id:000006,orig:reserve_status.req (renamed from src/mint/afl-tests/id:000006,orig:reserve_status.req)0
-rw-r--r--src/exchange/afl-tests/id:000007,orig:reserve_withdraw.req (renamed from src/mint/afl-tests/id:000007,orig:reserve_withdraw.req)0
-rw-r--r--src/exchange/afl-tests/id:000008,orig:wire.req (renamed from src/mint/afl-tests/id:000008,orig:wire.req)0
-rw-r--r--src/exchange/afl-tests/id:000009,orig:wire_sepa.req (renamed from src/mint/afl-tests/id:000009,orig:wire_sepa.req)0
-rw-r--r--src/exchange/afl-tests/id:000010,orig:wire_test.req (renamed from src/mint/afl-tests/id:000010,orig:wire_test.req)0
-rw-r--r--src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov (renamed from src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov (renamed from src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov (renamed from src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov (renamed from src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000013,src:000000,op:flip1,pos:4,+cov (renamed from src/mint/afl-tests/id:000013,src:000000,op:flip1,pos:4,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000013,src:000000,op:flip1,pos:5,+cov (renamed from src/mint/afl-tests/id:000013,src:000000,op:flip1,pos:5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000014,src:000000,op:flip1,pos:5,+cov (renamed from src/mint/afl-tests/id:000014,src:000000,op:flip1,pos:5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000015,src:000000,op:flip1,pos:5,+cov (renamed from src/mint/afl-tests/id:000015,src:000000,op:flip1,pos:5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000015,src:000000,op:flip1,pos:8,+cov (renamed from src/mint/afl-tests/id:000015,src:000000,op:flip1,pos:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000016,src:000000,op:flip1,pos:11 (renamed from src/mint/afl-tests/id:000016,src:000000,op:flip1,pos:11)0
-rw-r--r--src/exchange/afl-tests/id:000016,src:000000,op:flip1,pos:5,+cov (renamed from src/mint/afl-tests/id:000016,src:000000,op:flip1,pos:5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000017,src:000000,op:flip1,pos:13,+cov (renamed from src/mint/afl-tests/id:000017,src:000000,op:flip1,pos:13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000017,src:000000,op:flip1,pos:7,+cov (renamed from src/mint/afl-tests/id:000017,src:000000,op:flip1,pos:7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000018,src:000000,op:flip1,pos:13,+cov (renamed from src/mint/afl-tests/id:000018,src:000000,op:flip1,pos:13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000018,src:000000,op:flip1,pos:9,+cov (renamed from src/mint/afl-tests/id:000018,src:000000,op:flip1,pos:9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000019,src:000000,op:flip1,pos:11 (renamed from src/mint/afl-tests/id:000019,src:000000,op:flip1,pos:11)0
-rw-r--r--src/exchange/afl-tests/id:000019,src:000000,op:flip1,pos:19,+cov (renamed from src/mint/afl-tests/id:000019,src:000000,op:flip1,pos:19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000020,src:000000,op:flip1,pos:12,+cov (renamed from src/mint/afl-tests/id:000020,src:000000,op:flip1,pos:12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000020,src:000000,op:flip1,pos:19,+cov (renamed from src/mint/afl-tests/id:000020,src:000000,op:flip1,pos:19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000021,src:000000,op:flip1,pos:13,+cov (renamed from src/mint/afl-tests/id:000021,src:000000,op:flip1,pos:13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000021,src:000000,op:flip1,pos:21,+cov (renamed from src/mint/afl-tests/id:000021,src:000000,op:flip1,pos:21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000022,src:000000,op:flip1,pos:17,+cov (renamed from src/mint/afl-tests/id:000022,src:000000,op:flip1,pos:17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000022,src:000000,op:flip1,pos:23,+cov (renamed from src/mint/afl-tests/id:000022,src:000000,op:flip1,pos:23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000023,src:000000,op:flip1,pos:22,+cov (renamed from src/mint/afl-tests/id:000023,src:000000,op:flip1,pos:22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000023,src:000000,op:flip1,pos:24,+cov (renamed from src/mint/afl-tests/id:000023,src:000000,op:flip1,pos:24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000024,src:000000,op:flip1,pos:24,+cov (renamed from src/mint/afl-tests/id:000024,src:000000,op:flip1,pos:24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000025,src:000000,op:flip1,pos:24,+cov (renamed from src/mint/afl-tests/id:000025,src:000000,op:flip1,pos:24,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000026,src:000000,op:flip1,pos:25,+cov (renamed from src/mint/afl-tests/id:000026,src:000000,op:flip1,pos:25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000027,src:000000,op:flip1,pos:26,+cov (renamed from src/mint/afl-tests/id:000027,src:000000,op:flip1,pos:26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000028,src:000000,op:flip1,pos:26,+cov (renamed from src/mint/afl-tests/id:000028,src:000000,op:flip1,pos:26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000029,src:000000,op:flip1,pos:26,+cov (renamed from src/mint/afl-tests/id:000029,src:000000,op:flip1,pos:26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000029,src:000000,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000029,src:000000,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000030,src:000000,op:flip1,pos:27 (renamed from src/mint/afl-tests/id:000030,src:000000,op:flip1,pos:27)0
-rw-r--r--src/exchange/afl-tests/id:000030,src:000000,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000030,src:000000,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000031,src:000000,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000031,src:000000,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000031,src:000000,op:flip1,pos:28,+cov (renamed from src/mint/afl-tests/id:000031,src:000000,op:flip1,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000032,src:000000,op:flip1,pos:28,+cov (renamed from src/mint/afl-tests/id:000032,src:000000,op:flip1,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000032,src:000000,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000032,src:000000,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000033,src:000000,op:flip1,pos:28,+cov (renamed from src/mint/afl-tests/id:000033,src:000000,op:flip1,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000033,src:000000,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000033,src:000000,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000034,src:000000,op:flip1,pos:28,+cov (renamed from src/mint/afl-tests/id:000034,src:000000,op:flip1,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000034,src:000000,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000034,src:000000,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000035,src:000000,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000035,src:000000,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000036,src:000000,op:flip1,pos:31,+cov (renamed from src/mint/afl-tests/id:000036,src:000000,op:flip1,pos:31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000037,src:000000,op:flip1,pos:32,+cov (renamed from src/mint/afl-tests/id:000037,src:000000,op:flip1,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000038,src:000000,op:flip1,pos:32 (renamed from src/mint/afl-tests/id:000038,src:000000,op:flip1,pos:32)0
-rw-r--r--src/exchange/afl-tests/id:000038,src:000000,op:flip1,pos:32,+cov (renamed from src/mint/afl-tests/id:000038,src:000000,op:flip1,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000039,src:000000,op:flip1,pos:32,+cov (renamed from src/mint/afl-tests/id:000039,src:000000,op:flip1,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000039,src:000000,op:flip1,pos:34,+cov (renamed from src/mint/afl-tests/id:000039,src:000000,op:flip1,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000040,src:000000,op:flip1,pos:32,+cov (renamed from src/mint/afl-tests/id:000040,src:000000,op:flip1,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000040,src:000000,op:flip1,pos:34,+cov (renamed from src/mint/afl-tests/id:000040,src:000000,op:flip1,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000041,src:000000,op:flip1,pos:34,+cov (renamed from src/mint/afl-tests/id:000041,src:000000,op:flip1,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000041,src:000000,op:flip1,pos:36,+cov (renamed from src/mint/afl-tests/id:000041,src:000000,op:flip1,pos:36,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000042,src:000000,op:flip1,pos:36,+cov (renamed from src/mint/afl-tests/id:000042,src:000000,op:flip1,pos:36,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000043,src:000000,op:flip1,pos:37,+cov (renamed from src/mint/afl-tests/id:000043,src:000000,op:flip1,pos:37,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000043,src:000000,op:flip1,pos:38 (renamed from src/mint/afl-tests/id:000043,src:000000,op:flip1,pos:38)0
-rw-r--r--src/exchange/afl-tests/id:000044,src:000000,op:flip1,pos:38 (renamed from src/mint/afl-tests/id:000044,src:000000,op:flip1,pos:38)0
-rw-r--r--src/exchange/afl-tests/id:000044,src:000000,op:flip1,pos:38,+cov (renamed from src/mint/afl-tests/id:000044,src:000000,op:flip1,pos:38,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000045,src:000000,op:flip1,pos:38,+cov (renamed from src/mint/afl-tests/id:000045,src:000000,op:flip1,pos:38,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000045,src:000000,op:flip1,pos:39,+cov (renamed from src/mint/afl-tests/id:000045,src:000000,op:flip1,pos:39,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000046,src:000000,op:flip1,pos:39,+cov (renamed from src/mint/afl-tests/id:000046,src:000000,op:flip1,pos:39,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000047,src:000000,op:flip1,pos:39 (renamed from src/mint/afl-tests/id:000047,src:000000,op:flip1,pos:39)0
-rw-r--r--src/exchange/afl-tests/id:000047,src:000000,op:flip1,pos:39,+cov (renamed from src/mint/afl-tests/id:000047,src:000000,op:flip1,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000048,src:000000,op:flip1,pos:39,+cov (renamed from src/mint/afl-tests/id:000048,src:000000,op:flip1,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000048,src:000000,op:flip1,pos:40,+cov (renamed from src/mint/afl-tests/id:000048,src:000000,op:flip1,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000049,src:000000,op:flip1,pos:41,+cov (renamed from src/mint/afl-tests/id:000049,src:000000,op:flip1,pos:41,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000050,src:000000,op:flip1,pos:41,+cov (renamed from src/mint/afl-tests/id:000050,src:000000,op:flip1,pos:41,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000050,src:000000,op:flip1,pos:42,+cov (renamed from src/mint/afl-tests/id:000050,src:000000,op:flip1,pos:42,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000051,src:000000,op:flip1,pos:41,+cov (renamed from src/mint/afl-tests/id:000051,src:000000,op:flip1,pos:41,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000051,src:000000,op:flip1,pos:47,+cov (renamed from src/mint/afl-tests/id:000051,src:000000,op:flip1,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000052,src:000000,op:flip1,pos:42,+cov (renamed from src/mint/afl-tests/id:000052,src:000000,op:flip1,pos:42,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000052,src:000000,op:flip1,pos:47,+cov (renamed from src/mint/afl-tests/id:000052,src:000000,op:flip1,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000053,src:000000,op:flip1,pos:42,+cov (renamed from src/mint/afl-tests/id:000053,src:000000,op:flip1,pos:42,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000053,src:000000,op:flip1,pos:47,+cov (renamed from src/mint/afl-tests/id:000053,src:000000,op:flip1,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000054,src:000000,op:flip1,pos:43,+cov (renamed from src/mint/afl-tests/id:000054,src:000000,op:flip1,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000054,src:000000,op:flip1,pos:49,+cov (renamed from src/mint/afl-tests/id:000054,src:000000,op:flip1,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000055,src:000000,op:flip1,pos:43,+cov (renamed from src/mint/afl-tests/id:000055,src:000000,op:flip1,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000055,src:000000,op:flip1,pos:52,+cov (renamed from src/mint/afl-tests/id:000055,src:000000,op:flip1,pos:52,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000056,src:000000,op:flip1,pos:44,+cov (renamed from src/mint/afl-tests/id:000056,src:000000,op:flip1,pos:44,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000056,src:000000,op:flip1,pos:52,+cov (renamed from src/mint/afl-tests/id:000056,src:000000,op:flip1,pos:52,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000057,src:000000,op:flip1,pos:47,+cov (renamed from src/mint/afl-tests/id:000057,src:000000,op:flip1,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000057,src:000000,op:flip1,pos:54,+cov (renamed from src/mint/afl-tests/id:000057,src:000000,op:flip1,pos:54,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000058,src:000000,op:flip1,pos:47,+cov (renamed from src/mint/afl-tests/id:000058,src:000000,op:flip1,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000058,src:000000,op:flip1,pos:54,+cov (renamed from src/mint/afl-tests/id:000058,src:000000,op:flip1,pos:54,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000059,src:000000,op:flip1,pos:48,+cov (renamed from src/mint/afl-tests/id:000059,src:000000,op:flip1,pos:48,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000059,src:000000,op:flip1,pos:55,+cov (renamed from src/mint/afl-tests/id:000059,src:000000,op:flip1,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000060,src:000000,op:flip1,pos:49,+cov (renamed from src/mint/afl-tests/id:000060,src:000000,op:flip1,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000060,src:000000,op:flip1,pos:56,+cov (renamed from src/mint/afl-tests/id:000060,src:000000,op:flip1,pos:56,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000061,src:000000,op:flip1,pos:50,+cov (renamed from src/mint/afl-tests/id:000061,src:000000,op:flip1,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000061,src:000000,op:flip1,pos:59,+cov (renamed from src/mint/afl-tests/id:000061,src:000000,op:flip1,pos:59,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000062,src:000000,op:flip1,pos:51,+cov (renamed from src/mint/afl-tests/id:000062,src:000000,op:flip1,pos:51,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000062,src:000000,op:flip1,pos:60,+cov (renamed from src/mint/afl-tests/id:000062,src:000000,op:flip1,pos:60,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000063,src:000000,op:flip1,pos:54 (renamed from src/mint/afl-tests/id:000063,src:000000,op:flip1,pos:54)0
-rw-r--r--src/exchange/afl-tests/id:000063,src:000000,op:flip1,pos:61,+cov (renamed from src/mint/afl-tests/id:000063,src:000000,op:flip1,pos:61,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000064,src:000000,op:flip1,pos:55,+cov (renamed from src/mint/afl-tests/id:000064,src:000000,op:flip1,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000064,src:000000,op:flip1,pos:62,+cov (renamed from src/mint/afl-tests/id:000064,src:000000,op:flip1,pos:62,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000065,src:000000,op:flip1,pos:55,+cov (renamed from src/mint/afl-tests/id:000065,src:000000,op:flip1,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000065,src:000000,op:flip1,pos:63,+cov (renamed from src/mint/afl-tests/id:000065,src:000000,op:flip1,pos:63,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000066,src:000000,op:flip1,pos:56,+cov (renamed from src/mint/afl-tests/id:000066,src:000000,op:flip1,pos:56,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000066,src:000000,op:flip1,pos:63,+cov (renamed from src/mint/afl-tests/id:000066,src:000000,op:flip1,pos:63,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000067,src:000000,op:flip1,pos:58,+cov (renamed from src/mint/afl-tests/id:000067,src:000000,op:flip1,pos:58,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000067,src:000000,op:flip1,pos:65,+cov (renamed from src/mint/afl-tests/id:000067,src:000000,op:flip1,pos:65,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000068,src:000000,op:flip1,pos:60,+cov (renamed from src/mint/afl-tests/id:000068,src:000000,op:flip1,pos:60,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000068,src:000000,op:flip1,pos:66,+cov (renamed from src/mint/afl-tests/id:000068,src:000000,op:flip1,pos:66,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000069,src:000000,op:flip1,pos:61,+cov (renamed from src/mint/afl-tests/id:000069,src:000000,op:flip1,pos:61,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000069,src:000000,op:flip1,pos:67,+cov (renamed from src/mint/afl-tests/id:000069,src:000000,op:flip1,pos:67,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000070,src:000000,op:flip1,pos:62,+cov (renamed from src/mint/afl-tests/id:000070,src:000000,op:flip1,pos:62,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000070,src:000000,op:flip1,pos:69,+cov (renamed from src/mint/afl-tests/id:000070,src:000000,op:flip1,pos:69,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000071,src:000000,op:flip1,pos:62,+cov (renamed from src/mint/afl-tests/id:000071,src:000000,op:flip1,pos:62,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000071,src:000000,op:flip1,pos:74,+cov (renamed from src/mint/afl-tests/id:000071,src:000000,op:flip1,pos:74,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000072,src:000000,op:flip1,pos:63,+cov (renamed from src/mint/afl-tests/id:000072,src:000000,op:flip1,pos:63,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000072,src:000000,op:flip1,pos:76,+cov (renamed from src/mint/afl-tests/id:000072,src:000000,op:flip1,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000073,src:000000,op:flip1,pos:64,+cov (renamed from src/mint/afl-tests/id:000073,src:000000,op:flip1,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000073,src:000000,op:flip1,pos:81,+cov (renamed from src/mint/afl-tests/id:000073,src:000000,op:flip1,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000074,src:000000,op:flip1,pos:65,+cov (renamed from src/mint/afl-tests/id:000074,src:000000,op:flip1,pos:65,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000074,src:000000,op:flip1,pos:82,+cov (renamed from src/mint/afl-tests/id:000074,src:000000,op:flip1,pos:82,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000075,src:000000,op:flip1,pos:71,+cov (renamed from src/mint/afl-tests/id:000075,src:000000,op:flip1,pos:71,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000075,src:000000,op:flip1,pos:82,+cov (renamed from src/mint/afl-tests/id:000075,src:000000,op:flip1,pos:82,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000076,src:000000,op:flip1,pos:71 (renamed from src/mint/afl-tests/id:000076,src:000000,op:flip1,pos:71)0
-rw-r--r--src/exchange/afl-tests/id:000076,src:000000,op:flip1,pos:83,+cov (renamed from src/mint/afl-tests/id:000076,src:000000,op:flip1,pos:83,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000077,src:000000,op:flip1,pos:72,+cov (renamed from src/mint/afl-tests/id:000077,src:000000,op:flip1,pos:72,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000077,src:000000,op:flip1,pos:85,+cov (renamed from src/mint/afl-tests/id:000077,src:000000,op:flip1,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000078,src:000000,op:flip1,pos:73,+cov (renamed from src/mint/afl-tests/id:000078,src:000000,op:flip1,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000078,src:000000,op:flip1,pos:87,+cov (renamed from src/mint/afl-tests/id:000078,src:000000,op:flip1,pos:87,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000079,src:000000,op:flip1,pos:74,+cov (renamed from src/mint/afl-tests/id:000079,src:000000,op:flip1,pos:74,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000079,src:000000,op:flip1,pos:87,+cov (renamed from src/mint/afl-tests/id:000079,src:000000,op:flip1,pos:87,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000080,src:000000,op:flip1,pos:75,+cov (renamed from src/mint/afl-tests/id:000080,src:000000,op:flip1,pos:75,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000080,src:000000,op:flip1,pos:87,+cov (renamed from src/mint/afl-tests/id:000080,src:000000,op:flip1,pos:87,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000081,src:000000,op:flip1,pos:75,+cov (renamed from src/mint/afl-tests/id:000081,src:000000,op:flip1,pos:75,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000081,src:000000,op:flip1,pos:90,+cov (renamed from src/mint/afl-tests/id:000081,src:000000,op:flip1,pos:90,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000082,src:000000,op:flip1,pos:76,+cov (renamed from src/mint/afl-tests/id:000082,src:000000,op:flip1,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000082,src:000000,op:flip1,pos:92,+cov (renamed from src/mint/afl-tests/id:000082,src:000000,op:flip1,pos:92,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000083,src:000000,op:flip1,pos:78,+cov (renamed from src/mint/afl-tests/id:000083,src:000000,op:flip1,pos:78,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000083,src:000000,op:flip1,pos:93,+cov (renamed from src/mint/afl-tests/id:000083,src:000000,op:flip1,pos:93,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000084,src:000000,op:flip1,pos:80,+cov (renamed from src/mint/afl-tests/id:000084,src:000000,op:flip1,pos:80,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000084,src:000000,op:flip1,pos:95,+cov (renamed from src/mint/afl-tests/id:000084,src:000000,op:flip1,pos:95,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000085,src:000000,op:flip1,pos:80,+cov (renamed from src/mint/afl-tests/id:000085,src:000000,op:flip1,pos:80,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000085,src:000000,op:flip1,pos:95,+cov (renamed from src/mint/afl-tests/id:000085,src:000000,op:flip1,pos:95,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000086,src:000000,op:flip1,pos:81,+cov (renamed from src/mint/afl-tests/id:000086,src:000000,op:flip1,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000086,src:000000,op:flip1,pos:96,+cov (renamed from src/mint/afl-tests/id:000086,src:000000,op:flip1,pos:96,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000087,src:000000,op:flip1,pos:82,+cov (renamed from src/mint/afl-tests/id:000087,src:000000,op:flip1,pos:82,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000087,src:000000,op:flip1,pos:96,+cov (renamed from src/mint/afl-tests/id:000087,src:000000,op:flip1,pos:96,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000088,src:000000,op:flip1,pos:100,+cov (renamed from src/mint/afl-tests/id:000088,src:000000,op:flip1,pos:100,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000088,src:000000,op:flip1,pos:82,+cov (renamed from src/mint/afl-tests/id:000088,src:000000,op:flip1,pos:82,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000089,src:000000,op:flip1,pos:105 (renamed from src/mint/afl-tests/id:000089,src:000000,op:flip1,pos:105)0
-rw-r--r--src/exchange/afl-tests/id:000089,src:000000,op:flip1,pos:84,+cov (renamed from src/mint/afl-tests/id:000089,src:000000,op:flip1,pos:84,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000090,src:000000,op:flip1,pos:113,+cov (renamed from src/mint/afl-tests/id:000090,src:000000,op:flip1,pos:113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000090,src:000000,op:flip1,pos:84,+cov (renamed from src/mint/afl-tests/id:000090,src:000000,op:flip1,pos:84,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000091,src:000000,op:flip1,pos:114,+cov (renamed from src/mint/afl-tests/id:000091,src:000000,op:flip1,pos:114,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000091,src:000000,op:flip1,pos:91,+cov (renamed from src/mint/afl-tests/id:000091,src:000000,op:flip1,pos:91,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000092,src:000000,op:flip1,pos:121,+cov (renamed from src/mint/afl-tests/id:000092,src:000000,op:flip1,pos:121,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000092,src:000000,op:flip1,pos:92,+cov (renamed from src/mint/afl-tests/id:000092,src:000000,op:flip1,pos:92,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000093,src:000000,op:flip1,pos:123,+cov (renamed from src/mint/afl-tests/id:000093,src:000000,op:flip1,pos:123,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000093,src:000000,op:flip1,pos:93,+cov (renamed from src/mint/afl-tests/id:000093,src:000000,op:flip1,pos:93,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000094,src:000000,op:flip1,pos:126,+cov (renamed from src/mint/afl-tests/id:000094,src:000000,op:flip1,pos:126,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000094,src:000000,op:flip1,pos:95,+cov (renamed from src/mint/afl-tests/id:000094,src:000000,op:flip1,pos:95,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000095,src:000000,op:flip1,pos:135,+cov (renamed from src/mint/afl-tests/id:000095,src:000000,op:flip1,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000095,src:000000,op:flip1,pos:96,+cov (renamed from src/mint/afl-tests/id:000095,src:000000,op:flip1,pos:96,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000096,src:000000,op:flip1,pos:135,+cov (renamed from src/mint/afl-tests/id:000096,src:000000,op:flip1,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000096,src:000000,op:flip1,pos:96,+cov (renamed from src/mint/afl-tests/id:000096,src:000000,op:flip1,pos:96,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000097,src:000000,op:flip1,pos:135,+cov (renamed from src/mint/afl-tests/id:000097,src:000000,op:flip1,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000097,src:000000,op:flip1,pos:97,+cov (renamed from src/mint/afl-tests/id:000097,src:000000,op:flip1,pos:97,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000098,src:000000,op:flip1,pos:105 (renamed from src/mint/afl-tests/id:000098,src:000000,op:flip1,pos:105)0
-rw-r--r--src/exchange/afl-tests/id:000098,src:000000,op:flip1,pos:136,+cov (renamed from src/mint/afl-tests/id:000098,src:000000,op:flip1,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000099,src:000000,op:flip1,pos:106 (renamed from src/mint/afl-tests/id:000099,src:000000,op:flip1,pos:106)0
-rw-r--r--src/exchange/afl-tests/id:000099,src:000000,op:flip1,pos:136,+cov (renamed from src/mint/afl-tests/id:000099,src:000000,op:flip1,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000100,src:000000,op:flip1,pos:113,+cov (renamed from src/mint/afl-tests/id:000100,src:000000,op:flip1,pos:113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000100,src:000000,op:flip1,pos:136,+cov (renamed from src/mint/afl-tests/id:000100,src:000000,op:flip1,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000101,src:000000,op:flip1,pos:114,+cov (renamed from src/mint/afl-tests/id:000101,src:000000,op:flip1,pos:114,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000101,src:000000,op:flip1,pos:136,+cov (renamed from src/mint/afl-tests/id:000101,src:000000,op:flip1,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000102,src:000000,op:flip1,pos:121,+cov (renamed from src/mint/afl-tests/id:000102,src:000000,op:flip1,pos:121,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000102,src:000000,op:flip1,pos:137,+cov (renamed from src/mint/afl-tests/id:000102,src:000000,op:flip1,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000103,src:000000,op:flip1,pos:130,+cov (renamed from src/mint/afl-tests/id:000103,src:000000,op:flip1,pos:130,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000103,src:000000,op:flip1,pos:138,+cov (renamed from src/mint/afl-tests/id:000103,src:000000,op:flip1,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000104,src:000000,op:flip1,pos:136,+cov (renamed from src/mint/afl-tests/id:000104,src:000000,op:flip1,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000104,src:000000,op:flip1,pos:138,+cov (renamed from src/mint/afl-tests/id:000104,src:000000,op:flip1,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000105,src:000000,op:flip1,pos:137,+cov (renamed from src/mint/afl-tests/id:000105,src:000000,op:flip1,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000105,src:000000,op:flip1,pos:139,+cov (renamed from src/mint/afl-tests/id:000105,src:000000,op:flip1,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000106,src:000000,op:flip1,pos:137,+cov (renamed from src/mint/afl-tests/id:000106,src:000000,op:flip1,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000106,src:000000,op:flip1,pos:139,+cov (renamed from src/mint/afl-tests/id:000106,src:000000,op:flip1,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000107,src:000000,op:flip1,pos:139,+cov (renamed from src/mint/afl-tests/id:000107,src:000000,op:flip1,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000107,src:000000,op:flip1,pos:140,+cov (renamed from src/mint/afl-tests/id:000107,src:000000,op:flip1,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000108,src:000000,op:flip1,pos:140,+cov (renamed from src/mint/afl-tests/id:000108,src:000000,op:flip1,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000108,src:000000,op:flip1,pos:141,+cov (renamed from src/mint/afl-tests/id:000108,src:000000,op:flip1,pos:141,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000109,src:000000,op:flip1,pos:140,+cov (renamed from src/mint/afl-tests/id:000109,src:000000,op:flip1,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000109,src:000000,op:flip1,pos:141,+cov (renamed from src/mint/afl-tests/id:000109,src:000000,op:flip1,pos:141,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000110,src:000000,op:flip1,pos:141,+cov (renamed from src/mint/afl-tests/id:000110,src:000000,op:flip1,pos:141,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000110,src:000000,op:flip1,pos:143,+cov (renamed from src/mint/afl-tests/id:000110,src:000000,op:flip1,pos:143,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000111,src:000000,op:flip1,pos:141,+cov (renamed from src/mint/afl-tests/id:000111,src:000000,op:flip1,pos:141,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000111,src:000000,op:flip1,pos:145,+cov (renamed from src/mint/afl-tests/id:000111,src:000000,op:flip1,pos:145,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000112,src:000000,op:flip1,pos:142,+cov (renamed from src/mint/afl-tests/id:000112,src:000000,op:flip1,pos:142,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000112,src:000000,op:flip1,pos:147,+cov (renamed from src/mint/afl-tests/id:000112,src:000000,op:flip1,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000113,src:000000,op:flip1,pos:143,+cov (renamed from src/mint/afl-tests/id:000113,src:000000,op:flip1,pos:143,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000113,src:000000,op:flip1,pos:147,+cov (renamed from src/mint/afl-tests/id:000113,src:000000,op:flip1,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000114,src:000000,op:flip1,pos:144,+cov (renamed from src/mint/afl-tests/id:000114,src:000000,op:flip1,pos:144,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000114,src:000000,op:flip1,pos:150,+cov (renamed from src/mint/afl-tests/id:000114,src:000000,op:flip1,pos:150,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000115,src:000000,op:flip1,pos:147,+cov (renamed from src/mint/afl-tests/id:000115,src:000000,op:flip1,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000115,src:000000,op:flip1,pos:153,+cov (renamed from src/mint/afl-tests/id:000115,src:000000,op:flip1,pos:153,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000116,src:000000,op:flip1,pos:150,+cov (renamed from src/mint/afl-tests/id:000116,src:000000,op:flip1,pos:150,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000116,src:000000,op:flip1,pos:154,+cov (renamed from src/mint/afl-tests/id:000116,src:000000,op:flip1,pos:154,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000117,src:000000,op:flip1,pos:151,+cov (renamed from src/mint/afl-tests/id:000117,src:000000,op:flip1,pos:151,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000117,src:000000,op:flip1,pos:155,+cov (renamed from src/mint/afl-tests/id:000117,src:000000,op:flip1,pos:155,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000118,src:000000,op:flip1,pos:151,+cov (renamed from src/mint/afl-tests/id:000118,src:000000,op:flip1,pos:151,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000118,src:000000,op:flip1,pos:157,+cov (renamed from src/mint/afl-tests/id:000118,src:000000,op:flip1,pos:157,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000119,src:000000,op:flip1,pos:154,+cov (renamed from src/mint/afl-tests/id:000119,src:000000,op:flip1,pos:154,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000119,src:000000,op:flip1,pos:158,+cov (renamed from src/mint/afl-tests/id:000119,src:000000,op:flip1,pos:158,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000120,src:000000,op:flip1,pos:155,+cov (renamed from src/mint/afl-tests/id:000120,src:000000,op:flip1,pos:155,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000120,src:000000,op:flip1,pos:158,+cov (renamed from src/mint/afl-tests/id:000120,src:000000,op:flip1,pos:158,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000121,src:000000,op:flip1,pos:156,+cov (renamed from src/mint/afl-tests/id:000121,src:000000,op:flip1,pos:156,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000121,src:000000,op:flip1,pos:159,+cov (renamed from src/mint/afl-tests/id:000121,src:000000,op:flip1,pos:159,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000122,src:000000,op:flip1,pos:157,+cov (renamed from src/mint/afl-tests/id:000122,src:000000,op:flip1,pos:157,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000122,src:000000,op:flip1,pos:159,+cov (renamed from src/mint/afl-tests/id:000122,src:000000,op:flip1,pos:159,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000123,src:000000,op:flip1,pos:160,+cov (renamed from src/mint/afl-tests/id:000123,src:000000,op:flip1,pos:160,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000123,src:000000,op:flip1,pos:161,+cov (renamed from src/mint/afl-tests/id:000123,src:000000,op:flip1,pos:161,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000124,src:000000,op:flip1,pos:161,+cov (renamed from src/mint/afl-tests/id:000124,src:000000,op:flip1,pos:161,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000124,src:000000,op:flip1,pos:164,+cov (renamed from src/mint/afl-tests/id:000124,src:000000,op:flip1,pos:164,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000125,src:000000,op:flip1,pos:161,+cov (renamed from src/mint/afl-tests/id:000125,src:000000,op:flip1,pos:161,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000125,src:000000,op:flip1,pos:166,+cov (renamed from src/mint/afl-tests/id:000125,src:000000,op:flip1,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000126,src:000000,op:flip1,pos:163 (renamed from src/mint/afl-tests/id:000126,src:000000,op:flip1,pos:163)0
-rw-r--r--src/exchange/afl-tests/id:000126,src:000000,op:flip1,pos:166,+cov (renamed from src/mint/afl-tests/id:000126,src:000000,op:flip1,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000127,src:000000,op:flip1,pos:166,+cov (renamed from src/mint/afl-tests/id:000127,src:000000,op:flip1,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000127,src:000000,op:flip1,pos:167,+cov (renamed from src/mint/afl-tests/id:000127,src:000000,op:flip1,pos:167,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000128,src:000000,op:flip1,pos:167,+cov (renamed from src/mint/afl-tests/id:000128,src:000000,op:flip1,pos:167,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000128,src:000000,op:flip1,pos:170,+cov (renamed from src/mint/afl-tests/id:000128,src:000000,op:flip1,pos:170,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000129,src:000000,op:flip1,pos:168,+cov (renamed from src/mint/afl-tests/id:000129,src:000000,op:flip1,pos:168,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000129,src:000000,op:flip1,pos:173,+cov (renamed from src/mint/afl-tests/id:000129,src:000000,op:flip1,pos:173,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000130,src:000000,op:flip1,pos:171,+cov (renamed from src/mint/afl-tests/id:000130,src:000000,op:flip1,pos:171,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000130,src:000000,op:flip1,pos:173,+cov (renamed from src/mint/afl-tests/id:000130,src:000000,op:flip1,pos:173,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000131,src:000000,op:flip1,pos:172,+cov (renamed from src/mint/afl-tests/id:000131,src:000000,op:flip1,pos:172,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000131,src:000000,op:flip1,pos:174,+cov (renamed from src/mint/afl-tests/id:000131,src:000000,op:flip1,pos:174,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000132,src:000000,op:flip1,pos:173,+cov (renamed from src/mint/afl-tests/id:000132,src:000000,op:flip1,pos:173,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000132,src:000000,op:flip1,pos:176,+cov (renamed from src/mint/afl-tests/id:000132,src:000000,op:flip1,pos:176,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000133,src:000000,op:flip1,pos:173,+cov (renamed from src/mint/afl-tests/id:000133,src:000000,op:flip1,pos:173,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000133,src:000000,op:flip1,pos:178,+cov (renamed from src/mint/afl-tests/id:000133,src:000000,op:flip1,pos:178,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000134,src:000000,op:flip1,pos:174,+cov (renamed from src/mint/afl-tests/id:000134,src:000000,op:flip1,pos:174,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000134,src:000000,op:flip1,pos:178,+cov (renamed from src/mint/afl-tests/id:000134,src:000000,op:flip1,pos:178,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000135,src:000000,op:flip1,pos:179,+cov (renamed from src/mint/afl-tests/id:000135,src:000000,op:flip1,pos:179,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000135,src:000000,op:flip1,pos:180 (renamed from src/mint/afl-tests/id:000135,src:000000,op:flip1,pos:180)0
-rw-r--r--src/exchange/afl-tests/id:000136,src:000000,op:flip1,pos:182,+cov (renamed from src/mint/afl-tests/id:000136,src:000000,op:flip1,pos:182,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000136,src:000000,op:flip1,pos:183,+cov (renamed from src/mint/afl-tests/id:000136,src:000000,op:flip1,pos:183,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000137,src:000000,op:flip1,pos:182,+cov (renamed from src/mint/afl-tests/id:000137,src:000000,op:flip1,pos:182,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000137,src:000000,op:flip1,pos:184,+cov (renamed from src/mint/afl-tests/id:000137,src:000000,op:flip1,pos:184,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000138,src:000000,op:flip1,pos:183 (renamed from src/mint/afl-tests/id:000138,src:000000,op:flip1,pos:183)0
-rw-r--r--src/exchange/afl-tests/id:000138,src:000000,op:flip1,pos:185,+cov (renamed from src/mint/afl-tests/id:000138,src:000000,op:flip1,pos:185,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000139,src:000000,op:flip1,pos:183,+cov (renamed from src/mint/afl-tests/id:000139,src:000000,op:flip1,pos:183,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000139,src:000000,op:flip1,pos:190 (renamed from src/mint/afl-tests/id:000139,src:000000,op:flip1,pos:190)0
-rw-r--r--src/exchange/afl-tests/id:000140,src:000000,op:flip1,pos:185,+cov (renamed from src/mint/afl-tests/id:000140,src:000000,op:flip1,pos:185,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000140,src:000000,op:flip1,pos:200,+cov (renamed from src/mint/afl-tests/id:000140,src:000000,op:flip1,pos:200,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000141,src:000000,op:flip1,pos:185,+cov (renamed from src/mint/afl-tests/id:000141,src:000000,op:flip1,pos:185,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000141,src:000000,op:flip1,pos:205,+cov (renamed from src/mint/afl-tests/id:000141,src:000000,op:flip1,pos:205,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000142,src:000000,op:flip1,pos:190 (renamed from src/mint/afl-tests/id:000142,src:000000,op:flip1,pos:190)0
-rw-r--r--src/exchange/afl-tests/id:000142,src:000000,op:flip1,pos:211,+cov (renamed from src/mint/afl-tests/id:000142,src:000000,op:flip1,pos:211,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000143,src:000000,op:flip1,pos:193,+cov (renamed from src/mint/afl-tests/id:000143,src:000000,op:flip1,pos:193,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000143,src:000000,op:flip1,pos:238,+cov (renamed from src/mint/afl-tests/id:000143,src:000000,op:flip1,pos:238,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000144,src:000000,op:flip1,pos:200,+cov (renamed from src/mint/afl-tests/id:000144,src:000000,op:flip1,pos:200,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000144,src:000000,op:flip1,pos:238,+cov (renamed from src/mint/afl-tests/id:000144,src:000000,op:flip1,pos:238,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000145,src:000000,op:flip1,pos:211,+cov (renamed from src/mint/afl-tests/id:000145,src:000000,op:flip1,pos:211,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000145,src:000000,op:flip1,pos:241,+cov (renamed from src/mint/afl-tests/id:000145,src:000000,op:flip1,pos:241,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000146,src:000000,op:flip1,pos:223,+cov (renamed from src/mint/afl-tests/id:000146,src:000000,op:flip1,pos:223,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000146,src:000000,op:flip1,pos:245 (renamed from src/mint/afl-tests/id:000146,src:000000,op:flip1,pos:245)0
-rw-r--r--src/exchange/afl-tests/id:000147,src:000000,op:flip1,pos:245 (renamed from src/mint/afl-tests/id:000147,src:000000,op:flip1,pos:245)0
-rw-r--r--src/exchange/afl-tests/id:000147,src:000000,op:flip1,pos:255,+cov (renamed from src/mint/afl-tests/id:000147,src:000000,op:flip1,pos:255,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000148,src:000000,op:flip1,pos:262,+cov (renamed from src/mint/afl-tests/id:000148,src:000000,op:flip1,pos:262,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000149,src:000000,op:flip1,pos:268,+cov (renamed from src/mint/afl-tests/id:000149,src:000000,op:flip1,pos:268,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000149,src:000000,op:flip1,pos:270,+cov (renamed from src/mint/afl-tests/id:000149,src:000000,op:flip1,pos:270,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000150,src:000000,op:flip1,pos:269,+cov (renamed from src/mint/afl-tests/id:000150,src:000000,op:flip1,pos:269,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000150,src:000000,op:flip1,pos:279,+cov (renamed from src/mint/afl-tests/id:000150,src:000000,op:flip1,pos:279,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000151,src:000000,op:flip1,pos:270,+cov (renamed from src/mint/afl-tests/id:000151,src:000000,op:flip1,pos:270,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000151,src:000000,op:flip1,pos:279,+cov (renamed from src/mint/afl-tests/id:000151,src:000000,op:flip1,pos:279,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000152,src:000000,op:flip1,pos:271,+cov (renamed from src/mint/afl-tests/id:000152,src:000000,op:flip1,pos:271,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000152,src:000000,op:flip1,pos:283,+cov (renamed from src/mint/afl-tests/id:000152,src:000000,op:flip1,pos:283,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000153,src:000000,op:flip1,pos:271,+cov (renamed from src/mint/afl-tests/id:000153,src:000000,op:flip1,pos:271,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000153,src:000000,op:flip1,pos:291,+cov (renamed from src/mint/afl-tests/id:000153,src:000000,op:flip1,pos:291,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000154,src:000000,op:flip1,pos:274,+cov (renamed from src/mint/afl-tests/id:000154,src:000000,op:flip1,pos:274,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000154,src:000000,op:flip1,pos:298,+cov (renamed from src/mint/afl-tests/id:000154,src:000000,op:flip1,pos:298,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000155,src:000000,op:flip1,pos:279,+cov (renamed from src/mint/afl-tests/id:000155,src:000000,op:flip1,pos:279,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000155,src:000000,op:flip1,pos:302,+cov (renamed from src/mint/afl-tests/id:000155,src:000000,op:flip1,pos:302,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000156,src:000000,op:flip1,pos:281,+cov (renamed from src/mint/afl-tests/id:000156,src:000000,op:flip1,pos:281,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000156,src:000000,op:flip1,pos:305,+cov (renamed from src/mint/afl-tests/id:000156,src:000000,op:flip1,pos:305,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000157,src:000000,op:flip1,pos:283,+cov (renamed from src/mint/afl-tests/id:000157,src:000000,op:flip1,pos:283,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000157,src:000000,op:flip1,pos:307,+cov (renamed from src/mint/afl-tests/id:000157,src:000000,op:flip1,pos:307,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000158,src:000000,op:flip1,pos:291,+cov (renamed from src/mint/afl-tests/id:000158,src:000000,op:flip1,pos:291,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000158,src:000000,op:flip1,pos:313,+cov (renamed from src/mint/afl-tests/id:000158,src:000000,op:flip1,pos:313,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000159,src:000000,op:flip1,pos:298,+cov (renamed from src/mint/afl-tests/id:000159,src:000000,op:flip1,pos:298,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000159,src:000000,op:flip1,pos:313,+cov (renamed from src/mint/afl-tests/id:000159,src:000000,op:flip1,pos:313,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000160,src:000000,op:flip1,pos:299,+cov (renamed from src/mint/afl-tests/id:000160,src:000000,op:flip1,pos:299,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000160,src:000000,op:flip1,pos:314,+cov (renamed from src/mint/afl-tests/id:000160,src:000000,op:flip1,pos:314,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000161,src:000000,op:flip1,pos:306,+cov (renamed from src/mint/afl-tests/id:000161,src:000000,op:flip1,pos:306,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000161,src:000000,op:flip1,pos:314,+cov (renamed from src/mint/afl-tests/id:000161,src:000000,op:flip1,pos:314,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000162,src:000000,op:flip1,pos:308,+cov (renamed from src/mint/afl-tests/id:000162,src:000000,op:flip1,pos:308,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000162,src:000000,op:flip1,pos:315,+cov (renamed from src/mint/afl-tests/id:000162,src:000000,op:flip1,pos:315,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000163,src:000000,op:flip1,pos:312,+cov (renamed from src/mint/afl-tests/id:000163,src:000000,op:flip1,pos:312,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000163,src:000000,op:flip1,pos:316,+cov (renamed from src/mint/afl-tests/id:000163,src:000000,op:flip1,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000164,src:000000,op:flip1,pos:315,+cov (renamed from src/mint/afl-tests/id:000164,src:000000,op:flip1,pos:315,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000164,src:000000,op:flip1,pos:317 (renamed from src/mint/afl-tests/id:000164,src:000000,op:flip1,pos:317)0
-rw-r--r--src/exchange/afl-tests/id:000165,src:000000,op:flip1,pos:316,+cov (renamed from src/mint/afl-tests/id:000165,src:000000,op:flip1,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000165,src:000000,op:flip1,pos:317,+cov (renamed from src/mint/afl-tests/id:000165,src:000000,op:flip1,pos:317,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000166,src:000000,op:flip1,pos:316,+cov (renamed from src/mint/afl-tests/id:000166,src:000000,op:flip1,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000166,src:000000,op:flip1,pos:319,+cov (renamed from src/mint/afl-tests/id:000166,src:000000,op:flip1,pos:319,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000167,src:000000,op:flip1,pos:317,+cov (renamed from src/mint/afl-tests/id:000167,src:000000,op:flip1,pos:317,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000167,src:000000,op:flip1,pos:320,+cov (renamed from src/mint/afl-tests/id:000167,src:000000,op:flip1,pos:320,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000168,src:000000,op:flip1,pos:317,+cov (renamed from src/mint/afl-tests/id:000168,src:000000,op:flip1,pos:317,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000168,src:000000,op:flip1,pos:322,+cov (renamed from src/mint/afl-tests/id:000168,src:000000,op:flip1,pos:322,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000169,src:000000,op:flip1,pos:318,+cov (renamed from src/mint/afl-tests/id:000169,src:000000,op:flip1,pos:318,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000169,src:000000,op:flip1,pos:326,+cov (renamed from src/mint/afl-tests/id:000169,src:000000,op:flip1,pos:326,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000170,src:000000,op:flip1,pos:319,+cov (renamed from src/mint/afl-tests/id:000170,src:000000,op:flip1,pos:319,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000170,src:000000,op:flip1,pos:328,+cov (renamed from src/mint/afl-tests/id:000170,src:000000,op:flip1,pos:328,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000171,src:000000,op:flip1,pos:326,+cov (renamed from src/mint/afl-tests/id:000171,src:000000,op:flip1,pos:326,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000171,src:000000,op:flip1,pos:329 (renamed from src/mint/afl-tests/id:000171,src:000000,op:flip1,pos:329)0
-rw-r--r--src/exchange/afl-tests/id:000172,src:000000,op:flip1,pos:327 (renamed from src/mint/afl-tests/id:000172,src:000000,op:flip1,pos:327)0
-rw-r--r--src/exchange/afl-tests/id:000172,src:000000,op:flip1,pos:332,+cov (renamed from src/mint/afl-tests/id:000172,src:000000,op:flip1,pos:332,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000173,src:000000,op:flip1,pos:330,+cov (renamed from src/mint/afl-tests/id:000173,src:000000,op:flip1,pos:330,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000173,src:000000,op:flip2,pos:8,+cov (renamed from src/mint/afl-tests/id:000173,src:000000,op:flip2,pos:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000174,src:000000,op:flip1,pos:331,+cov (renamed from src/mint/afl-tests/id:000174,src:000000,op:flip1,pos:331,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000174,src:000000,op:flip2,pos:8,+cov (renamed from src/mint/afl-tests/id:000174,src:000000,op:flip2,pos:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000175,src:000000,op:flip1,pos:338,+cov (renamed from src/mint/afl-tests/id:000175,src:000000,op:flip1,pos:338,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000175,src:000000,op:flip2,pos:28,+cov (renamed from src/mint/afl-tests/id:000175,src:000000,op:flip2,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000176,src:000000,op:flip2,pos:30,+cov (renamed from src/mint/afl-tests/id:000176,src:000000,op:flip2,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000176,src:000000,op:flip2,pos:8,+cov (renamed from src/mint/afl-tests/id:000176,src:000000,op:flip2,pos:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000177,src:000000,op:flip2,pos:25,+cov (renamed from src/mint/afl-tests/id:000177,src:000000,op:flip2,pos:25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000177,src:000000,op:flip2,pos:30,+cov (renamed from src/mint/afl-tests/id:000177,src:000000,op:flip2,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000178,src:000000,op:flip2,pos:26,+cov (renamed from src/mint/afl-tests/id:000178,src:000000,op:flip2,pos:26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000178,src:000000,op:flip2,pos:31,+cov (renamed from src/mint/afl-tests/id:000178,src:000000,op:flip2,pos:31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000179,src:000000,op:flip2,pos:29,+cov (renamed from src/mint/afl-tests/id:000179,src:000000,op:flip2,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000179,src:000000,op:flip2,pos:31,+cov (renamed from src/mint/afl-tests/id:000179,src:000000,op:flip2,pos:31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000180,src:000000,op:flip2,pos:30,+cov (renamed from src/mint/afl-tests/id:000180,src:000000,op:flip2,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000180,src:000000,op:flip2,pos:32,+cov (renamed from src/mint/afl-tests/id:000180,src:000000,op:flip2,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000181,src:000000,op:flip2,pos:33,+cov (renamed from src/mint/afl-tests/id:000181,src:000000,op:flip2,pos:33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000181,src:000000,op:flip2,pos:36,+cov (renamed from src/mint/afl-tests/id:000181,src:000000,op:flip2,pos:36,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000182,src:000000,op:flip2,pos:38 (renamed from src/mint/afl-tests/id:000182,src:000000,op:flip2,pos:38)0
-rw-r--r--src/exchange/afl-tests/id:000183,src:000000,op:flip2,pos:39,+cov (renamed from src/mint/afl-tests/id:000183,src:000000,op:flip2,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000184,src:000000,op:flip2,pos:40,+cov (renamed from src/mint/afl-tests/id:000184,src:000000,op:flip2,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000184,src:000000,op:flip2,pos:43,+cov (renamed from src/mint/afl-tests/id:000184,src:000000,op:flip2,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000185,src:000000,op:flip2,pos:40,+cov (renamed from src/mint/afl-tests/id:000185,src:000000,op:flip2,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000185,src:000000,op:flip2,pos:49,+cov (renamed from src/mint/afl-tests/id:000185,src:000000,op:flip2,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000186,src:000000,op:flip2,pos:40,+cov (renamed from src/mint/afl-tests/id:000186,src:000000,op:flip2,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000186,src:000000,op:flip2,pos:54,+cov (renamed from src/mint/afl-tests/id:000186,src:000000,op:flip2,pos:54,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000187,src:000000,op:flip2,pos:46,+cov (renamed from src/mint/afl-tests/id:000187,src:000000,op:flip2,pos:46,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000187,src:000000,op:flip2,pos:60,+cov (renamed from src/mint/afl-tests/id:000187,src:000000,op:flip2,pos:60,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000188,src:000000,op:flip2,pos:47,+cov (renamed from src/mint/afl-tests/id:000188,src:000000,op:flip2,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000188,src:000000,op:flip2,pos:64,+cov (renamed from src/mint/afl-tests/id:000188,src:000000,op:flip2,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000189,src:000000,op:flip2,pos:48,+cov (renamed from src/mint/afl-tests/id:000189,src:000000,op:flip2,pos:48,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000189,src:000000,op:flip2,pos:69,+cov (renamed from src/mint/afl-tests/id:000189,src:000000,op:flip2,pos:69,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000190,src:000000,op:flip2,pos:49,+cov (renamed from src/mint/afl-tests/id:000190,src:000000,op:flip2,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000190,src:000000,op:flip2,pos:71,+cov (renamed from src/mint/afl-tests/id:000190,src:000000,op:flip2,pos:71,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000191,src:000000,op:flip2,pos:53,+cov (renamed from src/mint/afl-tests/id:000191,src:000000,op:flip2,pos:53,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000191,src:000000,op:flip2,pos:73,+cov (renamed from src/mint/afl-tests/id:000191,src:000000,op:flip2,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000192,src:000000,op:flip2,pos:53,+cov (renamed from src/mint/afl-tests/id:000192,src:000000,op:flip2,pos:53,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000192,src:000000,op:flip2,pos:73,+cov (renamed from src/mint/afl-tests/id:000192,src:000000,op:flip2,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000193,src:000000,op:flip2,pos:62,+cov (renamed from src/mint/afl-tests/id:000193,src:000000,op:flip2,pos:62,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000193,src:000000,op:flip2,pos:75 (renamed from src/mint/afl-tests/id:000193,src:000000,op:flip2,pos:75)0
-rw-r--r--src/exchange/afl-tests/id:000194,src:000000,op:flip2,pos:68,+cov (renamed from src/mint/afl-tests/id:000194,src:000000,op:flip2,pos:68,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000194,src:000000,op:flip2,pos:77,+cov (renamed from src/mint/afl-tests/id:000194,src:000000,op:flip2,pos:77,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000195,src:000000,op:flip2,pos:70,+cov (renamed from src/mint/afl-tests/id:000195,src:000000,op:flip2,pos:70,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000195,src:000000,op:flip2,pos:81,+cov (renamed from src/mint/afl-tests/id:000195,src:000000,op:flip2,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000196,src:000000,op:flip2,pos:73,+cov (renamed from src/mint/afl-tests/id:000196,src:000000,op:flip2,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000196,src:000000,op:flip2,pos:81,+cov (renamed from src/mint/afl-tests/id:000196,src:000000,op:flip2,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000197,src:000000,op:flip2,pos:73,+cov (renamed from src/mint/afl-tests/id:000197,src:000000,op:flip2,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000197,src:000000,op:flip2,pos:83,+cov (renamed from src/mint/afl-tests/id:000197,src:000000,op:flip2,pos:83,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000198,src:000000,op:flip2,pos:76,+cov (renamed from src/mint/afl-tests/id:000198,src:000000,op:flip2,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000198,src:000000,op:flip2,pos:84,+cov (renamed from src/mint/afl-tests/id:000198,src:000000,op:flip2,pos:84,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000199,src:000000,op:flip2,pos:76,+cov (renamed from src/mint/afl-tests/id:000199,src:000000,op:flip2,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000199,src:000000,op:flip2,pos:85,+cov (renamed from src/mint/afl-tests/id:000199,src:000000,op:flip2,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000200,src:000000,op:flip2,pos:80,+cov (renamed from src/mint/afl-tests/id:000200,src:000000,op:flip2,pos:80,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000200,src:000000,op:flip2,pos:86,+cov (renamed from src/mint/afl-tests/id:000200,src:000000,op:flip2,pos:86,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000201,src:000000,op:flip2,pos:86,+cov (renamed from src/mint/afl-tests/id:000201,src:000000,op:flip2,pos:86,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000201,src:000000,op:flip2,pos:89,+cov (renamed from src/mint/afl-tests/id:000201,src:000000,op:flip2,pos:89,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000202,src:000000,op:flip2,pos:101,+cov (renamed from src/mint/afl-tests/id:000202,src:000000,op:flip2,pos:101,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000202,src:000000,op:flip2,pos:90,+cov (renamed from src/mint/afl-tests/id:000202,src:000000,op:flip2,pos:90,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000203,src:000000,op:flip2,pos:114 (renamed from src/mint/afl-tests/id:000203,src:000000,op:flip2,pos:114)0
-rw-r--r--src/exchange/afl-tests/id:000203,src:000000,op:flip2,pos:93,+cov (renamed from src/mint/afl-tests/id:000203,src:000000,op:flip2,pos:93,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000204,src:000000,op:flip2,pos:100,+cov (renamed from src/mint/afl-tests/id:000204,src:000000,op:flip2,pos:100,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000204,src:000000,op:flip2,pos:115,+cov (renamed from src/mint/afl-tests/id:000204,src:000000,op:flip2,pos:115,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000205,src:000000,op:flip2,pos:114 (renamed from src/mint/afl-tests/id:000205,src:000000,op:flip2,pos:114)0
-rw-r--r--src/exchange/afl-tests/id:000205,src:000000,op:flip2,pos:116,+cov (renamed from src/mint/afl-tests/id:000205,src:000000,op:flip2,pos:116,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000206,src:000000,op:flip2,pos:115,+cov (renamed from src/mint/afl-tests/id:000206,src:000000,op:flip2,pos:115,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000206,src:000000,op:flip2,pos:140,+cov (renamed from src/mint/afl-tests/id:000206,src:000000,op:flip2,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000207,src:000000,op:flip2,pos:116,+cov (renamed from src/mint/afl-tests/id:000207,src:000000,op:flip2,pos:116,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000207,src:000000,op:flip2,pos:140,+cov (renamed from src/mint/afl-tests/id:000207,src:000000,op:flip2,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000208,src:000000,op:flip2,pos:124,+cov (renamed from src/mint/afl-tests/id:000208,src:000000,op:flip2,pos:124,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000208,src:000000,op:flip2,pos:146,+cov (renamed from src/mint/afl-tests/id:000208,src:000000,op:flip2,pos:146,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000209,src:000000,op:flip2,pos:135,+cov (renamed from src/mint/afl-tests/id:000209,src:000000,op:flip2,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000209,src:000000,op:flip2,pos:147,+cov (renamed from src/mint/afl-tests/id:000209,src:000000,op:flip2,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000210,src:000000,op:flip2,pos:137,+cov (renamed from src/mint/afl-tests/id:000210,src:000000,op:flip2,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000210,src:000000,op:flip2,pos:148,+cov (renamed from src/mint/afl-tests/id:000210,src:000000,op:flip2,pos:148,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000211,src:000000,op:flip2,pos:138,+cov (renamed from src/mint/afl-tests/id:000211,src:000000,op:flip2,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000211,src:000000,op:flip2,pos:148,+cov (renamed from src/mint/afl-tests/id:000211,src:000000,op:flip2,pos:148,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000212,src:000000,op:flip2,pos:138,+cov (renamed from src/mint/afl-tests/id:000212,src:000000,op:flip2,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000212,src:000000,op:flip2,pos:159,+cov (renamed from src/mint/afl-tests/id:000212,src:000000,op:flip2,pos:159,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000213,src:000000,op:flip2,pos:139,+cov (renamed from src/mint/afl-tests/id:000213,src:000000,op:flip2,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000213,src:000000,op:flip2,pos:161,+cov (renamed from src/mint/afl-tests/id:000213,src:000000,op:flip2,pos:161,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000214,src:000000,op:flip2,pos:143,+cov (renamed from src/mint/afl-tests/id:000214,src:000000,op:flip2,pos:143,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000214,src:000000,op:flip2,pos:164,+cov (renamed from src/mint/afl-tests/id:000214,src:000000,op:flip2,pos:164,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000215,src:000000,op:flip2,pos:146,+cov (renamed from src/mint/afl-tests/id:000215,src:000000,op:flip2,pos:146,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000215,src:000000,op:flip2,pos:164,+cov (renamed from src/mint/afl-tests/id:000215,src:000000,op:flip2,pos:164,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000216,src:000000,op:flip2,pos:156,+cov (renamed from src/mint/afl-tests/id:000216,src:000000,op:flip2,pos:156,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000216,src:000000,op:flip2,pos:166,+cov (renamed from src/mint/afl-tests/id:000216,src:000000,op:flip2,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000217,src:000000,op:flip2,pos:161,+cov (renamed from src/mint/afl-tests/id:000217,src:000000,op:flip2,pos:161,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000217,src:000000,op:flip2,pos:170,+cov (renamed from src/mint/afl-tests/id:000217,src:000000,op:flip2,pos:170,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000218,src:000000,op:flip2,pos:171,+cov (renamed from src/mint/afl-tests/id:000218,src:000000,op:flip2,pos:171,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000218,src:000000,op:flip2,pos:176,+cov (renamed from src/mint/afl-tests/id:000218,src:000000,op:flip2,pos:176,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000219,src:000000,op:flip2,pos:180 (renamed from src/mint/afl-tests/id:000219,src:000000,op:flip2,pos:180)0
-rw-r--r--src/exchange/afl-tests/id:000219,src:000000,op:flip2,pos:185,+cov (renamed from src/mint/afl-tests/id:000219,src:000000,op:flip2,pos:185,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000220,src:000000,op:flip2,pos:184,+cov (renamed from src/mint/afl-tests/id:000220,src:000000,op:flip2,pos:184,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000220,src:000000,op:flip2,pos:193,+cov (renamed from src/mint/afl-tests/id:000220,src:000000,op:flip2,pos:193,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000221,src:000000,op:flip2,pos:211,+cov (renamed from src/mint/afl-tests/id:000221,src:000000,op:flip2,pos:211,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000221,src:000000,op:flip2,pos:226,+cov (renamed from src/mint/afl-tests/id:000221,src:000000,op:flip2,pos:226,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000222,src:000000,op:flip2,pos:218,+cov (renamed from src/mint/afl-tests/id:000222,src:000000,op:flip2,pos:218,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000222,src:000000,op:flip2,pos:232,+cov (renamed from src/mint/afl-tests/id:000222,src:000000,op:flip2,pos:232,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000223,src:000000,op:flip2,pos:239,+cov (renamed from src/mint/afl-tests/id:000223,src:000000,op:flip2,pos:239,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000223,src:000000,op:flip2,pos:271,+cov (renamed from src/mint/afl-tests/id:000223,src:000000,op:flip2,pos:271,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000224,src:000000,op:flip2,pos:241,+cov (renamed from src/mint/afl-tests/id:000224,src:000000,op:flip2,pos:241,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000224,src:000000,op:flip2,pos:279,+cov (renamed from src/mint/afl-tests/id:000224,src:000000,op:flip2,pos:279,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000225,src:000000,op:flip2,pos:250,+cov (renamed from src/mint/afl-tests/id:000225,src:000000,op:flip2,pos:250,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000225,src:000000,op:flip2,pos:308,+cov (renamed from src/mint/afl-tests/id:000225,src:000000,op:flip2,pos:308,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000226,src:000000,op:flip2,pos:272,+cov (renamed from src/mint/afl-tests/id:000226,src:000000,op:flip2,pos:272,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000226,src:000000,op:flip2,pos:315,+cov (renamed from src/mint/afl-tests/id:000226,src:000000,op:flip2,pos:315,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000227,src:000000,op:flip2,pos:277,+cov (renamed from src/mint/afl-tests/id:000227,src:000000,op:flip2,pos:277,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000227,src:000000,op:flip2,pos:316,+cov (renamed from src/mint/afl-tests/id:000227,src:000000,op:flip2,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000228,src:000000,op:flip2,pos:316,+cov (renamed from src/mint/afl-tests/id:000228,src:000000,op:flip2,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000228,src:000000,op:flip2,pos:317,+cov (renamed from src/mint/afl-tests/id:000228,src:000000,op:flip2,pos:317,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000229,src:000000,op:flip2,pos:316,+cov (renamed from src/mint/afl-tests/id:000229,src:000000,op:flip2,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000229,src:000000,op:flip2,pos:319,+cov (renamed from src/mint/afl-tests/id:000229,src:000000,op:flip2,pos:319,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000230,src:000000,op:flip2,pos:316,+cov (renamed from src/mint/afl-tests/id:000230,src:000000,op:flip2,pos:316,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000230,src:000000,op:flip2,pos:320,+cov (renamed from src/mint/afl-tests/id:000230,src:000000,op:flip2,pos:320,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000231,src:000000,op:flip2,pos:317,+cov (renamed from src/mint/afl-tests/id:000231,src:000000,op:flip2,pos:317,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000231,src:000000,op:flip2,pos:326,+cov (renamed from src/mint/afl-tests/id:000231,src:000000,op:flip2,pos:326,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000232,src:000000,op:flip2,pos:320,+cov (renamed from src/mint/afl-tests/id:000232,src:000000,op:flip2,pos:320,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000232,src:000000,op:flip2,pos:327,+cov (renamed from src/mint/afl-tests/id:000232,src:000000,op:flip2,pos:327,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000233,src:000000,op:flip2,pos:321,+cov (renamed from src/mint/afl-tests/id:000233,src:000000,op:flip2,pos:321,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000233,src:000000,op:flip2,pos:331,+cov (renamed from src/mint/afl-tests/id:000233,src:000000,op:flip2,pos:331,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000234,src:000000,op:flip2,pos:327,+cov (renamed from src/mint/afl-tests/id:000234,src:000000,op:flip2,pos:327,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000234,src:000000,op:flip4,pos:5,+cov (renamed from src/mint/afl-tests/id:000234,src:000000,op:flip4,pos:5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000235,src:000000,op:flip2,pos:328,+cov (renamed from src/mint/afl-tests/id:000235,src:000000,op:flip2,pos:328,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000235,src:000000,op:flip4,pos:20,+cov (renamed from src/mint/afl-tests/id:000235,src:000000,op:flip4,pos:20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000236,src:000000,op:flip2,pos:330,+cov (renamed from src/mint/afl-tests/id:000236,src:000000,op:flip2,pos:330,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000236,src:000000,op:flip4,pos:27,+cov (renamed from src/mint/afl-tests/id:000236,src:000000,op:flip4,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000237,src:000000,op:flip2,pos:331,+cov (renamed from src/mint/afl-tests/id:000237,src:000000,op:flip2,pos:331,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000237,src:000000,op:flip4,pos:30 (renamed from src/mint/afl-tests/id:000237,src:000000,op:flip4,pos:30)0
-rw-r--r--src/exchange/afl-tests/id:000238,src:000000,op:flip4,pos:32 (renamed from src/mint/afl-tests/id:000238,src:000000,op:flip4,pos:32)0
-rw-r--r--src/exchange/afl-tests/id:000238,src:000000,op:flip4,pos:5,+cov (renamed from src/mint/afl-tests/id:000238,src:000000,op:flip4,pos:5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000239,src:000000,op:flip4,pos:25,+cov (renamed from src/mint/afl-tests/id:000239,src:000000,op:flip4,pos:25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000239,src:000000,op:flip4,pos:34,+cov (renamed from src/mint/afl-tests/id:000239,src:000000,op:flip4,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000240,src:000000,op:flip4,pos:29,+cov (renamed from src/mint/afl-tests/id:000240,src:000000,op:flip4,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000240,src:000000,op:flip4,pos:35 (renamed from src/mint/afl-tests/id:000240,src:000000,op:flip4,pos:35)0
-rw-r--r--src/exchange/afl-tests/id:000241,src:000000,op:flip4,pos:30 (renamed from src/mint/afl-tests/id:000241,src:000000,op:flip4,pos:30)0
-rw-r--r--src/exchange/afl-tests/id:000241,src:000000,op:flip4,pos:36 (renamed from src/mint/afl-tests/id:000241,src:000000,op:flip4,pos:36)0
-rw-r--r--src/exchange/afl-tests/id:000242,src:000000,op:flip4,pos:32 (renamed from src/mint/afl-tests/id:000242,src:000000,op:flip4,pos:32)0
-rw-r--r--src/exchange/afl-tests/id:000242,src:000000,op:flip4,pos:39,+cov (renamed from src/mint/afl-tests/id:000242,src:000000,op:flip4,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000243,src:000000,op:flip4,pos:37,+cov (renamed from src/mint/afl-tests/id:000243,src:000000,op:flip4,pos:37,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000243,src:000000,op:flip4,pos:44,+cov (renamed from src/mint/afl-tests/id:000243,src:000000,op:flip4,pos:44,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000244,src:000000,op:flip4,pos:39,+cov (renamed from src/mint/afl-tests/id:000244,src:000000,op:flip4,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000244,src:000000,op:flip4,pos:48,+cov (renamed from src/mint/afl-tests/id:000244,src:000000,op:flip4,pos:48,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000245,src:000000,op:flip4,pos:45,+cov (renamed from src/mint/afl-tests/id:000245,src:000000,op:flip4,pos:45,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000245,src:000000,op:flip4,pos:56,+cov (renamed from src/mint/afl-tests/id:000245,src:000000,op:flip4,pos:56,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000246,src:000000,op:flip4,pos:47,+cov (renamed from src/mint/afl-tests/id:000246,src:000000,op:flip4,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000246,src:000000,op:flip4,pos:59,+cov (renamed from src/mint/afl-tests/id:000246,src:000000,op:flip4,pos:59,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000247,src:000000,op:flip4,pos:50,+cov (renamed from src/mint/afl-tests/id:000247,src:000000,op:flip4,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000247,src:000000,op:flip4,pos:65,+cov (renamed from src/mint/afl-tests/id:000247,src:000000,op:flip4,pos:65,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000248,src:000000,op:flip4,pos:60,+cov (renamed from src/mint/afl-tests/id:000248,src:000000,op:flip4,pos:60,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000248,src:000000,op:flip4,pos:68,+cov (renamed from src/mint/afl-tests/id:000248,src:000000,op:flip4,pos:68,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000249,src:000000,op:flip4,pos:68,+cov (renamed from src/mint/afl-tests/id:000249,src:000000,op:flip4,pos:68,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000250,src:000000,op:flip4,pos:68,+cov (renamed from src/mint/afl-tests/id:000250,src:000000,op:flip4,pos:68,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000250,src:000000,op:flip4,pos:73,+cov (renamed from src/mint/afl-tests/id:000250,src:000000,op:flip4,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000251,src:000000,op:flip4,pos:74,+cov (renamed from src/mint/afl-tests/id:000251,src:000000,op:flip4,pos:74,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000251,src:000000,op:flip4,pos:81,+cov (renamed from src/mint/afl-tests/id:000251,src:000000,op:flip4,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000252,src:000000,op:flip4,pos:75,+cov (renamed from src/mint/afl-tests/id:000252,src:000000,op:flip4,pos:75,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000252,src:000000,op:flip4,pos:82,+cov (renamed from src/mint/afl-tests/id:000252,src:000000,op:flip4,pos:82,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000253,src:000000,op:flip4,pos:75,+cov (renamed from src/mint/afl-tests/id:000253,src:000000,op:flip4,pos:75,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000253,src:000000,op:flip4,pos:85,+cov (renamed from src/mint/afl-tests/id:000253,src:000000,op:flip4,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000254,src:000000,op:flip4,pos:76,+cov (renamed from src/mint/afl-tests/id:000254,src:000000,op:flip4,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000254,src:000000,op:flip4,pos:88,+cov (renamed from src/mint/afl-tests/id:000254,src:000000,op:flip4,pos:88,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000255,src:000000,op:flip4,pos:81,+cov (renamed from src/mint/afl-tests/id:000255,src:000000,op:flip4,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000255,src:000000,op:flip4,pos:91,+cov (renamed from src/mint/afl-tests/id:000255,src:000000,op:flip4,pos:91,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000256,src:000000,op:flip4,pos:83,+cov (renamed from src/mint/afl-tests/id:000256,src:000000,op:flip4,pos:83,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000256,src:000000,op:flip4,pos:94,+cov (renamed from src/mint/afl-tests/id:000256,src:000000,op:flip4,pos:94,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000257,src:000000,op:flip4,pos:86,+cov (renamed from src/mint/afl-tests/id:000257,src:000000,op:flip4,pos:86,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000257,src:000000,op:flip4,pos:95,+cov (renamed from src/mint/afl-tests/id:000257,src:000000,op:flip4,pos:95,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000258,src:000000,op:flip4,pos:88,+cov (renamed from src/mint/afl-tests/id:000258,src:000000,op:flip4,pos:88,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000258,src:000000,op:flip4,pos:95,+cov (renamed from src/mint/afl-tests/id:000258,src:000000,op:flip4,pos:95,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000259,src:000000,op:flip4,pos:114 (renamed from src/mint/afl-tests/id:000259,src:000000,op:flip4,pos:114)0
-rw-r--r--src/exchange/afl-tests/id:000259,src:000000,op:flip4,pos:91,+cov (renamed from src/mint/afl-tests/id:000259,src:000000,op:flip4,pos:91,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000260,src:000000,op:flip4,pos:112,+cov (renamed from src/mint/afl-tests/id:000260,src:000000,op:flip4,pos:112,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000260,src:000000,op:flip4,pos:137,+cov (renamed from src/mint/afl-tests/id:000260,src:000000,op:flip4,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000261,src:000000,op:flip4,pos:139,+cov (renamed from src/mint/afl-tests/id:000261,src:000000,op:flip4,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000261,src:000000,op:flip4,pos:147,+cov (renamed from src/mint/afl-tests/id:000261,src:000000,op:flip4,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000262,src:000000,op:flip4,pos:142,+cov (renamed from src/mint/afl-tests/id:000262,src:000000,op:flip4,pos:142,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000262,src:000000,op:flip4,pos:164,+cov (renamed from src/mint/afl-tests/id:000262,src:000000,op:flip4,pos:164,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000263,src:000000,op:flip4,pos:147,+cov (renamed from src/mint/afl-tests/id:000263,src:000000,op:flip4,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000263,src:000000,op:flip4,pos:169,+cov (renamed from src/mint/afl-tests/id:000263,src:000000,op:flip4,pos:169,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000264,src:000000,op:flip4,pos:157,+cov (renamed from src/mint/afl-tests/id:000264,src:000000,op:flip4,pos:157,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000264,src:000000,op:flip4,pos:172,+cov (renamed from src/mint/afl-tests/id:000264,src:000000,op:flip4,pos:172,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000265,src:000000,op:flip4,pos:157,+cov (renamed from src/mint/afl-tests/id:000265,src:000000,op:flip4,pos:157,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000265,src:000000,op:flip4,pos:175,+cov (renamed from src/mint/afl-tests/id:000265,src:000000,op:flip4,pos:175,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000266,src:000000,op:flip4,pos:176,+cov (renamed from src/mint/afl-tests/id:000266,src:000000,op:flip4,pos:176,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000266,src:000000,op:flip4,pos:177,+cov (renamed from src/mint/afl-tests/id:000266,src:000000,op:flip4,pos:177,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000267,src:000000,op:flip4,pos:179,+cov (renamed from src/mint/afl-tests/id:000267,src:000000,op:flip4,pos:179,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000267,src:000000,op:flip4,pos:225,+cov (renamed from src/mint/afl-tests/id:000267,src:000000,op:flip4,pos:225,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000268,src:000000,op:flip4,pos:183,+cov (renamed from src/mint/afl-tests/id:000268,src:000000,op:flip4,pos:183,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000268,src:000000,op:flip4,pos:258,+cov (renamed from src/mint/afl-tests/id:000268,src:000000,op:flip4,pos:258,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000269,src:000000,op:flip4,pos:262,+cov (renamed from src/mint/afl-tests/id:000269,src:000000,op:flip4,pos:262,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000269,src:000000,op:flip4,pos:270,+cov (renamed from src/mint/afl-tests/id:000269,src:000000,op:flip4,pos:270,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000270,src:000000,op:flip4,pos:276,+cov (renamed from src/mint/afl-tests/id:000270,src:000000,op:flip4,pos:276,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000270,src:000000,op:flip4,pos:280,+cov (renamed from src/mint/afl-tests/id:000270,src:000000,op:flip4,pos:280,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000271,src:000000,op:flip4,pos:284,+cov (renamed from src/mint/afl-tests/id:000271,src:000000,op:flip4,pos:284,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000271,src:000000,op:flip4,pos:307,+cov (renamed from src/mint/afl-tests/id:000271,src:000000,op:flip4,pos:307,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000272,src:000000,op:flip4,pos:314,+cov (renamed from src/mint/afl-tests/id:000272,src:000000,op:flip4,pos:314,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000272,src:000000,op:flip4,pos:317,+cov (renamed from src/mint/afl-tests/id:000272,src:000000,op:flip4,pos:317,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000273,src:000000,op:flip4,pos:318,+cov (renamed from src/mint/afl-tests/id:000273,src:000000,op:flip4,pos:318,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000273,src:000000,op:flip4,pos:328,+cov (renamed from src/mint/afl-tests/id:000273,src:000000,op:flip4,pos:328,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000274,src:000000,op:flip4,pos:330,+cov (renamed from src/mint/afl-tests/id:000274,src:000000,op:flip4,pos:330,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000275,src:000000,op:flip4,pos:331,+cov (renamed from src/mint/afl-tests/id:000275,src:000000,op:flip4,pos:331,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000275,src:000000,op:flip8,pos:32,+cov (renamed from src/mint/afl-tests/id:000275,src:000000,op:flip8,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000276,src:000000,op:flip8,pos:43,+cov (renamed from src/mint/afl-tests/id:000276,src:000000,op:flip8,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000276,src:000000,op:flip8,pos:47,+cov (renamed from src/mint/afl-tests/id:000276,src:000000,op:flip8,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000277,src:000000,op:flip8,pos:190,+cov (renamed from src/mint/afl-tests/id:000277,src:000000,op:flip8,pos:190,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000277,src:000000,op:flip8,pos:52,+cov (renamed from src/mint/afl-tests/id:000277,src:000000,op:flip8,pos:52,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000278,src:000000,op:flip16,pos:51,+cov (renamed from src/mint/afl-tests/id:000278,src:000000,op:flip16,pos:51,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000278,src:000000,op:flip8,pos:62,+cov (renamed from src/mint/afl-tests/id:000278,src:000000,op:flip8,pos:62,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000279,src:000000,op:flip16,pos:219,+cov (renamed from src/mint/afl-tests/id:000279,src:000000,op:flip16,pos:219,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000279,src:000000,op:flip8,pos:87,+cov (renamed from src/mint/afl-tests/id:000279,src:000000,op:flip8,pos:87,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000280,src:000000,op:flip32,pos:55,+cov (renamed from src/mint/afl-tests/id:000280,src:000000,op:flip32,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000280,src:000000,op:flip8,pos:88,+cov (renamed from src/mint/afl-tests/id:000280,src:000000,op:flip8,pos:88,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000281,src:000000,op:flip32,pos:68,+cov (renamed from src/mint/afl-tests/id:000281,src:000000,op:flip32,pos:68,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000281,src:000000,op:flip8,pos:331,+cov (renamed from src/mint/afl-tests/id:000281,src:000000,op:flip8,pos:331,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000282,src:000000,op:arith8,pos:4,val:-19 (renamed from src/mint/afl-tests/id:000282,src:000000,op:arith8,pos:4,val:-19)0
-rw-r--r--src/exchange/afl-tests/id:000282,src:000000,op:flip16,pos:39,+cov (renamed from src/mint/afl-tests/id:000282,src:000000,op:flip16,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000283,src:000000,op:arith8,pos:4,val:-22 (renamed from src/mint/afl-tests/id:000283,src:000000,op:arith8,pos:4,val:-22)0
-rw-r--r--src/exchange/afl-tests/id:000283,src:000000,op:flip16,pos:85,+cov (renamed from src/mint/afl-tests/id:000283,src:000000,op:flip16,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000284,src:000000,op:arith8,pos:5,val:-10,+cov (renamed from src/mint/afl-tests/id:000284,src:000000,op:arith8,pos:5,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000284,src:000000,op:flip32,pos:49,+cov (renamed from src/mint/afl-tests/id:000284,src:000000,op:flip32,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000285,src:000000,op:arith8,pos:5,val:-34 (renamed from src/mint/afl-tests/id:000285,src:000000,op:arith8,pos:5,val:-34)0
-rw-r--r--src/exchange/afl-tests/id:000285,src:000000,op:flip32,pos:62 (renamed from src/mint/afl-tests/id:000285,src:000000,op:flip32,pos:62)0
-rw-r--r--src/exchange/afl-tests/id:000286,src:000000,op:arith8,pos:6,val:-34,+cov (renamed from src/mint/afl-tests/id:000286,src:000000,op:arith8,pos:6,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000286,src:000000,op:flip32,pos:86,+cov (renamed from src/mint/afl-tests/id:000286,src:000000,op:flip32,pos:86,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000287,src:000000,op:arith8,pos:11,val:-34 (renamed from src/mint/afl-tests/id:000287,src:000000,op:arith8,pos:11,val:-34)0
-rw-r--r--src/exchange/afl-tests/id:000287,src:000000,op:flip32,pos:92,+cov (renamed from src/mint/afl-tests/id:000287,src:000000,op:flip32,pos:92,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000288,src:000000,op:arith8,pos:15,val:-10,+cov (renamed from src/mint/afl-tests/id:000288,src:000000,op:arith8,pos:15,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000288,src:000000,op:arith8,pos:4,val:-19 (renamed from src/mint/afl-tests/id:000288,src:000000,op:arith8,pos:4,val:-19)0
-rw-r--r--src/exchange/afl-tests/id:000289,src:000000,op:arith8,pos:22,val:+5,+cov (renamed from src/mint/afl-tests/id:000289,src:000000,op:arith8,pos:22,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000289,src:000000,op:arith8,pos:4,val:-22 (renamed from src/mint/afl-tests/id:000289,src:000000,op:arith8,pos:4,val:-22)0
-rw-r--r--src/exchange/afl-tests/id:000290,src:000000,op:arith8,pos:24,val:+10,+cov (renamed from src/mint/afl-tests/id:000290,src:000000,op:arith8,pos:24,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000290,src:000000,op:arith8,pos:5,val:-10,+cov (renamed from src/mint/afl-tests/id:000290,src:000000,op:arith8,pos:5,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000291,src:000000,op:arith8,pos:25,val:-6,+cov (renamed from src/mint/afl-tests/id:000291,src:000000,op:arith8,pos:25,val:-6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000291,src:000000,op:arith8,pos:5,val:-34 (renamed from src/mint/afl-tests/id:000291,src:000000,op:arith8,pos:5,val:-34)0
-rw-r--r--src/exchange/afl-tests/id:000292,src:000000,op:arith8,pos:25,val:-25,+cov (renamed from src/mint/afl-tests/id:000292,src:000000,op:arith8,pos:25,val:-25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000292,src:000000,op:arith8,pos:6,val:-34,+cov (renamed from src/mint/afl-tests/id:000292,src:000000,op:arith8,pos:6,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000293,src:000000,op:arith8,pos:25,val:-29,+cov (renamed from src/mint/afl-tests/id:000293,src:000000,op:arith8,pos:25,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000293,src:000000,op:arith8,pos:7,val:-34,+cov (renamed from src/mint/afl-tests/id:000293,src:000000,op:arith8,pos:7,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000294,src:000000,op:arith8,pos:11,val:-34 (renamed from src/mint/afl-tests/id:000294,src:000000,op:arith8,pos:11,val:-34)0
-rw-r--r--src/exchange/afl-tests/id:000294,src:000000,op:arith8,pos:26,val:+12,+cov (renamed from src/mint/afl-tests/id:000294,src:000000,op:arith8,pos:26,val:+12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000295,src:000000,op:arith8,pos:15,val:-10,+cov (renamed from src/mint/afl-tests/id:000295,src:000000,op:arith8,pos:15,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000295,src:000000,op:arith8,pos:26,val:+17,+cov (renamed from src/mint/afl-tests/id:000295,src:000000,op:arith8,pos:26,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000296,src:000000,op:arith8,pos:25,val:+24,+cov (renamed from src/mint/afl-tests/id:000296,src:000000,op:arith8,pos:25,val:+24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000296,src:000000,op:arith8,pos:27,val:-29,+cov (renamed from src/mint/afl-tests/id:000296,src:000000,op:arith8,pos:27,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+26,+cov (renamed from src/mint/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+33,+cov (renamed from src/mint/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+13,+cov (renamed from src/mint/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+9,+cov (renamed from src/mint/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-15,+cov (renamed from src/mint/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-17 (renamed from src/mint/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-17)0
-rw-r--r--src/exchange/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:+27,+cov (renamed from src/mint/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:-33,+cov (renamed from src/mint/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000301,src:000000,op:arith8,pos:28,val:-31,+cov (renamed from src/mint/afl-tests/id:000301,src:000000,op:arith8,pos:28,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000301,src:000000,op:arith8,pos:29,val:+14,+cov (renamed from src/mint/afl-tests/id:000301,src:000000,op:arith8,pos:29,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000302,src:000000,op:arith8,pos:29,val:-29,+cov (renamed from src/mint/afl-tests/id:000302,src:000000,op:arith8,pos:29,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000302,src:000000,op:arith8,pos:30,val:+3,+cov (renamed from src/mint/afl-tests/id:000302,src:000000,op:arith8,pos:30,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+18,+cov (renamed from src/mint/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+31,+cov (renamed from src/mint/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:+19,+cov (renamed from src/mint/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:-33,+cov (renamed from src/mint/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000305,src:000000,op:arith8,pos:31,val:-29,+cov (renamed from src/mint/afl-tests/id:000305,src:000000,op:arith8,pos:31,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000305,src:000000,op:arith8,pos:32,val:+19,+cov (renamed from src/mint/afl-tests/id:000305,src:000000,op:arith8,pos:32,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000306,src:000000,op:arith8,pos:31,val:-33,+cov (renamed from src/mint/afl-tests/id:000306,src:000000,op:arith8,pos:31,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000306,src:000000,op:arith8,pos:33,val:+15,+cov (renamed from src/mint/afl-tests/id:000306,src:000000,op:arith8,pos:33,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000307,src:000000,op:arith8,pos:31,val:+34,+cov (renamed from src/mint/afl-tests/id:000307,src:000000,op:arith8,pos:31,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000307,src:000000,op:arith8,pos:33,val:-15,+cov (renamed from src/mint/afl-tests/id:000307,src:000000,op:arith8,pos:33,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000308,src:000000,op:arith8,pos:32,val:+10,+cov (renamed from src/mint/afl-tests/id:000308,src:000000,op:arith8,pos:32,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000308,src:000000,op:arith8,pos:34,val:-27,+cov (renamed from src/mint/afl-tests/id:000308,src:000000,op:arith8,pos:34,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000309,src:000000,op:arith8,pos:32,val:-20,+cov (renamed from src/mint/afl-tests/id:000309,src:000000,op:arith8,pos:32,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000309,src:000000,op:arith8,pos:34,val:+34,+cov (renamed from src/mint/afl-tests/id:000309,src:000000,op:arith8,pos:34,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000310,src:000000,op:arith8,pos:33,val:+20,+cov (renamed from src/mint/afl-tests/id:000310,src:000000,op:arith8,pos:33,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000310,src:000000,op:arith8,pos:35,val:+18,+cov (renamed from src/mint/afl-tests/id:000310,src:000000,op:arith8,pos:35,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000311,src:000000,op:arith8,pos:33,val:+24,+cov (renamed from src/mint/afl-tests/id:000311,src:000000,op:arith8,pos:33,val:+24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000311,src:000000,op:arith8,pos:35,val:-27,+cov (renamed from src/mint/afl-tests/id:000311,src:000000,op:arith8,pos:35,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000312,src:000000,op:arith8,pos:34,val:-3,+cov (renamed from src/mint/afl-tests/id:000312,src:000000,op:arith8,pos:34,val:-3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000312,src:000000,op:arith8,pos:35,val:+35,+cov (renamed from src/mint/afl-tests/id:000312,src:000000,op:arith8,pos:35,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000313,src:000000,op:arith8,pos:34,val:+18,+cov (renamed from src/mint/afl-tests/id:000313,src:000000,op:arith8,pos:34,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000313,src:000000,op:arith8,pos:36,val:+13,+cov (renamed from src/mint/afl-tests/id:000313,src:000000,op:arith8,pos:36,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000314,src:000000,op:arith8,pos:34,val:-30,+cov (renamed from src/mint/afl-tests/id:000314,src:000000,op:arith8,pos:34,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000314,src:000000,op:arith8,pos:36,val:+32,+cov (renamed from src/mint/afl-tests/id:000314,src:000000,op:arith8,pos:36,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000315,src:000000,op:arith8,pos:35,val:+17,+cov (renamed from src/mint/afl-tests/id:000315,src:000000,op:arith8,pos:35,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000315,src:000000,op:arith8,pos:37,val:+24,+cov (renamed from src/mint/afl-tests/id:000315,src:000000,op:arith8,pos:37,val:+24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000316,src:000000,op:arith8,pos:35,val:-19,+cov (renamed from src/mint/afl-tests/id:000316,src:000000,op:arith8,pos:35,val:-19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000316,src:000000,op:arith8,pos:37,val:+32,+cov (renamed from src/mint/afl-tests/id:000316,src:000000,op:arith8,pos:37,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000317,src:000000,op:arith8,pos:36,val:-26,+cov (renamed from src/mint/afl-tests/id:000317,src:000000,op:arith8,pos:36,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000317,src:000000,op:arith8,pos:38,val:-35,+cov (renamed from src/mint/afl-tests/id:000317,src:000000,op:arith8,pos:38,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000318,src:000000,op:arith8,pos:36,val:+27,+cov (renamed from src/mint/afl-tests/id:000318,src:000000,op:arith8,pos:36,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000318,src:000000,op:arith8,pos:39,val:+18,+cov (renamed from src/mint/afl-tests/id:000318,src:000000,op:arith8,pos:39,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000319,src:000000,op:arith8,pos:36,val:+32,+cov (renamed from src/mint/afl-tests/id:000319,src:000000,op:arith8,pos:36,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000319,src:000000,op:arith8,pos:39,val:-23,+cov (renamed from src/mint/afl-tests/id:000319,src:000000,op:arith8,pos:39,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000320,src:000000,op:arith8,pos:37,val:-9,+cov (renamed from src/mint/afl-tests/id:000320,src:000000,op:arith8,pos:37,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000320,src:000000,op:arith8,pos:39,val:-24,+cov (renamed from src/mint/afl-tests/id:000320,src:000000,op:arith8,pos:39,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000321,src:000000,op:arith8,pos:37,val:+21 (renamed from src/mint/afl-tests/id:000321,src:000000,op:arith8,pos:37,val:+21)0
-rw-r--r--src/exchange/afl-tests/id:000321,src:000000,op:arith8,pos:39,val:+25,+cov (renamed from src/mint/afl-tests/id:000321,src:000000,op:arith8,pos:39,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000322,src:000000,op:arith8,pos:37,val:+24,+cov (renamed from src/mint/afl-tests/id:000322,src:000000,op:arith8,pos:37,val:+24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000322,src:000000,op:arith8,pos:40,val:-21,+cov (renamed from src/mint/afl-tests/id:000322,src:000000,op:arith8,pos:40,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000323,src:000000,op:arith8,pos:39,val:+13,+cov (renamed from src/mint/afl-tests/id:000323,src:000000,op:arith8,pos:39,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000323,src:000000,op:arith8,pos:41,val:-5,+cov (renamed from src/mint/afl-tests/id:000323,src:000000,op:arith8,pos:41,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000324,src:000000,op:arith8,pos:39,val:-23,+cov (renamed from src/mint/afl-tests/id:000324,src:000000,op:arith8,pos:39,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000324,src:000000,op:arith8,pos:41,val:+13,+cov (renamed from src/mint/afl-tests/id:000324,src:000000,op:arith8,pos:41,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000325,src:000000,op:arith8,pos:40,val:+20,+cov (renamed from src/mint/afl-tests/id:000325,src:000000,op:arith8,pos:40,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000325,src:000000,op:arith8,pos:41,val:+26,+cov (renamed from src/mint/afl-tests/id:000325,src:000000,op:arith8,pos:41,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000326,src:000000,op:arith8,pos:40,val:+27,+cov (renamed from src/mint/afl-tests/id:000326,src:000000,op:arith8,pos:40,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000326,src:000000,op:arith8,pos:41,val:+27,+cov (renamed from src/mint/afl-tests/id:000326,src:000000,op:arith8,pos:41,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000327,src:000000,op:arith8,pos:41,val:-33,+cov (renamed from src/mint/afl-tests/id:000327,src:000000,op:arith8,pos:41,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000327,src:000000,op:arith8,pos:42,val:+29,+cov (renamed from src/mint/afl-tests/id:000327,src:000000,op:arith8,pos:42,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000328,src:000000,op:arith8,pos:41,val:+35,+cov (renamed from src/mint/afl-tests/id:000328,src:000000,op:arith8,pos:41,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000328,src:000000,op:arith8,pos:43,val:-33,+cov (renamed from src/mint/afl-tests/id:000328,src:000000,op:arith8,pos:43,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000329,src:000000,op:arith8,pos:42,val:-6,+cov (renamed from src/mint/afl-tests/id:000329,src:000000,op:arith8,pos:42,val:-6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000329,src:000000,op:arith8,pos:44,val:+17,+cov (renamed from src/mint/afl-tests/id:000329,src:000000,op:arith8,pos:44,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000330,src:000000,op:arith8,pos:42,val:+13,+cov (renamed from src/mint/afl-tests/id:000330,src:000000,op:arith8,pos:42,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000330,src:000000,op:arith8,pos:45,val:-5,+cov (renamed from src/mint/afl-tests/id:000330,src:000000,op:arith8,pos:45,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000331,src:000000,op:arith8,pos:42,val:+18,+cov (renamed from src/mint/afl-tests/id:000331,src:000000,op:arith8,pos:42,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000331,src:000000,op:arith8,pos:45,val:-11,+cov (renamed from src/mint/afl-tests/id:000331,src:000000,op:arith8,pos:45,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000332,src:000000,op:arith8,pos:43,val:-23,+cov (renamed from src/mint/afl-tests/id:000332,src:000000,op:arith8,pos:43,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000332,src:000000,op:arith8,pos:45,val:+19,+cov (renamed from src/mint/afl-tests/id:000332,src:000000,op:arith8,pos:45,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000333,src:000000,op:arith8,pos:43,val:+33,+cov (renamed from src/mint/afl-tests/id:000333,src:000000,op:arith8,pos:43,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000333,src:000000,op:arith8,pos:51,val:-12,+cov (renamed from src/mint/afl-tests/id:000333,src:000000,op:arith8,pos:51,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000334,src:000000,op:arith8,pos:44,val:+11,+cov (renamed from src/mint/afl-tests/id:000334,src:000000,op:arith8,pos:44,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000334,src:000000,op:arith8,pos:51,val:+14,+cov (renamed from src/mint/afl-tests/id:000334,src:000000,op:arith8,pos:51,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000335,src:000000,op:arith8,pos:45,val:-24,+cov (renamed from src/mint/afl-tests/id:000335,src:000000,op:arith8,pos:45,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000335,src:000000,op:arith8,pos:51,val:-22,+cov (renamed from src/mint/afl-tests/id:000335,src:000000,op:arith8,pos:51,val:-22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000336,src:000000,op:arith8,pos:45,val:-27,+cov (renamed from src/mint/afl-tests/id:000336,src:000000,op:arith8,pos:45,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000336,src:000000,op:arith8,pos:51,val:-23,+cov (renamed from src/mint/afl-tests/id:000336,src:000000,op:arith8,pos:51,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000337,src:000000,op:arith8,pos:46,val:+7,+cov (renamed from src/mint/afl-tests/id:000337,src:000000,op:arith8,pos:46,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000337,src:000000,op:arith8,pos:52,val:-14,+cov (renamed from src/mint/afl-tests/id:000337,src:000000,op:arith8,pos:52,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000338,src:000000,op:arith8,pos:46,val:-21,+cov (renamed from src/mint/afl-tests/id:000338,src:000000,op:arith8,pos:46,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000338,src:000000,op:arith8,pos:52,val:+28,+cov (renamed from src/mint/afl-tests/id:000338,src:000000,op:arith8,pos:52,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000339,src:000000,op:arith8,pos:46,val:+31,+cov (renamed from src/mint/afl-tests/id:000339,src:000000,op:arith8,pos:46,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000339,src:000000,op:arith8,pos:53,val:+9,+cov (renamed from src/mint/afl-tests/id:000339,src:000000,op:arith8,pos:53,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000340,src:000000,op:arith8,pos:49,val:+16,+cov (renamed from src/mint/afl-tests/id:000340,src:000000,op:arith8,pos:49,val:+16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000340,src:000000,op:arith8,pos:53,val:-11,+cov (renamed from src/mint/afl-tests/id:000340,src:000000,op:arith8,pos:53,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000341,src:000000,op:arith8,pos:49,val:-26,+cov (renamed from src/mint/afl-tests/id:000341,src:000000,op:arith8,pos:49,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000341,src:000000,op:arith8,pos:53,val:-17,+cov (renamed from src/mint/afl-tests/id:000341,src:000000,op:arith8,pos:53,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000342,src:000000,op:arith8,pos:49,val:+34,+cov (renamed from src/mint/afl-tests/id:000342,src:000000,op:arith8,pos:49,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000342,src:000000,op:arith8,pos:53,val:-18,+cov (renamed from src/mint/afl-tests/id:000342,src:000000,op:arith8,pos:53,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000343,src:000000,op:arith8,pos:50,val:-7,+cov (renamed from src/mint/afl-tests/id:000343,src:000000,op:arith8,pos:50,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000343,src:000000,op:arith8,pos:53,val:-35,+cov (renamed from src/mint/afl-tests/id:000343,src:000000,op:arith8,pos:53,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000344,src:000000,op:arith8,pos:50,val:+22,+cov (renamed from src/mint/afl-tests/id:000344,src:000000,op:arith8,pos:50,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000344,src:000000,op:arith8,pos:54,val:-15,+cov (renamed from src/mint/afl-tests/id:000344,src:000000,op:arith8,pos:54,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000345,src:000000,op:arith8,pos:50,val:+24,+cov (renamed from src/mint/afl-tests/id:000345,src:000000,op:arith8,pos:50,val:+24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000345,src:000000,op:arith8,pos:54,val:-22,+cov (renamed from src/mint/afl-tests/id:000345,src:000000,op:arith8,pos:54,val:-22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000346,src:000000,op:arith8,pos:50,val:-31,+cov (renamed from src/mint/afl-tests/id:000346,src:000000,op:arith8,pos:50,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000346,src:000000,op:arith8,pos:55,val:-7 (renamed from src/mint/afl-tests/id:000346,src:000000,op:arith8,pos:55,val:-7)0
-rw-r--r--src/exchange/afl-tests/id:000347,src:000000,op:arith8,pos:51,val:-1,+cov (renamed from src/mint/afl-tests/id:000347,src:000000,op:arith8,pos:51,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000347,src:000000,op:arith8,pos:55,val:-33,+cov (renamed from src/mint/afl-tests/id:000347,src:000000,op:arith8,pos:55,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000348,src:000000,op:arith8,pos:51,val:+18,+cov (renamed from src/mint/afl-tests/id:000348,src:000000,op:arith8,pos:51,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000348,src:000000,op:arith8,pos:55,val:-35,+cov (renamed from src/mint/afl-tests/id:000348,src:000000,op:arith8,pos:55,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000349,src:000000,op:arith8,pos:52,val:-6,+cov (renamed from src/mint/afl-tests/id:000349,src:000000,op:arith8,pos:52,val:-6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000349,src:000000,op:arith8,pos:57,val:-14,+cov (renamed from src/mint/afl-tests/id:000349,src:000000,op:arith8,pos:57,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000350,src:000000,op:arith8,pos:52,val:+22,+cov (renamed from src/mint/afl-tests/id:000350,src:000000,op:arith8,pos:52,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000350,src:000000,op:arith8,pos:57,val:+28,+cov (renamed from src/mint/afl-tests/id:000350,src:000000,op:arith8,pos:57,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000351,src:000000,op:arith8,pos:52,val:-31,+cov (renamed from src/mint/afl-tests/id:000351,src:000000,op:arith8,pos:52,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000351,src:000000,op:arith8,pos:57,val:-29,+cov (renamed from src/mint/afl-tests/id:000351,src:000000,op:arith8,pos:57,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000352,src:000000,op:arith8,pos:53,val:-18,+cov (renamed from src/mint/afl-tests/id:000352,src:000000,op:arith8,pos:53,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000352,src:000000,op:arith8,pos:58,val:-29,+cov (renamed from src/mint/afl-tests/id:000352,src:000000,op:arith8,pos:58,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000353,src:000000,op:arith8,pos:53,val:+27,+cov (renamed from src/mint/afl-tests/id:000353,src:000000,op:arith8,pos:53,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000353,src:000000,op:arith8,pos:59,val:+10,+cov (renamed from src/mint/afl-tests/id:000353,src:000000,op:arith8,pos:59,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000354,src:000000,op:arith8,pos:53,val:-27,+cov (renamed from src/mint/afl-tests/id:000354,src:000000,op:arith8,pos:53,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000354,src:000000,op:arith8,pos:59,val:+23,+cov (renamed from src/mint/afl-tests/id:000354,src:000000,op:arith8,pos:59,val:+23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000355,src:000000,op:arith8,pos:53,val:-28,+cov (renamed from src/mint/afl-tests/id:000355,src:000000,op:arith8,pos:53,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000355,src:000000,op:arith8,pos:62,val:+9,+cov (renamed from src/mint/afl-tests/id:000355,src:000000,op:arith8,pos:62,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000356,src:000000,op:arith8,pos:55,val:-2,+cov (renamed from src/mint/afl-tests/id:000356,src:000000,op:arith8,pos:55,val:-2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000356,src:000000,op:arith8,pos:62,val:-21,+cov (renamed from src/mint/afl-tests/id:000356,src:000000,op:arith8,pos:62,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000357,src:000000,op:arith8,pos:55,val:-7 (renamed from src/mint/afl-tests/id:000357,src:000000,op:arith8,pos:55,val:-7)0
-rw-r--r--src/exchange/afl-tests/id:000357,src:000000,op:arith8,pos:62,val:-23,+cov (renamed from src/mint/afl-tests/id:000357,src:000000,op:arith8,pos:62,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000358,src:000000,op:arith8,pos:55,val:-33,+cov (renamed from src/mint/afl-tests/id:000358,src:000000,op:arith8,pos:55,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000358,src:000000,op:arith8,pos:62,val:-35,+cov (renamed from src/mint/afl-tests/id:000358,src:000000,op:arith8,pos:62,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000359,src:000000,op:arith8,pos:56,val:-17,+cov (renamed from src/mint/afl-tests/id:000359,src:000000,op:arith8,pos:56,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000359,src:000000,op:arith8,pos:63,val:+3,+cov (renamed from src/mint/afl-tests/id:000359,src:000000,op:arith8,pos:63,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000360,src:000000,op:arith8,pos:56,val:+34,+cov (renamed from src/mint/afl-tests/id:000360,src:000000,op:arith8,pos:56,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000360,src:000000,op:arith8,pos:64,val:-5,+cov (renamed from src/mint/afl-tests/id:000360,src:000000,op:arith8,pos:64,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000361,src:000000,op:arith8,pos:57,val:-23,+cov (renamed from src/mint/afl-tests/id:000361,src:000000,op:arith8,pos:57,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000361,src:000000,op:arith8,pos:64,val:-26,+cov (renamed from src/mint/afl-tests/id:000361,src:000000,op:arith8,pos:64,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000362,src:000000,op:arith8,pos:58,val:+34,+cov (renamed from src/mint/afl-tests/id:000362,src:000000,op:arith8,pos:58,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000362,src:000000,op:arith8,pos:65,val:-10,+cov (renamed from src/mint/afl-tests/id:000362,src:000000,op:arith8,pos:65,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000363,src:000000,op:arith8,pos:60,val:-14,+cov (renamed from src/mint/afl-tests/id:000363,src:000000,op:arith8,pos:60,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000363,src:000000,op:arith8,pos:65,val:-27,+cov (renamed from src/mint/afl-tests/id:000363,src:000000,op:arith8,pos:65,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000364,src:000000,op:arith8,pos:60,val:-15,+cov (renamed from src/mint/afl-tests/id:000364,src:000000,op:arith8,pos:60,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000364,src:000000,op:arith8,pos:65,val:-30,+cov (renamed from src/mint/afl-tests/id:000364,src:000000,op:arith8,pos:65,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000365,src:000000,op:arith8,pos:60,val:-27,+cov (renamed from src/mint/afl-tests/id:000365,src:000000,op:arith8,pos:60,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000365,src:000000,op:arith8,pos:66,val:+13,+cov (renamed from src/mint/afl-tests/id:000365,src:000000,op:arith8,pos:66,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000366,src:000000,op:arith8,pos:62,val:+13,+cov (renamed from src/mint/afl-tests/id:000366,src:000000,op:arith8,pos:62,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000366,src:000000,op:arith8,pos:67,val:-9 (renamed from src/mint/afl-tests/id:000366,src:000000,op:arith8,pos:67,val:-9)0
-rw-r--r--src/exchange/afl-tests/id:000367,src:000000,op:arith8,pos:62,val:-21,+cov (renamed from src/mint/afl-tests/id:000367,src:000000,op:arith8,pos:62,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000367,src:000000,op:arith8,pos:67,val:+15,+cov (renamed from src/mint/afl-tests/id:000367,src:000000,op:arith8,pos:67,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000368,src:000000,op:arith8,pos:62,val:-23,+cov (renamed from src/mint/afl-tests/id:000368,src:000000,op:arith8,pos:62,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000368,src:000000,op:arith8,pos:67,val:-35 (renamed from src/mint/afl-tests/id:000368,src:000000,op:arith8,pos:67,val:-35)0
-rw-r--r--src/exchange/afl-tests/id:000369,src:000000,op:arith8,pos:63,val:+6,+cov (renamed from src/mint/afl-tests/id:000369,src:000000,op:arith8,pos:63,val:+6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000369,src:000000,op:arith8,pos:72,val:+30,+cov (renamed from src/mint/afl-tests/id:000369,src:000000,op:arith8,pos:72,val:+30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000370,src:000000,op:arith8,pos:63,val:-18,+cov (renamed from src/mint/afl-tests/id:000370,src:000000,op:arith8,pos:63,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000370,src:000000,op:arith8,pos:72,val:-35,+cov (renamed from src/mint/afl-tests/id:000370,src:000000,op:arith8,pos:72,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000371,src:000000,op:arith8,pos:63,val:-28,+cov (renamed from src/mint/afl-tests/id:000371,src:000000,op:arith8,pos:63,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000371,src:000000,op:arith8,pos:74,val:+5,+cov (renamed from src/mint/afl-tests/id:000371,src:000000,op:arith8,pos:74,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000372,src:000000,op:arith8,pos:64,val:-5,+cov (renamed from src/mint/afl-tests/id:000372,src:000000,op:arith8,pos:64,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000372,src:000000,op:arith8,pos:75,val:-23,+cov (renamed from src/mint/afl-tests/id:000372,src:000000,op:arith8,pos:75,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000373,src:000000,op:arith8,pos:64,val:-13,+cov (renamed from src/mint/afl-tests/id:000373,src:000000,op:arith8,pos:64,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000373,src:000000,op:arith8,pos:75,val:+28,+cov (renamed from src/mint/afl-tests/id:000373,src:000000,op:arith8,pos:75,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000374,src:000000,op:arith8,pos:64,val:-18,+cov (renamed from src/mint/afl-tests/id:000374,src:000000,op:arith8,pos:64,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000374,src:000000,op:arith8,pos:76,val:-5,+cov (renamed from src/mint/afl-tests/id:000374,src:000000,op:arith8,pos:76,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000375,src:000000,op:arith8,pos:64,val:-35,+cov (renamed from src/mint/afl-tests/id:000375,src:000000,op:arith8,pos:64,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000375,src:000000,op:arith8,pos:76,val:-20,+cov (renamed from src/mint/afl-tests/id:000375,src:000000,op:arith8,pos:76,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000376,src:000000,op:arith8,pos:65,val:-27,+cov (renamed from src/mint/afl-tests/id:000376,src:000000,op:arith8,pos:65,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000376,src:000000,op:arith8,pos:77,val:-5,+cov (renamed from src/mint/afl-tests/id:000376,src:000000,op:arith8,pos:77,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000377,src:000000,op:arith8,pos:65,val:+29,+cov (renamed from src/mint/afl-tests/id:000377,src:000000,op:arith8,pos:65,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000377,src:000000,op:arith8,pos:77,val:+25,+cov (renamed from src/mint/afl-tests/id:000377,src:000000,op:arith8,pos:77,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000378,src:000000,op:arith8,pos:66,val:-20,+cov (renamed from src/mint/afl-tests/id:000378,src:000000,op:arith8,pos:66,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000378,src:000000,op:arith8,pos:80,val:+20,+cov (renamed from src/mint/afl-tests/id:000378,src:000000,op:arith8,pos:80,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000379,src:000000,op:arith8,pos:66,val:+28,+cov (renamed from src/mint/afl-tests/id:000379,src:000000,op:arith8,pos:66,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000379,src:000000,op:arith8,pos:81,val:+20,+cov (renamed from src/mint/afl-tests/id:000379,src:000000,op:arith8,pos:81,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000380,src:000000,op:arith8,pos:66,val:-31,+cov (renamed from src/mint/afl-tests/id:000380,src:000000,op:arith8,pos:66,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000380,src:000000,op:arith8,pos:82,val:-5,+cov (renamed from src/mint/afl-tests/id:000380,src:000000,op:arith8,pos:82,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000381,src:000000,op:arith8,pos:67,val:-9 (renamed from src/mint/afl-tests/id:000381,src:000000,op:arith8,pos:67,val:-9)0
-rw-r--r--src/exchange/afl-tests/id:000381,src:000000,op:arith8,pos:83,val:-18,+cov (renamed from src/mint/afl-tests/id:000381,src:000000,op:arith8,pos:83,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000382,src:000000,op:arith8,pos:67,val:+10,+cov (renamed from src/mint/afl-tests/id:000382,src:000000,op:arith8,pos:67,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000382,src:000000,op:arith8,pos:84,val:+10,+cov (renamed from src/mint/afl-tests/id:000382,src:000000,op:arith8,pos:84,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000383,src:000000,op:arith8,pos:67,val:-15,+cov (renamed from src/mint/afl-tests/id:000383,src:000000,op:arith8,pos:67,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000383,src:000000,op:arith8,pos:84,val:-30,+cov (renamed from src/mint/afl-tests/id:000383,src:000000,op:arith8,pos:84,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000384,src:000000,op:arith8,pos:67,val:-35 (renamed from src/mint/afl-tests/id:000384,src:000000,op:arith8,pos:67,val:-35)0
-rw-r--r--src/exchange/afl-tests/id:000384,src:000000,op:arith8,pos:84,val:+34,+cov (renamed from src/mint/afl-tests/id:000384,src:000000,op:arith8,pos:84,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000385,src:000000,op:arith8,pos:68,val:+32,+cov (renamed from src/mint/afl-tests/id:000385,src:000000,op:arith8,pos:68,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000385,src:000000,op:arith8,pos:86,val:-9,+cov (renamed from src/mint/afl-tests/id:000385,src:000000,op:arith8,pos:86,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000386,src:000000,op:arith8,pos:69,val:+14,+cov (renamed from src/mint/afl-tests/id:000386,src:000000,op:arith8,pos:69,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000386,src:000000,op:arith8,pos:86,val:-19,+cov (renamed from src/mint/afl-tests/id:000386,src:000000,op:arith8,pos:86,val:-19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000387,src:000000,op:arith8,pos:70,val:-21,+cov (renamed from src/mint/afl-tests/id:000387,src:000000,op:arith8,pos:70,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000387,src:000000,op:arith8,pos:87,val:+10,+cov (renamed from src/mint/afl-tests/id:000387,src:000000,op:arith8,pos:87,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000388,src:000000,op:arith8,pos:71,val:+3 (renamed from src/mint/afl-tests/id:000388,src:000000,op:arith8,pos:71,val:+3)0
-rw-r--r--src/exchange/afl-tests/id:000388,src:000000,op:arith8,pos:87,val:+15,+cov (renamed from src/mint/afl-tests/id:000388,src:000000,op:arith8,pos:87,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000389,src:000000,op:arith8,pos:72,val:-7,+cov (renamed from src/mint/afl-tests/id:000389,src:000000,op:arith8,pos:72,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000389,src:000000,op:arith8,pos:87,val:-26,+cov (renamed from src/mint/afl-tests/id:000389,src:000000,op:arith8,pos:87,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000390,src:000000,op:arith8,pos:72,val:+30,+cov (renamed from src/mint/afl-tests/id:000390,src:000000,op:arith8,pos:72,val:+30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000390,src:000000,op:arith8,pos:88,val:+9,+cov (renamed from src/mint/afl-tests/id:000390,src:000000,op:arith8,pos:88,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000391,src:000000,op:arith8,pos:73,val:-13,+cov (renamed from src/mint/afl-tests/id:000391,src:000000,op:arith8,pos:73,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000391,src:000000,op:arith8,pos:88,val:+25 (renamed from src/mint/afl-tests/id:000391,src:000000,op:arith8,pos:88,val:+25)0
-rw-r--r--src/exchange/afl-tests/id:000392,src:000000,op:arith8,pos:73,val:-29,+cov (renamed from src/mint/afl-tests/id:000392,src:000000,op:arith8,pos:73,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000392,src:000000,op:arith8,pos:88,val:+26,+cov (renamed from src/mint/afl-tests/id:000392,src:000000,op:arith8,pos:88,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000393,src:000000,op:arith8,pos:73,val:-35,+cov (renamed from src/mint/afl-tests/id:000393,src:000000,op:arith8,pos:73,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000393,src:000000,op:arith8,pos:90,val:-33,+cov (renamed from src/mint/afl-tests/id:000393,src:000000,op:arith8,pos:90,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000394,src:000000,op:arith8,pos:75,val:-20,+cov (renamed from src/mint/afl-tests/id:000394,src:000000,op:arith8,pos:75,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000394,src:000000,op:arith8,pos:91,val:-14,+cov (renamed from src/mint/afl-tests/id:000394,src:000000,op:arith8,pos:91,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000395,src:000000,op:arith8,pos:76,val:+21,+cov (renamed from src/mint/afl-tests/id:000395,src:000000,op:arith8,pos:76,val:+21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000395,src:000000,op:arith8,pos:91,val:+24 (renamed from src/mint/afl-tests/id:000395,src:000000,op:arith8,pos:91,val:+24)0
-rw-r--r--src/exchange/afl-tests/id:000396,src:000000,op:arith8,pos:77,val:+24,+cov (renamed from src/mint/afl-tests/id:000396,src:000000,op:arith8,pos:77,val:+24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000396,src:000000,op:arith8,pos:92,val:+11,+cov (renamed from src/mint/afl-tests/id:000396,src:000000,op:arith8,pos:92,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000397,src:000000,op:arith8,pos:80,val:-11,+cov (renamed from src/mint/afl-tests/id:000397,src:000000,op:arith8,pos:80,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000397,src:000000,op:arith8,pos:92,val:-23,+cov (renamed from src/mint/afl-tests/id:000397,src:000000,op:arith8,pos:92,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000398,src:000000,op:arith8,pos:80,val:+18,+cov (renamed from src/mint/afl-tests/id:000398,src:000000,op:arith8,pos:80,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000398,src:000000,op:arith8,pos:93,val:+19,+cov (renamed from src/mint/afl-tests/id:000398,src:000000,op:arith8,pos:93,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000399,src:000000,op:arith8,pos:81,val:+22,+cov (renamed from src/mint/afl-tests/id:000399,src:000000,op:arith8,pos:81,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000399,src:000000,op:arith8,pos:93,val:-25,+cov (renamed from src/mint/afl-tests/id:000399,src:000000,op:arith8,pos:93,val:-25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000400,src:000000,op:arith8,pos:81,val:-30,+cov (renamed from src/mint/afl-tests/id:000400,src:000000,op:arith8,pos:81,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000400,src:000000,op:arith8,pos:93,val:+35,+cov (renamed from src/mint/afl-tests/id:000400,src:000000,op:arith8,pos:93,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000401,src:000000,op:arith8,pos:83,val:-1 (renamed from src/mint/afl-tests/id:000401,src:000000,op:arith8,pos:83,val:-1)0
-rw-r--r--src/exchange/afl-tests/id:000401,src:000000,op:arith8,pos:96,val:-5,+cov (renamed from src/mint/afl-tests/id:000401,src:000000,op:arith8,pos:96,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000402,src:000000,op:arith8,pos:83,val:-22,+cov (renamed from src/mint/afl-tests/id:000402,src:000000,op:arith8,pos:83,val:-22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000402,src:000000,op:arith8,pos:96,val:+32,+cov (renamed from src/mint/afl-tests/id:000402,src:000000,op:arith8,pos:96,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000403,src:000000,op:arith8,pos:83,val:+35,+cov (renamed from src/mint/afl-tests/id:000403,src:000000,op:arith8,pos:83,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000403,src:000000,op:arith8,pos:96,val:-34,+cov (renamed from src/mint/afl-tests/id:000403,src:000000,op:arith8,pos:96,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000404,src:000000,op:arith8,pos:84,val:+7,+cov (renamed from src/mint/afl-tests/id:000404,src:000000,op:arith8,pos:84,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000404,src:000000,op:arith8,pos:98,val:-34,+cov (renamed from src/mint/afl-tests/id:000404,src:000000,op:arith8,pos:98,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000405,src:000000,op:arith8,pos:84,val:+31,+cov (renamed from src/mint/afl-tests/id:000405,src:000000,op:arith8,pos:84,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000405,src:000000,op:arith8,pos:98,val:-35 (renamed from src/mint/afl-tests/id:000405,src:000000,op:arith8,pos:98,val:-35)0
-rw-r--r--src/exchange/afl-tests/id:000406,src:000000,op:arith8,pos:113,val:-19 (renamed from src/mint/afl-tests/id:000406,src:000000,op:arith8,pos:113,val:-19)0
-rw-r--r--src/exchange/afl-tests/id:000406,src:000000,op:arith8,pos:86,val:-11,+cov (renamed from src/mint/afl-tests/id:000406,src:000000,op:arith8,pos:86,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000407,src:000000,op:arith8,pos:113,val:-22 (renamed from src/mint/afl-tests/id:000407,src:000000,op:arith8,pos:113,val:-22)0
-rw-r--r--src/exchange/afl-tests/id:000407,src:000000,op:arith8,pos:86,val:+22,+cov (renamed from src/mint/afl-tests/id:000407,src:000000,op:arith8,pos:86,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000408,src:000000,op:arith8,pos:121,val:-13,+cov (renamed from src/mint/afl-tests/id:000408,src:000000,op:arith8,pos:121,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000408,src:000000,op:arith8,pos:86,val:-24 (renamed from src/mint/afl-tests/id:000408,src:000000,op:arith8,pos:86,val:-24)0
-rw-r--r--src/exchange/afl-tests/id:000409,src:000000,op:arith8,pos:135,val:+23,+cov (renamed from src/mint/afl-tests/id:000409,src:000000,op:arith8,pos:135,val:+23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000409,src:000000,op:arith8,pos:87,val:-2,+cov (renamed from src/mint/afl-tests/id:000409,src:000000,op:arith8,pos:87,val:-2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000410,src:000000,op:arith8,pos:136,val:-9,+cov (renamed from src/mint/afl-tests/id:000410,src:000000,op:arith8,pos:136,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000410,src:000000,op:arith8,pos:87,val:+9,+cov (renamed from src/mint/afl-tests/id:000410,src:000000,op:arith8,pos:87,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000411,src:000000,op:arith8,pos:136,val:-21,+cov (renamed from src/mint/afl-tests/id:000411,src:000000,op:arith8,pos:136,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000411,src:000000,op:arith8,pos:87,val:-15,+cov (renamed from src/mint/afl-tests/id:000411,src:000000,op:arith8,pos:87,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000412,src:000000,op:arith8,pos:137,val:+8,+cov (renamed from src/mint/afl-tests/id:000412,src:000000,op:arith8,pos:137,val:+8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000412,src:000000,op:arith8,pos:87,val:-24,+cov (renamed from src/mint/afl-tests/id:000412,src:000000,op:arith8,pos:87,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000413,src:000000,op:arith8,pos:137,val:-11 (renamed from src/mint/afl-tests/id:000413,src:000000,op:arith8,pos:137,val:-11)0
-rw-r--r--src/exchange/afl-tests/id:000413,src:000000,op:arith8,pos:88,val:+30,+cov (renamed from src/mint/afl-tests/id:000413,src:000000,op:arith8,pos:88,val:+30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000414,src:000000,op:arith8,pos:137,val:-19,+cov (renamed from src/mint/afl-tests/id:000414,src:000000,op:arith8,pos:137,val:-19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000414,src:000000,op:arith8,pos:89,val:+29,+cov (renamed from src/mint/afl-tests/id:000414,src:000000,op:arith8,pos:89,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000415,src:000000,op:arith8,pos:138,val:+3,+cov (renamed from src/mint/afl-tests/id:000415,src:000000,op:arith8,pos:138,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000415,src:000000,op:arith8,pos:90,val:-21,+cov (renamed from src/mint/afl-tests/id:000415,src:000000,op:arith8,pos:90,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000416,src:000000,op:arith8,pos:138,val:-12,+cov (renamed from src/mint/afl-tests/id:000416,src:000000,op:arith8,pos:138,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000416,src:000000,op:arith8,pos:91,val:+28,+cov (renamed from src/mint/afl-tests/id:000416,src:000000,op:arith8,pos:91,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000417,src:000000,op:arith8,pos:139,val:-10,+cov (renamed from src/mint/afl-tests/id:000417,src:000000,op:arith8,pos:139,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000417,src:000000,op:arith8,pos:91,val:+34,+cov (renamed from src/mint/afl-tests/id:000417,src:000000,op:arith8,pos:91,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000418,src:000000,op:arith8,pos:139,val:-26,+cov (renamed from src/mint/afl-tests/id:000418,src:000000,op:arith8,pos:139,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000418,src:000000,op:arith8,pos:94,val:-23,+cov (renamed from src/mint/afl-tests/id:000418,src:000000,op:arith8,pos:94,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000419,src:000000,op:arith8,pos:143,val:+21,+cov (renamed from src/mint/afl-tests/id:000419,src:000000,op:arith8,pos:143,val:+21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000419,src:000000,op:arith8,pos:95,val:+3,+cov (renamed from src/mint/afl-tests/id:000419,src:000000,op:arith8,pos:95,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000420,src:000000,op:arith8,pos:145,val:+15,+cov (renamed from src/mint/afl-tests/id:000420,src:000000,op:arith8,pos:145,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000420,src:000000,op:arith8,pos:95,val:-23,+cov (renamed from src/mint/afl-tests/id:000420,src:000000,op:arith8,pos:95,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000421,src:000000,op:arith8,pos:146,val:-14,+cov (renamed from src/mint/afl-tests/id:000421,src:000000,op:arith8,pos:146,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000421,src:000000,op:arith8,pos:95,val:+31,+cov (renamed from src/mint/afl-tests/id:000421,src:000000,op:arith8,pos:95,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000422,src:000000,op:arith8,pos:148,val:+28,+cov (renamed from src/mint/afl-tests/id:000422,src:000000,op:arith8,pos:148,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000422,src:000000,op:arith8,pos:98,val:-35 (renamed from src/mint/afl-tests/id:000422,src:000000,op:arith8,pos:98,val:-35)0
-rw-r--r--src/exchange/afl-tests/id:000423,src:000000,op:arith8,pos:100,val:-33,+cov (renamed from src/mint/afl-tests/id:000423,src:000000,op:arith8,pos:100,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000423,src:000000,op:arith8,pos:151,val:-35,+cov (renamed from src/mint/afl-tests/id:000423,src:000000,op:arith8,pos:151,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000424,src:000000,op:arith8,pos:113,val:-19 (renamed from src/mint/afl-tests/id:000424,src:000000,op:arith8,pos:113,val:-19)0
-rw-r--r--src/exchange/afl-tests/id:000424,src:000000,op:arith8,pos:152,val:-12,+cov (renamed from src/mint/afl-tests/id:000424,src:000000,op:arith8,pos:152,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000425,src:000000,op:arith8,pos:113,val:-22 (renamed from src/mint/afl-tests/id:000425,src:000000,op:arith8,pos:113,val:-22)0
-rw-r--r--src/exchange/afl-tests/id:000425,src:000000,op:arith8,pos:152,val:+27,+cov (renamed from src/mint/afl-tests/id:000425,src:000000,op:arith8,pos:152,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000426,src:000000,op:arith8,pos:127,val:-20,+cov (renamed from src/mint/afl-tests/id:000426,src:000000,op:arith8,pos:127,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000426,src:000000,op:arith8,pos:152,val:+31,+cov (renamed from src/mint/afl-tests/id:000426,src:000000,op:arith8,pos:152,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000427,src:000000,op:arith8,pos:131,val:-20,+cov (renamed from src/mint/afl-tests/id:000427,src:000000,op:arith8,pos:131,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000427,src:000000,op:arith8,pos:153,val:+20,+cov (renamed from src/mint/afl-tests/id:000427,src:000000,op:arith8,pos:153,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000428,src:000000,op:arith8,pos:132,val:+6,+cov (renamed from src/mint/afl-tests/id:000428,src:000000,op:arith8,pos:132,val:+6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000428,src:000000,op:arith8,pos:154,val:+7,+cov (renamed from src/mint/afl-tests/id:000428,src:000000,op:arith8,pos:154,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000429,src:000000,op:arith8,pos:135,val:-28,+cov (renamed from src/mint/afl-tests/id:000429,src:000000,op:arith8,pos:135,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000429,src:000000,op:arith8,pos:156,val:+18,+cov (renamed from src/mint/afl-tests/id:000429,src:000000,op:arith8,pos:156,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000430,src:000000,op:arith8,pos:135,val:-35,+cov (renamed from src/mint/afl-tests/id:000430,src:000000,op:arith8,pos:135,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000430,src:000000,op:arith8,pos:156,val:+28,+cov (renamed from src/mint/afl-tests/id:000430,src:000000,op:arith8,pos:156,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000431,src:000000,op:arith8,pos:136,val:+3,+cov (renamed from src/mint/afl-tests/id:000431,src:000000,op:arith8,pos:136,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000431,src:000000,op:arith8,pos:159,val:-30,+cov (renamed from src/mint/afl-tests/id:000431,src:000000,op:arith8,pos:159,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000432,src:000000,op:arith8,pos:136,val:-5,+cov (renamed from src/mint/afl-tests/id:000432,src:000000,op:arith8,pos:136,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000432,src:000000,op:arith8,pos:160,val:-31,+cov (renamed from src/mint/afl-tests/id:000432,src:000000,op:arith8,pos:160,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000433,src:000000,op:arith8,pos:136,val:-9,+cov (renamed from src/mint/afl-tests/id:000433,src:000000,op:arith8,pos:136,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000433,src:000000,op:arith8,pos:161,val:+5,+cov (renamed from src/mint/afl-tests/id:000433,src:000000,op:arith8,pos:161,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000434,src:000000,op:arith8,pos:136,val:+20,+cov (renamed from src/mint/afl-tests/id:000434,src:000000,op:arith8,pos:136,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000434,src:000000,op:arith8,pos:161,val:-11,+cov (renamed from src/mint/afl-tests/id:000434,src:000000,op:arith8,pos:161,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000435,src:000000,op:arith8,pos:136,val:-29,+cov (renamed from src/mint/afl-tests/id:000435,src:000000,op:arith8,pos:136,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000435,src:000000,op:arith8,pos:162,val:+22 (renamed from src/mint/afl-tests/id:000435,src:000000,op:arith8,pos:162,val:+22)0
-rw-r--r--src/exchange/afl-tests/id:000436,src:000000,op:arith8,pos:137,val:+7,+cov (renamed from src/mint/afl-tests/id:000436,src:000000,op:arith8,pos:137,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000436,src:000000,op:arith8,pos:163,val:+19,+cov (renamed from src/mint/afl-tests/id:000436,src:000000,op:arith8,pos:163,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000437,src:000000,op:arith8,pos:137,val:+10,+cov (renamed from src/mint/afl-tests/id:000437,src:000000,op:arith8,pos:137,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000437,src:000000,op:arith8,pos:164,val:+27,+cov (renamed from src/mint/afl-tests/id:000437,src:000000,op:arith8,pos:164,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000438,src:000000,op:arith8,pos:138,val:+19,+cov (renamed from src/mint/afl-tests/id:000438,src:000000,op:arith8,pos:138,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000438,src:000000,op:arith8,pos:166,val:+13,+cov (renamed from src/mint/afl-tests/id:000438,src:000000,op:arith8,pos:166,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000439,src:000000,op:arith8,pos:139,val:+25,+cov (renamed from src/mint/afl-tests/id:000439,src:000000,op:arith8,pos:139,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000439,src:000000,op:arith8,pos:167,val:+33,+cov (renamed from src/mint/afl-tests/id:000439,src:000000,op:arith8,pos:167,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000440,src:000000,op:arith8,pos:139,val:-26,+cov (renamed from src/mint/afl-tests/id:000440,src:000000,op:arith8,pos:139,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000440,src:000000,op:arith8,pos:168,val:-17,+cov (renamed from src/mint/afl-tests/id:000440,src:000000,op:arith8,pos:168,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000441,src:000000,op:arith8,pos:140,val:+20,+cov (renamed from src/mint/afl-tests/id:000441,src:000000,op:arith8,pos:140,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000441,src:000000,op:arith8,pos:168,val:+29,+cov (renamed from src/mint/afl-tests/id:000441,src:000000,op:arith8,pos:168,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000442,src:000000,op:arith8,pos:141,val:+6,+cov (renamed from src/mint/afl-tests/id:000442,src:000000,op:arith8,pos:141,val:+6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000442,src:000000,op:arith8,pos:168,val:+30,+cov (renamed from src/mint/afl-tests/id:000442,src:000000,op:arith8,pos:168,val:+30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000443,src:000000,op:arith8,pos:141,val:+10,+cov (renamed from src/mint/afl-tests/id:000443,src:000000,op:arith8,pos:141,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000443,src:000000,op:arith8,pos:171,val:+22,+cov (renamed from src/mint/afl-tests/id:000443,src:000000,op:arith8,pos:171,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000444,src:000000,op:arith8,pos:141,val:+13,+cov (renamed from src/mint/afl-tests/id:000444,src:000000,op:arith8,pos:141,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000444,src:000000,op:arith8,pos:171,val:+25,+cov (renamed from src/mint/afl-tests/id:000444,src:000000,op:arith8,pos:171,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000445,src:000000,op:arith8,pos:141,val:+20,+cov (renamed from src/mint/afl-tests/id:000445,src:000000,op:arith8,pos:141,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000445,src:000000,op:arith8,pos:172,val:-13,+cov (renamed from src/mint/afl-tests/id:000445,src:000000,op:arith8,pos:172,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000446,src:000000,op:arith8,pos:142,val:+6,+cov (renamed from src/mint/afl-tests/id:000446,src:000000,op:arith8,pos:142,val:+6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000446,src:000000,op:arith8,pos:172,val:+19,+cov (renamed from src/mint/afl-tests/id:000446,src:000000,op:arith8,pos:172,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000447,src:000000,op:arith8,pos:142,val:-20,+cov (renamed from src/mint/afl-tests/id:000447,src:000000,op:arith8,pos:142,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000447,src:000000,op:arith8,pos:173,val:-15,+cov (renamed from src/mint/afl-tests/id:000447,src:000000,op:arith8,pos:173,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000448,src:000000,op:arith8,pos:143,val:+17,+cov (renamed from src/mint/afl-tests/id:000448,src:000000,op:arith8,pos:143,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000448,src:000000,op:arith8,pos:174,val:+23,+cov (renamed from src/mint/afl-tests/id:000448,src:000000,op:arith8,pos:174,val:+23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000449,src:000000,op:arith8,pos:144,val:+28,+cov (renamed from src/mint/afl-tests/id:000449,src:000000,op:arith8,pos:144,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000449,src:000000,op:arith8,pos:174,val:+33,+cov (renamed from src/mint/afl-tests/id:000449,src:000000,op:arith8,pos:174,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000450,src:000000,op:arith8,pos:145,val:+27,+cov (renamed from src/mint/afl-tests/id:000450,src:000000,op:arith8,pos:145,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000450,src:000000,op:arith8,pos:176,val:+20,+cov (renamed from src/mint/afl-tests/id:000450,src:000000,op:arith8,pos:176,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000451,src:000000,op:arith8,pos:146,val:-11,+cov (renamed from src/mint/afl-tests/id:000451,src:000000,op:arith8,pos:146,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000451,src:000000,op:arith8,pos:177,val:+33,+cov (renamed from src/mint/afl-tests/id:000451,src:000000,op:arith8,pos:177,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000452,src:000000,op:arith8,pos:146,val:-13,+cov (renamed from src/mint/afl-tests/id:000452,src:000000,op:arith8,pos:146,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000452,src:000000,op:arith8,pos:181,val:+12,+cov (renamed from src/mint/afl-tests/id:000452,src:000000,op:arith8,pos:181,val:+12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000453,src:000000,op:arith8,pos:146,val:-21,+cov (renamed from src/mint/afl-tests/id:000453,src:000000,op:arith8,pos:146,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000453,src:000000,op:arith8,pos:181,val:+21 (renamed from src/mint/afl-tests/id:000453,src:000000,op:arith8,pos:181,val:+21)0
-rw-r--r--src/exchange/afl-tests/id:000454,src:000000,op:arith8,pos:147,val:-3,+cov (renamed from src/mint/afl-tests/id:000454,src:000000,op:arith8,pos:147,val:-3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000454,src:000000,op:arith8,pos:181,val:+25,+cov (renamed from src/mint/afl-tests/id:000454,src:000000,op:arith8,pos:181,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000455,src:000000,op:arith8,pos:147,val:-9,+cov (renamed from src/mint/afl-tests/id:000455,src:000000,op:arith8,pos:147,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000455,src:000000,op:arith8,pos:183,val:-3 (renamed from src/mint/afl-tests/id:000455,src:000000,op:arith8,pos:183,val:-3)0
-rw-r--r--src/exchange/afl-tests/id:000456,src:000000,op:arith8,pos:147,val:-13,+cov (renamed from src/mint/afl-tests/id:000456,src:000000,op:arith8,pos:147,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000456,src:000000,op:arith8,pos:184,val:-13 (renamed from src/mint/afl-tests/id:000456,src:000000,op:arith8,pos:184,val:-13)0
-rw-r--r--src/exchange/afl-tests/id:000457,src:000000,op:arith8,pos:148,val:+12,+cov (renamed from src/mint/afl-tests/id:000457,src:000000,op:arith8,pos:148,val:+12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000457,src:000000,op:arith8,pos:184,val:-34,+cov (renamed from src/mint/afl-tests/id:000457,src:000000,op:arith8,pos:184,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000458,src:000000,op:arith8,pos:151,val:-7,+cov (renamed from src/mint/afl-tests/id:000458,src:000000,op:arith8,pos:151,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000458,src:000000,op:arith8,pos:185,val:-6,+cov (renamed from src/mint/afl-tests/id:000458,src:000000,op:arith8,pos:185,val:-6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000459,src:000000,op:arith8,pos:151,val:+15,+cov (renamed from src/mint/afl-tests/id:000459,src:000000,op:arith8,pos:151,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000459,src:000000,op:arith8,pos:185,val:+14,+cov (renamed from src/mint/afl-tests/id:000459,src:000000,op:arith8,pos:185,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000460,src:000000,op:arith8,pos:152,val:-7,+cov (renamed from src/mint/afl-tests/id:000460,src:000000,op:arith8,pos:152,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000460,src:000000,op:arith8,pos:185,val:+29,+cov (renamed from src/mint/afl-tests/id:000460,src:000000,op:arith8,pos:185,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000461,src:000000,op:arith8,pos:152,val:+25,+cov (renamed from src/mint/afl-tests/id:000461,src:000000,op:arith8,pos:152,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000461,src:000000,op:arith8,pos:186,val:+23,+cov (renamed from src/mint/afl-tests/id:000461,src:000000,op:arith8,pos:186,val:+23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000462,src:000000,op:arith8,pos:152,val:-30 (renamed from src/mint/afl-tests/id:000462,src:000000,op:arith8,pos:152,val:-30)0
-rw-r--r--src/exchange/afl-tests/id:000462,src:000000,op:arith8,pos:191,val:-26,+cov (renamed from src/mint/afl-tests/id:000462,src:000000,op:arith8,pos:191,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000463,src:000000,op:arith8,pos:153,val:+28,+cov (renamed from src/mint/afl-tests/id:000463,src:000000,op:arith8,pos:153,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000463,src:000000,op:arith8,pos:196,val:-18,+cov (renamed from src/mint/afl-tests/id:000463,src:000000,op:arith8,pos:196,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000464,src:000000,op:arith8,pos:157,val:+8,+cov (renamed from src/mint/afl-tests/id:000464,src:000000,op:arith8,pos:157,val:+8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000464,src:000000,op:arith8,pos:203,val:+22,+cov (renamed from src/mint/afl-tests/id:000464,src:000000,op:arith8,pos:203,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000465,src:000000,op:arith8,pos:157,val:-9,+cov (renamed from src/mint/afl-tests/id:000465,src:000000,op:arith8,pos:157,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000465,src:000000,op:arith8,pos:225,val:-6,+cov (renamed from src/mint/afl-tests/id:000465,src:000000,op:arith8,pos:225,val:-6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000466,src:000000,op:arith8,pos:157,val:-12,+cov (renamed from src/mint/afl-tests/id:000466,src:000000,op:arith8,pos:157,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000466,src:000000,op:arith8,pos:241,val:-26,+cov (renamed from src/mint/afl-tests/id:000466,src:000000,op:arith8,pos:241,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000467,src:000000,op:arith8,pos:157,val:-21,+cov (renamed from src/mint/afl-tests/id:000467,src:000000,op:arith8,pos:157,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000467,src:000000,op:arith8,pos:268,val:-4,+cov (renamed from src/mint/afl-tests/id:000467,src:000000,op:arith8,pos:268,val:-4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000468,src:000000,op:arith8,pos:158,val:-9,+cov (renamed from src/mint/afl-tests/id:000468,src:000000,op:arith8,pos:158,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000468,src:000000,op:arith8,pos:268,val:+7,+cov (renamed from src/mint/afl-tests/id:000468,src:000000,op:arith8,pos:268,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000469,src:000000,op:arith8,pos:158,val:+25,+cov (renamed from src/mint/afl-tests/id:000469,src:000000,op:arith8,pos:158,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000469,src:000000,op:arith8,pos:269,val:+11,+cov (renamed from src/mint/afl-tests/id:000469,src:000000,op:arith8,pos:269,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000470,src:000000,op:arith8,pos:159,val:-7,+cov (renamed from src/mint/afl-tests/id:000470,src:000000,op:arith8,pos:159,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000470,src:000000,op:arith8,pos:272,val:+29,+cov (renamed from src/mint/afl-tests/id:000470,src:000000,op:arith8,pos:272,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000471,src:000000,op:arith8,pos:159,val:+10,+cov (renamed from src/mint/afl-tests/id:000471,src:000000,op:arith8,pos:159,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000471,src:000000,op:arith8,pos:273,val:+29,+cov (renamed from src/mint/afl-tests/id:000471,src:000000,op:arith8,pos:273,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000472,src:000000,op:arith8,pos:159,val:-11,+cov (renamed from src/mint/afl-tests/id:000472,src:000000,op:arith8,pos:159,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000472,src:000000,op:arith8,pos:274,val:+11,+cov (renamed from src/mint/afl-tests/id:000472,src:000000,op:arith8,pos:274,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000473,src:000000,op:arith8,pos:160,val:+19,+cov (renamed from src/mint/afl-tests/id:000473,src:000000,op:arith8,pos:160,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000473,src:000000,op:arith8,pos:276,val:+9,+cov (renamed from src/mint/afl-tests/id:000473,src:000000,op:arith8,pos:276,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000474,src:000000,op:arith8,pos:161,val:+14,+cov (renamed from src/mint/afl-tests/id:000474,src:000000,op:arith8,pos:161,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000474,src:000000,op:arith8,pos:276,val:+19,+cov (renamed from src/mint/afl-tests/id:000474,src:000000,op:arith8,pos:276,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000475,src:000000,op:arith8,pos:162,val:+7,+cov (renamed from src/mint/afl-tests/id:000475,src:000000,op:arith8,pos:162,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000475,src:000000,op:arith8,pos:277,val:+35,+cov (renamed from src/mint/afl-tests/id:000475,src:000000,op:arith8,pos:277,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000476,src:000000,op:arith8,pos:163,val:+26,+cov (renamed from src/mint/afl-tests/id:000476,src:000000,op:arith8,pos:163,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000476,src:000000,op:arith8,pos:278,val:+5,+cov (renamed from src/mint/afl-tests/id:000476,src:000000,op:arith8,pos:278,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000477,src:000000,op:arith8,pos:163,val:+31,+cov (renamed from src/mint/afl-tests/id:000477,src:000000,op:arith8,pos:163,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000477,src:000000,op:arith8,pos:305,val:+14,+cov (renamed from src/mint/afl-tests/id:000477,src:000000,op:arith8,pos:305,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000478,src:000000,op:arith8,pos:164,val:+2,+cov (renamed from src/mint/afl-tests/id:000478,src:000000,op:arith8,pos:164,val:+2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000478,src:000000,op:arith8,pos:306,val:-20,+cov (renamed from src/mint/afl-tests/id:000478,src:000000,op:arith8,pos:306,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000479,src:000000,op:arith8,pos:169,val:+7,+cov (renamed from src/mint/afl-tests/id:000479,src:000000,op:arith8,pos:169,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000479,src:000000,op:arith8,pos:314,val:-17,+cov (renamed from src/mint/afl-tests/id:000479,src:000000,op:arith8,pos:314,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000480,src:000000,op:arith8,pos:169,val:-9,+cov (renamed from src/mint/afl-tests/id:000480,src:000000,op:arith8,pos:169,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000480,src:000000,op:arith8,pos:315,val:-17,+cov (renamed from src/mint/afl-tests/id:000480,src:000000,op:arith8,pos:315,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000481,src:000000,op:arith8,pos:169,val:+19,+cov (renamed from src/mint/afl-tests/id:000481,src:000000,op:arith8,pos:169,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000481,src:000000,op:arith8,pos:315,val:-19,+cov (renamed from src/mint/afl-tests/id:000481,src:000000,op:arith8,pos:315,val:-19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000482,src:000000,op:arith8,pos:172,val:-3,+cov (renamed from src/mint/afl-tests/id:000482,src:000000,op:arith8,pos:172,val:-3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000482,src:000000,op:arith8,pos:315,val:-29,+cov (renamed from src/mint/afl-tests/id:000482,src:000000,op:arith8,pos:315,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000483,src:000000,op:arith8,pos:172,val:-33,+cov (renamed from src/mint/afl-tests/id:000483,src:000000,op:arith8,pos:172,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000483,src:000000,op:arith8,pos:316,val:+14,+cov (renamed from src/mint/afl-tests/id:000483,src:000000,op:arith8,pos:316,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000484,src:000000,op:arith8,pos:175,val:+20,+cov (renamed from src/mint/afl-tests/id:000484,src:000000,op:arith8,pos:175,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000484,src:000000,op:arith8,pos:316,val:+17,+cov (renamed from src/mint/afl-tests/id:000484,src:000000,op:arith8,pos:316,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000485,src:000000,op:arith8,pos:176,val:+7,+cov (renamed from src/mint/afl-tests/id:000485,src:000000,op:arith8,pos:176,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000485,src:000000,op:arith8,pos:316,val:-23,+cov (renamed from src/mint/afl-tests/id:000485,src:000000,op:arith8,pos:316,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000486,src:000000,op:arith8,pos:176,val:-28,+cov (renamed from src/mint/afl-tests/id:000486,src:000000,op:arith8,pos:176,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000486,src:000000,op:arith8,pos:317,val:-30,+cov (renamed from src/mint/afl-tests/id:000486,src:000000,op:arith8,pos:317,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000487,src:000000,op:arith8,pos:177,val:+11,+cov (renamed from src/mint/afl-tests/id:000487,src:000000,op:arith8,pos:177,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000487,src:000000,op:arith8,pos:319,val:-7,+cov (renamed from src/mint/afl-tests/id:000487,src:000000,op:arith8,pos:319,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000488,src:000000,op:arith8,pos:177,val:+17,+cov (renamed from src/mint/afl-tests/id:000488,src:000000,op:arith8,pos:177,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000488,src:000000,op:arith8,pos:319,val:+9,+cov (renamed from src/mint/afl-tests/id:000488,src:000000,op:arith8,pos:319,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000489,src:000000,op:arith8,pos:177,val:+22,+cov (renamed from src/mint/afl-tests/id:000489,src:000000,op:arith8,pos:177,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000489,src:000000,op:arith8,pos:320,val:-7,+cov (renamed from src/mint/afl-tests/id:000489,src:000000,op:arith8,pos:320,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000490,src:000000,op:arith8,pos:178,val:-5,+cov (renamed from src/mint/afl-tests/id:000490,src:000000,op:arith8,pos:178,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000490,src:000000,op:arith8,pos:320,val:-25,+cov (renamed from src/mint/afl-tests/id:000490,src:000000,op:arith8,pos:320,val:-25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000491,src:000000,op:arith8,pos:178,val:+23,+cov (renamed from src/mint/afl-tests/id:000491,src:000000,op:arith8,pos:178,val:+23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000491,src:000000,op:arith8,pos:321,val:+11,+cov (renamed from src/mint/afl-tests/id:000491,src:000000,op:arith8,pos:321,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000492,src:000000,op:arith8,pos:181,val:-12,+cov (renamed from src/mint/afl-tests/id:000492,src:000000,op:arith8,pos:181,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000492,src:000000,op:arith8,pos:321,val:-24,+cov (renamed from src/mint/afl-tests/id:000492,src:000000,op:arith8,pos:321,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000493,src:000000,op:arith8,pos:182,val:-15,+cov (renamed from src/mint/afl-tests/id:000493,src:000000,op:arith8,pos:182,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000493,src:000000,op:arith8,pos:322,val:-21,+cov (renamed from src/mint/afl-tests/id:000493,src:000000,op:arith8,pos:322,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000494,src:000000,op:arith8,pos:182,val:+22,+cov (renamed from src/mint/afl-tests/id:000494,src:000000,op:arith8,pos:182,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000494,src:000000,op:arith8,pos:326,val:-20,+cov (renamed from src/mint/afl-tests/id:000494,src:000000,op:arith8,pos:326,val:-20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000495,src:000000,op:arith8,pos:183,val:-11 (renamed from src/mint/afl-tests/id:000495,src:000000,op:arith8,pos:183,val:-11)0
-rw-r--r--src/exchange/afl-tests/id:000495,src:000000,op:arith8,pos:328,val:+27,+cov (renamed from src/mint/afl-tests/id:000495,src:000000,op:arith8,pos:328,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000496,src:000000,op:arith8,pos:183,val:+15,+cov (renamed from src/mint/afl-tests/id:000496,src:000000,op:arith8,pos:183,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000496,src:000000,op:arith8,pos:328,val:-27,+cov (renamed from src/mint/afl-tests/id:000496,src:000000,op:arith8,pos:328,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000497,src:000000,op:arith8,pos:184,val:-14,+cov (renamed from src/mint/afl-tests/id:000497,src:000000,op:arith8,pos:184,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000497,src:000000,op:arith8,pos:329,val:+5,+cov (renamed from src/mint/afl-tests/id:000497,src:000000,op:arith8,pos:329,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000498,src:000000,op:arith8,pos:184,val:+33,+cov (renamed from src/mint/afl-tests/id:000498,src:000000,op:arith8,pos:184,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000498,src:000000,op:arith8,pos:329,val:-24,+cov (renamed from src/mint/afl-tests/id:000498,src:000000,op:arith8,pos:329,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000499,src:000000,op:arith8,pos:184,val:-35,+cov (renamed from src/mint/afl-tests/id:000499,src:000000,op:arith8,pos:184,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000499,src:000000,op:arith8,pos:330,val:-3,+cov (renamed from src/mint/afl-tests/id:000499,src:000000,op:arith8,pos:330,val:-3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000500,src:000000,op:arith8,pos:185,val:+3,+cov (renamed from src/mint/afl-tests/id:000500,src:000000,op:arith8,pos:185,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000500,src:000000,op:arith8,pos:331,val:-14,+cov (renamed from src/mint/afl-tests/id:000500,src:000000,op:arith8,pos:331,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000501,src:000000,op:arith8,pos:185,val:+7,+cov (renamed from src/mint/afl-tests/id:000501,src:000000,op:arith8,pos:185,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000501,src:000000,op:arith8,pos:332,val:-15,+cov (renamed from src/mint/afl-tests/id:000501,src:000000,op:arith8,pos:332,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000502,src:000000,op:arith16,pos:33,val:-12,+cov (renamed from src/mint/afl-tests/id:000502,src:000000,op:arith16,pos:33,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000502,src:000000,op:arith8,pos:192,val:+9,+cov (renamed from src/mint/afl-tests/id:000502,src:000000,op:arith8,pos:192,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000503,src:000000,op:arith16,pos:65,val:be:-27,+cov (renamed from src/mint/afl-tests/id:000503,src:000000,op:arith16,pos:65,val:be:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000503,src:000000,op:arith8,pos:237,val:-26,+cov (renamed from src/mint/afl-tests/id:000503,src:000000,op:arith8,pos:237,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000504,src:000000,op:arith8,pos:238,val:+5,+cov (renamed from src/mint/afl-tests/id:000504,src:000000,op:arith8,pos:238,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000504,src:000000,op:int8,pos:6,val:+0 (renamed from src/mint/afl-tests/id:000504,src:000000,op:int8,pos:6,val:+0)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000505,src:000000,op:arith8,pos:241,val:+7,+cov (renamed from src/mint/afl-tests/id:000505,src:000000,op:arith8,pos:241,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000505,src:000000,op:int8,pos:7,val:+0 (renamed from src/mint/afl-tests/id:000505,src:000000,op:int8,pos:7,val:+0)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000506,src:000000,op:arith8,pos:268,val:-4,+cov (renamed from src/mint/afl-tests/id:000506,src:000000,op:arith8,pos:268,val:-4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000506,src:000000,op:int8,pos:9,val:+0 (renamed from src/mint/afl-tests/id:000506,src:000000,op:int8,pos:9,val:+0)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000507,src:000000,op:arith8,pos:269,val:+19,+cov (renamed from src/mint/afl-tests/id:000507,src:000000,op:arith8,pos:269,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000507,src:000000,op:int8,pos:26,val:+32,+cov (renamed from src/mint/afl-tests/id:000507,src:000000,op:int8,pos:26,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000508,src:000000,op:arith8,pos:271,val:-12,+cov (renamed from src/mint/afl-tests/id:000508,src:000000,op:arith8,pos:271,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000508,src:000000,op:int8,pos:27,val:+127,+cov (renamed from src/mint/afl-tests/id:000508,src:000000,op:int8,pos:27,val:+127,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000509,src:000000,op:arith8,pos:272,val:+7,+cov (renamed from src/mint/afl-tests/id:000509,src:000000,op:arith8,pos:272,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000509,src:000000,op:int8,pos:34,val:+0,+cov (renamed from src/mint/afl-tests/id:000509,src:000000,op:int8,pos:34,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000510,src:000000,op:arith8,pos:274,val:+11,+cov (renamed from src/mint/afl-tests/id:000510,src:000000,op:arith8,pos:274,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000510,src:000000,op:int8,pos:40,val:+0,+cov (renamed from src/mint/afl-tests/id:000510,src:000000,op:int8,pos:40,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000511,src:000000,op:arith8,pos:274,val:+25,+cov (renamed from src/mint/afl-tests/id:000511,src:000000,op:arith8,pos:274,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000511,src:000000,op:int8,pos:40,val:+32 (renamed from src/mint/afl-tests/id:000511,src:000000,op:int8,pos:40,val:+32)0
-rw-r--r--src/exchange/afl-tests/id:000512,src:000000,op:arith8,pos:275,val:-11,+cov (renamed from src/mint/afl-tests/id:000512,src:000000,op:arith8,pos:275,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000512,src:000000,op:int8,pos:46,val:+1,+cov (renamed from src/mint/afl-tests/id:000512,src:000000,op:int8,pos:46,val:+1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000513,src:000000,op:arith8,pos:275,val:-12,+cov (renamed from src/mint/afl-tests/id:000513,src:000000,op:arith8,pos:275,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000513,src:000000,op:int8,pos:51,val:+1 (renamed from src/mint/afl-tests/id:000513,src:000000,op:int8,pos:51,val:+1)0
-rw-r--r--src/exchange/afl-tests/id:000514,src:000000,op:arith8,pos:275,val:+27,+cov (renamed from src/mint/afl-tests/id:000514,src:000000,op:arith8,pos:275,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000514,src:000000,op:int8,pos:52,val:-128,+cov (renamed from src/mint/afl-tests/id:000514,src:000000,op:int8,pos:52,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000515,src:000000,op:arith8,pos:277,val:-10,+cov (renamed from src/mint/afl-tests/id:000515,src:000000,op:arith8,pos:277,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000515,src:000000,op:int8,pos:53,val:-1,+cov (renamed from src/mint/afl-tests/id:000515,src:000000,op:int8,pos:53,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000516,src:000000,op:arith8,pos:277,val:+35,+cov (renamed from src/mint/afl-tests/id:000516,src:000000,op:arith8,pos:277,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000516,src:000000,op:int8,pos:69,val:+32,+cov (renamed from src/mint/afl-tests/id:000516,src:000000,op:int8,pos:69,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000517,src:000000,op:arith8,pos:279,val:+28,+cov (renamed from src/mint/afl-tests/id:000517,src:000000,op:arith8,pos:279,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000517,src:000000,op:int8,pos:70,val:+32,+cov (renamed from src/mint/afl-tests/id:000517,src:000000,op:int8,pos:70,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000518,src:000000,op:arith8,pos:290,val:-28,+cov (renamed from src/mint/afl-tests/id:000518,src:000000,op:arith8,pos:290,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000518,src:000000,op:int8,pos:71,val:+64,+cov (renamed from src/mint/afl-tests/id:000518,src:000000,op:int8,pos:71,val:+64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000519,src:000000,op:arith8,pos:305,val:-3,+cov (renamed from src/mint/afl-tests/id:000519,src:000000,op:arith8,pos:305,val:-3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000519,src:000000,op:int8,pos:74,val:-1,+cov (renamed from src/mint/afl-tests/id:000519,src:000000,op:int8,pos:74,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000520,src:000000,op:arith8,pos:306,val:+7,+cov (renamed from src/mint/afl-tests/id:000520,src:000000,op:arith8,pos:306,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000520,src:000000,op:int8,pos:115,val:+0,+cov (renamed from src/mint/afl-tests/id:000520,src:000000,op:int8,pos:115,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000521,src:000000,op:arith8,pos:306,val:-12,+cov (renamed from src/mint/afl-tests/id:000521,src:000000,op:arith8,pos:306,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000521,src:000000,op:int8,pos:188,val:+1,+cov (renamed from src/mint/afl-tests/id:000521,src:000000,op:int8,pos:188,val:+1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000522,src:000000,op:arith8,pos:306,val:+20,+cov (renamed from src/mint/afl-tests/id:000522,src:000000,op:arith8,pos:306,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000522,src:000000,op:int8,pos:276,val:+100,+cov (renamed from src/mint/afl-tests/id:000522,src:000000,op:int8,pos:276,val:+100,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000523,src:000000,op:arith8,pos:307,val:+13,+cov (renamed from src/mint/afl-tests/id:000523,src:000000,op:arith8,pos:307,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000523,src:000000,op:int8,pos:307,val:+32,+cov (renamed from src/mint/afl-tests/id:000523,src:000000,op:int8,pos:307,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000524,src:000000,op:arith8,pos:308,val:+19,+cov (renamed from src/mint/afl-tests/id:000524,src:000000,op:arith8,pos:308,val:+19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000524,src:000000,op:int8,pos:313,val:+64,+cov (renamed from src/mint/afl-tests/id:000524,src:000000,op:int8,pos:313,val:+64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000525,src:000000,op:arith8,pos:308,val:-27,+cov (renamed from src/mint/afl-tests/id:000525,src:000000,op:arith8,pos:308,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000525,src:000000,op:int8,pos:314,val:-1,+cov (renamed from src/mint/afl-tests/id:000525,src:000000,op:int8,pos:314,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000526,src:000000,op:arith8,pos:312,val:+3,+cov (renamed from src/mint/afl-tests/id:000526,src:000000,op:arith8,pos:312,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000526,src:000000,op:int8,pos:322,val:+32,+cov (renamed from src/mint/afl-tests/id:000526,src:000000,op:int8,pos:322,val:+32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000527,src:000000,op:arith8,pos:312,val:+5,+cov (renamed from src/mint/afl-tests/id:000527,src:000000,op:arith8,pos:312,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000527,src:000000,op:int16,pos:25,val:be:+100,+cov (renamed from src/mint/afl-tests/id:000527,src:000000,op:int16,pos:25,val:be:+100,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000528,src:000000,op:arith8,pos:312,val:-11,+cov (renamed from src/mint/afl-tests/id:000528,src:000000,op:arith8,pos:312,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000528,src:000000,op:int16,pos:29,val:-1,+cov (renamed from src/mint/afl-tests/id:000528,src:000000,op:int16,pos:29,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000529,src:000000,op:arith8,pos:313,val:-33,+cov (renamed from src/mint/afl-tests/id:000529,src:000000,op:arith8,pos:313,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000529,src:000000,op:int16,pos:32,val:+32767,+cov (renamed from src/mint/afl-tests/id:000529,src:000000,op:int16,pos:32,val:+32767,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000530,src:000000,op:arith8,pos:314,val:-3,+cov (renamed from src/mint/afl-tests/id:000530,src:000000,op:arith8,pos:314,val:-3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000530,src:000000,op:int16,pos:41,val:-128,+cov (renamed from src/mint/afl-tests/id:000530,src:000000,op:int16,pos:41,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000531,src:000000,op:arith8,pos:314,val:-25,+cov (renamed from src/mint/afl-tests/id:000531,src:000000,op:arith8,pos:314,val:-25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000531,src:000000,op:int16,pos:41,val:+32,+cov (renamed from src/mint/afl-tests/id:000531,src:000000,op:int16,pos:41,val:+32,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000532,src:000000,op:arith8,pos:316,val:+20,+cov (renamed from src/mint/afl-tests/id:000532,src:000000,op:arith8,pos:316,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000532,src:000000,op:int16,pos:42,val:+64,+cov (renamed from src/mint/afl-tests/id:000532,src:000000,op:int16,pos:42,val:+64,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000533,src:000000,op:arith8,pos:316,val:-23,+cov (renamed from src/mint/afl-tests/id:000533,src:000000,op:arith8,pos:316,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000533,src:000000,op:int16,pos:47,val:+128,+cov (renamed from src/mint/afl-tests/id:000533,src:000000,op:int16,pos:47,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000534,src:000000,op:arith8,pos:316,val:-28,+cov (renamed from src/mint/afl-tests/id:000534,src:000000,op:arith8,pos:316,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000534,src:000000,op:int16,pos:48,val:be:+1000,+cov (renamed from src/mint/afl-tests/id:000534,src:000000,op:int16,pos:48,val:be:+1000,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000535,src:000000,op:arith8,pos:317,val:-31,+cov (renamed from src/mint/afl-tests/id:000535,src:000000,op:arith8,pos:317,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000535,src:000000,op:int16,pos:50,val:+16,+cov (renamed from src/mint/afl-tests/id:000535,src:000000,op:int16,pos:50,val:+16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000536,src:000000,op:arith8,pos:318,val:+23,+cov (renamed from src/mint/afl-tests/id:000536,src:000000,op:arith8,pos:318,val:+23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000536,src:000000,op:int16,pos:50,val:be:+1024,+cov (renamed from src/mint/afl-tests/id:000536,src:000000,op:int16,pos:50,val:be:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000537,src:000000,op:arith8,pos:319,val:-12,+cov (renamed from src/mint/afl-tests/id:000537,src:000000,op:arith8,pos:319,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000537,src:000000,op:int16,pos:52,val:-129,+cov (renamed from src/mint/afl-tests/id:000537,src:000000,op:int16,pos:52,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000538,src:000000,op:arith8,pos:320,val:+17,+cov (renamed from src/mint/afl-tests/id:000538,src:000000,op:arith8,pos:320,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000538,src:000000,op:int16,pos:52,val:+128,+cov (renamed from src/mint/afl-tests/id:000538,src:000000,op:int16,pos:52,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000539,src:000000,op:arith8,pos:320,val:-31,+cov (renamed from src/mint/afl-tests/id:000539,src:000000,op:arith8,pos:320,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000539,src:000000,op:int16,pos:52,val:be:+255,+cov (renamed from src/mint/afl-tests/id:000539,src:000000,op:int16,pos:52,val:be:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000540,src:000000,op:arith8,pos:321,val:-34,+cov (renamed from src/mint/afl-tests/id:000540,src:000000,op:arith8,pos:321,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000540,src:000000,op:int16,pos:53,val:+0,+cov (renamed from src/mint/afl-tests/id:000540,src:000000,op:int16,pos:53,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000541,src:000000,op:arith8,pos:322,val:+3,+cov (renamed from src/mint/afl-tests/id:000541,src:000000,op:arith8,pos:322,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000541,src:000000,op:int16,pos:54,val:+1,+cov (renamed from src/mint/afl-tests/id:000541,src:000000,op:int16,pos:54,val:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000542,src:000000,op:arith8,pos:322,val:+7,+cov (renamed from src/mint/afl-tests/id:000542,src:000000,op:arith8,pos:322,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000542,src:000000,op:int16,pos:69,val:-129,+cov (renamed from src/mint/afl-tests/id:000542,src:000000,op:int16,pos:69,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000543,src:000000,op:arith8,pos:326,val:-9,+cov (renamed from src/mint/afl-tests/id:000543,src:000000,op:arith8,pos:326,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000543,src:000000,op:int16,pos:74,val:be:-128,+cov (renamed from src/mint/afl-tests/id:000543,src:000000,op:int16,pos:74,val:be:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000544,src:000000,op:arith8,pos:326,val:-31,+cov (renamed from src/mint/afl-tests/id:000544,src:000000,op:arith8,pos:326,val:-31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000544,src:000000,op:int16,pos:78,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000544,src:000000,op:int16,pos:78,val:be:+127,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000545,src:000000,op:arith8,pos:326,val:-35,+cov (renamed from src/mint/afl-tests/id:000545,src:000000,op:arith8,pos:326,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000545,src:000000,op:int16,pos:81,val:+32767,+cov (renamed from src/mint/afl-tests/id:000545,src:000000,op:int16,pos:81,val:+32767,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000546,src:000000,op:arith8,pos:327,val:+5 (renamed from src/mint/afl-tests/id:000546,src:000000,op:arith8,pos:327,val:+5)0
-rw-r--r--src/exchange/afl-tests/id:000546,src:000000,op:int16,pos:83,val:+127,+cov (renamed from src/mint/afl-tests/id:000546,src:000000,op:int16,pos:83,val:+127,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000547,src:000000,op:arith8,pos:327,val:+7,+cov (renamed from src/mint/afl-tests/id:000547,src:000000,op:arith8,pos:327,val:+7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000547,src:000000,op:int16,pos:86,val:+4096,+cov (renamed from src/mint/afl-tests/id:000547,src:000000,op:int16,pos:86,val:+4096,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000548,src:000000,op:arith8,pos:327,val:+11,+cov (renamed from src/mint/afl-tests/id:000548,src:000000,op:arith8,pos:327,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000548,src:000000,op:int16,pos:87,val:+16,+cov (renamed from src/mint/afl-tests/id:000548,src:000000,op:int16,pos:87,val:+16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000549,src:000000,op:arith8,pos:327,val:-24,+cov (renamed from src/mint/afl-tests/id:000549,src:000000,op:arith8,pos:327,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000549,src:000000,op:int16,pos:87,val:-32768,+cov (renamed from src/mint/afl-tests/id:000549,src:000000,op:int16,pos:87,val:-32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000550,src:000000,op:arith8,pos:328,val:+14,+cov (renamed from src/mint/afl-tests/id:000550,src:000000,op:arith8,pos:328,val:+14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000550,src:000000,op:int16,pos:90,val:+256,+cov (renamed from src/mint/afl-tests/id:000550,src:000000,op:int16,pos:90,val:+256,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000551,src:000000,op:arith8,pos:329,val:+1,+cov (renamed from src/mint/afl-tests/id:000551,src:000000,op:arith8,pos:329,val:+1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000551,src:000000,op:int16,pos:91,val:+32,+cov (renamed from src/mint/afl-tests/id:000551,src:000000,op:int16,pos:91,val:+32,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000552,src:000000,op:arith8,pos:330,val:+9,+cov (renamed from src/mint/afl-tests/id:000552,src:000000,op:arith8,pos:330,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000552,src:000000,op:int16,pos:91,val:-129,+cov (renamed from src/mint/afl-tests/id:000552,src:000000,op:int16,pos:91,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000553,src:000000,op:arith8,pos:330,val:-24,+cov (renamed from src/mint/afl-tests/id:000553,src:000000,op:arith8,pos:330,val:-24,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000553,src:000000,op:int16,pos:93,val:+0,+cov (renamed from src/mint/afl-tests/id:000553,src:000000,op:int16,pos:93,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000554,src:000000,op:int16,pos:94,val:be:+64,+cov (renamed from src/mint/afl-tests/id:000554,src:000000,op:int16,pos:94,val:be:+64,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000554,src:000000,op:int8,pos:6,val:+0 (renamed from src/mint/afl-tests/id:000554,src:000000,op:int8,pos:6,val:+0)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000555,src:000000,op:int16,pos:94,val:be:+100,+cov (renamed from src/mint/afl-tests/id:000555,src:000000,op:int16,pos:94,val:be:+100,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000555,src:000000,op:int8,pos:7,val:+0 (renamed from src/mint/afl-tests/id:000555,src:000000,op:int8,pos:7,val:+0)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000556,src:000000,op:int16,pos:232,val:+1,+cov (renamed from src/mint/afl-tests/id:000556,src:000000,op:int16,pos:232,val:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000556,src:000000,op:int8,pos:9,val:+0 (renamed from src/mint/afl-tests/id:000556,src:000000,op:int8,pos:9,val:+0)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000557,src:000000,op:int16,pos:254,val:+256,+cov (renamed from src/mint/afl-tests/id:000557,src:000000,op:int16,pos:254,val:+256,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000557,src:000000,op:int8,pos:34,val:+0,+cov (renamed from src/mint/afl-tests/id:000557,src:000000,op:int8,pos:34,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000558,src:000000,op:int16,pos:262,val:+1000,+cov (renamed from src/mint/afl-tests/id:000558,src:000000,op:int16,pos:262,val:+1000,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000558,src:000000,op:int8,pos:40,val:+0,+cov (renamed from src/mint/afl-tests/id:000558,src:000000,op:int8,pos:40,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000559,src:000000,op:int16,pos:303,val:+128,+cov (renamed from src/mint/afl-tests/id:000559,src:000000,op:int16,pos:303,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000559,src:000000,op:int8,pos:40,val:+32 (renamed from src/mint/afl-tests/id:000559,src:000000,op:int8,pos:40,val:+32)0
-rw-r--r--src/exchange/afl-tests/id:000560,src:000000,op:int32,pos:3,val:be:+1000 (renamed from src/mint/afl-tests/id:000560,src:000000,op:int32,pos:3,val:be:+1000)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000560,src:000000,op:int8,pos:44,val:-1,+cov (renamed from src/mint/afl-tests/id:000560,src:000000,op:int8,pos:44,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000561,src:000000,op:int32,pos:28,val:+32768,+cov (renamed from src/mint/afl-tests/id:000561,src:000000,op:int32,pos:28,val:+32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000561,src:000000,op:int8,pos:51,val:-1,+cov (renamed from src/mint/afl-tests/id:000561,src:000000,op:int8,pos:51,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000562,src:000000,op:int32,pos:29,val:-128,+cov (renamed from src/mint/afl-tests/id:000562,src:000000,op:int32,pos:29,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000562,src:000000,op:int8,pos:62,val:-128,+cov (renamed from src/mint/afl-tests/id:000562,src:000000,op:int8,pos:62,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000563,src:000000,op:int32,pos:33,val:-128,+cov (renamed from src/mint/afl-tests/id:000563,src:000000,op:int32,pos:33,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000563,src:000000,op:int8,pos:135,val:+127,+cov (renamed from src/mint/afl-tests/id:000563,src:000000,op:int8,pos:135,val:+127,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000564,src:000000,op:int32,pos:33,val:+1024,+cov (renamed from src/mint/afl-tests/id:000564,src:000000,op:int32,pos:33,val:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000564,src:000000,op:int8,pos:140,val:+100,+cov (renamed from src/mint/afl-tests/id:000564,src:000000,op:int8,pos:140,val:+100,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000565,src:000000,op:int32,pos:33,val:be:-32769,+cov (renamed from src/mint/afl-tests/id:000565,src:000000,op:int32,pos:33,val:be:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000565,src:000000,op:int8,pos:178,val:+100,+cov (renamed from src/mint/afl-tests/id:000565,src:000000,op:int8,pos:178,val:+100,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000566,src:000000,op:int16,pos:27,val:-128,+cov (renamed from src/mint/afl-tests/id:000566,src:000000,op:int16,pos:27,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000566,src:000000,op:int32,pos:39,val:be:+255,+cov (renamed from src/mint/afl-tests/id:000566,src:000000,op:int32,pos:39,val:be:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000567,src:000000,op:int16,pos:28,val:be:+32,+cov (renamed from src/mint/afl-tests/id:000567,src:000000,op:int16,pos:28,val:be:+32,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000567,src:000000,op:int32,pos:40,val:+32767,+cov (renamed from src/mint/afl-tests/id:000567,src:000000,op:int32,pos:40,val:+32767,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000568,src:000000,op:int16,pos:28,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000568,src:000000,op:int16,pos:28,val:be:+127,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000568,src:000000,op:int32,pos:41,val:+16,+cov (renamed from src/mint/afl-tests/id:000568,src:000000,op:int32,pos:41,val:+16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000569,src:000000,op:int16,pos:33,val:be:+512,+cov (renamed from src/mint/afl-tests/id:000569,src:000000,op:int16,pos:33,val:be:+512,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000569,src:000000,op:int32,pos:41,val:+1024,+cov (renamed from src/mint/afl-tests/id:000569,src:000000,op:int32,pos:41,val:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000570,src:000000,op:int16,pos:34,val:+1000,+cov (renamed from src/mint/afl-tests/id:000570,src:000000,op:int16,pos:34,val:+1000,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000570,src:000000,op:int32,pos:44,val:-32769,+cov (renamed from src/mint/afl-tests/id:000570,src:000000,op:int32,pos:44,val:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000571,src:000000,op:int16,pos:44,val:+512,+cov (renamed from src/mint/afl-tests/id:000571,src:000000,op:int16,pos:44,val:+512,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000571,src:000000,op:int32,pos:45,val:be:+1024,+cov (renamed from src/mint/afl-tests/id:000571,src:000000,op:int32,pos:45,val:be:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000572,src:000000,op:int16,pos:46,val:+100,+cov (renamed from src/mint/afl-tests/id:000572,src:000000,op:int16,pos:46,val:+100,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000572,src:000000,op:int32,pos:48,val:+256,+cov (renamed from src/mint/afl-tests/id:000572,src:000000,op:int32,pos:48,val:+256,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000573,src:000000,op:int16,pos:46,val:be:+512,+cov (renamed from src/mint/afl-tests/id:000573,src:000000,op:int16,pos:46,val:be:+512,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000573,src:000000,op:int32,pos:53,val:+32768,+cov (renamed from src/mint/afl-tests/id:000573,src:000000,op:int32,pos:53,val:+32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000574,src:000000,op:int16,pos:52,val:-128,+cov (renamed from src/mint/afl-tests/id:000574,src:000000,op:int16,pos:52,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000574,src:000000,op:int32,pos:54,val:be:-32768,+cov (renamed from src/mint/afl-tests/id:000574,src:000000,op:int32,pos:54,val:be:-32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000575,src:000000,op:int16,pos:54,val:-128,+cov (renamed from src/mint/afl-tests/id:000575,src:000000,op:int16,pos:54,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000575,src:000000,op:int32,pos:54,val:-32769,+cov (renamed from src/mint/afl-tests/id:000575,src:000000,op:int32,pos:54,val:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000576,src:000000,op:int16,pos:54,val:+100,+cov (renamed from src/mint/afl-tests/id:000576,src:000000,op:int16,pos:54,val:+100,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000576,src:000000,op:int32,pos:54,val:+2147483647,+cov (renamed from src/mint/afl-tests/id:000576,src:000000,op:int32,pos:54,val:+2147483647,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000577,src:000000,op:int16,pos:54,val:+255,+cov (renamed from src/mint/afl-tests/id:000577,src:000000,op:int16,pos:54,val:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000577,src:000000,op:int32,pos:63,val:-1,+cov (renamed from src/mint/afl-tests/id:000577,src:000000,op:int32,pos:63,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000578,src:000000,op:int16,pos:62,val:+255,+cov (renamed from src/mint/afl-tests/id:000578,src:000000,op:int16,pos:62,val:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000578,src:000000,op:int32,pos:64,val:-128,+cov (renamed from src/mint/afl-tests/id:000578,src:000000,op:int32,pos:64,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000579,src:000000,op:int16,pos:63,val:+32,+cov (renamed from src/mint/afl-tests/id:000579,src:000000,op:int16,pos:63,val:+32,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000579,src:000000,op:int32,pos:69,val:+128,+cov (renamed from src/mint/afl-tests/id:000579,src:000000,op:int32,pos:69,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000580,src:000000,op:int16,pos:65,val:be:+100,+cov (renamed from src/mint/afl-tests/id:000580,src:000000,op:int16,pos:65,val:be:+100,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000580,src:000000,op:int32,pos:80,val:+1024,+cov (renamed from src/mint/afl-tests/id:000580,src:000000,op:int32,pos:80,val:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000581,src:000000,op:int16,pos:66,val:+0,+cov (renamed from src/mint/afl-tests/id:000581,src:000000,op:int16,pos:66,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000581,src:000000,op:int32,pos:80,val:+65535,+cov (renamed from src/mint/afl-tests/id:000581,src:000000,op:int32,pos:80,val:+65535,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000582,src:000000,op:int16,pos:80,val:+1000,+cov (renamed from src/mint/afl-tests/id:000582,src:000000,op:int16,pos:80,val:+1000,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000582,src:000000,op:int32,pos:82,val:be:+16,+cov (renamed from src/mint/afl-tests/id:000582,src:000000,op:int32,pos:82,val:be:+16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000583,src:000000,op:int16,pos:82,val:+256,+cov (renamed from src/mint/afl-tests/id:000583,src:000000,op:int16,pos:82,val:+256,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000583,src:000000,op:int32,pos:83,val:+100,+cov (renamed from src/mint/afl-tests/id:000583,src:000000,op:int32,pos:83,val:+100,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000584,src:000000,op:int16,pos:83,val:be:+1024,+cov (renamed from src/mint/afl-tests/id:000584,src:000000,op:int16,pos:83,val:be:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000584,src:000000,op:int32,pos:84,val:+32,+cov (renamed from src/mint/afl-tests/id:000584,src:000000,op:int32,pos:84,val:+32,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000585,src:000000,op:int16,pos:87,val:-128,+cov (renamed from src/mint/afl-tests/id:000585,src:000000,op:int16,pos:87,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000585,src:000000,op:int32,pos:84,val:+128,+cov (renamed from src/mint/afl-tests/id:000585,src:000000,op:int32,pos:84,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000586,src:000000,op:int16,pos:87,val:-32768,+cov (renamed from src/mint/afl-tests/id:000586,src:000000,op:int16,pos:87,val:-32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000586,src:000000,op:int32,pos:87,val:be:-32768,+cov (renamed from src/mint/afl-tests/id:000586,src:000000,op:int32,pos:87,val:be:-32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000587,src:000000,op:int16,pos:94,val:-129,+cov (renamed from src/mint/afl-tests/id:000587,src:000000,op:int16,pos:94,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000587,src:000000,op:int32,pos:88,val:be:-32769,+cov (renamed from src/mint/afl-tests/id:000587,src:000000,op:int32,pos:88,val:be:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000588,src:000000,op:int16,pos:193,val:+16 (renamed from src/mint/afl-tests/id:000588,src:000000,op:int16,pos:193,val:+16)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000588,src:000000,op:int32,pos:89,val:-128,+cov (renamed from src/mint/afl-tests/id:000588,src:000000,op:int32,pos:89,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000589,src:000000,op:int32,pos:0,val:be:+32767 (renamed from src/mint/afl-tests/id:000589,src:000000,op:int32,pos:0,val:be:+32767)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000589,src:000000,op:int32,pos:92,val:+32767,+cov (renamed from src/mint/afl-tests/id:000589,src:000000,op:int32,pos:92,val:+32767,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000590,src:000000,op:int32,pos:164,val:+256,+cov (renamed from src/mint/afl-tests/id:000590,src:000000,op:int32,pos:164,val:+256,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000590,src:000000,op:int32,pos:2,val:+65535 (renamed from src/mint/afl-tests/id:000590,src:000000,op:int32,pos:2,val:+65535)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000591,src:000000,op:int32,pos:178,val:be:-32769,+cov (renamed from src/mint/afl-tests/id:000591,src:000000,op:int32,pos:178,val:be:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000591,src:000000,op:int32,pos:7,val:-2147483648,+cov (renamed from src/mint/afl-tests/id:000591,src:000000,op:int32,pos:7,val:-2147483648,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000592,src:000000,op:int32,pos:232,val:be:+65535,+cov (renamed from src/mint/afl-tests/id:000592,src:000000,op:int32,pos:232,val:be:+65535,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000592,src:000000,op:int32,pos:24,val:be:+32,+cov (renamed from src/mint/afl-tests/id:000592,src:000000,op:int32,pos:24,val:be:+32,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000593,src:000000,op:int32,pos:26,val:+255,+cov (renamed from src/mint/afl-tests/id:000593,src:000000,op:int32,pos:26,val:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000593,src:000000,op:int32,pos:313,val:+1,+cov (renamed from src/mint/afl-tests/id:000593,src:000000,op:int32,pos:313,val:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000594,src:000000,op:int32,pos:27,val:be:+1,+cov (renamed from src/mint/afl-tests/id:000594,src:000000,op:int32,pos:27,val:be:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000594,src:000000,op:int32,pos:333,val:be:+255,+cov (renamed from src/mint/afl-tests/id:000594,src:000000,op:int32,pos:333,val:be:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000595,src:000000,op:ext_AO,pos:26,+cov (renamed from src/mint/afl-tests/id:000595,src:000000,op:ext_AO,pos:26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000595,src:000000,op:int32,pos:29,val:+1000,+cov (renamed from src/mint/afl-tests/id:000595,src:000000,op:int32,pos:29,val:+1000,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000596,src:000000,op:ext_AO,pos:43,+cov (renamed from src/mint/afl-tests/id:000596,src:000000,op:ext_AO,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000596,src:000000,op:int32,pos:30,val:be:+32 (renamed from src/mint/afl-tests/id:000596,src:000000,op:int32,pos:30,val:be:+32)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000597,src:000000,op:ext_AO,pos:49,+cov (renamed from src/mint/afl-tests/id:000597,src:000000,op:ext_AO,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000597,src:000000,op:int32,pos:30,val:be:+512,+cov (renamed from src/mint/afl-tests/id:000597,src:000000,op:int32,pos:30,val:be:+512,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000598,src:000000,op:ext_AO,pos:52,+cov (renamed from src/mint/afl-tests/id:000598,src:000000,op:ext_AO,pos:52,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000598,src:000000,op:int32,pos:39,val:be:+1,+cov (renamed from src/mint/afl-tests/id:000598,src:000000,op:int32,pos:39,val:be:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000599,src:000000,op:ext_AO,pos:56,+cov (renamed from src/mint/afl-tests/id:000599,src:000000,op:ext_AO,pos:56,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000599,src:000000,op:int32,pos:40,val:+1024,+cov (renamed from src/mint/afl-tests/id:000599,src:000000,op:int32,pos:40,val:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000600,src:000000,op:ext_AO,pos:64,+cov (renamed from src/mint/afl-tests/id:000600,src:000000,op:ext_AO,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000600,src:000000,op:int32,pos:42,val:be:+16,+cov (renamed from src/mint/afl-tests/id:000600,src:000000,op:int32,pos:42,val:be:+16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000601,src:000000,op:ext_AO,pos:65,+cov (renamed from src/mint/afl-tests/id:000601,src:000000,op:ext_AO,pos:65,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000601,src:000000,op:int32,pos:48,val:+100663045,+cov (renamed from src/mint/afl-tests/id:000601,src:000000,op:int32,pos:48,val:+100663045,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000602,src:000000,op:ext_AO,pos:65,+cov (renamed from src/mint/afl-tests/id:000602,src:000000,op:ext_AO,pos:65,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000602,src:000000,op:int32,pos:49,val:be:+4096,+cov (renamed from src/mint/afl-tests/id:000602,src:000000,op:int32,pos:49,val:be:+4096,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000603,src:000000,op:ext_AO,pos:69,+cov (renamed from src/mint/afl-tests/id:000603,src:000000,op:ext_AO,pos:69,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000603,src:000000,op:int32,pos:51,val:+128,+cov (renamed from src/mint/afl-tests/id:000603,src:000000,op:int32,pos:51,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000604,src:000000,op:ext_AO,pos:69,+cov (renamed from src/mint/afl-tests/id:000604,src:000000,op:ext_AO,pos:69,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000604,src:000000,op:int32,pos:53,val:-128,+cov (renamed from src/mint/afl-tests/id:000604,src:000000,op:int32,pos:53,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000605,src:000000,op:ext_AO,pos:72,+cov (renamed from src/mint/afl-tests/id:000605,src:000000,op:ext_AO,pos:72,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000605,src:000000,op:int32,pos:53,val:+128,+cov (renamed from src/mint/afl-tests/id:000605,src:000000,op:int32,pos:53,val:+128,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000606,src:000000,op:ext_AO,pos:72,+cov (renamed from src/mint/afl-tests/id:000606,src:000000,op:ext_AO,pos:72,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000606,src:000000,op:int32,pos:53,val:+1024,+cov (renamed from src/mint/afl-tests/id:000606,src:000000,op:int32,pos:53,val:+1024,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000607,src:000000,op:ext_AO,pos:76,+cov (renamed from src/mint/afl-tests/id:000607,src:000000,op:ext_AO,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000607,src:000000,op:int32,pos:64,val:+256,+cov (renamed from src/mint/afl-tests/id:000607,src:000000,op:int32,pos:64,val:+256,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000608,src:000000,op:ext_AO,pos:81,+cov (renamed from src/mint/afl-tests/id:000608,src:000000,op:ext_AO,pos:81,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000608,src:000000,op:int32,pos:65,val:+1,+cov (renamed from src/mint/afl-tests/id:000608,src:000000,op:int32,pos:65,val:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000609,src:000000,op:ext_AO,pos:90,+cov (renamed from src/mint/afl-tests/id:000609,src:000000,op:ext_AO,pos:90,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000609,src:000000,op:int32,pos:65,val:be:+64,+cov (renamed from src/mint/afl-tests/id:000609,src:000000,op:int32,pos:65,val:be:+64,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000610,src:000000,op:ext_AO,pos:111,+cov (renamed from src/mint/afl-tests/id:000610,src:000000,op:ext_AO,pos:111,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000610,src:000000,op:int32,pos:66,val:+16,+cov (renamed from src/mint/afl-tests/id:000610,src:000000,op:int32,pos:66,val:+16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000611,src:000000,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000611,src:000000,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000611,src:000000,op:int32,pos:73,val:+100663045,+cov (renamed from src/mint/afl-tests/id:000611,src:000000,op:int32,pos:73,val:+100663045,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000612,src:000000,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000612,src:000000,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000612,src:000000,op:int32,pos:81,val:+0,+cov (renamed from src/mint/afl-tests/id:000612,src:000000,op:int32,pos:81,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000613,src:000000,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000613,src:000000,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000613,src:000000,op:int32,pos:82,val:+32767,+cov (renamed from src/mint/afl-tests/id:000613,src:000000,op:int32,pos:82,val:+32767,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000614,src:000000,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000614,src:000000,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000614,src:000000,op:int32,pos:83,val:be:+1000,+cov (renamed from src/mint/afl-tests/id:000614,src:000000,op:int32,pos:83,val:be:+1000,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000615,src:000000,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000615,src:000000,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000615,src:000000,op:int32,pos:84,val:-129,+cov (renamed from src/mint/afl-tests/id:000615,src:000000,op:int32,pos:84,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000616,src:000000,op:ext_AO,pos:136,+cov (renamed from src/mint/afl-tests/id:000616,src:000000,op:ext_AO,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000616,src:000000,op:int32,pos:84,val:+65536,+cov (renamed from src/mint/afl-tests/id:000616,src:000000,op:int32,pos:84,val:+65536,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000617,src:000000,op:ext_AO,pos:136,+cov (renamed from src/mint/afl-tests/id:000617,src:000000,op:ext_AO,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000617,src:000000,op:int32,pos:85,val:be:+255,+cov (renamed from src/mint/afl-tests/id:000617,src:000000,op:int32,pos:85,val:be:+255,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000618,src:000000,op:ext_AO,pos:137,+cov (renamed from src/mint/afl-tests/id:000618,src:000000,op:ext_AO,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000618,src:000000,op:int32,pos:85,val:-32769,+cov (renamed from src/mint/afl-tests/id:000618,src:000000,op:int32,pos:85,val:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000619,src:000000,op:ext_AO,pos:137,+cov (renamed from src/mint/afl-tests/id:000619,src:000000,op:ext_AO,pos:137,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000619,src:000000,op:int32,pos:88,val:be:-32768,+cov (renamed from src/mint/afl-tests/id:000619,src:000000,op:int32,pos:88,val:be:-32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000620,src:000000,op:ext_AO,pos:138,+cov (renamed from src/mint/afl-tests/id:000620,src:000000,op:ext_AO,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000620,src:000000,op:int32,pos:91,val:+127,+cov (renamed from src/mint/afl-tests/id:000620,src:000000,op:int32,pos:91,val:+127,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000621,src:000000,op:ext_AO,pos:142,+cov (renamed from src/mint/afl-tests/id:000621,src:000000,op:ext_AO,pos:142,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000621,src:000000,op:int32,pos:92,val:-32768,+cov (renamed from src/mint/afl-tests/id:000621,src:000000,op:int32,pos:92,val:-32768,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000622,src:000000,op:ext_AO,pos:143,+cov (renamed from src/mint/afl-tests/id:000622,src:000000,op:ext_AO,pos:143,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000622,src:000000,op:int32,pos:98,val:-129,+cov (renamed from src/mint/afl-tests/id:000622,src:000000,op:int32,pos:98,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000623,src:000000,op:ext_AO,pos:144,+cov (renamed from src/mint/afl-tests/id:000623,src:000000,op:ext_AO,pos:144,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000623,src:000000,op:int32,pos:128,val:-32769,+cov (renamed from src/mint/afl-tests/id:000623,src:000000,op:int32,pos:128,val:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000624,src:000000,op:ext_AO,pos:144,+cov (renamed from src/mint/afl-tests/id:000624,src:000000,op:ext_AO,pos:144,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000624,src:000000,op:int32,pos:160,val:be:+512,+cov (renamed from src/mint/afl-tests/id:000624,src:000000,op:int32,pos:160,val:be:+512,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000625,src:000000,op:ext_AO,pos:145,+cov (renamed from src/mint/afl-tests/id:000625,src:000000,op:ext_AO,pos:145,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000625,src:000000,op:int32,pos:203,val:be:+1,+cov (renamed from src/mint/afl-tests/id:000625,src:000000,op:int32,pos:203,val:be:+1,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000626,src:000000,op:ext_AO,pos:146,+cov (renamed from src/mint/afl-tests/id:000626,src:000000,op:ext_AO,pos:146,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000626,src:000000,op:int32,pos:263,val:+0,+cov (renamed from src/mint/afl-tests/id:000626,src:000000,op:int32,pos:263,val:+0,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000627,src:000000,op:ext_AO,pos:146,+cov (renamed from src/mint/afl-tests/id:000627,src:000000,op:ext_AO,pos:146,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000627,src:000000,op:int32,pos:264,val:be:-32769,+cov (renamed from src/mint/afl-tests/id:000627,src:000000,op:int32,pos:264,val:be:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000628,src:000000,op:ext_AO,pos:147,+cov (renamed from src/mint/afl-tests/id:000628,src:000000,op:ext_AO,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000628,src:000000,op:int32,pos:285,val:+100663045,+cov (renamed from src/mint/afl-tests/id:000628,src:000000,op:int32,pos:285,val:+100663045,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000629,src:000000,op:ext_AO,pos:147,+cov (renamed from src/mint/afl-tests/id:000629,src:000000,op:ext_AO,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000629,src:000000,op:ext_AO,pos:34,+cov (renamed from src/mint/afl-tests/id:000629,src:000000,op:ext_AO,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000630,src:000000,op:ext_AO,pos:148,+cov (renamed from src/mint/afl-tests/id:000630,src:000000,op:ext_AO,pos:148,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000630,src:000000,op:ext_AO,pos:34,+cov (renamed from src/mint/afl-tests/id:000630,src:000000,op:ext_AO,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000631,src:000000,op:ext_AO,pos:148 (renamed from src/mint/afl-tests/id:000631,src:000000,op:ext_AO,pos:148)0
-rw-r--r--src/exchange/afl-tests/id:000631,src:000000,op:ext_AO,pos:37,+cov (renamed from src/mint/afl-tests/id:000631,src:000000,op:ext_AO,pos:37,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000632,src:000000,op:ext_AO,pos:149,+cov (renamed from src/mint/afl-tests/id:000632,src:000000,op:ext_AO,pos:149,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000632,src:000000,op:ext_AO,pos:39,+cov (renamed from src/mint/afl-tests/id:000632,src:000000,op:ext_AO,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000633,src:000000,op:ext_AO,pos:152,+cov (renamed from src/mint/afl-tests/id:000633,src:000000,op:ext_AO,pos:152,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000633,src:000000,op:ext_AO,pos:49,+cov (renamed from src/mint/afl-tests/id:000633,src:000000,op:ext_AO,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000634,src:000000,op:ext_AO,pos:154 (renamed from src/mint/afl-tests/id:000634,src:000000,op:ext_AO,pos:154)0
-rw-r--r--src/exchange/afl-tests/id:000634,src:000000,op:ext_AO,pos:51,+cov (renamed from src/mint/afl-tests/id:000634,src:000000,op:ext_AO,pos:51,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000635,src:000000,op:ext_AO,pos:155,+cov (renamed from src/mint/afl-tests/id:000635,src:000000,op:ext_AO,pos:155,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000635,src:000000,op:ext_AO,pos:52,+cov (renamed from src/mint/afl-tests/id:000635,src:000000,op:ext_AO,pos:52,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000636,src:000000,op:ext_AO,pos:156,+cov (renamed from src/mint/afl-tests/id:000636,src:000000,op:ext_AO,pos:156,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000636,src:000000,op:ext_AO,pos:52,+cov (renamed from src/mint/afl-tests/id:000636,src:000000,op:ext_AO,pos:52,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000637,src:000000,op:ext_AO,pos:157 (renamed from src/mint/afl-tests/id:000637,src:000000,op:ext_AO,pos:157)0
-rw-r--r--src/exchange/afl-tests/id:000637,src:000000,op:ext_AO,pos:58,+cov (renamed from src/mint/afl-tests/id:000637,src:000000,op:ext_AO,pos:58,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000638,src:000000,op:ext_AO,pos:159,+cov (renamed from src/mint/afl-tests/id:000638,src:000000,op:ext_AO,pos:159,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000638,src:000000,op:ext_AO,pos:64,+cov (renamed from src/mint/afl-tests/id:000638,src:000000,op:ext_AO,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000639,src:000000,op:ext_AO,pos:161,+cov (renamed from src/mint/afl-tests/id:000639,src:000000,op:ext_AO,pos:161,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000639,src:000000,op:ext_AO,pos:86,+cov (renamed from src/mint/afl-tests/id:000639,src:000000,op:ext_AO,pos:86,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000640,src:000000,op:ext_AO,pos:166,+cov (renamed from src/mint/afl-tests/id:000640,src:000000,op:ext_AO,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000640,src:000000,op:ext_AO,pos:88,+cov (renamed from src/mint/afl-tests/id:000640,src:000000,op:ext_AO,pos:88,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000641,src:000000,op:ext_AO,pos:168,+cov (renamed from src/mint/afl-tests/id:000641,src:000000,op:ext_AO,pos:168,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000641,src:000000,op:ext_AO,pos:93,+cov (renamed from src/mint/afl-tests/id:000641,src:000000,op:ext_AO,pos:93,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000642,src:000000,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000642,src:000000,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000642,src:000000,op:ext_AO,pos:169,+cov (renamed from src/mint/afl-tests/id:000642,src:000000,op:ext_AO,pos:169,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000643,src:000000,op:ext_AO,pos:136,+cov (renamed from src/mint/afl-tests/id:000643,src:000000,op:ext_AO,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000643,src:000000,op:ext_AO,pos:173,+cov (renamed from src/mint/afl-tests/id:000643,src:000000,op:ext_AO,pos:173,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000644,src:000000,op:ext_AO,pos:138,+cov (renamed from src/mint/afl-tests/id:000644,src:000000,op:ext_AO,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000644,src:000000,op:ext_AO,pos:174,+cov (renamed from src/mint/afl-tests/id:000644,src:000000,op:ext_AO,pos:174,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000645,src:000000,op:ext_AO,pos:140,+cov (renamed from src/mint/afl-tests/id:000645,src:000000,op:ext_AO,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000645,src:000000,op:ext_AO,pos:174,+cov (renamed from src/mint/afl-tests/id:000645,src:000000,op:ext_AO,pos:174,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000646,src:000000,op:ext_AO,pos:143,+cov (renamed from src/mint/afl-tests/id:000646,src:000000,op:ext_AO,pos:143,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000646,src:000000,op:ext_AO,pos:184,+cov (renamed from src/mint/afl-tests/id:000646,src:000000,op:ext_AO,pos:184,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000647,src:000000,op:ext_AO,pos:144,+cov (renamed from src/mint/afl-tests/id:000647,src:000000,op:ext_AO,pos:144,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000647,src:000000,op:ext_AO,pos:191,+cov (renamed from src/mint/afl-tests/id:000647,src:000000,op:ext_AO,pos:191,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000648,src:000000,op:ext_AO,pos:155,+cov (renamed from src/mint/afl-tests/id:000648,src:000000,op:ext_AO,pos:155,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000648,src:000000,op:ext_AO,pos:216,+cov (renamed from src/mint/afl-tests/id:000648,src:000000,op:ext_AO,pos:216,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000649,src:000000,op:ext_AO,pos:166,+cov (renamed from src/mint/afl-tests/id:000649,src:000000,op:ext_AO,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000649,src:000000,op:ext_AO,pos:236,+cov (renamed from src/mint/afl-tests/id:000649,src:000000,op:ext_AO,pos:236,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000650,src:000000,op:ext_AO,pos:166,+cov (renamed from src/mint/afl-tests/id:000650,src:000000,op:ext_AO,pos:166,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000650,src:000000,op:ext_AO,pos:270,+cov (renamed from src/mint/afl-tests/id:000650,src:000000,op:ext_AO,pos:270,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000651,src:000000,op:ext_AO,pos:173,+cov (renamed from src/mint/afl-tests/id:000651,src:000000,op:ext_AO,pos:173,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000651,src:000000,op:ext_AO,pos:270,+cov (renamed from src/mint/afl-tests/id:000651,src:000000,op:ext_AO,pos:270,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000652,src:000000,op:ext_AO,pos:175,+cov (renamed from src/mint/afl-tests/id:000652,src:000000,op:ext_AO,pos:175,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000652,src:000000,op:ext_AO,pos:272,+cov (renamed from src/mint/afl-tests/id:000652,src:000000,op:ext_AO,pos:272,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000653,src:000000,op:ext_AO,pos:176,+cov (renamed from src/mint/afl-tests/id:000653,src:000000,op:ext_AO,pos:176,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000653,src:000000,op:ext_AO,pos:283,+cov (renamed from src/mint/afl-tests/id:000653,src:000000,op:ext_AO,pos:283,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000654,src:000000,op:ext_AO,pos:177,+cov (renamed from src/mint/afl-tests/id:000654,src:000000,op:ext_AO,pos:177,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000654,src:000000,op:ext_AO,pos:305,+cov (renamed from src/mint/afl-tests/id:000654,src:000000,op:ext_AO,pos:305,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000655,src:000000,op:ext_AO,pos:177,+cov (renamed from src/mint/afl-tests/id:000655,src:000000,op:ext_AO,pos:177,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000655,src:000000,op:ext_AO,pos:305,+cov (renamed from src/mint/afl-tests/id:000655,src:000000,op:ext_AO,pos:305,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000656,src:000000,op:ext_AO,pos:177,+cov (renamed from src/mint/afl-tests/id:000656,src:000000,op:ext_AO,pos:177,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000656,src:000000,op:ext_AO,pos:313,+cov (renamed from src/mint/afl-tests/id:000656,src:000000,op:ext_AO,pos:313,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000657,src:000000,op:ext_AO,pos:180,+cov (renamed from src/mint/afl-tests/id:000657,src:000000,op:ext_AO,pos:180,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000657,src:000000,op:ext_AO,pos:315,+cov (renamed from src/mint/afl-tests/id:000657,src:000000,op:ext_AO,pos:315,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000658,src:000000,op:ext_AO,pos:182,+cov (renamed from src/mint/afl-tests/id:000658,src:000000,op:ext_AO,pos:182,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000658,src:000000,op:ext_AO,pos:326 (renamed from src/mint/afl-tests/id:000658,src:000000,op:ext_AO,pos:326)0
-rw-r--r--src/exchange/afl-tests/id:000659,src:000000,op:ext_AO,pos:269,+cov (renamed from src/mint/afl-tests/id:000659,src:000000,op:ext_AO,pos:269,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000659,src:000000,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000659,src:000000,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000660,src:000000,op:ext_AO,pos:270,+cov (renamed from src/mint/afl-tests/id:000660,src:000000,op:ext_AO,pos:270,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000660,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000660,src:000000,op:havoc,rep:32)bin389 -> 389 bytes
-rw-r--r--src/exchange/afl-tests/id:000661,src:000000,op:ext_AO,pos:271,+cov (renamed from src/mint/afl-tests/id:000661,src:000000,op:ext_AO,pos:271,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000661,src:000000,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000661,src:000000,op:havoc,rep:4)bin309 -> 309 bytes
-rw-r--r--src/exchange/afl-tests/id:000662,src:000000,op:ext_AO,pos:274,+cov (renamed from src/mint/afl-tests/id:000662,src:000000,op:ext_AO,pos:274,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000662,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000662,src:000000,op:havoc,rep:128)bin115 -> 115 bytes
-rw-r--r--src/exchange/afl-tests/id:000663,src:000000,op:ext_AO,pos:275,+cov (renamed from src/mint/afl-tests/id:000663,src:000000,op:ext_AO,pos:275,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000663,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000663,src:000000,op:havoc,rep:32)bin307 -> 307 bytes
-rw-r--r--src/exchange/afl-tests/id:000664,src:000000,op:ext_AO,pos:305,+cov (renamed from src/mint/afl-tests/id:000664,src:000000,op:ext_AO,pos:305,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000664,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000664,src:000000,op:havoc,rep:128)bin23 -> 23 bytes
-rw-r--r--src/exchange/afl-tests/id:000665,src:000000,op:ext_AO,pos:312,+cov (renamed from src/mint/afl-tests/id:000665,src:000000,op:ext_AO,pos:312,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000665,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000665,src:000000,op:havoc,rep:16,+cov)bin364 -> 364 bytes
-rw-r--r--src/exchange/afl-tests/id:000666,src:000000,op:ext_AO,pos:314,+cov (renamed from src/mint/afl-tests/id:000666,src:000000,op:ext_AO,pos:314,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000666,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000666,src:000000,op:havoc,rep:64)bin323 -> 323 bytes
-rw-r--r--src/exchange/afl-tests/id:000667,src:000000,op:ext_AO,pos:319,+cov (renamed from src/mint/afl-tests/id:000667,src:000000,op:ext_AO,pos:319,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000667,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000667,src:000000,op:havoc,rep:16)bin375 -> 375 bytes
-rw-r--r--src/exchange/afl-tests/id:000668,src:000000,op:ext_AO,pos:328,+cov (renamed from src/mint/afl-tests/id:000668,src:000000,op:ext_AO,pos:328,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000668,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000668,src:000000,op:havoc,rep:128)bin121 -> 121 bytes
-rw-r--r--src/exchange/afl-tests/id:000669,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000669,src:000000,op:havoc,rep:16)bin290 -> 290 bytes
-rw-r--r--src/exchange/afl-tests/id:000669,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000669,src:000000,op:havoc,rep:64)bin341 -> 341 bytes
-rw-r--r--src/exchange/afl-tests/id:000670,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000670,src:000000,op:havoc,rep:32)bin285 -> 285 bytes
-rw-r--r--src/exchange/afl-tests/id:000671,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000671,src:000000,op:havoc,rep:16)bin299 -> 299 bytes
-rw-r--r--src/exchange/afl-tests/id:000671,src:000000,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000671,src:000000,op:havoc,rep:8)0
-rw-r--r--src/exchange/afl-tests/id:000672,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000672,src:000000,op:havoc,rep:16)bin293 -> 293 bytes
-rw-r--r--src/exchange/afl-tests/id:000672,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000672,src:000000,op:havoc,rep:32)bin308 -> 308 bytes
-rw-r--r--src/exchange/afl-tests/id:000673,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000673,src:000000,op:havoc,rep:128)bin224 -> 224 bytes
-rw-r--r--src/exchange/afl-tests/id:000673,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000673,src:000000,op:havoc,rep:16)bin323 -> 323 bytes
-rw-r--r--src/exchange/afl-tests/id:000674,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000674,src:000000,op:havoc,rep:32)bin361 -> 361 bytes
-rw-r--r--src/exchange/afl-tests/id:000675,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000675,src:000000,op:havoc,rep:128)bin349 -> 349 bytes
-rw-r--r--src/exchange/afl-tests/id:000675,src:000000,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000675,src:000000,op:havoc,rep:8)0
-rw-r--r--src/exchange/afl-tests/id:000676,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000676,src:000000,op:havoc,rep:32)bin287 -> 287 bytes
-rw-r--r--src/exchange/afl-tests/id:000677,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000677,src:000000,op:havoc,rep:64)bin243 -> 243 bytes
-rw-r--r--src/exchange/afl-tests/id:000677,src:000000,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000677,src:000000,op:havoc,rep:8)bin304 -> 304 bytes
-rw-r--r--src/exchange/afl-tests/id:000678,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000678,src:000000,op:havoc,rep:16)bin343 -> 343 bytes
-rw-r--r--src/exchange/afl-tests/id:000678,src:000000,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000678,src:000000,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000679,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000679,src:000000,op:havoc,rep:128)bin144 -> 144 bytes
-rw-r--r--src/exchange/afl-tests/id:000679,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000679,src:000000,op:havoc,rep:16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000680,src:000000,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000680,src:000000,op:havoc,rep:128,+cov)bin293 -> 293 bytes
-rw-r--r--src/exchange/afl-tests/id:000680,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000680,src:000000,op:havoc,rep:32)bin298 -> 298 bytes
-rw-r--r--src/exchange/afl-tests/id:000681,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000681,src:000000,op:havoc,rep:16)bin344 -> 344 bytes
-rw-r--r--src/exchange/afl-tests/id:000681,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000681,src:000000,op:havoc,rep:32)bin393 -> 393 bytes
-rw-r--r--src/exchange/afl-tests/id:000682,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000682,src:000000,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000682,src:000000,op:havoc,rep:64,+cov (renamed from src/mint/afl-tests/id:000682,src:000000,op:havoc,rep:64,+cov)bin360 -> 360 bytes
-rw-r--r--src/exchange/afl-tests/id:000683,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000683,src:000000,op:havoc,rep:16,+cov)bin299 -> 299 bytes
-rw-r--r--src/exchange/afl-tests/id:000683,src:000000,op:havoc,rep:32,+cov (renamed from src/mint/afl-tests/id:000683,src:000000,op:havoc,rep:32,+cov)bin257 -> 257 bytes
-rw-r--r--src/exchange/afl-tests/id:000684,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000684,src:000000,op:havoc,rep:16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000684,src:000000,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000684,src:000000,op:havoc,rep:8)0
-rw-r--r--src/exchange/afl-tests/id:000685,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000685,src:000000,op:havoc,rep:16)bin321 -> 321 bytes
-rw-r--r--src/exchange/afl-tests/id:000685,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000685,src:000000,op:havoc,rep:16,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000686,src:000000,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000686,src:000000,op:havoc,rep:128,+cov)bin251 -> 251 bytes
-rw-r--r--src/exchange/afl-tests/id:000686,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000686,src:000000,op:havoc,rep:16,+cov)bin288 -> 288 bytes
-rw-r--r--src/exchange/afl-tests/id:000687,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000687,src:000000,op:havoc,rep:16)bin384 -> 384 bytes
-rw-r--r--src/exchange/afl-tests/id:000687,src:000000,op:havoc,rep:32,+cov (renamed from src/mint/afl-tests/id:000687,src:000000,op:havoc,rep:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000688,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000688,src:000000,op:havoc,rep:128)bin333 -> 333 bytes
-rw-r--r--src/exchange/afl-tests/id:000689,src:000000,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000689,src:000000,op:havoc,rep:128,+cov)bin324 -> 324 bytes
-rw-r--r--src/exchange/afl-tests/id:000689,src:000000,op:havoc,rep:64,+cov (renamed from src/mint/afl-tests/id:000689,src:000000,op:havoc,rep:64,+cov)bin148 -> 148 bytes
-rw-r--r--src/exchange/afl-tests/id:000690,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000690,src:000000,op:havoc,rep:32)bin366 -> 366 bytes
-rw-r--r--src/exchange/afl-tests/id:000690,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000690,src:000000,op:havoc,rep:64)0
-rw-r--r--src/exchange/afl-tests/id:000691,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000691,src:000000,op:havoc,rep:64)bin241 -> 241 bytes
-rw-r--r--src/exchange/afl-tests/id:000692,src:000000,op:havoc,rep:4,+cov (renamed from src/mint/afl-tests/id:000692,src:000000,op:havoc,rep:4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000693,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000693,src:000000,op:havoc,rep:16,+cov)bin330 -> 330 bytes
-rw-r--r--src/exchange/afl-tests/id:000693,src:000000,op:havoc,rep:4,+cov (renamed from src/mint/afl-tests/id:000693,src:000000,op:havoc,rep:4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000694,src:000000,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000694,src:000000,op:havoc,rep:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000694,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000694,src:000000,op:havoc,rep:32)bin360 -> 360 bytes
-rw-r--r--src/exchange/afl-tests/id:000695,src:000000,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000695,src:000000,op:havoc,rep:128,+cov)bin304 -> 304 bytes
-rw-r--r--src/exchange/afl-tests/id:000695,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000695,src:000000,op:havoc,rep:64)bin288 -> 288 bytes
-rw-r--r--src/exchange/afl-tests/id:000696,src:000000,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000696,src:000000,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000696,src:000000,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000696,src:000000,op:havoc,rep:2,+cov)bin339 -> 339 bytes
-rw-r--r--src/exchange/afl-tests/id:000697,src:000000,op:havoc,rep:64,+cov (renamed from src/mint/afl-tests/id:000697,src:000000,op:havoc,rep:64,+cov)bin237 -> 237 bytes
-rw-r--r--src/exchange/afl-tests/id:000697,src:000000,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000697,src:000000,op:havoc,rep:8)0
-rw-r--r--src/exchange/afl-tests/id:000698,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000698,src:000000,op:havoc,rep:128)bin121 -> 121 bytes
-rw-r--r--src/exchange/afl-tests/id:000699,src:000000,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000699,src:000000,op:havoc,rep:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000699,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000699,src:000000,op:havoc,rep:32)bin315 -> 315 bytes
-rw-r--r--src/exchange/afl-tests/id:000700,src:000000,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000700,src:000000,op:havoc,rep:128,+cov)bin85 -> 85 bytes
-rw-r--r--src/exchange/afl-tests/id:000700,src:000000,op:havoc,rep:32,+cov (renamed from src/mint/afl-tests/id:000700,src:000000,op:havoc,rep:32,+cov)bin316 -> 316 bytes
-rw-r--r--src/exchange/afl-tests/id:000701,src:000000,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000701,src:000000,op:havoc,rep:16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000701,src:000000,op:havoc,rep:2 (renamed from src/mint/afl-tests/id:000701,src:000000,op:havoc,rep:2)bin371 -> 371 bytes
-rw-r--r--src/exchange/afl-tests/id:000702,src:000000,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000702,src:000000,op:havoc,rep:128)bin237 -> 237 bytes
-rw-r--r--src/exchange/afl-tests/id:000702,src:000000,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000702,src:000000,op:havoc,rep:8)bin317 -> 317 bytes
-rw-r--r--src/exchange/afl-tests/id:000703,src:000000,op:havoc,rep:32,+cov (renamed from src/mint/afl-tests/id:000703,src:000000,op:havoc,rep:32,+cov)bin271 -> 271 bytes
-rw-r--r--src/exchange/afl-tests/id:000703,src:000001,op:flip1,pos:34,+cov (renamed from src/mint/afl-tests/id:000703,src:000001,op:flip1,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000704,src:000000,op:havoc,rep:64,+cov (renamed from src/mint/afl-tests/id:000704,src:000000,op:havoc,rep:64,+cov)bin335 -> 335 bytes
-rw-r--r--src/exchange/afl-tests/id:000704,src:000001,op:flip1,pos:50,+cov (renamed from src/mint/afl-tests/id:000704,src:000001,op:flip1,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000705,src:000000,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000705,src:000000,op:havoc,rep:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000705,src:000001,op:flip1,pos:61,+cov (renamed from src/mint/afl-tests/id:000705,src:000001,op:flip1,pos:61,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000706,src:000000,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000706,src:000000,op:havoc,rep:32)bin292 -> 292 bytes
-rw-r--r--src/exchange/afl-tests/id:000706,src:000001,op:flip1,pos:91 (renamed from src/mint/afl-tests/id:000706,src:000001,op:flip1,pos:91)0
-rw-r--r--src/exchange/afl-tests/id:000707,src:000000,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000707,src:000000,op:havoc,rep:128,+cov)bin49 -> 49 bytes
-rw-r--r--src/exchange/afl-tests/id:000707,src:000001,op:flip1,pos:103,+cov (renamed from src/mint/afl-tests/id:000707,src:000001,op:flip1,pos:103,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000708,src:000000,op:havoc,rep:2 (renamed from src/mint/afl-tests/id:000708,src:000000,op:havoc,rep:2)0
-rw-r--r--src/exchange/afl-tests/id:000708,src:000001,op:flip1,pos:120,+cov (renamed from src/mint/afl-tests/id:000708,src:000001,op:flip1,pos:120,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000709,src:000000,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000709,src:000000,op:havoc,rep:64)bin235 -> 235 bytes
-rw-r--r--src/exchange/afl-tests/id:000709,src:000001,op:flip1,pos:129,+cov (renamed from src/mint/afl-tests/id:000709,src:000001,op:flip1,pos:129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000710,src:000000,op:havoc,rep:8,+cov (renamed from src/mint/afl-tests/id:000710,src:000000,op:havoc,rep:8,+cov)bin329 -> 329 bytes
-rw-r--r--src/exchange/afl-tests/id:000710,src:000001,op:flip1,pos:129,+cov (renamed from src/mint/afl-tests/id:000710,src:000001,op:flip1,pos:129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000711,src:000000,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000711,src:000000,op:havoc,rep:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000711,src:000001,op:flip1,pos:131,+cov (renamed from src/mint/afl-tests/id:000711,src:000001,op:flip1,pos:131,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000712,src:000000,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000712,src:000000,op:havoc,rep:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000712,src:000001,op:flip1,pos:139,+cov (renamed from src/mint/afl-tests/id:000712,src:000001,op:flip1,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000713,src:000000,op:havoc,rep:64,+cov (renamed from src/mint/afl-tests/id:000713,src:000000,op:havoc,rep:64,+cov)bin249 -> 249 bytes
-rw-r--r--src/exchange/afl-tests/id:000713,src:000001,op:flip1,pos:197,+cov (renamed from src/mint/afl-tests/id:000713,src:000001,op:flip1,pos:197,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000714,src:000000,op:havoc,rep:8,+cov (renamed from src/mint/afl-tests/id:000714,src:000000,op:havoc,rep:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000714,src:000001,op:flip1,pos:243,+cov (renamed from src/mint/afl-tests/id:000714,src:000001,op:flip1,pos:243,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000715,src:000000,op:havoc,rep:8,+cov (renamed from src/mint/afl-tests/id:000715,src:000000,op:havoc,rep:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000715,src:000001,op:flip1,pos:365,+cov (renamed from src/mint/afl-tests/id:000715,src:000001,op:flip1,pos:365,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000716,src:000001,op:flip1,pos:2 (renamed from src/mint/afl-tests/id:000716,src:000001,op:flip1,pos:2)0
-rw-r--r--src/exchange/afl-tests/id:000716,src:000001,op:flip1,pos:456,+cov (renamed from src/mint/afl-tests/id:000716,src:000001,op:flip1,pos:456,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000717,src:000001,op:flip1,pos:50,+cov (renamed from src/mint/afl-tests/id:000717,src:000001,op:flip1,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000717,src:000001,op:flip1,pos:596 (renamed from src/mint/afl-tests/id:000717,src:000001,op:flip1,pos:596)0
-rw-r--r--src/exchange/afl-tests/id:000718,src:000001,op:flip1,pos:55,+cov (renamed from src/mint/afl-tests/id:000718,src:000001,op:flip1,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000718,src:000001,op:flip1,pos:614,+cov (renamed from src/mint/afl-tests/id:000718,src:000001,op:flip1,pos:614,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000719,src:000001,op:flip1,pos:629,+cov (renamed from src/mint/afl-tests/id:000719,src:000001,op:flip1,pos:629,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000719,src:000001,op:flip1,pos:95 (renamed from src/mint/afl-tests/id:000719,src:000001,op:flip1,pos:95)0
-rw-r--r--src/exchange/afl-tests/id:000720,src:000001,op:flip1,pos:102,+cov (renamed from src/mint/afl-tests/id:000720,src:000001,op:flip1,pos:102,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000720,src:000001,op:flip1,pos:635,+cov (renamed from src/mint/afl-tests/id:000720,src:000001,op:flip1,pos:635,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000721,src:000001,op:flip1,pos:107,+cov (renamed from src/mint/afl-tests/id:000721,src:000001,op:flip1,pos:107,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000721,src:000001,op:flip1,pos:683,+cov (renamed from src/mint/afl-tests/id:000721,src:000001,op:flip1,pos:683,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000722,src:000001,op:flip1,pos:118,+cov (renamed from src/mint/afl-tests/id:000722,src:000001,op:flip1,pos:118,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000722,src:000001,op:flip1,pos:730,+cov (renamed from src/mint/afl-tests/id:000722,src:000001,op:flip1,pos:730,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000723,src:000001,op:flip1,pos:124,+cov (renamed from src/mint/afl-tests/id:000723,src:000001,op:flip1,pos:124,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000723,src:000001,op:flip1,pos:786,+cov (renamed from src/mint/afl-tests/id:000723,src:000001,op:flip1,pos:786,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000724,src:000001,op:flip1,pos:133,+cov (renamed from src/mint/afl-tests/id:000724,src:000001,op:flip1,pos:133,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000724,src:000001,op:flip1,pos:796 (renamed from src/mint/afl-tests/id:000724,src:000001,op:flip1,pos:796)0
-rw-r--r--src/exchange/afl-tests/id:000725,src:000001,op:flip1,pos:133,+cov (renamed from src/mint/afl-tests/id:000725,src:000001,op:flip1,pos:133,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000725,src:000001,op:flip1,pos:915,+cov (renamed from src/mint/afl-tests/id:000725,src:000001,op:flip1,pos:915,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000726,src:000001,op:flip1,pos:1112,+cov (renamed from src/mint/afl-tests/id:000726,src:000001,op:flip1,pos:1112,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000726,src:000001,op:flip1,pos:135,+cov (renamed from src/mint/afl-tests/id:000726,src:000001,op:flip1,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000727,src:000001,op:flip1,pos:1112,+cov (renamed from src/mint/afl-tests/id:000727,src:000001,op:flip1,pos:1112,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000727,src:000001,op:flip1,pos:457,+cov (renamed from src/mint/afl-tests/id:000727,src:000001,op:flip1,pos:457,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000728,src:000001,op:flip1,pos:1114,+cov (renamed from src/mint/afl-tests/id:000728,src:000001,op:flip1,pos:1114,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000728,src:000001,op:flip1,pos:469,+cov (renamed from src/mint/afl-tests/id:000728,src:000001,op:flip1,pos:469,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000729,src:000001,op:flip1,pos:1215,+cov (renamed from src/mint/afl-tests/id:000729,src:000001,op:flip1,pos:1215,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000729,src:000001,op:flip1,pos:508,+cov (renamed from src/mint/afl-tests/id:000729,src:000001,op:flip1,pos:508,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000730,src:000001,op:flip1,pos:1353,+cov (renamed from src/mint/afl-tests/id:000730,src:000001,op:flip1,pos:1353,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000730,src:000001,op:flip1,pos:600 (renamed from src/mint/afl-tests/id:000730,src:000001,op:flip1,pos:600)0
-rw-r--r--src/exchange/afl-tests/id:000731,src:000001,op:flip1,pos:1453,+cov (renamed from src/mint/afl-tests/id:000731,src:000001,op:flip1,pos:1453,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000731,src:000001,op:flip1,pos:618,+cov (renamed from src/mint/afl-tests/id:000731,src:000001,op:flip1,pos:618,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000732,src:000001,op:flip1,pos:1574,+cov (renamed from src/mint/afl-tests/id:000732,src:000001,op:flip1,pos:1574,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000732,src:000001,op:flip1,pos:633,+cov (renamed from src/mint/afl-tests/id:000732,src:000001,op:flip1,pos:633,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000733,src:000001,op:flip1,pos:1630 (renamed from src/mint/afl-tests/id:000733,src:000001,op:flip1,pos:1630)0
-rw-r--r--src/exchange/afl-tests/id:000733,src:000001,op:flip1,pos:687,+cov (renamed from src/mint/afl-tests/id:000733,src:000001,op:flip1,pos:687,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000734,src:000001,op:flip1,pos:722,+cov (renamed from src/mint/afl-tests/id:000734,src:000001,op:flip1,pos:722,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000734,src:000001,op:flip2,pos:453,+cov (renamed from src/mint/afl-tests/id:000734,src:000001,op:flip2,pos:453,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000735,src:000001,op:flip1,pos:734,+cov (renamed from src/mint/afl-tests/id:000735,src:000001,op:flip1,pos:734,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000735,src:000001,op:flip2,pos:484,+cov (renamed from src/mint/afl-tests/id:000735,src:000001,op:flip2,pos:484,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000736,src:000001,op:flip1,pos:800 (renamed from src/mint/afl-tests/id:000736,src:000001,op:flip1,pos:800)0
-rw-r--r--src/exchange/afl-tests/id:000736,src:000001,op:flip2,pos:696,+cov (renamed from src/mint/afl-tests/id:000736,src:000001,op:flip2,pos:696,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000737,src:000001,op:flip1,pos:888,+cov (renamed from src/mint/afl-tests/id:000737,src:000001,op:flip1,pos:888,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000737,src:000001,op:flip2,pos:843,+cov (renamed from src/mint/afl-tests/id:000737,src:000001,op:flip2,pos:843,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000738,src:000001,op:flip1,pos:893,+cov (renamed from src/mint/afl-tests/id:000738,src:000001,op:flip1,pos:893,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000738,src:000001,op:flip2,pos:845,+cov (renamed from src/mint/afl-tests/id:000738,src:000001,op:flip2,pos:845,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000739,src:000001,op:flip1,pos:1116,+cov (renamed from src/mint/afl-tests/id:000739,src:000001,op:flip1,pos:1116,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000739,src:000001,op:flip2,pos:917,+cov (renamed from src/mint/afl-tests/id:000739,src:000001,op:flip2,pos:917,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000740,src:000001,op:flip1,pos:1116,+cov (renamed from src/mint/afl-tests/id:000740,src:000001,op:flip1,pos:1116,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000740,src:000001,op:flip2,pos:995,+cov (renamed from src/mint/afl-tests/id:000740,src:000001,op:flip2,pos:995,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000741,src:000001,op:flip1,pos:1118,+cov (renamed from src/mint/afl-tests/id:000741,src:000001,op:flip1,pos:1118,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000741,src:000001,op:flip2,pos:1031,+cov (renamed from src/mint/afl-tests/id:000741,src:000001,op:flip2,pos:1031,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000742,src:000001,op:flip1,pos:1170,+cov (renamed from src/mint/afl-tests/id:000742,src:000001,op:flip1,pos:1170,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000742,src:000001,op:flip2,pos:1135,+cov (renamed from src/mint/afl-tests/id:000742,src:000001,op:flip2,pos:1135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000743,src:000001,op:flip1,pos:1205,+cov (renamed from src/mint/afl-tests/id:000743,src:000001,op:flip1,pos:1205,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000743,src:000001,op:flip2,pos:1286,+cov (renamed from src/mint/afl-tests/id:000743,src:000001,op:flip2,pos:1286,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000744,src:000001,op:flip1,pos:1301,+cov (renamed from src/mint/afl-tests/id:000744,src:000001,op:flip1,pos:1301,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000744,src:000001,op:flip2,pos:1655,+cov (renamed from src/mint/afl-tests/id:000744,src:000001,op:flip2,pos:1655,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000745,src:000001,op:flip1,pos:1369,+cov (renamed from src/mint/afl-tests/id:000745,src:000001,op:flip1,pos:1369,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000745,src:000001,op:flip4,pos:50,+cov (renamed from src/mint/afl-tests/id:000745,src:000001,op:flip4,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000746,src:000001,op:flip1,pos:1378,+cov (renamed from src/mint/afl-tests/id:000746,src:000001,op:flip1,pos:1378,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000746,src:000001,op:flip4,pos:122,+cov (renamed from src/mint/afl-tests/id:000746,src:000001,op:flip4,pos:122,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000747,src:000001,op:flip1,pos:1474,+cov (renamed from src/mint/afl-tests/id:000747,src:000001,op:flip1,pos:1474,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000747,src:000001,op:flip4,pos:351,+cov (renamed from src/mint/afl-tests/id:000747,src:000001,op:flip4,pos:351,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000748,src:000001,op:flip1,pos:1510,+cov (renamed from src/mint/afl-tests/id:000748,src:000001,op:flip1,pos:1510,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000748,src:000001,op:flip4,pos:569,+cov (renamed from src/mint/afl-tests/id:000748,src:000001,op:flip4,pos:569,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000749,src:000001,op:flip1,pos:1634 (renamed from src/mint/afl-tests/id:000749,src:000001,op:flip1,pos:1634)0
-rw-r--r--src/exchange/afl-tests/id:000749,src:000001,op:flip4,pos:788,+cov (renamed from src/mint/afl-tests/id:000749,src:000001,op:flip4,pos:788,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000750,src:000001,op:flip1,pos:1657,+cov (renamed from src/mint/afl-tests/id:000750,src:000001,op:flip1,pos:1657,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000750,src:000001,op:flip4,pos:1198,+cov (renamed from src/mint/afl-tests/id:000750,src:000001,op:flip4,pos:1198,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000751,src:000001,op:flip1,pos:1712,+cov (renamed from src/mint/afl-tests/id:000751,src:000001,op:flip1,pos:1712,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000751,src:000001,op:flip8,pos:67,+cov (renamed from src/mint/afl-tests/id:000751,src:000001,op:flip8,pos:67,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000752,src:000001,op:flip2,pos:21,+cov (renamed from src/mint/afl-tests/id:000752,src:000001,op:flip2,pos:21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000752,src:000001,op:flip8,pos:1661,+cov (renamed from src/mint/afl-tests/id:000752,src:000001,op:flip8,pos:1661,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000753,src:000001,op:flip16,pos:390,+cov (renamed from src/mint/afl-tests/id:000753,src:000001,op:flip16,pos:390,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000753,src:000001,op:flip2,pos:39,+cov (renamed from src/mint/afl-tests/id:000753,src:000001,op:flip2,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000754,src:000001,op:flip2,pos:105,+cov (renamed from src/mint/afl-tests/id:000754,src:000001,op:flip2,pos:105,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000754,src:000001,op:flip32,pos:339,+cov (renamed from src/mint/afl-tests/id:000754,src:000001,op:flip32,pos:339,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000755,src:000001,op:flip2,pos:890,+cov (renamed from src/mint/afl-tests/id:000755,src:000001,op:flip2,pos:890,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000755,src:000001,op:flip32,pos:975,+cov (renamed from src/mint/afl-tests/id:000755,src:000001,op:flip32,pos:975,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000756,src:000001,op:arith8,pos:10,val:-30,+cov (renamed from src/mint/afl-tests/id:000756,src:000001,op:arith8,pos:10,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000756,src:000001,op:flip2,pos:975,+cov (renamed from src/mint/afl-tests/id:000756,src:000001,op:flip2,pos:975,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000757,src:000001,op:arith8,pos:46,val:+9,+cov (renamed from src/mint/afl-tests/id:000757,src:000001,op:arith8,pos:46,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000757,src:000001,op:flip2,pos:1509,+cov (renamed from src/mint/afl-tests/id:000757,src:000001,op:flip2,pos:1509,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000758,src:000001,op:arith8,pos:72,val:+5,+cov (renamed from src/mint/afl-tests/id:000758,src:000001,op:arith8,pos:72,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000758,src:000001,op:flip2,pos:1662,+cov (renamed from src/mint/afl-tests/id:000758,src:000001,op:flip2,pos:1662,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000759,src:000001,op:flip4,pos:32,+cov (renamed from src/mint/afl-tests/id:000759,src:000001,op:flip4,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000759,src:000002,op:flip1,pos:30 (renamed from src/mint/afl-tests/id:000759,src:000002,op:flip1,pos:30)0
-rw-r--r--src/exchange/afl-tests/id:000760,src:000001,op:flip4,pos:300,+cov (renamed from src/mint/afl-tests/id:000760,src:000001,op:flip4,pos:300,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000760,src:000002,op:flip1,pos:50 (renamed from src/mint/afl-tests/id:000760,src:000002,op:flip1,pos:50)0
-rw-r--r--src/exchange/afl-tests/id:000761,src:000001,op:flip4,pos:457,+cov (renamed from src/mint/afl-tests/id:000761,src:000001,op:flip4,pos:457,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000761,src:000002,op:flip1,pos:50,+cov (renamed from src/mint/afl-tests/id:000761,src:000002,op:flip1,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000762,src:000001,op:flip4,pos:1507,+cov (renamed from src/mint/afl-tests/id:000762,src:000001,op:flip4,pos:1507,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000762,src:000002,op:flip1,pos:63 (renamed from src/mint/afl-tests/id:000762,src:000002,op:flip1,pos:63)0
-rw-r--r--src/exchange/afl-tests/id:000763,src:000001,op:flip4,pos:1549,+cov (renamed from src/mint/afl-tests/id:000763,src:000001,op:flip4,pos:1549,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000763,src:000002,op:flip1,pos:76 (renamed from src/mint/afl-tests/id:000763,src:000002,op:flip1,pos:76)0
-rw-r--r--src/exchange/afl-tests/id:000764,src:000001,op:flip4,pos:1577,+cov (renamed from src/mint/afl-tests/id:000764,src:000001,op:flip4,pos:1577,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000764,src:000002,op:flip1,pos:135 (renamed from src/mint/afl-tests/id:000764,src:000002,op:flip1,pos:135)0
-rw-r--r--src/exchange/afl-tests/id:000765,src:000001,op:flip8,pos:899,+cov (renamed from src/mint/afl-tests/id:000765,src:000001,op:flip8,pos:899,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000765,src:000002,op:flip1,pos:143,+cov (renamed from src/mint/afl-tests/id:000765,src:000002,op:flip1,pos:143,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000766,src:000001,op:flip8,pos:1457,+cov (renamed from src/mint/afl-tests/id:000766,src:000001,op:flip8,pos:1457,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000766,src:000002,op:flip4,pos:8,+cov (renamed from src/mint/afl-tests/id:000766,src:000002,op:flip4,pos:8,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000767,src:000001,op:flip32,pos:301,+cov (renamed from src/mint/afl-tests/id:000767,src:000001,op:flip32,pos:301,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000767,src:000002,op:flip4,pos:117,+cov (renamed from src/mint/afl-tests/id:000767,src:000002,op:flip4,pos:117,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000768,src:000001,op:arith8,pos:18,val:+11,+cov (renamed from src/mint/afl-tests/id:000768,src:000001,op:arith8,pos:18,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000768,src:000002,op:arith8,pos:11,val:-1,+cov (renamed from src/mint/afl-tests/id:000768,src:000002,op:arith8,pos:11,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000769,src:000001,op:arith8,pos:33,val:+17,+cov (renamed from src/mint/afl-tests/id:000769,src:000001,op:arith8,pos:33,val:+17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000769,src:000002,op:arith8,pos:20,val:+13,+cov (renamed from src/mint/afl-tests/id:000769,src:000002,op:arith8,pos:20,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000770,src:000002,op:arith8,pos:34,val:-6,+cov (renamed from src/mint/afl-tests/id:000770,src:000002,op:arith8,pos:34,val:-6,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000770,src:000002,op:flip1,pos:30 (renamed from src/mint/afl-tests/id:000770,src:000002,op:flip1,pos:30)0
-rw-r--r--src/exchange/afl-tests/id:000771,src:000002,op:arith8,pos:105,val:+35,+cov (renamed from src/mint/afl-tests/id:000771,src:000002,op:arith8,pos:105,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000771,src:000002,op:flip1,pos:45,+cov (renamed from src/mint/afl-tests/id:000771,src:000002,op:flip1,pos:45,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000772,src:000002,op:arith8,pos:109,val:-35 (renamed from src/mint/afl-tests/id:000772,src:000002,op:arith8,pos:109,val:-35)0
-rw-r--r--src/exchange/afl-tests/id:000772,src:000002,op:flip1,pos:50 (renamed from src/mint/afl-tests/id:000772,src:000002,op:flip1,pos:50)0
-rw-r--r--src/exchange/afl-tests/id:000773,src:000002,op:arith8,pos:131,val:+5,+cov (renamed from src/mint/afl-tests/id:000773,src:000002,op:arith8,pos:131,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000773,src:000002,op:flip1,pos:63 (renamed from src/mint/afl-tests/id:000773,src:000002,op:flip1,pos:63)0
-rw-r--r--src/exchange/afl-tests/id:000774,src:000002,op:arith8,pos:137,val:+9,+cov (renamed from src/mint/afl-tests/id:000774,src:000002,op:arith8,pos:137,val:+9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000774,src:000002,op:flip1,pos:76 (renamed from src/mint/afl-tests/id:000774,src:000002,op:flip1,pos:76)0
-rw-r--r--src/exchange/afl-tests/id:000775,src:000002,op:arith16,pos:55,val:-29,+cov (renamed from src/mint/afl-tests/id:000775,src:000002,op:arith16,pos:55,val:-29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000775,src:000002,op:flip1,pos:107,+cov (renamed from src/mint/afl-tests/id:000775,src:000002,op:flip1,pos:107,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000776,src:000002,op:flip1,pos:135 (renamed from src/mint/afl-tests/id:000776,src:000002,op:flip1,pos:135)0
-rw-r--r--src/exchange/afl-tests/id:000776,src:000002,op:int16,pos:27,val:+16,+cov (renamed from src/mint/afl-tests/id:000776,src:000002,op:int16,pos:27,val:+16,+cov)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000777,src:000002,op:flip2,pos:56,+cov (renamed from src/mint/afl-tests/id:000777,src:000002,op:flip2,pos:56,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000777,src:000002,op:int16,pos:96,val:+32 (renamed from src/mint/afl-tests/id:000777,src:000002,op:int16,pos:96,val:+32)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000778,src:000002,op:flip2,pos:113,+cov (renamed from src/mint/afl-tests/id:000778,src:000002,op:flip2,pos:113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000778,src:000002,op:int32,pos:53,val:be:+32767,+cov (renamed from src/mint/afl-tests/id:000778,src:000002,op:int32,pos:53,val:be:+32767,+cov)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000779,src:000002,op:ext_AO,pos:22,+cov (renamed from src/mint/afl-tests/id:000779,src:000002,op:ext_AO,pos:22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000779,src:000002,op:flip4,pos:15,+cov (renamed from src/mint/afl-tests/id:000779,src:000002,op:flip4,pos:15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000780,src:000002,op:arith8,pos:10,val:-7,+cov (renamed from src/mint/afl-tests/id:000780,src:000002,op:arith8,pos:10,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000780,src:000002,op:ext_AO,pos:130,+cov (renamed from src/mint/afl-tests/id:000780,src:000002,op:ext_AO,pos:130,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000781,src:000002,op:arith8,pos:29,val:+21,+cov (renamed from src/mint/afl-tests/id:000781,src:000002,op:arith8,pos:29,val:+21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000781,src:000002,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000781,src:000002,op:havoc,rep:8)0
-rw-r--r--src/exchange/afl-tests/id:000782,src:000002,op:arith8,pos:109,val:-35 (renamed from src/mint/afl-tests/id:000782,src:000002,op:arith8,pos:109,val:-35)0
-rw-r--r--src/exchange/afl-tests/id:000782,src:000002,op:havoc,rep:2 (renamed from src/mint/afl-tests/id:000782,src:000002,op:havoc,rep:2)0
-rw-r--r--src/exchange/afl-tests/id:000783,src:000002,op:arith8,pos:132,val:+34,+cov (renamed from src/mint/afl-tests/id:000783,src:000002,op:arith8,pos:132,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000783,src:000002,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000783,src:000002,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000784,src:000002,op:havoc,rep:64,+cov (renamed from src/mint/afl-tests/id:000784,src:000002,op:havoc,rep:64,+cov)bin95 -> 95 bytes
-rw-r--r--src/exchange/afl-tests/id:000784,src:000002,op:int16,pos:20,val:-129,+cov (renamed from src/mint/afl-tests/id:000784,src:000002,op:int16,pos:20,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000785,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000785,src:000002,op:havoc,rep:64)bin188 -> 188 bytes
-rw-r--r--src/exchange/afl-tests/id:000785,src:000002,op:int16,pos:82,val:+64,+cov (renamed from src/mint/afl-tests/id:000785,src:000002,op:int16,pos:82,val:+64,+cov)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000786,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000786,src:000002,op:havoc,rep:16)bin110 -> 110 bytes
-rw-r--r--src/exchange/afl-tests/id:000786,src:000002,op:int16,pos:96,val:+32 (renamed from src/mint/afl-tests/id:000786,src:000002,op:int16,pos:96,val:+32)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000787,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000787,src:000002,op:havoc,rep:64)bin241 -> 241 bytes
-rw-r--r--src/exchange/afl-tests/id:000787,src:000002,op:int16,pos:112,val:be:-128,+cov (renamed from src/mint/afl-tests/id:000787,src:000002,op:int16,pos:112,val:be:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000788,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000788,src:000002,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000788,src:000002,op:int32,pos:26,val:+65536,+cov (renamed from src/mint/afl-tests/id:000788,src:000002,op:int32,pos:26,val:+65536,+cov)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000789,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000789,src:000002,op:havoc,rep:16)bin187 -> 187 bytes
-rw-r--r--src/exchange/afl-tests/id:000789,src:000002,op:int32,pos:54,val:+32,+cov (renamed from src/mint/afl-tests/id:000789,src:000002,op:int32,pos:54,val:+32,+cov)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000790,src:000002,op:ext_AO,pos:95,+cov (renamed from src/mint/afl-tests/id:000790,src:000002,op:ext_AO,pos:95,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000790,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000790,src:000002,op:havoc,rep:64)bin182 -> 182 bytes
-rw-r--r--src/exchange/afl-tests/id:000791,src:000002,op:ext_AO,pos:98,+cov (renamed from src/mint/afl-tests/id:000791,src:000002,op:ext_AO,pos:98,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000791,src:000002,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000791,src:000002,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000792,src:000002,op:ext_AO,pos:130,+cov (renamed from src/mint/afl-tests/id:000792,src:000002,op:ext_AO,pos:130,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000792,src:000002,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000792,src:000002,op:havoc,rep:8)bin220 -> 220 bytes
-rw-r--r--src/exchange/afl-tests/id:000793,src:000002,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:000793,src:000002,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000793,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000793,src:000002,op:havoc,rep:64)bin107 -> 107 bytes
-rw-r--r--src/exchange/afl-tests/id:000794,src:000002,op:ext_AO,pos:138,+cov (renamed from src/mint/afl-tests/id:000794,src:000002,op:ext_AO,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000794,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000794,src:000002,op:havoc,rep:64)bin45 -> 45 bytes
-rw-r--r--src/exchange/afl-tests/id:000795,src:000002,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000795,src:000002,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000795,src:000002,op:havoc,rep:8 (renamed from src/mint/afl-tests/id:000795,src:000002,op:havoc,rep:8)bin177 -> 177 bytes
-rw-r--r--src/exchange/afl-tests/id:000796,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000796,src:000002,op:havoc,rep:16)bin129 -> 129 bytes
-rw-r--r--src/exchange/afl-tests/id:000796,src:000002,op:havoc,rep:32,+cov (renamed from src/mint/afl-tests/id:000796,src:000002,op:havoc,rep:32,+cov)bin109 -> 109 bytes
-rw-r--r--src/exchange/afl-tests/id:000797,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000797,src:000002,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000797,src:000002,op:havoc,rep:2 (renamed from src/mint/afl-tests/id:000797,src:000002,op:havoc,rep:2)0
-rw-r--r--src/exchange/afl-tests/id:000798,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000798,src:000002,op:havoc,rep:16)bin145 -> 145 bytes
-rw-r--r--src/exchange/afl-tests/id:000798,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000798,src:000002,op:havoc,rep:64)bin95 -> 95 bytes
-rw-r--r--src/exchange/afl-tests/id:000799,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000799,src:000002,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000799,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000799,src:000002,op:havoc,rep:64)0
-rw-r--r--src/exchange/afl-tests/id:000800,src:000002,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000800,src:000002,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000801,src:000002,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000801,src:000002,op:havoc,rep:128)bin135 -> 135 bytes
-rw-r--r--src/exchange/afl-tests/id:000801,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000801,src:000002,op:havoc,rep:64)bin201 -> 201 bytes
-rw-r--r--src/exchange/afl-tests/id:000802,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000802,src:000002,op:havoc,rep:16)bin168 -> 168 bytes
-rw-r--r--src/exchange/afl-tests/id:000802,src:000002,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000802,src:000002,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000803,src:000002,op:havoc,rep:128,+cov (renamed from src/mint/afl-tests/id:000803,src:000002,op:havoc,rep:128,+cov)bin106 -> 106 bytes
-rw-r--r--src/exchange/afl-tests/id:000803,src:000002,op:havoc,rep:2 (renamed from src/mint/afl-tests/id:000803,src:000002,op:havoc,rep:2)0
-rw-r--r--src/exchange/afl-tests/id:000804,src:000002,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000804,src:000002,op:havoc,rep:32)bin158 -> 158 bytes
-rw-r--r--src/exchange/afl-tests/id:000804,src:000002,op:havoc,rep:64 (renamed from src/mint/afl-tests/id:000804,src:000002,op:havoc,rep:64)0
-rw-r--r--src/exchange/afl-tests/id:000805,src:000002,op:havoc,rep:4 (renamed from src/mint/afl-tests/id:000805,src:000002,op:havoc,rep:4)0
-rw-r--r--src/exchange/afl-tests/id:000805,src:000003,op:flip1,pos:0,+cov (renamed from src/mint/afl-tests/id:000805,src:000003,op:flip1,pos:0,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000806,src:000002,op:havoc,rep:32 (renamed from src/mint/afl-tests/id:000806,src:000002,op:havoc,rep:32)bin191 -> 191 bytes
-rw-r--r--src/exchange/afl-tests/id:000806,src:000003,op:flip1,pos:13,+cov (renamed from src/mint/afl-tests/id:000806,src:000003,op:flip1,pos:13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000807,src:000002,op:havoc,rep:128 (renamed from src/mint/afl-tests/id:000807,src:000002,op:havoc,rep:128)bin202 -> 202 bytes
-rw-r--r--src/exchange/afl-tests/id:000807,src:000003,op:flip1,pos:18,+cov (renamed from src/mint/afl-tests/id:000807,src:000003,op:flip1,pos:18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000808,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000808,src:000002,op:havoc,rep:16)bin159 -> 159 bytes
-rw-r--r--src/exchange/afl-tests/id:000808,src:000003,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000808,src:000003,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000809,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000809,src:000002,op:havoc,rep:16)bin100 -> 100 bytes
-rw-r--r--src/exchange/afl-tests/id:000809,src:000003,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000809,src:000003,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000810,src:000002,op:havoc,rep:32,+cov (renamed from src/mint/afl-tests/id:000810,src:000002,op:havoc,rep:32,+cov)bin155 -> 155 bytes
-rw-r--r--src/exchange/afl-tests/id:000810,src:000003,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000810,src:000003,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000811,src:000002,op:havoc,rep:2,+cov (renamed from src/mint/afl-tests/id:000811,src:000002,op:havoc,rep:2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000811,src:000003,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000811,src:000003,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000812,src:000002,op:havoc,rep:4,+cov (renamed from src/mint/afl-tests/id:000812,src:000002,op:havoc,rep:4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000812,src:000003,op:flip1,pos:32,+cov (renamed from src/mint/afl-tests/id:000812,src:000003,op:flip1,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000813,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000813,src:000002,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000813,src:000003,op:flip1,pos:34,+cov (renamed from src/mint/afl-tests/id:000813,src:000003,op:flip1,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000814,src:000002,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000814,src:000002,op:havoc,rep:16,+cov)bin129 -> 129 bytes
-rw-r--r--src/exchange/afl-tests/id:000814,src:000003,op:flip1,pos:40,+cov (renamed from src/mint/afl-tests/id:000814,src:000003,op:flip1,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000815,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000815,src:000002,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000815,src:000003,op:flip1,pos:42,+cov (renamed from src/mint/afl-tests/id:000815,src:000003,op:flip1,pos:42,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000816,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000816,src:000002,op:havoc,rep:16)bin188 -> 188 bytes
-rw-r--r--src/exchange/afl-tests/id:000816,src:000003,op:flip1,pos:43,+cov (renamed from src/mint/afl-tests/id:000816,src:000003,op:flip1,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000817,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000817,src:000002,op:havoc,rep:16)0
-rw-r--r--src/exchange/afl-tests/id:000817,src:000003,op:flip1,pos:48,+cov (renamed from src/mint/afl-tests/id:000817,src:000003,op:flip1,pos:48,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000818,src:000002,op:havoc,rep:16 (renamed from src/mint/afl-tests/id:000818,src:000002,op:havoc,rep:16)bin105 -> 105 bytes
-rw-r--r--src/exchange/afl-tests/id:000818,src:000003,op:flip1,pos:50,+cov (renamed from src/mint/afl-tests/id:000818,src:000003,op:flip1,pos:50,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000819,src:000002,op:havoc,rep:16,+cov (renamed from src/mint/afl-tests/id:000819,src:000002,op:havoc,rep:16,+cov)bin167 -> 167 bytes
-rw-r--r--src/exchange/afl-tests/id:000819,src:000003,op:flip1,pos:61,+cov (renamed from src/mint/afl-tests/id:000819,src:000003,op:flip1,pos:61,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000820,src:000002,op:havoc,rep:2 (renamed from src/mint/afl-tests/id:000820,src:000002,op:havoc,rep:2)0
-rw-r--r--src/exchange/afl-tests/id:000820,src:000003,op:flip1,pos:67,+cov (renamed from src/mint/afl-tests/id:000820,src:000003,op:flip1,pos:67,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000821,src:000003,op:flip1,pos:18,+cov (renamed from src/mint/afl-tests/id:000821,src:000003,op:flip1,pos:18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000821,src:000003,op:flip1,pos:70 (renamed from src/mint/afl-tests/id:000821,src:000003,op:flip1,pos:70)0
-rw-r--r--src/exchange/afl-tests/id:000822,src:000003,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000822,src:000003,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000822,src:000003,op:flip1,pos:73,+cov (renamed from src/mint/afl-tests/id:000822,src:000003,op:flip1,pos:73,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000823,src:000003,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000823,src:000003,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000823,src:000003,op:flip1,pos:77,+cov (renamed from src/mint/afl-tests/id:000823,src:000003,op:flip1,pos:77,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000824,src:000003,op:flip1,pos:27,+cov (renamed from src/mint/afl-tests/id:000824,src:000003,op:flip1,pos:27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000824,src:000003,op:flip1,pos:83,+cov (renamed from src/mint/afl-tests/id:000824,src:000003,op:flip1,pos:83,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000825,src:000003,op:flip1,pos:28,+cov (renamed from src/mint/afl-tests/id:000825,src:000003,op:flip1,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000825,src:000003,op:flip1,pos:85,+cov (renamed from src/mint/afl-tests/id:000825,src:000003,op:flip1,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000826,src:000003,op:flip1,pos:28,+cov (renamed from src/mint/afl-tests/id:000826,src:000003,op:flip1,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000826,src:000003,op:flip1,pos:85,+cov (renamed from src/mint/afl-tests/id:000826,src:000003,op:flip1,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000827,src:000003,op:flip1,pos:29,+cov (renamed from src/mint/afl-tests/id:000827,src:000003,op:flip1,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000827,src:000003,op:flip1,pos:88,+cov (renamed from src/mint/afl-tests/id:000827,src:000003,op:flip1,pos:88,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000828,src:000003,op:flip1,pos:29,+cov (renamed from src/mint/afl-tests/id:000828,src:000003,op:flip1,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000828,src:000003,op:flip1,pos:89 (renamed from src/mint/afl-tests/id:000828,src:000003,op:flip1,pos:89)0
-rw-r--r--src/exchange/afl-tests/id:000829,src:000003,op:flip1,pos:29,+cov (renamed from src/mint/afl-tests/id:000829,src:000003,op:flip1,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000829,src:000003,op:flip1,pos:91,+cov (renamed from src/mint/afl-tests/id:000829,src:000003,op:flip1,pos:91,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000830,src:000003,op:flip1,pos:30,+cov (renamed from src/mint/afl-tests/id:000830,src:000003,op:flip1,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000830,src:000003,op:flip1,pos:93,+cov (renamed from src/mint/afl-tests/id:000830,src:000003,op:flip1,pos:93,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000831,src:000003,op:flip1,pos:32,+cov (renamed from src/mint/afl-tests/id:000831,src:000003,op:flip1,pos:32,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000831,src:000003,op:flip1,pos:93,+cov (renamed from src/mint/afl-tests/id:000831,src:000003,op:flip1,pos:93,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000832,src:000003,op:flip1,pos:34,+cov (renamed from src/mint/afl-tests/id:000832,src:000003,op:flip1,pos:34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000832,src:000003,op:flip1,pos:97,+cov (renamed from src/mint/afl-tests/id:000832,src:000003,op:flip1,pos:97,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000833,src:000003,op:flip1,pos:109,+cov (renamed from src/mint/afl-tests/id:000833,src:000003,op:flip1,pos:109,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000833,src:000003,op:flip1,pos:36,+cov (renamed from src/mint/afl-tests/id:000833,src:000003,op:flip1,pos:36,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000834,src:000003,op:flip1,pos:111,+cov (renamed from src/mint/afl-tests/id:000834,src:000003,op:flip1,pos:111,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000834,src:000003,op:flip1,pos:39 (renamed from src/mint/afl-tests/id:000834,src:000003,op:flip1,pos:39)0
-rw-r--r--src/exchange/afl-tests/id:000835,src:000003,op:flip1,pos:113,+cov (renamed from src/mint/afl-tests/id:000835,src:000003,op:flip1,pos:113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000835,src:000003,op:flip1,pos:39,+cov (renamed from src/mint/afl-tests/id:000835,src:000003,op:flip1,pos:39,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000836,src:000003,op:flip1,pos:114,+cov (renamed from src/mint/afl-tests/id:000836,src:000003,op:flip1,pos:114,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000836,src:000003,op:flip1,pos:40,+cov (renamed from src/mint/afl-tests/id:000836,src:000003,op:flip1,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000837,src:000003,op:flip1,pos:119,+cov (renamed from src/mint/afl-tests/id:000837,src:000003,op:flip1,pos:119,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000837,src:000003,op:flip1,pos:41,+cov (renamed from src/mint/afl-tests/id:000837,src:000003,op:flip1,pos:41,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000838,src:000003,op:flip1,pos:120,+cov (renamed from src/mint/afl-tests/id:000838,src:000003,op:flip1,pos:120,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000838,src:000003,op:flip1,pos:44,+cov (renamed from src/mint/afl-tests/id:000838,src:000003,op:flip1,pos:44,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000839,src:000003,op:flip1,pos:128,+cov (renamed from src/mint/afl-tests/id:000839,src:000003,op:flip1,pos:128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000839,src:000003,op:flip1,pos:46,+cov (renamed from src/mint/afl-tests/id:000839,src:000003,op:flip1,pos:46,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000840,src:000003,op:flip1,pos:141,+cov (renamed from src/mint/afl-tests/id:000840,src:000003,op:flip1,pos:141,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000840,src:000003,op:flip1,pos:48,+cov (renamed from src/mint/afl-tests/id:000840,src:000003,op:flip1,pos:48,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000841,src:000003,op:flip1,pos:145,+cov (renamed from src/mint/afl-tests/id:000841,src:000003,op:flip1,pos:145,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000841,src:000003,op:flip1,pos:48,+cov (renamed from src/mint/afl-tests/id:000841,src:000003,op:flip1,pos:48,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000842,src:000003,op:flip1,pos:147,+cov (renamed from src/mint/afl-tests/id:000842,src:000003,op:flip1,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000842,src:000003,op:flip1,pos:51 (renamed from src/mint/afl-tests/id:000842,src:000003,op:flip1,pos:51)0
-rw-r--r--src/exchange/afl-tests/id:000843,src:000003,op:flip1,pos:150,+cov (renamed from src/mint/afl-tests/id:000843,src:000003,op:flip1,pos:150,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000843,src:000003,op:flip1,pos:51,+cov (renamed from src/mint/afl-tests/id:000843,src:000003,op:flip1,pos:51,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000844,src:000003,op:flip1,pos:150,+cov (renamed from src/mint/afl-tests/id:000844,src:000003,op:flip1,pos:150,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000844,src:000003,op:flip1,pos:54,+cov (renamed from src/mint/afl-tests/id:000844,src:000003,op:flip1,pos:54,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000845,src:000003,op:flip1,pos:58,+cov (renamed from src/mint/afl-tests/id:000845,src:000003,op:flip1,pos:58,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000845,src:000003,op:flip2,pos:65,+cov (renamed from src/mint/afl-tests/id:000845,src:000003,op:flip2,pos:65,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000846,src:000003,op:flip1,pos:64,+cov (renamed from src/mint/afl-tests/id:000846,src:000003,op:flip1,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000846,src:000003,op:flip2,pos:84,+cov (renamed from src/mint/afl-tests/id:000846,src:000003,op:flip2,pos:84,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000847,src:000003,op:flip1,pos:64,+cov (renamed from src/mint/afl-tests/id:000847,src:000003,op:flip1,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000847,src:000003,op:flip2,pos:99,+cov (renamed from src/mint/afl-tests/id:000847,src:000003,op:flip2,pos:99,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000848,src:000003,op:flip1,pos:66,+cov (renamed from src/mint/afl-tests/id:000848,src:000003,op:flip1,pos:66,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000848,src:000003,op:flip2,pos:102,+cov (renamed from src/mint/afl-tests/id:000848,src:000003,op:flip2,pos:102,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000849,src:000003,op:flip1,pos:67,+cov (renamed from src/mint/afl-tests/id:000849,src:000003,op:flip1,pos:67,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000849,src:000003,op:flip2,pos:115,+cov (renamed from src/mint/afl-tests/id:000849,src:000003,op:flip2,pos:115,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000850,src:000003,op:flip1,pos:67,+cov (renamed from src/mint/afl-tests/id:000850,src:000003,op:flip1,pos:67,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000850,src:000003,op:flip2,pos:132,+cov (renamed from src/mint/afl-tests/id:000850,src:000003,op:flip2,pos:132,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000851,src:000003,op:flip1,pos:74,+cov (renamed from src/mint/afl-tests/id:000851,src:000003,op:flip1,pos:74,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000851,src:000003,op:flip2,pos:133,+cov (renamed from src/mint/afl-tests/id:000851,src:000003,op:flip2,pos:133,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000852,src:000003,op:flip1,pos:76,+cov (renamed from src/mint/afl-tests/id:000852,src:000003,op:flip1,pos:76,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000852,src:000003,op:flip2,pos:139,+cov (renamed from src/mint/afl-tests/id:000852,src:000003,op:flip2,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000853,src:000003,op:flip1,pos:78,+cov (renamed from src/mint/afl-tests/id:000853,src:000003,op:flip1,pos:78,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000853,src:000003,op:flip2,pos:139,+cov (renamed from src/mint/afl-tests/id:000853,src:000003,op:flip2,pos:139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000854,src:000003,op:flip2,pos:145,+cov (renamed from src/mint/afl-tests/id:000854,src:000003,op:flip2,pos:145,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000854,src:000003,op:flip2,pos:28,+cov (renamed from src/mint/afl-tests/id:000854,src:000003,op:flip2,pos:28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000855,src:000003,op:flip2,pos:147,+cov (renamed from src/mint/afl-tests/id:000855,src:000003,op:flip2,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000855,src:000003,op:flip2,pos:29,+cov (renamed from src/mint/afl-tests/id:000855,src:000003,op:flip2,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000856,src:000003,op:flip2,pos:151,+cov (renamed from src/mint/afl-tests/id:000856,src:000003,op:flip2,pos:151,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000856,src:000003,op:flip2,pos:29,+cov (renamed from src/mint/afl-tests/id:000856,src:000003,op:flip2,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000857,src:000003,op:flip2,pos:30,+cov (renamed from src/mint/afl-tests/id:000857,src:000003,op:flip2,pos:30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000857,src:000003,op:flip4,pos:110,+cov (renamed from src/mint/afl-tests/id:000857,src:000003,op:flip4,pos:110,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000858,src:000003,op:flip2,pos:35 (renamed from src/mint/afl-tests/id:000858,src:000003,op:flip2,pos:35)0
-rw-r--r--src/exchange/afl-tests/id:000858,src:000003,op:flip4,pos:120,+cov (renamed from src/mint/afl-tests/id:000858,src:000003,op:flip4,pos:120,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000859,src:000003,op:flip2,pos:37,+cov (renamed from src/mint/afl-tests/id:000859,src:000003,op:flip2,pos:37,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000859,src:000003,op:flip4,pos:123,+cov (renamed from src/mint/afl-tests/id:000859,src:000003,op:flip4,pos:123,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000860,src:000003,op:flip2,pos:41,+cov (renamed from src/mint/afl-tests/id:000860,src:000003,op:flip2,pos:41,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000860,src:000003,op:flip4,pos:124,+cov (renamed from src/mint/afl-tests/id:000860,src:000003,op:flip4,pos:124,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000861,src:000003,op:flip2,pos:42,+cov (renamed from src/mint/afl-tests/id:000861,src:000003,op:flip2,pos:42,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000861,src:000003,op:flip4,pos:124,+cov (renamed from src/mint/afl-tests/id:000861,src:000003,op:flip4,pos:124,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000862,src:000003,op:flip2,pos:43,+cov (renamed from src/mint/afl-tests/id:000862,src:000003,op:flip2,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000862,src:000003,op:flip4,pos:124,+cov (renamed from src/mint/afl-tests/id:000862,src:000003,op:flip4,pos:124,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000863,src:000003,op:flip2,pos:43,+cov (renamed from src/mint/afl-tests/id:000863,src:000003,op:flip2,pos:43,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000863,src:000003,op:flip4,pos:129,+cov (renamed from src/mint/afl-tests/id:000863,src:000003,op:flip4,pos:129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000864,src:000003,op:flip2,pos:43 (renamed from src/mint/afl-tests/id:000864,src:000003,op:flip2,pos:43)0
-rw-r--r--src/exchange/afl-tests/id:000864,src:000003,op:flip4,pos:138,+cov (renamed from src/mint/afl-tests/id:000864,src:000003,op:flip4,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000865,src:000003,op:flip2,pos:45,+cov (renamed from src/mint/afl-tests/id:000865,src:000003,op:flip2,pos:45,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000865,src:000003,op:flip8,pos:118,+cov (renamed from src/mint/afl-tests/id:000865,src:000003,op:flip8,pos:118,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000866,src:000003,op:flip2,pos:47,+cov (renamed from src/mint/afl-tests/id:000866,src:000003,op:flip2,pos:47,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000866,src:000003,op:flip8,pos:129,+cov (renamed from src/mint/afl-tests/id:000866,src:000003,op:flip8,pos:129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000867,src:000003,op:flip2,pos:49,+cov (renamed from src/mint/afl-tests/id:000867,src:000003,op:flip2,pos:49,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000867,src:000003,op:flip8,pos:130,+cov (renamed from src/mint/afl-tests/id:000867,src:000003,op:flip8,pos:130,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000868,src:000003,op:flip2,pos:54,+cov (renamed from src/mint/afl-tests/id:000868,src:000003,op:flip2,pos:54,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000868,src:000003,op:flip8,pos:132,+cov (renamed from src/mint/afl-tests/id:000868,src:000003,op:flip8,pos:132,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000869,src:000003,op:arith8,pos:17,val:-31 (renamed from src/mint/afl-tests/id:000869,src:000003,op:arith8,pos:17,val:-31)0
-rw-r--r--src/exchange/afl-tests/id:000869,src:000003,op:flip2,pos:62,+cov (renamed from src/mint/afl-tests/id:000869,src:000003,op:flip2,pos:62,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000870,src:000003,op:arith8,pos:27,val:+26,+cov (renamed from src/mint/afl-tests/id:000870,src:000003,op:arith8,pos:27,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000870,src:000003,op:flip2,pos:63,+cov (renamed from src/mint/afl-tests/id:000870,src:000003,op:flip2,pos:63,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000871,src:000003,op:arith8,pos:29,val:+11,+cov (renamed from src/mint/afl-tests/id:000871,src:000003,op:arith8,pos:29,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000871,src:000003,op:flip2,pos:68,+cov (renamed from src/mint/afl-tests/id:000871,src:000003,op:flip2,pos:68,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000872,src:000003,op:arith8,pos:29,val:+33 (renamed from src/mint/afl-tests/id:000872,src:000003,op:arith8,pos:29,val:+33)0
-rw-r--r--src/exchange/afl-tests/id:000873,src:000003,op:arith8,pos:30,val:-14,+cov (renamed from src/mint/afl-tests/id:000873,src:000003,op:arith8,pos:30,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000874,src:000003,op:arith8,pos:30,val:+28,+cov (renamed from src/mint/afl-tests/id:000874,src:000003,op:arith8,pos:30,val:+28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000875,src:000003,op:arith8,pos:35,val:+18,+cov (renamed from src/mint/afl-tests/id:000875,src:000003,op:arith8,pos:35,val:+18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000876,src:000003,op:arith8,pos:35,val:+26,+cov (renamed from src/mint/afl-tests/id:000876,src:000003,op:arith8,pos:35,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000877,src:000003,op:arith8,pos:36,val:-23,+cov (renamed from src/mint/afl-tests/id:000877,src:000003,op:arith8,pos:36,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000878,src:000003,op:arith8,pos:37,val:+20,+cov (renamed from src/mint/afl-tests/id:000878,src:000003,op:arith8,pos:37,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000879,src:000003,op:arith8,pos:37,val:-27,+cov (renamed from src/mint/afl-tests/id:000879,src:000003,op:arith8,pos:37,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000880,src:000003,op:arith8,pos:42,val:+31,+cov (renamed from src/mint/afl-tests/id:000880,src:000003,op:arith8,pos:42,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000881,src:000003,op:arith8,pos:46,val:+26,+cov (renamed from src/mint/afl-tests/id:000881,src:000003,op:arith8,pos:46,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000882,src:000003,op:arith8,pos:47,val:-35,+cov (renamed from src/mint/afl-tests/id:000882,src:000003,op:arith8,pos:47,val:-35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000883,src:000003,op:arith8,pos:49,val:-2,+cov (renamed from src/mint/afl-tests/id:000883,src:000003,op:arith8,pos:49,val:-2,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000884,src:000003,op:arith8,pos:51,val:+15,+cov (renamed from src/mint/afl-tests/id:000884,src:000003,op:arith8,pos:51,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000885,src:000003,op:arith8,pos:52,val:+11,+cov (renamed from src/mint/afl-tests/id:000885,src:000003,op:arith8,pos:52,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000886,src:000003,op:arith8,pos:61,val:+34 (renamed from src/mint/afl-tests/id:000886,src:000003,op:arith8,pos:61,val:+34)0
-rw-r--r--src/exchange/afl-tests/id:000887,src:000003,op:arith8,pos:62,val:-18,+cov (renamed from src/mint/afl-tests/id:000887,src:000003,op:arith8,pos:62,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000888,src:000003,op:arith8,pos:68,val:+21,+cov (renamed from src/mint/afl-tests/id:000888,src:000003,op:arith8,pos:68,val:+21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000889,src:000003,op:arith8,pos:71,val:-12,+cov (renamed from src/mint/afl-tests/id:000889,src:000003,op:arith8,pos:71,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000890,src:000003,op:arith8,pos:75,val:+15,+cov (renamed from src/mint/afl-tests/id:000890,src:000003,op:arith8,pos:75,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000891,src:000003,op:arith8,pos:77,val:+13,+cov (renamed from src/mint/afl-tests/id:000891,src:000003,op:arith8,pos:77,val:+13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000892,src:000003,op:arith8,pos:80,val:-17,+cov (renamed from src/mint/afl-tests/id:000892,src:000003,op:arith8,pos:80,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000893,src:000003,op:arith8,pos:80,val:-23,+cov (renamed from src/mint/afl-tests/id:000893,src:000003,op:arith8,pos:80,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000894,src:000003,op:arith8,pos:81,val:-9,+cov (renamed from src/mint/afl-tests/id:000894,src:000003,op:arith8,pos:81,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000895,src:000003,op:arith8,pos:83,val:-18,+cov (renamed from src/mint/afl-tests/id:000895,src:000003,op:arith8,pos:83,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000896,src:000003,op:arith8,pos:83,val:+25,+cov (renamed from src/mint/afl-tests/id:000896,src:000003,op:arith8,pos:83,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000897,src:000003,op:arith8,pos:84,val:-18,+cov (renamed from src/mint/afl-tests/id:000897,src:000003,op:arith8,pos:84,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000898,src:000003,op:arith8,pos:86,val:+11,+cov (renamed from src/mint/afl-tests/id:000898,src:000003,op:arith8,pos:86,val:+11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000899,src:000003,op:arith8,pos:86,val:+27,+cov (renamed from src/mint/afl-tests/id:000899,src:000003,op:arith8,pos:86,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000900,src:000003,op:arith8,pos:87,val:-23,+cov (renamed from src/mint/afl-tests/id:000900,src:000003,op:arith8,pos:87,val:-23,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000901,src:000003,op:arith8,pos:88,val:+35,+cov (renamed from src/mint/afl-tests/id:000901,src:000003,op:arith8,pos:88,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000902,src:000003,op:arith8,pos:89,val:-14,+cov (renamed from src/mint/afl-tests/id:000902,src:000003,op:arith8,pos:89,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000903,src:000003,op:arith8,pos:89,val:-33,+cov (renamed from src/mint/afl-tests/id:000903,src:000003,op:arith8,pos:89,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000904,src:000003,op:arith8,pos:90,val:-25,+cov (renamed from src/mint/afl-tests/id:000904,src:000003,op:arith8,pos:90,val:-25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000905,src:000003,op:arith8,pos:92,val:-25,+cov (renamed from src/mint/afl-tests/id:000905,src:000003,op:arith8,pos:92,val:-25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000906,src:000003,op:arith8,pos:96,val:+10,+cov (renamed from src/mint/afl-tests/id:000906,src:000003,op:arith8,pos:96,val:+10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000907,src:000003,op:arith8,pos:96,val:-19,+cov (renamed from src/mint/afl-tests/id:000907,src:000003,op:arith8,pos:96,val:-19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000908,src:000003,op:arith8,pos:96,val:+25,+cov (renamed from src/mint/afl-tests/id:000908,src:000003,op:arith8,pos:96,val:+25,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000909,src:000003,op:arith8,pos:97,val:-17,+cov (renamed from src/mint/afl-tests/id:000909,src:000003,op:arith8,pos:97,val:-17,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000910,src:000003,op:arith8,pos:100,val:-15,+cov (renamed from src/mint/afl-tests/id:000910,src:000003,op:arith8,pos:100,val:-15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000911,src:000003,op:arith8,pos:102,val:-27,+cov (renamed from src/mint/afl-tests/id:000911,src:000003,op:arith8,pos:102,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000912,src:000003,op:arith8,pos:102,val:-34,+cov (renamed from src/mint/afl-tests/id:000912,src:000003,op:arith8,pos:102,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000913,src:000003,op:arith8,pos:103,val:-9,+cov (renamed from src/mint/afl-tests/id:000913,src:000003,op:arith8,pos:103,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000914,src:000003,op:arith8,pos:103,val:+12 (renamed from src/mint/afl-tests/id:000914,src:000003,op:arith8,pos:103,val:+12)0
-rw-r--r--src/exchange/afl-tests/id:000915,src:000003,op:arith8,pos:103,val:+20,+cov (renamed from src/mint/afl-tests/id:000915,src:000003,op:arith8,pos:103,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000916,src:000003,op:arith8,pos:103,val:+22,+cov (renamed from src/mint/afl-tests/id:000916,src:000003,op:arith8,pos:103,val:+22,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000917,src:000003,op:arith8,pos:103,val:+29,+cov (renamed from src/mint/afl-tests/id:000917,src:000003,op:arith8,pos:103,val:+29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000918,src:000003,op:arith8,pos:103,val:+33,+cov (renamed from src/mint/afl-tests/id:000918,src:000003,op:arith8,pos:103,val:+33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000919,src:000003,op:arith8,pos:104,val:-10,+cov (renamed from src/mint/afl-tests/id:000919,src:000003,op:arith8,pos:104,val:-10,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000920,src:000003,op:arith8,pos:104,val:-12,+cov (renamed from src/mint/afl-tests/id:000920,src:000003,op:arith8,pos:104,val:-12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000921,src:000003,op:arith8,pos:104,val:+34,+cov (renamed from src/mint/afl-tests/id:000921,src:000003,op:arith8,pos:104,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000922,src:000003,op:arith8,pos:106,val:+5,+cov (renamed from src/mint/afl-tests/id:000922,src:000003,op:arith8,pos:106,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000923,src:000003,op:arith8,pos:106,val:-13,+cov (renamed from src/mint/afl-tests/id:000923,src:000003,op:arith8,pos:106,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000924,src:000003,op:arith8,pos:110,val:+15,+cov (renamed from src/mint/afl-tests/id:000924,src:000003,op:arith8,pos:110,val:+15,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000925,src:000003,op:arith8,pos:112,val:-13,+cov (renamed from src/mint/afl-tests/id:000925,src:000003,op:arith8,pos:112,val:-13,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000926,src:000003,op:arith8,pos:113,val:+34,+cov (renamed from src/mint/afl-tests/id:000926,src:000003,op:arith8,pos:113,val:+34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000927,src:000003,op:arith8,pos:114,val:+5,+cov (renamed from src/mint/afl-tests/id:000927,src:000003,op:arith8,pos:114,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000928,src:000003,op:arith8,pos:114,val:+26,+cov (renamed from src/mint/afl-tests/id:000928,src:000003,op:arith8,pos:114,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000929,src:000003,op:arith8,pos:114,val:-27,+cov (renamed from src/mint/afl-tests/id:000929,src:000003,op:arith8,pos:114,val:-27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000930,src:000003,op:arith8,pos:118,val:-28,+cov (renamed from src/mint/afl-tests/id:000930,src:000003,op:arith8,pos:118,val:-28,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000931,src:000003,op:arith8,pos:119,val:+12,+cov (renamed from src/mint/afl-tests/id:000931,src:000003,op:arith8,pos:119,val:+12,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000932,src:000003,op:arith8,pos:119,val:+27,+cov (renamed from src/mint/afl-tests/id:000932,src:000003,op:arith8,pos:119,val:+27,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000933,src:000003,op:arith8,pos:122,val:-4,+cov (renamed from src/mint/afl-tests/id:000933,src:000003,op:arith8,pos:122,val:-4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000934,src:000003,op:arith8,pos:122,val:-26,+cov (renamed from src/mint/afl-tests/id:000934,src:000003,op:arith8,pos:122,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000935,src:000003,op:arith8,pos:122,val:+35,+cov (renamed from src/mint/afl-tests/id:000935,src:000003,op:arith8,pos:122,val:+35,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000936,src:000003,op:arith8,pos:123,val:-11,+cov (renamed from src/mint/afl-tests/id:000936,src:000003,op:arith8,pos:123,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000937,src:000003,op:arith8,pos:124,val:-14,+cov (renamed from src/mint/afl-tests/id:000937,src:000003,op:arith8,pos:124,val:-14,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000938,src:000003,op:arith8,pos:128,val:+5,+cov (renamed from src/mint/afl-tests/id:000938,src:000003,op:arith8,pos:128,val:+5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000939,src:000003,op:arith8,pos:129,val:+21,+cov (renamed from src/mint/afl-tests/id:000939,src:000003,op:arith8,pos:129,val:+21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000940,src:000003,op:arith8,pos:133,val:-7,+cov (renamed from src/mint/afl-tests/id:000940,src:000003,op:arith8,pos:133,val:-7,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000941,src:000003,op:arith8,pos:133,val:+20,+cov (renamed from src/mint/afl-tests/id:000941,src:000003,op:arith8,pos:133,val:+20,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000942,src:000003,op:arith8,pos:135,val:-26,+cov (renamed from src/mint/afl-tests/id:000942,src:000003,op:arith8,pos:135,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000943,src:000003,op:arith8,pos:141,val:+1,+cov (renamed from src/mint/afl-tests/id:000943,src:000003,op:arith8,pos:141,val:+1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000944,src:000003,op:arith8,pos:143,val:-5,+cov (renamed from src/mint/afl-tests/id:000944,src:000003,op:arith8,pos:143,val:-5,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000945,src:000003,op:arith8,pos:145,val:+21,+cov (renamed from src/mint/afl-tests/id:000945,src:000003,op:arith8,pos:145,val:+21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000946,src:000003,op:arith8,pos:147,val:-9,+cov (renamed from src/mint/afl-tests/id:000946,src:000003,op:arith8,pos:147,val:-9,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000947,src:000003,op:arith8,pos:147,val:+31,+cov (renamed from src/mint/afl-tests/id:000947,src:000003,op:arith8,pos:147,val:+31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000948,src:000003,op:arith8,pos:148,val:+3,+cov (renamed from src/mint/afl-tests/id:000948,src:000003,op:arith8,pos:148,val:+3,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000949,src:000003,op:arith8,pos:148,val:-11,+cov (renamed from src/mint/afl-tests/id:000949,src:000003,op:arith8,pos:148,val:-11,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000950,src:000003,op:arith8,pos:149,val:-18,+cov (renamed from src/mint/afl-tests/id:000950,src:000003,op:arith8,pos:149,val:-18,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000951,src:000003,op:arith8,pos:151,val:-21,+cov (renamed from src/mint/afl-tests/id:000951,src:000003,op:arith8,pos:151,val:-21,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000952,src:000003,op:arith8,pos:151,val:+26,+cov (renamed from src/mint/afl-tests/id:000952,src:000003,op:arith8,pos:151,val:+26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000953,src:000003,op:arith8,pos:151,val:-30,+cov (renamed from src/mint/afl-tests/id:000953,src:000003,op:arith8,pos:151,val:-30,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000954,src:000003,op:arith16,pos:88,val:-16,+cov (renamed from src/mint/afl-tests/id:000954,src:000003,op:arith16,pos:88,val:-16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000955,src:000003,op:arith16,pos:109,val:-19,+cov (renamed from src/mint/afl-tests/id:000955,src:000003,op:arith16,pos:109,val:-19,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000956,src:000003,op:arith16,pos:109,val:-26,+cov (renamed from src/mint/afl-tests/id:000956,src:000003,op:arith16,pos:109,val:-26,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000957,src:000003,op:arith16,pos:109,val:-33,+cov (renamed from src/mint/afl-tests/id:000957,src:000003,op:arith16,pos:109,val:-33,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000958,src:000003,op:arith16,pos:121,val:-34,+cov (renamed from src/mint/afl-tests/id:000958,src:000003,op:arith16,pos:121,val:-34,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000959,src:000003,op:int8,pos:80,val:+16,+cov (renamed from src/mint/afl-tests/id:000959,src:000003,op:int8,pos:80,val:+16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000960,src:000003,op:int8,pos:83,val:+1,+cov (renamed from src/mint/afl-tests/id:000960,src:000003,op:int8,pos:83,val:+1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000961,src:000003,op:int8,pos:101,val:+64,+cov (renamed from src/mint/afl-tests/id:000961,src:000003,op:int8,pos:101,val:+64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000962,src:000003,op:int8,pos:120,val:-128,+cov (renamed from src/mint/afl-tests/id:000962,src:000003,op:int8,pos:120,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000963,src:000003,op:int8,pos:139,val:+16,+cov (renamed from src/mint/afl-tests/id:000963,src:000003,op:int8,pos:139,val:+16,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000964,src:000003,op:int16,pos:81,val:+127,+cov (renamed from src/mint/afl-tests/id:000964,src:000003,op:int16,pos:81,val:+127,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000965,src:000003,op:int16,pos:95,val:+1,+cov (renamed from src/mint/afl-tests/id:000965,src:000003,op:int16,pos:95,val:+1,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000966,src:000003,op:int16,pos:97,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000966,src:000003,op:int16,pos:97,val:be:+127,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000967,src:000003,op:int16,pos:98,val:+1,+cov (renamed from src/mint/afl-tests/id:000967,src:000003,op:int16,pos:98,val:+1,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000968,src:000003,op:int16,pos:100,val:-1,+cov (renamed from src/mint/afl-tests/id:000968,src:000003,op:int16,pos:100,val:-1,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000969,src:000003,op:int16,pos:102,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000969,src:000003,op:int16,pos:102,val:be:+127,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000970,src:000003,op:int16,pos:107,val:-128,+cov (renamed from src/mint/afl-tests/id:000970,src:000003,op:int16,pos:107,val:-128,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000971,src:000003,op:int16,pos:108,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000971,src:000003,op:int16,pos:108,val:be:+127,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000972,src:000003,op:int16,pos:109,val:be:+100,+cov (renamed from src/mint/afl-tests/id:000972,src:000003,op:int16,pos:109,val:be:+100,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000973,src:000003,op:int16,pos:125,val:+1000,+cov (renamed from src/mint/afl-tests/id:000973,src:000003,op:int16,pos:125,val:+1000,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000974,src:000003,op:int16,pos:137,val:be:+32,+cov (renamed from src/mint/afl-tests/id:000974,src:000003,op:int16,pos:137,val:be:+32,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000975,src:000003,op:int16,pos:150,val:be:+255,+cov (renamed from src/mint/afl-tests/id:000975,src:000003,op:int16,pos:150,val:be:+255,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000976,src:000003,op:int32,pos:1,val:be:+65535 (renamed from src/mint/afl-tests/id:000976,src:000003,op:int32,pos:1,val:be:+65535)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000977,src:000003,op:int32,pos:54,val:+32768,+cov (renamed from src/mint/afl-tests/id:000977,src:000003,op:int32,pos:54,val:+32768,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000978,src:000003,op:int32,pos:80,val:be:+32767,+cov (renamed from src/mint/afl-tests/id:000978,src:000003,op:int32,pos:80,val:be:+32767,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000979,src:000003,op:int32,pos:84,val:+2147483647 (renamed from src/mint/afl-tests/id:000979,src:000003,op:int32,pos:84,val:+2147483647)0
-rw-r--r--src/exchange/afl-tests/id:000980,src:000003,op:int32,pos:89,val:be:+4096,+cov (renamed from src/mint/afl-tests/id:000980,src:000003,op:int32,pos:89,val:be:+4096,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000981,src:000003,op:int32,pos:98,val:-129,+cov (renamed from src/mint/afl-tests/id:000981,src:000003,op:int32,pos:98,val:-129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000982,src:000003,op:int32,pos:99,val:-32769,+cov (renamed from src/mint/afl-tests/id:000982,src:000003,op:int32,pos:99,val:-32769,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000983,src:000003,op:int32,pos:99,val:+100663045,+cov (renamed from src/mint/afl-tests/id:000983,src:000003,op:int32,pos:99,val:+100663045,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000984,src:000003,op:int32,pos:101,val:+64,+cov (renamed from src/mint/afl-tests/id:000984,src:000003,op:int32,pos:101,val:+64,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000985,src:000003,op:int32,pos:102,val:be:+32,+cov (renamed from src/mint/afl-tests/id:000985,src:000003,op:int32,pos:102,val:be:+32,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000986,src:000003,op:int32,pos:105,val:be:+512,+cov (renamed from src/mint/afl-tests/id:000986,src:000003,op:int32,pos:105,val:be:+512,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000987,src:000003,op:int32,pos:106,val:+100,+cov (renamed from src/mint/afl-tests/id:000987,src:000003,op:int32,pos:106,val:+100,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000988,src:000003,op:int32,pos:109,val:-100663046,+cov (renamed from src/mint/afl-tests/id:000988,src:000003,op:int32,pos:109,val:-100663046,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000989,src:000003,op:int32,pos:120,val:+255,+cov (renamed from src/mint/afl-tests/id:000989,src:000003,op:int32,pos:120,val:+255,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000990,src:000003,op:int32,pos:121,val:+1000,+cov (renamed from src/mint/afl-tests/id:000990,src:000003,op:int32,pos:121,val:+1000,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000991,src:000003,op:int32,pos:121,val:-100663046,+cov (renamed from src/mint/afl-tests/id:000991,src:000003,op:int32,pos:121,val:-100663046,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000992,src:000003,op:int32,pos:121,val:be:+65535,+cov (renamed from src/mint/afl-tests/id:000992,src:000003,op:int32,pos:121,val:be:+65535,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000993,src:000003,op:int32,pos:130,val:+100663045,+cov (renamed from src/mint/afl-tests/id:000993,src:000003,op:int32,pos:130,val:+100663045,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000994,src:000003,op:int32,pos:135,val:be:+32,+cov (renamed from src/mint/afl-tests/id:000994,src:000003,op:int32,pos:135,val:be:+32,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000995,src:000003,op:int32,pos:136,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000995,src:000003,op:int32,pos:136,val:be:+127,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000996,src:000003,op:int32,pos:138,val:+1,+cov (renamed from src/mint/afl-tests/id:000996,src:000003,op:int32,pos:138,val:+1,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000997,src:000003,op:int32,pos:147,val:be:+127,+cov (renamed from src/mint/afl-tests/id:000997,src:000003,op:int32,pos:147,val:be:+127,+cov)bin154 -> 154 bytes
-rw-r--r--src/exchange/afl-tests/id:000998,src:000003,op:ext_AO,pos:29,+cov (renamed from src/mint/afl-tests/id:000998,src:000003,op:ext_AO,pos:29,+cov)0
-rw-r--r--src/exchange/afl-tests/id:000999,src:000003,op:ext_AO,pos:31,+cov (renamed from src/mint/afl-tests/id:000999,src:000003,op:ext_AO,pos:31,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001000,src:000003,op:ext_AO,pos:37,+cov (renamed from src/mint/afl-tests/id:001000,src:000003,op:ext_AO,pos:37,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001001,src:000003,op:ext_AO,pos:40,+cov (renamed from src/mint/afl-tests/id:001001,src:000003,op:ext_AO,pos:40,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001002,src:000003,op:ext_AO,pos:44,+cov (renamed from src/mint/afl-tests/id:001002,src:000003,op:ext_AO,pos:44,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001003,src:000003,op:ext_AO,pos:44,+cov (renamed from src/mint/afl-tests/id:001003,src:000003,op:ext_AO,pos:44,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001004,src:000003,op:ext_AO,pos:51,+cov (renamed from src/mint/afl-tests/id:001004,src:000003,op:ext_AO,pos:51,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001005,src:000003,op:ext_AO,pos:54,+cov (renamed from src/mint/afl-tests/id:001005,src:000003,op:ext_AO,pos:54,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001006,src:000003,op:ext_AO,pos:55,+cov (renamed from src/mint/afl-tests/id:001006,src:000003,op:ext_AO,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001007,src:000003,op:ext_AO,pos:61,+cov (renamed from src/mint/afl-tests/id:001007,src:000003,op:ext_AO,pos:61,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001008,src:000003,op:ext_AO,pos:64,+cov (renamed from src/mint/afl-tests/id:001008,src:000003,op:ext_AO,pos:64,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001009,src:000003,op:ext_AO,pos:66,+cov (renamed from src/mint/afl-tests/id:001009,src:000003,op:ext_AO,pos:66,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001010,src:000003,op:ext_AO,pos:67,+cov (renamed from src/mint/afl-tests/id:001010,src:000003,op:ext_AO,pos:67,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001011,src:000003,op:ext_AO,pos:71,+cov (renamed from src/mint/afl-tests/id:001011,src:000003,op:ext_AO,pos:71,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001012,src:000003,op:ext_AO,pos:80,+cov (renamed from src/mint/afl-tests/id:001012,src:000003,op:ext_AO,pos:80,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001013,src:000003,op:ext_AO,pos:84,+cov (renamed from src/mint/afl-tests/id:001013,src:000003,op:ext_AO,pos:84,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001014,src:000003,op:ext_AO,pos:84,+cov (renamed from src/mint/afl-tests/id:001014,src:000003,op:ext_AO,pos:84,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001015,src:000003,op:ext_AO,pos:85,+cov (renamed from src/mint/afl-tests/id:001015,src:000003,op:ext_AO,pos:85,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001016,src:000003,op:ext_AO,pos:86,+cov (renamed from src/mint/afl-tests/id:001016,src:000003,op:ext_AO,pos:86,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001017,src:000003,op:ext_AO,pos:89,+cov (renamed from src/mint/afl-tests/id:001017,src:000003,op:ext_AO,pos:89,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001018,src:000003,op:ext_AO,pos:90,+cov (renamed from src/mint/afl-tests/id:001018,src:000003,op:ext_AO,pos:90,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001019,src:000003,op:ext_AO,pos:90,+cov (renamed from src/mint/afl-tests/id:001019,src:000003,op:ext_AO,pos:90,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001020,src:000003,op:ext_AO,pos:101,+cov (renamed from src/mint/afl-tests/id:001020,src:000003,op:ext_AO,pos:101,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001021,src:000003,op:ext_AO,pos:102,+cov (renamed from src/mint/afl-tests/id:001021,src:000003,op:ext_AO,pos:102,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001022,src:000003,op:ext_AO,pos:103,+cov (renamed from src/mint/afl-tests/id:001022,src:000003,op:ext_AO,pos:103,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001023,src:000003,op:ext_AO,pos:106,+cov (renamed from src/mint/afl-tests/id:001023,src:000003,op:ext_AO,pos:106,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001024,src:000003,op:ext_AO,pos:107,+cov (renamed from src/mint/afl-tests/id:001024,src:000003,op:ext_AO,pos:107,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001025,src:000003,op:ext_AO,pos:109,+cov (renamed from src/mint/afl-tests/id:001025,src:000003,op:ext_AO,pos:109,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001026,src:000003,op:ext_AO,pos:109,+cov (renamed from src/mint/afl-tests/id:001026,src:000003,op:ext_AO,pos:109,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001027,src:000003,op:ext_AO,pos:113,+cov (renamed from src/mint/afl-tests/id:001027,src:000003,op:ext_AO,pos:113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001028,src:000003,op:ext_AO,pos:117,+cov (renamed from src/mint/afl-tests/id:001028,src:000003,op:ext_AO,pos:117,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001029,src:000003,op:ext_AO,pos:122,+cov (renamed from src/mint/afl-tests/id:001029,src:000003,op:ext_AO,pos:122,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001030,src:000003,op:ext_AO,pos:122,+cov (renamed from src/mint/afl-tests/id:001030,src:000003,op:ext_AO,pos:122,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001031,src:000003,op:ext_AO,pos:124,+cov (renamed from src/mint/afl-tests/id:001031,src:000003,op:ext_AO,pos:124,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001032,src:000003,op:ext_AO,pos:125,+cov (renamed from src/mint/afl-tests/id:001032,src:000003,op:ext_AO,pos:125,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001033,src:000003,op:ext_AO,pos:125,+cov (renamed from src/mint/afl-tests/id:001033,src:000003,op:ext_AO,pos:125,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001034,src:000003,op:ext_AO,pos:126,+cov (renamed from src/mint/afl-tests/id:001034,src:000003,op:ext_AO,pos:126,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001035,src:000003,op:ext_AO,pos:126,+cov (renamed from src/mint/afl-tests/id:001035,src:000003,op:ext_AO,pos:126,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001036,src:000003,op:ext_AO,pos:129,+cov (renamed from src/mint/afl-tests/id:001036,src:000003,op:ext_AO,pos:129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001037,src:000003,op:ext_AO,pos:129,+cov (renamed from src/mint/afl-tests/id:001037,src:000003,op:ext_AO,pos:129,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001038,src:000003,op:ext_AO,pos:130,+cov (renamed from src/mint/afl-tests/id:001038,src:000003,op:ext_AO,pos:130,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001039,src:000003,op:ext_AO,pos:135,+cov (renamed from src/mint/afl-tests/id:001039,src:000003,op:ext_AO,pos:135,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001040,src:000003,op:ext_AO,pos:136,+cov (renamed from src/mint/afl-tests/id:001040,src:000003,op:ext_AO,pos:136,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001041,src:000003,op:ext_AO,pos:140,+cov (renamed from src/mint/afl-tests/id:001041,src:000003,op:ext_AO,pos:140,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001042,src:000003,op:ext_AO,pos:142,+cov (renamed from src/mint/afl-tests/id:001042,src:000003,op:ext_AO,pos:142,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001043,src:000003,op:ext_AO,pos:142,+cov (renamed from src/mint/afl-tests/id:001043,src:000003,op:ext_AO,pos:142,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001044,src:000003,op:ext_AO,pos:145,+cov (renamed from src/mint/afl-tests/id:001044,src:000003,op:ext_AO,pos:145,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001045,src:000003,op:ext_AO,pos:147,+cov (renamed from src/mint/afl-tests/id:001045,src:000003,op:ext_AO,pos:147,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001046,src:000003,op:ext_AO,pos:149,+cov (renamed from src/mint/afl-tests/id:001046,src:000003,op:ext_AO,pos:149,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001047,src:000004,op:flip1,pos:0,+cov (renamed from src/mint/afl-tests/id:001047,src:000004,op:flip1,pos:0,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001048,src:000004,op:flip1,pos:4,+cov (renamed from src/mint/afl-tests/id:001048,src:000004,op:flip1,pos:4,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001049,src:000004,op:flip1,pos:4 (renamed from src/mint/afl-tests/id:001049,src:000004,op:flip1,pos:4)bin34273 -> 34273 bytes
-rw-r--r--src/exchange/afl-tests/id:001050,src:000004,op:flip1,pos:18 (renamed from src/mint/afl-tests/id:001050,src:000004,op:flip1,pos:18)bin34273 -> 34273 bytes
-rw-r--r--src/exchange/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov (renamed from src/mint/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001052,src:000004,op:flip1,pos:59 (renamed from src/mint/afl-tests/id:001052,src:000004,op:flip1,pos:59)0
-rw-r--r--src/exchange/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov (renamed from src/mint/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001054,src:000004,op:flip1,pos:89 (renamed from src/mint/afl-tests/id:001054,src:000004,op:flip1,pos:89)0
-rw-r--r--src/exchange/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov (renamed from src/mint/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001056,src:000004,op:flip1,pos:108 (renamed from src/mint/afl-tests/id:001056,src:000004,op:flip1,pos:108)0
-rw-r--r--src/exchange/afl-tests/id:001057,src:000004,op:flip1,pos:108 (renamed from src/mint/afl-tests/id:001057,src:000004,op:flip1,pos:108)0
-rw-r--r--src/exchange/afl-tests/id:001058,src:000004,op:flip1,pos:110 (renamed from src/mint/afl-tests/id:001058,src:000004,op:flip1,pos:110)0
-rw-r--r--src/exchange/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov (renamed from src/mint/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001060,src:000004,op:flip1,pos:112 (renamed from src/mint/afl-tests/id:001060,src:000004,op:flip1,pos:112)0
-rw-r--r--src/exchange/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov (renamed from src/mint/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov (renamed from src/mint/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov (renamed from src/mint/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov (renamed from src/mint/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov (renamed from src/mint/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov (renamed from src/mint/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov (renamed from src/mint/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001068,src:000004,op:flip1,pos:1150 (renamed from src/mint/afl-tests/id:001068,src:000004,op:flip1,pos:1150)0
-rw-r--r--src/exchange/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov (renamed from src/mint/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001070,src:000004,op:flip1,pos:1649 (renamed from src/mint/afl-tests/id:001070,src:000004,op:flip1,pos:1649)0
-rw-r--r--src/exchange/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov (renamed from src/mint/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001072,src:000004,op:flip1,pos:2148 (renamed from src/mint/afl-tests/id:001072,src:000004,op:flip1,pos:2148)0
-rw-r--r--src/exchange/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov (renamed from src/mint/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001074,src:000004,op:flip1,pos:2647 (renamed from src/mint/afl-tests/id:001074,src:000004,op:flip1,pos:2647)0
-rw-r--r--src/exchange/afl-tests/id:001075,src:000004,op:flip1,pos:3146 (renamed from src/mint/afl-tests/id:001075,src:000004,op:flip1,pos:3146)0
-rw-r--r--src/exchange/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov (renamed from src/mint/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001077,src:000004,op:flip1,pos:3645 (renamed from src/mint/afl-tests/id:001077,src:000004,op:flip1,pos:3645)0
-rw-r--r--src/exchange/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov (renamed from src/mint/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001079,src:000004,op:flip1,pos:4144 (renamed from src/mint/afl-tests/id:001079,src:000004,op:flip1,pos:4144)0
-rw-r--r--src/exchange/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov (renamed from src/mint/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov (renamed from src/mint/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov (renamed from src/mint/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov (renamed from src/mint/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov (renamed from src/mint/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov (renamed from src/mint/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001086,src:000004,op:flip1,pos:5362 (renamed from src/mint/afl-tests/id:001086,src:000004,op:flip1,pos:5362)0
-rw-r--r--src/exchange/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov (renamed from src/mint/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001088,src:000004,op:flip1,pos:6639 (renamed from src/mint/afl-tests/id:001088,src:000004,op:flip1,pos:6639)0
-rw-r--r--src/exchange/afl-tests/id:001089,src:000004,op:flip1,pos:7138 (renamed from src/mint/afl-tests/id:001089,src:000004,op:flip1,pos:7138)0
-rw-r--r--src/exchange/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov (renamed from src/mint/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001091,src:000004,op:flip1,pos:8136 (renamed from src/mint/afl-tests/id:001091,src:000004,op:flip1,pos:8136)0
-rw-r--r--src/exchange/afl-tests/id:001092,src:000004,op:flip1,pos:8636 (renamed from src/mint/afl-tests/id:001092,src:000004,op:flip1,pos:8636)0
-rw-r--r--src/exchange/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov (renamed from src/mint/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001094,src:000004,op:flip1,pos:8712 (renamed from src/mint/afl-tests/id:001094,src:000004,op:flip1,pos:8712)0
-rw-r--r--src/exchange/afl-tests/id:001095,src:000004,op:flip1,pos:8768 (renamed from src/mint/afl-tests/id:001095,src:000004,op:flip1,pos:8768)0
-rw-r--r--src/exchange/afl-tests/id:001096,src:000004,op:flip1,pos:8825 (renamed from src/mint/afl-tests/id:001096,src:000004,op:flip1,pos:8825)0
-rw-r--r--src/exchange/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov (renamed from src/mint/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov (renamed from src/mint/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov (renamed from src/mint/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov (renamed from src/mint/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov (renamed from src/mint/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov (renamed from src/mint/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov (renamed from src/mint/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov (renamed from src/mint/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov (renamed from src/mint/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov (renamed from src/mint/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001107,src:000004,op:flip1,pos:10417 (renamed from src/mint/afl-tests/id:001107,src:000004,op:flip1,pos:10417)0
-rw-r--r--src/exchange/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov (renamed from src/mint/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001109,src:000004,op:flip1,pos:10639 (renamed from src/mint/afl-tests/id:001109,src:000004,op:flip1,pos:10639)0
-rw-r--r--src/exchange/afl-tests/id:001110,src:000004,op:flip1,pos:10846 (renamed from src/mint/afl-tests/id:001110,src:000004,op:flip1,pos:10846)0
-rw-r--r--src/exchange/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov (renamed from src/mint/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001112,src:000004,op:flip1,pos:11055 (renamed from src/mint/afl-tests/id:001112,src:000004,op:flip1,pos:11055)0
-rw-r--r--src/exchange/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov (renamed from src/mint/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001114,src:000004,op:flip1,pos:11262 (renamed from src/mint/afl-tests/id:001114,src:000004,op:flip1,pos:11262)0
-rw-r--r--src/exchange/afl-tests/id:001115,src:000004,op:flip1,pos:11471 (renamed from src/mint/afl-tests/id:001115,src:000004,op:flip1,pos:11471)0
-rw-r--r--src/exchange/afl-tests/id:001116,src:000004,op:flip1,pos:11887 (renamed from src/mint/afl-tests/id:001116,src:000004,op:flip1,pos:11887)0
-rw-r--r--src/exchange/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov (renamed from src/mint/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001118,src:000004,op:flip1,pos:12094 (renamed from src/mint/afl-tests/id:001118,src:000004,op:flip1,pos:12094)0
-rw-r--r--src/exchange/afl-tests/id:001119,src:000004,op:flip1,pos:12302 (renamed from src/mint/afl-tests/id:001119,src:000004,op:flip1,pos:12302)0
-rw-r--r--src/exchange/afl-tests/id:001120,src:000004,op:flip1,pos:12511 (renamed from src/mint/afl-tests/id:001120,src:000004,op:flip1,pos:12511)0
-rw-r--r--src/exchange/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov (renamed from src/mint/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov (renamed from src/mint/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001123,src:000004,op:flip1,pos:13342 (renamed from src/mint/afl-tests/id:001123,src:000004,op:flip1,pos:13342)0
-rw-r--r--src/exchange/afl-tests/id:001124,src:000004,op:flip1,pos:13550 (renamed from src/mint/afl-tests/id:001124,src:000004,op:flip1,pos:13550)0
-rw-r--r--src/exchange/afl-tests/id:001125,src:000004,op:flip1,pos:13758 (renamed from src/mint/afl-tests/id:001125,src:000004,op:flip1,pos:13758)0
-rw-r--r--src/exchange/afl-tests/id:001126,src:000004,op:flip1,pos:13968 (renamed from src/mint/afl-tests/id:001126,src:000004,op:flip1,pos:13968)0
-rw-r--r--src/exchange/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov (renamed from src/mint/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov (renamed from src/mint/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001129,src:000004,op:flip1,pos:14603 (renamed from src/mint/afl-tests/id:001129,src:000004,op:flip1,pos:14603)0
-rw-r--r--src/exchange/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov (renamed from src/mint/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov (renamed from src/mint/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov (renamed from src/mint/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov (renamed from src/mint/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001134,src:000004,op:flip1,pos:17507 (renamed from src/mint/afl-tests/id:001134,src:000004,op:flip1,pos:17507)0
-rw-r--r--src/exchange/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov (renamed from src/mint/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov (renamed from src/mint/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov (renamed from src/mint/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov (renamed from src/mint/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov (renamed from src/mint/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov (renamed from src/mint/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov (renamed from src/mint/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov (renamed from src/mint/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001143,src:000004,op:flip1,pos:21044 (renamed from src/mint/afl-tests/id:001143,src:000004,op:flip1,pos:21044)0
-rw-r--r--src/exchange/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov (renamed from src/mint/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov (renamed from src/mint/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov (renamed from src/mint/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov (renamed from src/mint/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov (renamed from src/mint/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov (renamed from src/mint/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov (renamed from src/mint/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov (renamed from src/mint/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov (renamed from src/mint/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov (renamed from src/mint/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov (renamed from src/mint/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov (renamed from src/mint/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov (renamed from src/mint/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov (renamed from src/mint/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov (renamed from src/mint/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov (renamed from src/mint/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov (renamed from src/mint/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001161,src:000004,op:flip2,pos:108 (renamed from src/mint/afl-tests/id:001161,src:000004,op:flip2,pos:108)0
-rw-r--r--src/exchange/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov (renamed from src/mint/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov (renamed from src/mint/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov (renamed from src/mint/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov (renamed from src/mint/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov (renamed from src/mint/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov (renamed from src/mint/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov (renamed from src/mint/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov (renamed from src/mint/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov (renamed from src/mint/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov (renamed from src/mint/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov (renamed from src/mint/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov (renamed from src/mint/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov (renamed from src/mint/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov (renamed from src/mint/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov (renamed from src/mint/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov (renamed from src/mint/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov (renamed from src/mint/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov (renamed from src/mint/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov (renamed from src/mint/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov (renamed from src/mint/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov (renamed from src/mint/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov (renamed from src/mint/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov (renamed from src/mint/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov (renamed from src/mint/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov (renamed from src/mint/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov (renamed from src/mint/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov (renamed from src/mint/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov (renamed from src/mint/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov (renamed from src/mint/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov (renamed from src/mint/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov (renamed from src/mint/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov (renamed from src/mint/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov (renamed from src/mint/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov (renamed from src/mint/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov (renamed from src/mint/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov (renamed from src/mint/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov (renamed from src/mint/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov (renamed from src/mint/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov (renamed from src/mint/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov (renamed from src/mint/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov (renamed from src/mint/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov (renamed from src/mint/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov (renamed from src/mint/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov (renamed from src/mint/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov (renamed from src/mint/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov (renamed from src/mint/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov (renamed from src/mint/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov (renamed from src/mint/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov (renamed from src/mint/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov (renamed from src/mint/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov (renamed from src/mint/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov (renamed from src/mint/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov (renamed from src/mint/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov (renamed from src/mint/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov (renamed from src/mint/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov (renamed from src/mint/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov (renamed from src/mint/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov (renamed from src/mint/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov (renamed from src/mint/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov (renamed from src/mint/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov (renamed from src/mint/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov (renamed from src/mint/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov (renamed from src/mint/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov (renamed from src/mint/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov (renamed from src/mint/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov (renamed from src/mint/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov (renamed from src/mint/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov (renamed from src/mint/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov (renamed from src/mint/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov (renamed from src/mint/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov (renamed from src/mint/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov (renamed from src/mint/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov (renamed from src/mint/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov (renamed from src/mint/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov (renamed from src/mint/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov (renamed from src/mint/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov (renamed from src/mint/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov (renamed from src/mint/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov (renamed from src/mint/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov (renamed from src/mint/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov (renamed from src/mint/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov (renamed from src/mint/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov (renamed from src/mint/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov (renamed from src/mint/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov)0
-rw-r--r--src/exchange/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov (renamed from src/mint/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov)0
-rw-r--r--src/exchange/taler-exchange-aggregator.c914
-rw-r--r--src/exchange/taler-exchange-httpd.c749
-rw-r--r--src/exchange/taler-exchange-httpd.h128
-rw-r--r--src/exchange/taler-exchange-httpd_admin.c164
-rw-r--r--src/exchange/taler-exchange-httpd_admin.h46
-rw-r--r--src/exchange/taler-exchange-httpd_db.c1900
-rw-r--r--src/exchange/taler-exchange-httpd_db.h230
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c281
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.h54
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c1011
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.h163
-rw-r--r--src/exchange/taler-exchange-httpd_mhd.c152
-rw-r--r--src/exchange/taler-exchange-httpd_mhd.h111
-rw-r--r--src/exchange/taler-exchange-httpd_parsing.c1137
-rw-r--r--src/exchange/taler-exchange-httpd_parsing.h408
-rw-r--r--src/exchange/taler-exchange-httpd_refresh.c911
-rw-r--r--src/exchange/taler-exchange-httpd_refresh.h94
-rw-r--r--src/exchange/taler-exchange-httpd_reserve.c186
-rw-r--r--src/exchange/taler-exchange-httpd_reserve.h73
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c1177
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h469
-rw-r--r--src/exchange/taler-exchange-httpd_test.c621
-rw-r--r--src/exchange/taler-exchange-httpd_test.h225
-rw-r--r--src/exchange/taler-exchange-httpd_tracking.c165
-rw-r--r--src/exchange/taler-exchange-httpd_tracking.h65
-rw-r--r--src/exchange/taler-exchange-httpd_validation.c231
-rw-r--r--src/exchange/taler-exchange-httpd_validation.h76
-rw-r--r--src/exchange/taler-exchange-httpd_wire.c220
-rw-r--r--src/exchange/taler-exchange-httpd_wire.h82
-rw-r--r--src/exchange/test-exchange-home/master.priv (renamed from src/mint/test-mint-home/master.priv)0
-rw-r--r--src/exchange/test_taler_exchange_httpd.data48
-rwxr-xr-xsrc/exchange/test_taler_exchange_httpd.sh35
-rw-r--r--src/exchange/test_taler_exchange_httpd_afl.sh41
-rw-r--r--src/exchangedb/Makefile.am110
-rw-r--r--src/exchangedb/exchangedb_keyio.c558
-rw-r--r--src/exchangedb/exchangedb_plugin.c87
-rw-r--r--src/exchangedb/perf_taler_exchangedb.c358
-rw-r--r--src/exchangedb/perf_taler_exchangedb_init.c622
-rw-r--r--src/exchangedb/perf_taler_exchangedb_init.h257
-rw-r--r--src/exchangedb/perf_taler_exchangedb_interpreter.c1998
-rw-r--r--src/exchangedb/perf_taler_exchangedb_interpreter.h1319
-rw-r--r--src/exchangedb/perf_taler_exchangedb_values.h25
-rw-r--r--src/exchangedb/plugin_exchangedb_common.c162
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c4295
-rw-r--r--src/exchangedb/test-exchange-db-postgres.conf8
-rw-r--r--src/exchangedb/test_exchangedb.c907
-rw-r--r--src/exchangedb/test_exchangedb_deposits.c152
-rw-r--r--src/exchangedb/test_exchangedb_keyio.c85
-rw-r--r--src/exchangedb/test_perf_taler_exchangedb.c182
-rw-r--r--src/include/Makefile.am6
-rw-r--r--src/include/taler_crypto_lib.h24
-rw-r--r--src/include/taler_exchange_service.h1220
-rw-r--r--src/include/taler_exchangedb_lib.h291
-rw-r--r--src/include/taler_exchangedb_plugin.h1431
-rw-r--r--src/include/taler_mint_service.h1220
-rw-r--r--src/include/taler_mintdb_lib.h291
-rw-r--r--src/include/taler_mintdb_plugin.h1431
-rw-r--r--src/include/taler_signatures.h200
-rw-r--r--src/mint-lib/Makefile.am62
-rw-r--r--src/mint-lib/afl-generate.sh34
-rw-r--r--src/mint-lib/mint_api_admin.c254
-rw-r--r--src/mint-lib/mint_api_common.c194
-rw-r--r--src/mint-lib/mint_api_common.h41
-rw-r--r--src/mint-lib/mint_api_context.c537
-rw-r--r--src/mint-lib/mint_api_context.h169
-rw-r--r--src/mint-lib/mint_api_deposit.c569
-rw-r--r--src/mint-lib/mint_api_deposit_wtid.c379
-rw-r--r--src/mint-lib/mint_api_handle.c902
-rw-r--r--src/mint-lib/mint_api_handle.h59
-rw-r--r--src/mint-lib/mint_api_json.c525
-rw-r--r--src/mint-lib/mint_api_json.h352
-rw-r--r--src/mint-lib/mint_api_refresh.c2061
-rw-r--r--src/mint-lib/mint_api_refresh_link.c482
-rw-r--r--src/mint-lib/mint_api_reserve.c930
-rw-r--r--src/mint-lib/mint_api_wire.c620
-rw-r--r--src/mint-lib/mint_api_wire_deposits.c284
-rw-r--r--src/mint-lib/test-mint-home/config/mint-common.conf30
-rw-r--r--src/mint-lib/test-mint-home/config/mint-keyup.conf86
-rw-r--r--src/mint-lib/test_mint_api.c2599
-rw-r--r--src/mint-tools/Makefile.am81
-rw-r--r--src/mint-tools/taler-auditor-sign.c321
-rw-r--r--src/mint-tools/taler-mint-dbinit.c105
-rw-r--r--src/mint-tools/taler-mint-keycheck.c247
-rw-r--r--src/mint-tools/taler-mint-keyup.c1039
-rw-r--r--src/mint-tools/taler-mint-reservemod.c206
-rw-r--r--src/mint-tools/taler-mint-sepa.c163
-rw-r--r--src/mint/.gitignore6
-rw-r--r--src/mint/Makefile.am59
-rw-r--r--src/mint/taler-mint-aggregator.c914
-rw-r--r--src/mint/taler-mint-httpd.c749
-rw-r--r--src/mint/taler-mint-httpd.h128
-rw-r--r--src/mint/taler-mint-httpd_admin.c164
-rw-r--r--src/mint/taler-mint-httpd_admin.h46
-rw-r--r--src/mint/taler-mint-httpd_db.c1900
-rw-r--r--src/mint/taler-mint-httpd_db.h230
-rw-r--r--src/mint/taler-mint-httpd_deposit.c281
-rw-r--r--src/mint/taler-mint-httpd_deposit.h54
-rw-r--r--src/mint/taler-mint-httpd_keystate.c1011
-rw-r--r--src/mint/taler-mint-httpd_keystate.h163
-rw-r--r--src/mint/taler-mint-httpd_mhd.c152
-rw-r--r--src/mint/taler-mint-httpd_mhd.h111
-rw-r--r--src/mint/taler-mint-httpd_parsing.c1137
-rw-r--r--src/mint/taler-mint-httpd_parsing.h408
-rw-r--r--src/mint/taler-mint-httpd_refresh.c911
-rw-r--r--src/mint/taler-mint-httpd_refresh.h94
-rw-r--r--src/mint/taler-mint-httpd_reserve.c186
-rw-r--r--src/mint/taler-mint-httpd_reserve.h73
-rw-r--r--src/mint/taler-mint-httpd_responses.c1177
-rw-r--r--src/mint/taler-mint-httpd_responses.h469
-rw-r--r--src/mint/taler-mint-httpd_test.c621
-rw-r--r--src/mint/taler-mint-httpd_test.h225
-rw-r--r--src/mint/taler-mint-httpd_tracking.c165
-rw-r--r--src/mint/taler-mint-httpd_tracking.h65
-rw-r--r--src/mint/taler-mint-httpd_validation.c231
-rw-r--r--src/mint/taler-mint-httpd_validation.h76
-rw-r--r--src/mint/taler-mint-httpd_wire.c220
-rw-r--r--src/mint/taler-mint-httpd_wire.h82
-rw-r--r--src/mint/test_taler_mint_httpd.data48
-rwxr-xr-xsrc/mint/test_taler_mint_httpd.sh35
-rwxr-xr-xsrc/mint/test_taler_mint_httpd_afl.sh41
-rw-r--r--src/mintdb/Makefile.am110
-rw-r--r--src/mintdb/mintdb_keyio.c558
-rw-r--r--src/mintdb/mintdb_plugin.c87
-rw-r--r--src/mintdb/perf_taler_mintdb.c358
-rw-r--r--src/mintdb/perf_taler_mintdb_init.c622
-rw-r--r--src/mintdb/perf_taler_mintdb_init.h257
-rw-r--r--src/mintdb/perf_taler_mintdb_interpreter.c1998
-rw-r--r--src/mintdb/perf_taler_mintdb_interpreter.h1319
-rw-r--r--src/mintdb/perf_taler_mintdb_values.h25
-rw-r--r--src/mintdb/plugin_mintdb_common.c162
-rw-r--r--src/mintdb/plugin_mintdb_postgres.c4295
-rw-r--r--src/mintdb/test-mint-db-postgres.conf8
-rw-r--r--src/mintdb/test_mintdb.c907
-rw-r--r--src/mintdb/test_mintdb_deposits.c152
-rw-r--r--src/mintdb/test_mintdb_keyio.c85
-rw-r--r--src/mintdb/test_perf_taler_mintdb.c182
-rw-r--r--src/util/os_installation.c4
-rw-r--r--src/util/wireformats.c2
-rw-r--r--src/wire/plugin_wire_sepa.c4
-rw-r--r--src/wire/plugin_wire_template.c4
-rw-r--r--src/wire/plugin_wire_test.c29
-rw-r--r--src/wire/test_sepa_wireformat.c2
2303 files changed, 40442 insertions, 40403 deletions
diff --git a/.gitignore b/.gitignore
index de64370a9..14d8fdb48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,16 +27,18 @@ GPATH
GRTAGS
GTAGS
*.swp
-src/lib/test_mint_api
+src/lib/test_exchange_api
doc/doxygen/doxygen_sqlite3.db
-src/mint-lib/test_mint_api
-src/mint-tools/taler-auditor-sign
-src/mint-tools/taler-mint-dbinit
-src/mint-tools/taler-mint-keycheck
-src/mint-tools/taler-mint-keyup
-src/mint-tools/taler-mint-reservemod
-src/mint-tools/taler-mint-sepa
-src/mintdb/perf-mintdb
+src/bank-lib/test_bank_api
+src/exchange-lib/test_exchange_api
+src/exchange/taler-exchange-aggregator
+src/exchange-tools/taler-auditor-sign
+src/exchange-tools/taler-exchange-dbinit
+src/exchange-tools/taler-exchange-keycheck
+src/exchange-tools/taler-exchange-keyup
+src/exchange-tools/taler-exchange-reservemod
+src/exchange-tools/taler-exchange-sepa
+src/exchangedb/perf-exchangedb
src/pq/test_pq
src/util/test_amount
src/util/test_crypto
diff --git a/README b/README
index a5211ee16..78665b551 100644
--- a/README
+++ b/README
@@ -6,7 +6,7 @@ What is Taler?
Taler is an electronic payment system providing the ability to pay
anonymously using digital cash. Taler consists of a network protocol
-definition (using a RESTful API over HTTP), a Mint (which creates
+definition (using a RESTful API over HTTP), a Exchange (which creates
digital coins), a Wallet (which allows customers to manage, store and
spend digital coins), and a Merchant website which allows customers to
spend their digital coins. Naturally, each Merchant is different, but
@@ -19,7 +19,7 @@ is free software and a GNU package (http://www.gnu.org/).
This is not even a release yet, but some raw development prototype
that does not work yet. This package also only includes the Taler
-mint, not the other components of the system.
+exchange, not the other components of the system.
Documentation about Taler can be found at http://taler.net/.
@@ -27,7 +27,7 @@ Documentation about Taler can be found at http://taler.net/.
Dependencies:
=============
-These are the direct dependencies for running a Taler mint:
+These are the direct dependencies for running a Taler exchange:
- GNUnet >= 0.10.2
- GNU libmicrohttpd >= 0.9.38
@@ -48,50 +48,50 @@ src/util/
src/pq/
-- Postgres-specific utility functions
-src/mintdb/
- -- Mint database backend (with DB-specific plugins)
+src/exchangedb/
+ -- Exchange database backend (with DB-specific plugins)
-src/mint/
- -- taler mint server
+src/exchange/
+ -- taler exchange server
-src/mint-tools/
- -- taler mint helper programs
+src/exchange-tools/
+ -- taler exchange helper programs
-src/mint-lib/
- -- libtalermint: C API to issue HTTP requests to mint
+src/exchange-lib/
+ -- libtalerexchange: C API to issue HTTP requests to exchange
Getting Started
==============
-The following steps illustrate how to set up a mint HTTP server.
-They take as a stub for configuring the mint the content of 'contrib/mint-template/config/'.
+The following steps illustrate how to set up a exchange HTTP server.
+They take as a stub for configuring the exchange the content of 'contrib/exchange-template/config/'.
1) Create a 'test/' directory and copy the stubs in it:
mkdir -p test/config/
-cp mint/contrib/mint-template/config/* test/config/
+cp exchange/contrib/exchange-template/config/* test/config/
cd test/
-2) Create the mint's master with the tool 'gnunet-ecc':
+2) Create the exchange's master with the tool 'gnunet-ecc':
gnunet-ecc -g1 master.priv
-3) Edit config/mint-common.conf by replacing the right value on the line with the
+3) Edit config/exchange-common.conf by replacing the right value on the line with the
MASTER_PUBLIC_KEY entry with the fresh generated (ASCII version of) master.priv.
This ASCII version is obtained by issuing:
gnunet-ecc -p master.priv
-4) Generate other mint related keys ('denomination' and 'signing' keys), by issuing:
+4) Generate other exchange related keys ('denomination' and 'signing' keys), by issuing:
-taler-mint-keyup -d `pwd` -m master.priv
+taler-exchange-keyup -d `pwd` -m master.priv
5) Check with:
-taler-mint-keycheck -d `pwd`
+taler-exchange-keycheck -d `pwd`
-6) A mint needs a database to operate, so the following instructions relate to
+6) A exchange needs a database to operate, so the following instructions relate to
how to set up PostgreSQL. On debian, the two packages needed are:
* postgresql
@@ -99,8 +99,8 @@ how to set up PostgreSQL. On debian, the two packages needed are:
For other operating systems, please refer to the relevant documentation.
-In this settlement, the mint wll use a database called 'talercheck' and will
-run under the username through which 'taler-mint-httpd' is launched. Thus assuming
+In this settlement, the exchange wll use a database called 'talercheck' and will
+run under the username through which 'taler-exchange-httpd' is launched. Thus assuming
that this user is 'demo', we need to create a 'demo' role for postgresql and make
him the owner of 'talercheck' database.
@@ -117,7 +117,7 @@ CREATE DATABASE talercheck OWNER demo;
# quit with CTRL-D
7) If any previous step has been successful, it is now possbile to start up the
-mint web server (by default it will listen on port 4241); issue:
+exchange web server (by default it will listen on port 4241); issue:
-taler-mint-httpd -d `pwd` # assuming we did not move outside of the 'test' directory
+taler-exchange-httpd -d `pwd` # assuming we did not move outside of the 'test' directory
diff --git a/configure.ac b/configure.ac
index 95457e5b4..6004a7d66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
#
#
AC_PREREQ([2.69])
-AC_INIT([taler-mint], [0.0.0], [taler-bug@gnunet.org])
+AC_INIT([taler-exchange], [0.0.0], [taler-bug@gnunet.org])
AC_CONFIG_SRCDIR([src/util/json.c])
AC_CONFIG_HEADERS([taler_config.h])
# support for non-recursive builds
@@ -359,9 +359,9 @@ AC_CONFIG_FILES([Makefile
src/pq/Makefile
src/bank-lib/Makefile
src/wire/Makefile
- src/mintdb/Makefile
- src/mint/Makefile
- src/mint-tools/Makefile
- src/mint-lib/Makefile
+ src/exchangedb/Makefile
+ src/exchange/Makefile
+ src/exchange-tools/Makefile
+ src/exchange-lib/Makefile
])
AC_OUTPUT
diff --git a/contrib/coverage.sh b/contrib/coverage.sh
index 15318967c..cce622283 100755..100644
--- a/contrib/coverage.sh
+++ b/contrib/coverage.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Run from 'taler-mint/' top-level directory to generate
+# Run from 'taler-exchange/' top-level directory to generate
# code coverage data.
TOP=`pwd`
mkdir -p doc/coverage/
diff --git a/contrib/exchange-template/README b/contrib/exchange-template/README
new file mode 100644
index 000000000..dbbd5c304
--- /dev/null
+++ b/contrib/exchange-template/README
@@ -0,0 +1 @@
+This directory is a template for the exchange directory.
diff --git a/contrib/exchange-template/config/exchange-common.conf b/contrib/exchange-template/config/exchange-common.conf
new file mode 100644
index 000000000..d1df222fe
--- /dev/null
+++ b/contrib/exchange-template/config/exchange-common.conf
@@ -0,0 +1,30 @@
+[exchange]
+# Currency supported by the exchange (can only be one)
+CURRENCY = EUR
+
+# Wire format supported by the exchange, case-insensitive.
+# Examples for formats include 'test' for testing and 'sepa' (for EU IBAN).
+WIREFORMAT = SEPA
+
+# HTTP port the exchange listens to
+PORT = 4241
+
+# Master public key used to sign the exchange's various keys
+MASTER_PUBLIC_KEY = NEGTF62MNGVPZNW19V7S3CRS9D7K04MAHDGX3N6WY2NXREN26J80
+
+# How to access our database
+DB = postgres
+
+# Is this for testing, or for real?
+TESTRUN = YES
+
+[exchangedb-postgres]
+DB_CONN_STR = "postgres:///talercheck"
+
+[wire-sepa]
+SEPA_RESPONSE_FILE = "sepa.json"
+
+[wire-test]
+REDIRECT_URL = "http://test/"
+BANK_URI = "http://bank/"
+BANK_ACCOUNT_NO = 2
diff --git a/contrib/exchange-template/config/exchange-keyup.conf b/contrib/exchange-template/config/exchange-keyup.conf
new file mode 100644
index 000000000..7eebfe975
--- /dev/null
+++ b/contrib/exchange-template/config/exchange-keyup.conf
@@ -0,0 +1,64 @@
+[exchange_keys]
+
+# how long is one signkey valid?
+signkey_duration = 4 weeks
+
+# how long are the signatures with the signkey valid?
+legal_duration = 2 years
+
+# how long do we generate denomination and signing keys
+# ahead of time?
+lookahead_sign = 32 weeks 1 day
+
+# how long do we provide to clients denomination and signing keys
+# ahead of time?
+lookahead_provide = 4 weeks 1 day
+
+
+# Coin definitions are detected because the section
+# name begins with "coin_". The rest of the
+# name is free, but of course following the convention
+# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense.
+[coin_eur_ct_10]
+value = EUR:0.10
+duration_overlap = 5 minutes
+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.01
+rsa_keysize = 1024
+
+[coin_eur_5]
+value = EUR:5
+duration_overlap = 5 minutes
+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.01
+rsa_keysize = 1024
+
+[coin_eur_10]
+value = EUR:10
+duration_overlap = 5 minutes
+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.01
+rsa_keysize = 1024
+
+[coin_eur_1000]
+value = EUR:1000
+duration_overlap = 5 minutes
+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.01
+rsa_keysize = 2048
diff --git a/contrib/mint-template/README b/contrib/mint-template/README
deleted file mode 100644
index fce5e0180..000000000
--- a/contrib/mint-template/README
+++ /dev/null
@@ -1 +0,0 @@
-This directory is a template for the mint directory.
diff --git a/contrib/mint-template/config/mint-common.conf b/contrib/mint-template/config/mint-common.conf
deleted file mode 100644
index 78a3310a1..000000000
--- a/contrib/mint-template/config/mint-common.conf
+++ /dev/null
@@ -1,28 +0,0 @@
-[mint]
-# Currency supported by the mint (can only be one)
-CURRENCY = EUR
-
-# Wire format supported by the mint, case-insensitive.
-# Examples for formats include 'test' for testing and 'sepa' (for EU IBAN).
-WIREFORMAT = SEPA
-
-# HTTP port the mint listens to
-PORT = 4241
-
-# Master public key used to sign the mint's various keys
-MASTER_PUBLIC_KEY = NEGTF62MNGVPZNW19V7S3CRS9D7K04MAHDGX3N6WY2NXREN26J80
-
-# How to access our database
-DB = postgres
-
-TESTRUN = YES
-
-[mintdb-postgres]
-
-DB_CONN_STR = "postgres:///talercheck"
-
-[mint-wire-sepa]
-SEPA_RESPONSE_FILE = "sepa.json"
-
-[mint-wire-test]
-REDIRECT_URL = "http://test/"
diff --git a/contrib/mint-template/config/mint-keyup.conf b/contrib/mint-template/config/mint-keyup.conf
deleted file mode 100644
index d8bbc9d20..000000000
--- a/contrib/mint-template/config/mint-keyup.conf
+++ /dev/null
@@ -1,64 +0,0 @@
-[mint_keys]
-
-# how long is one signkey valid?
-signkey_duration = 4 weeks
-
-# how long are the signatures with the signkey valid?
-legal_duration = 2 years
-
-# how long do we generate denomination and signing keys
-# ahead of time?
-lookahead_sign = 32 weeks 1 day
-
-# how long do we provide to clients denomination and signing keys
-# ahead of time?
-lookahead_provide = 4 weeks 1 day
-
-
-# Coin definitions are detected because the section
-# name begins with "coin_". The rest of the
-# name is free, but of course following the convention
-# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense.
-[coin_eur_ct_10]
-value = EUR:0.10
-duration_overlap = 5 minutes
-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.01
-rsa_keysize = 1024
-
-[coin_eur_5]
-value = EUR:5
-duration_overlap = 5 minutes
-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.01
-rsa_keysize = 1024
-
-[coin_eur_10]
-value = EUR:10
-duration_overlap = 5 minutes
-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.01
-rsa_keysize = 1024
-
-[coin_eur_1000]
-value = EUR:1000
-duration_overlap = 5 minutes
-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.01
-rsa_keysize = 2048
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 51e1ed897..0b3dc39c4 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -4,11 +4,11 @@ SUBDIRS = . doxygen
man_MANS = \
taler-auditor-sign.1 \
- taler-mint-dbinit.1 \
- taler-mint-httpd.1 \
- taler-mint-keyup.1 \
- taler-mint-keycheck.1 \
- taler-mint-reservemod.1 \
+ taler-exchange-dbinit.1 \
+ taler-exchange-httpd.1 \
+ taler-exchange-keyup.1 \
+ taler-exchange-keycheck.1 \
+ taler-exchange-reservemod.1 \
taler.conf.5
EXTRA_DIST = \
diff --git a/doc/coding-style.txt b/doc/coding-style.txt
index 093e14d31..fe7bfed12 100644
--- a/doc/coding-style.txt
+++ b/doc/coding-style.txt
@@ -14,10 +14,10 @@ Naming conventions:
SHOULD NOT be included from outside of their own directory
+ end in "_lib" for "simple" libraries
+ end in "_plugin" for plugins
- + end in "_service" for libraries accessing a service, i.e. the mint
+ + end in "_service" for libraries accessing a service, i.e. the exchange
* binaries:
- + taler-mint-xxx: mint programs
+ + taler-exchange-xxx: exchange programs
+ taler-merchant-xxx: merchant programs (demos)
+ taler-wallet-xxx: wallet programs
+ plugins should be libtaler_plugin_xxx_yyy.so: plugin yyy for API xxx
@@ -25,16 +25,16 @@ Naming conventions:
* logging
+ tools use their full name in GNUNET_log_setup
- (i.e. 'taler-mint-keyup') and log using plain 'GNUNET_log'.
+ (i.e. 'taler-exchange-keyup') and log using plain 'GNUNET_log'.
+ pure libraries (without associated service) use 'GNUNET_log_from'
with the component set to their library name (without lib or '.so'),
which should also be their directory name (i.e. 'util')
+ plugin libraries (without associated service) use 'GNUNET_log_from'
with the component set to their type and plugin name (without lib or '.so'),
- which should also be their directory name (i.e. 'mintdb-postgres')
+ which should also be their directory name (i.e. 'exchangedb-postgres')
+ libraries with associated service) use 'GNUNET_log_from'
with the name of the service, which should also be their
- directory name (i.e. 'mint')
+ directory name (i.e. 'exchange')
* configuration
+ same rules as for GNUnet
@@ -44,7 +44,7 @@ Naming conventions:
MUST match the subdirectory of src/ in which the symbol is defined
+ from libtalerutil start just with TALER_, without subsystemname
+ if scope is ONE binary and symbols are not in a shared library,
- use binary-specific prefix (such as TMH = taler-mint-httpd) for
+ use binary-specific prefix (such as TMH = taler-exchange-httpd) for
globals, possibly followed by the subsystem (TMH_DB_xxx).
* structs:
diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
index 6b6f1ed72..da4dbc140 100644
--- a/doc/doxygen/Makefile.am
+++ b/doc/doxygen/Makefile.am
@@ -5,14 +5,14 @@ all:
"\tmake full - full documentation with dependency graphs (slow)\n" \
"\tmake fast - fast mode without dependency graphs"
-full: taler-mint.doxy
+full: taler-exchange.doxy
doxygen $<
-fast: taler-mint.doxy
+fast: taler-exchange.doxy
sed 's/\(HAVE_DOT.*=\).*/\1 NO/' $< | doxygen -
clean:
rm -rf html
-EXTRA_DIST = taler-mint.doxy
+EXTRA_DIST = taler-exchange.doxy
diff --git a/doc/doxygen/taler-mint.doxy b/doc/doxygen/taler-mint.doxy
index 2949fac0d..23c2fbe07 100644
--- a/doc/doxygen/taler-mint.doxy
+++ b/doc/doxygen/taler-mint.doxy
@@ -4,7 +4,7 @@
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
-PROJECT_NAME = "GNU Taler: Mint"
+PROJECT_NAME = "GNU Taler: Exchange"
PROJECT_NUMBER = 0.0
OUTPUT_DIRECTORY = .
CREATE_SUBDIRS = YES
diff --git a/doc/logos/fonts/OldNewspaperTypes.ttf b/doc/logos/fonts/OldNewspaperTypes.ttf
index 7b9cf31b9..7b9cf31b9 100755..100644
--- a/doc/logos/fonts/OldNewspaperTypes.ttf
+++ b/doc/logos/fonts/OldNewspaperTypes.ttf
Binary files differ
diff --git a/doc/paper/rfc.bib b/doc/paper/rfc.bib
index 700f3a99a..99c427e58 100644
--- a/doc/paper/rfc.bib
+++ b/doc/paper/rfc.bib
@@ -9025,7 +9025,7 @@
organization="Internet Engineering Task Force",
year=1978,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc748.txt",
}
@@ -13671,7 +13671,7 @@
organization="Internet Engineering Task Force",
year=1989,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1097.txt",
}
@@ -14377,7 +14377,7 @@
organization="Internet Engineering Task Force",
year=1990,
month=apr,
- day="1",
+ day="1",
note="Updated by RFCs 2549, 6214",
url="http://www.ietf.org/rfc/rfc1149.txt",
}
@@ -15260,7 +15260,7 @@
organization="Internet Engineering Task Force",
year=1991,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1216.txt",
}
@@ -15274,7 +15274,7 @@
organization="Internet Engineering Task Force",
year=1991,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1217.txt",
}
@@ -16551,7 +16551,7 @@
organization="Internet Engineering Task Force",
year=1992,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1313.txt",
}
@@ -18223,7 +18223,7 @@
organization="Internet Engineering Task Force",
year=1993,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1437.txt",
}
@@ -18237,7 +18237,7 @@
organization="Internet Engineering Task Force",
year=1993,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1438.txt",
}
@@ -20478,7 +20478,7 @@
organization="Internet Engineering Task Force",
year=1994,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1605.txt",
}
@@ -20492,7 +20492,7 @@
organization="Internet Engineering Task Force",
year=1994,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1606.txt",
}
@@ -20506,7 +20506,7 @@
organization="Internet Engineering Task Force",
year=1994,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1607.txt",
}
@@ -22753,7 +22753,7 @@
organization="Internet Engineering Task Force",
year=1995,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1776.txt",
}
@@ -24716,7 +24716,7 @@
organization="Internet Engineering Task Force",
year=1996,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1924.txt",
}
@@ -24730,7 +24730,7 @@
organization="Internet Engineering Task Force",
year=1996,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1925.txt",
}
@@ -24744,7 +24744,7 @@
organization="Internet Engineering Task Force",
year=1996,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1926.txt",
}
@@ -24758,7 +24758,7 @@
organization="Internet Engineering Task Force",
year=1996,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc1927.txt",
}
@@ -27077,7 +27077,7 @@
organization="Internet Engineering Task Force",
year=1997,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2100.txt",
}
@@ -30038,7 +30038,7 @@
organization="Internet Engineering Task Force",
year=1998,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2321.txt",
}
@@ -30052,7 +30052,7 @@
organization="Internet Engineering Task Force",
year=1998,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2322.txt",
}
@@ -30066,7 +30066,7 @@
organization="Internet Engineering Task Force",
year=1998,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2323.txt",
}
@@ -30080,7 +30080,7 @@
organization="Internet Engineering Task Force",
year=1998,
month=apr,
- day="1",
+ day="1",
note="Updated by RFC 7168",
url="http://www.ietf.org/rfc/rfc2324.txt",
}
@@ -30095,7 +30095,7 @@
organization="Internet Engineering Task Force",
year=1998,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2325.txt",
}
@@ -33099,7 +33099,7 @@
organization="Internet Engineering Task Force",
year=1999,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2549.txt",
}
@@ -33113,7 +33113,7 @@
organization="Internet Engineering Task Force",
year=1999,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2550.txt",
}
@@ -33127,7 +33127,7 @@
organization="Internet Engineering Task Force",
year=1999,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2551.txt",
}
@@ -36388,7 +36388,7 @@
organization="Internet Engineering Task Force",
year=2000,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc2795.txt",
}
@@ -40323,7 +40323,7 @@
organization="Internet Engineering Task Force",
year=2001,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3091.txt",
}
@@ -40337,7 +40337,7 @@
organization="Internet Engineering Task Force",
year=2001,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3092.txt",
}
@@ -40351,7 +40351,7 @@
organization="Internet Engineering Task Force",
year=2001,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3093.txt",
}
@@ -42397,7 +42397,7 @@
organization="Internet Engineering Task Force",
year=2002,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3251.txt",
}
@@ -42411,7 +42411,7 @@
organization="Internet Engineering Task Force",
year=2002,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3252.txt",
}
@@ -45820,7 +45820,7 @@
organization="Internet Engineering Task Force",
year=2003,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3514.txt",
}
@@ -48951,7 +48951,7 @@
organization="Internet Engineering Task Force",
year=2004,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc3751.txt",
}
@@ -52675,7 +52675,7 @@
organization="Internet Engineering Task Force",
year=2005,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc4041.txt",
}
@@ -52689,7 +52689,7 @@
organization="Internet Engineering Task Force",
year=2005,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc4042.txt",
}
@@ -62743,7 +62743,7 @@
organization="Internet Engineering Task Force",
year=2007,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc4824.txt",
}
@@ -68094,7 +68094,7 @@
organization="Internet Engineering Task Force",
year=2008,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc5241.txt",
}
@@ -68108,7 +68108,7 @@
organization="Internet Engineering Task Force",
year=2008,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc5242.txt",
}
@@ -71194,7 +71194,7 @@
@misc{rfc5486,
author="D. Malas and D. Meyer",
- title="{Session Peering for Multimedia Interconnect (SPEERMINT) Terminology}",
+ title="{Session Peering for Multimedia Interconnect (SPEEREXCHANGE) Terminology}",
series="Request for Comments",
number="5486",
howpublished="RFC 5486 (Informational)",
@@ -71529,7 +71529,7 @@
organization="Internet Engineering Task Force",
year=2009,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc5513.txt",
}
@@ -71543,7 +71543,7 @@
organization="Internet Engineering Task Force",
year=2009,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc5514.txt",
}
@@ -75706,7 +75706,7 @@
organization="Internet Engineering Task Force",
year=2010,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc5841.txt",
}
@@ -77555,7 +77555,7 @@
organization="Internet Engineering Task Force",
year=2011,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc5984.txt",
}
@@ -80463,7 +80463,7 @@
organization="Internet Engineering Task Force",
year=2011,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc6214.txt",
}
@@ -80503,7 +80503,7 @@
organization="Internet Engineering Task Force",
year=2011,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc6217.txt",
}
@@ -82898,7 +82898,7 @@
@misc{rfc6404,
author="J. Seedorf and S. Niccolini and E. Chen and H. Scholz",
- title="{Session PEERing for Multimedia INTerconnect (SPEERMINT) Security Threats and Suggested Countermeasures}",
+ title="{Session PEERing for Multimedia INTerconnect (SPEEREXCHANGE) Security Threats and Suggested Countermeasures}",
series="Request for Comments",
number="6404",
howpublished="RFC 6404 (Informational)",
@@ -82924,7 +82924,7 @@
@misc{rfc6406,
author="D. Malas and J. Livingood",
- title="{Session PEERing for Multimedia INTerconnect (SPEERMINT) Architecture}",
+ title="{Session PEERing for Multimedia INTerconnect (SPEEREXCHANGE) Architecture}",
series="Request for Comments",
number="6406",
howpublished="RFC 6406 (Informational)",
@@ -85310,7 +85310,7 @@
organization="Internet Engineering Task Force",
year=2012,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc6592.txt",
}
@@ -85324,7 +85324,7 @@
organization="Internet Engineering Task Force",
year=2012,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc6593.txt",
}
@@ -89460,7 +89460,7 @@
organization="Internet Engineering Task Force",
year=2013,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc6919.txt",
}
@@ -89487,7 +89487,7 @@
organization="Internet Engineering Task Force",
year=2013,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc6921.txt",
}
@@ -92639,7 +92639,7 @@
organization="Internet Engineering Task Force",
year=2014,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc7168.txt",
}
@@ -92653,7 +92653,7 @@
organization="Internet Engineering Task Force",
year=2014,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc7169.txt",
}
@@ -97095,7 +97095,7 @@
organization="Internet Engineering Task Force",
year=2015,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc7511.txt",
}
@@ -97135,7 +97135,7 @@
organization="Internet Engineering Task Force",
year=2015,
month=apr,
- day="1",
+ day="1",
url="http://www.ietf.org/rfc/rfc7514.txt",
}
@@ -98711,4 +98711,3 @@
month=sep,
url="http://www.ietf.org/rfc/rfc7651.txt",
}
-
diff --git a/doc/paper/taler.tex b/doc/paper/taler.tex
index e9c795857..5ad93ec32 100644
--- a/doc/paper/taler.tex
+++ b/doc/paper/taler.tex
@@ -41,17 +41,17 @@
% 'transaction' already when we talk about taxable
% transfers of Taler coins and database 'transactions'.
% - wallet = coins at customer
-% - reserve = currency entrusted to mint waiting for withdrawal
-% - deposit = SEPA to mint
-% - withdrawal = mint to customer
+% - reserve = currency entrusted to exchange waiting for withdrawal
+% - deposit = SEPA to exchange
+% - withdrawal = exchange to customer
% - spending = customer to merchant
-% - redeeming = merchant to mint (and then mint SEPA to merchant)
-% - refreshing = customer-mint-customer
+% - redeeming = merchant to exchange (and then exchange SEPA to merchant)
+% - refreshing = customer-exchange-customer
% - dirty coin = coin with exposed public key
% - fresh coin = coin that was refreshed or is new
-% - coin signing key = mint's online key used to (blindly) sign coin
-% - message signing key = mint's online key to sign mint messages
-% - mint master key = mint's key used to sign other mint keys
+% - coin signing key = exchange's online key used to (blindly) sign coin
+% - message signing key = exchange's online key to sign exchange messages
+% - exchange master key = exchange's key used to sign other exchange keys
% - owner = entity that knows coin private key
% - transaction = coin ownership transfer that should be taxed
% - sharing = coin copying that should not be taxed
@@ -74,7 +74,7 @@ blind signatures that enables anonymous payments while ensuring that
entities that receive payments are auditable and thus taxable. Taler
differs from Chaum's original proposal in that customers can never
defraud anyone, merchants can only fail to deliver the merchandise to
-the customer, and mints can be fully audited. Consequently,
+the customer, and exchanges can be fully audited. Consequently,
enforcement of honest behavior is better and more timely than with
Chaum, and is at least as strict as with legacy credit card payment
systems that do not provide for privacy. Furthermore, Taler allows
@@ -112,11 +112,11 @@ anarchistic economies.
The Taler protocol is heavily based on ideas from
Chaum~\cite{chaum1983blind} and also follows Chaum's basic architecture of
-customer, merchant and mint (Figure~\ref{fig:cmm}). The two designs
+customer, merchant and exchange (Figure~\ref{fig:cmm}). The two designs
share the key first step where the {\em customer} withdraws digital
-{\em coins} from the {\em mint} with unlinkability provided via blind
+{\em coins} from the {\em exchange} with unlinkability provided via blind
signatures. The coins can then be spent at a {\em merchant} who {\em
- deposits} them at the mint. Taler uses online detection of
+ deposits} them at the exchange. Taler uses online detection of
double-spending, thus assuring the merchant instantly that a
transaction is valid.
@@ -125,17 +125,17 @@ transaction is valid.
\begin{tikzpicture}
\tikzstyle{def} = [node distance= 5em and 7em, inner sep=1em, outer sep=.3em];
\node (origin) at (0,0) {};
- \node (mint) [def,above=of origin,draw]{Mint};
+ \node (exchange) [def,above=of origin,draw]{Exchange};
\node (customer) [def, draw, below left=of origin] {Customer};
\node (merchant) [def, draw, below right=of origin] {Merchant};
\node (auditor) [def, draw, above right=of origin]{Auditor};
\tikzstyle{C} = [color=black, line width=1pt]
- \draw [<-, C] (customer) -- (mint) node [midway, above, sloped] (TextNode) {withdraw coins};
- \draw [<-, C] (mint) -- (merchant) node [midway, above, sloped] (TextNode) {deposit coins};
+ \draw [<-, C] (customer) -- (exchange) node [midway, above, sloped] (TextNode) {withdraw coins};
+ \draw [<-, C] (exchange) -- (merchant) node [midway, above, sloped] (TextNode) {deposit coins};
\draw [<-, C] (merchant) -- (customer) node [midway, above, sloped] (TextNode) {spend coins};
- \draw [<-, C] (mint) -- (auditor) node [midway, above, sloped] (TextNode) {verify};
+ \draw [<-, C] (exchange) -- (auditor) node [midway, above, sloped] (TextNode) {verify};
\end{tikzpicture}
\caption{Taler's system model for the payment system is based on Chaum~\cite{chaum1983blind}.}
@@ -147,7 +147,7 @@ believe needs a payment system with the following properties:
\begin{description}
\item[Customer Anonymity]
- It must be impossible for mints, merchants and even a global active
+ It must be impossible for exchanges, merchants and even a global active
adversary, to trace the spending behavior of a customer.
\item[Unlinkability]
As a strong form of customer anonymity, it must be infeasible to
@@ -170,11 +170,11 @@ believe needs a payment system with the following properties:
Nevertheless, customers must never be able to defraud anyone, and
merchants must at best be able to defraud their customers by not
delivering on the agreed contract. Neither merchants nor customers
- should ever be able to commit fraud against the mint. Additionally,
+ should ever be able to commit fraud against the exchange. Additionally,
both customers and merchants must receive cryptographic proofs of
- bad behavior in case of protocol violations by the mint.
- In this way, only the mint will need to be tightly audited and regulated.
- The design must make it easy to audit the finances of the mint.
+ bad behavior in case of protocol violations by the exchange.
+ In this way, only the exchange will need to be tightly audited and regulated.
+ The design must make it easy to audit the finances of the exchange.
\item[Ease of Deployment] %The system should be easy to deploy for
% real-world applications. In order to lower the entry barrier and
% acceptance of the system, a gateway to the existing financial
@@ -206,8 +206,8 @@ say a \EUR{0,01} coin and a \EUR{50,00} coin.
A merchant cannot simply give the customer their coins in another transaction;
however, as this reverses the role of merchant and customer, and
our taxability requirement would deanonymize the customer. The customer
-also cannot withdraw exact change from his account from the mint, as this
-would allow the mint to link the identity of the customer that is revealed
+also cannot withdraw exact change from his account from the exchange, as this
+would allow the exchange to link the identity of the customer that is revealed
during withdrawal to the subsequent deposit operation that follows shortly
afterwards.
Instead, the customer should obtain new freshly anonymized coins that cannot be
@@ -226,9 +226,9 @@ A key contribution of Taler is the {\em refresh} protocol, which enables
a customer to exchange the residual value of the exchanged coin for
unlinkable freshly anonymized change.
-Taler mints ensure that all transactions involving the same coin
+Taler exchanges ensure that all transactions involving the same coin
do not exceed the total value of the coin simply by
-requiring that merchants clear transactions immediately with the mint.
+requiring that merchants clear transactions immediately with the exchange.
This improves dramatically on systems that support offline merchants with
cryptographic threats to deanonymizing customers who double-spend, like
restrictive blind signatures~\cite{brands1993efficient}.
@@ -308,17 +308,17 @@ Taler avoids include:
\item The use of patents to protect the technology; a payment system
should be free software (libre) to have a chance for widespread adoption.
\item The use of off-line payments and thus deferred detection of
- double-spending, which could require the mint to attempt to recover
+ double-spending, which could require the exchange to attempt to recover
funds from customers via the legal system. This creates a
- significant business risk for the mint, as the system is not
- self-enforcing from the perspective of the mint. In 1983 off-line
+ significant business risk for the exchange, as the system is not
+ self-enforcing from the perspective of the exchange. In 1983 off-line
payments might have been a necessary feature. However, today
requiring network connectivity is feasible and avoids the business
risks associated with deferred fraud detection.
\item % In addition to the risk of legal disputes with fraudulent
% merchants and customers,
Chaum's published design does not clearly
- limit the financial damage a mint might suffer from the
+ limit the financial damage a exchange might suffer from the
disclosure of its private online signing key.
\item Chaum did not support fractional payments or refunds without
breaking customer anonymity.
@@ -359,16 +359,16 @@ description of the Opencoin protocol is available to date.
Peppercoin~\cite{rivest2004peppercoin} is a microdonation protocol.
The main idea of the protocol is to reduce transaction costs by
minimizing the number of transactions that are processed directly by
-the mint. Instead of always paying, the customer ``gambles'' with the
+the exchange. Instead of always paying, the customer ``gambles'' with the
merchant for each microdonation. Only if the merchant wins, the
microdonation is upgraded to a macropayment to be deposited at the
-mint. Peppercoin does not provide customer-anonymity. The proposed
-statistical method by which mints detect fraudulent cooperation between
-customers and merchants at the expense of the mint not only creates
-legal risks for the mint, but would also require that the mint learns
+exchange. Peppercoin does not provide customer-anonymity. The proposed
+statistical method by which exchanges detect fraudulent cooperation between
+customers and merchants at the expense of the exchange not only creates
+legal risks for the exchange, but would also require that the exchange learns
about microdonations where the merchant did not get upgraded to a
macropayment. It is therefore unclear how Peppercoin would actually
-reduce the computational burden on the mint.
+reduce the computational burden on the exchange.
\section{Design}
@@ -382,32 +382,32 @@ As with Chaum, the Taler system comprises three principal types of
actors (Figure~\ref{fig:cmm}): The \emph{customer} is interested in
receiving goods or services from the \emph{merchant} in exchange for
payment. When making a transaction, both the customer and the
-merchant must agree on the same \emph{mint}, which serves as an
-intermediary for the financial transaction between the two. The mint
+merchant must agree on the same \emph{exchange}, which serves as an
+intermediary for the financial transaction between the two. The exchange
is responsible for allowing the customer to obtain the anonymous
digital currency and for enabling the merchant to convert the
digital coins back to some traditional currency. The \emph{auditor}
-assures customers and merchants that the mint operates correctly.
+assures customers and merchants that the exchange operates correctly.
\subsection{Security model}
Taler's security model assumes that cryptographic primitives are
secure and that each participant is under full control of his system.
-The contact information of the mint is known to both customer and
+The contact information of the exchange is known to both customer and
merchant from the start. Furthermore, the merchant communication's
authenticity is assured to the customer, such as by using X.509
certificates~\cite{rfc5280}, and we assume that an anonymous, reliable
bi-directional communication channel can be established by the
-customer to both the mint and the merchant, such as by using Tor.
+customer to both the exchange and the merchant, such as by using Tor.
-The mint is trusted to hold funds of its customers and to forward them
+The exchange is trusted to hold funds of its customers and to forward them
when receiving the respective deposit instructions from the merchants.
-Customer and merchant can have some assurances about the mint's
-liquidity and operation, as the mint has proven reserves, is subject
+Customer and merchant can have some assurances about the exchange's
+liquidity and operation, as the exchange has proven reserves, is subject
to the law, and can have its business regularly audited
by a government or third party.
-Regular audits of the mint's accounts should reveal any possible fraud
-before the mint is allowed to destroy the corresponding accumulated
+Regular audits of the exchange's accounts should reveal any possible fraud
+before the exchange is allowed to destroy the corresponding accumulated
cryptographic proofs and book its fees as profits.
%
The merchant is trusted to deliver the service or goods to the
@@ -416,7 +416,7 @@ to achieve this, as he must get cryptographic proofs of the contract
and that he paid his obligations.
%
Neither the merchant nor the customer may have any ability to {\em
- effectively} defraud the mint or the state collecting taxes. Here,
+ effectively} defraud the exchange or the state collecting taxes. Here,
``effectively'' means that the expected return for fraud is negative.
Note that customers do not need to be trusted in any way, and that in
particular it is never necessary for anyone to try to recover funds
@@ -455,10 +455,10 @@ thus {\bf not} recorded for taxation.
Taler ensures taxability only when some entity acquires exclusive
control over the value of digital coins, which requires an interaction
-with the mint. For such transactions, the state can obtain information
-from the mint, or a bank, that identifies the entity that received the
+with the exchange. For such transactions, the state can obtain information
+from the exchange, or a bank, that identifies the entity that received the
digital coins as well as the exact value of those coins.
-Taler also allows the mint, and hence the state, to learn the value of
+Taler also allows the exchange, and hence the state, to learn the value of
digital coins withdrawn by a customer---but not how, where, or when
they were spent.
@@ -468,7 +468,7 @@ An anonymous communication channel such as Tor~\cite{tor-design} is
used for all communication between the customer and the merchant.
Ideally, the customer's anonymity is limited only by this channel;
however, the payment system does additionally reveal that the customer
-is one of the patrons of the mint.
+is one of the patrons of the exchange.
There are naturally risks that the customer-merchant business operation
may leak identifying information about the customer. At least, customers
have some options to defend their privacy against nosey merchants however,
@@ -477,7 +477,7 @@ We consider information leakage specific to the business logic to be
outside of the scope of the design of Taler.
Ideally, customer should use an anonymous communication channel with
-the mint to avoid leaking IP address information; however, the mint
+the exchange to avoid leaking IP address information; however, the exchange
would typically learn the customer's identity from the wire transfer
that funds the customer's withdraw anonymous digital coins.
In fact, this is desirable as there might be rules and regulations
@@ -485,33 +485,33 @@ designed to limit the amount of anonymous digital cash that an
individual customer can withdraw in a given time period, similar to
how states today sometimes impose limits on cash
withdrawals~\cite{france2015cash,greece2015cash}.
-Taler is only anonymous with respect to {\em payments}, as the mint
+Taler is only anonymous with respect to {\em payments}, as the exchange
will be unable to link the known identity of the customer that withdrew
anonymous digital currency to the {\em purchase} performed later at the
merchant. In this respect, Taler provides exactly the same scheme for
unconditional anonymous payments as was proposed by
Chaum~\cite{chaum1983blind,chaum1990untraceable} over 30 years ago.
-While the customer thus has anonymity for purchases, the mint will
+While the customer thus has anonymity for purchases, the exchange will
always learn the merchant's identity in order to credit the merchant's
account. This is simply necessary for taxation, as Taler is supposed
to make information about funds received by any entity transparent
to the state.
% Technically, the merchant could still
-%use an anonymous communication channel to communicate with the mint.
-%However, in order to receive the traditional currency the mint will
+%use an anonymous communication channel to communicate with the exchange.
+%However, in order to receive the traditional currency the exchange will
%require (SEPA) account details for the deposit.
-%As both the initial transaction between the customer and the mint as
-%well as the transactions between the merchant and the mint do not have
+%As both the initial transaction between the customer and the exchange as
+%well as the transactions between the merchant and the exchange do not have
%to be done anonymously, there might be a formal business contract
-%between the customer and the mint and the merchant and the mint. Such
+%between the customer and the exchange and the merchant and the exchange. Such
%a contract may provide customers and merchants some assurance that
-%they will actually receive the traditional currency from the mint
+%they will actually receive the traditional currency from the exchange
%given cryptographic proof about the validity of the transaction(s).
%However, given the business overheads for establishing such contracts
-%and the natural goal for the mint to establish a reputation and to
-%minimize cost, it is more likely that the mint will advertise its
+%and the natural goal for the exchange to establish a reputation and to
+%minimize cost, it is more likely that the exchange will advertise its
%external auditors and proven reserves and thereby try to convince
%customers and merchants to trust it without a formal contract.
@@ -519,57 +519,57 @@ to the state.
\subsection{Coins}
A \emph{coin} in Taler is a public-private key pair which derives its
-financial value from a signature over the coin's public key by a mint.
-The mint is expected to have multiple {\em coin signing key} pairs
+financial value from a signature over the coin's public key by a exchange.
+The exchange is expected to have multiple {\em coin signing key} pairs
available for signing, each representing a different coin
denomination.
These coin signing keys have an expiration date, before which any coins
-signed with it must be spent or refreshed. This allows the mint to
+signed with it must be spent or refreshed. This allows the exchange to
eventually discard records of old transactions, thus limiting the
-records that the mint must retain and search to detect double-spending
-attempts. Furthermore, the mint is expected to use each coin signing
+records that the exchange must retain and search to detect double-spending
+attempts. Furthermore, the exchange is expected to use each coin signing
key only for a limited number of coins.
% for example by limiting its use to sign coins to a week or a month.
In this way, if a private coin signing key were to be compromised,
-the mint would detect this once more coins were redeemed than the total
+the exchange would detect this once more coins were redeemed than the total
that was signed into existence using that coin signing key.
-In this case, the mint could allow authentic customers to exchange their
+In this case, the exchange could allow authentic customers to exchange their
unspent coins that were signed with the compromised private key,
while refusing further anonymous transactions involving those coins.
As a result, the financial damage of losing a private signing key can be
limited to at most twice the amount originally signed with that key.
-To ensure that the mint does not enable deanonymization of users by
-signing each coin with a fresh coin signing key, the mint must publicly
+To ensure that the exchange does not enable deanonymization of users by
+signing each coin with a fresh coin signing key, the exchange must publicly
announce the coin signing keys in advance. Those announcements are
expected to be signed with an off-line long-term private {\em master
-signing key} of the mint and the auditor.
+signing key} of the exchange and the auditor.
-Before a customer can withdraw a coin from the mint,
-he has to pay the mint the value of the coin, as well as processing fees.
+Before a customer can withdraw a coin from the exchange,
+he has to pay the exchange the value of the coin, as well as processing fees.
This is done using other means of payments, such as wire transfers or
-by having a personal {\em reserve} at the mint,
+by having a personal {\em reserve} at the exchange,
which is equivalent to a bank account with a positive balance.
Taler assumes that the customer has a {\em withdrawal authorization key}
to identify himself as authorized to withdraw funds from the reserve.
By signing the withdrawal request messages using this withdrawal
-authorization key, the customer can prove to the mint that he is the
+authorization key, the customer can prove to the exchange that he is the
individual authorized to withdraw anonymous digital coins from his reserve.
-The mint will record the withdrawal messages with the reserve record as
+The exchange will record the withdrawal messages with the reserve record as
proof that the anonymous digital coin was created for the correct
customer. We note that the specifics of how the customer authenticates
-to the mint are orthogonal to the rest of the system, and
+to the exchange are orthogonal to the rest of the system, and
multiple methods can be supported.
%To put it differently, unlike
%modern cryptocurrencies like BitCoin, Taler's design simply
%acknowledges that primitive accumulation~\cite{engels1844} predates
%the system and that a secure method to authenticate owners exists.
-After a coin is minted, the customer is the only entity that knows the
+After a coin is exchanged, the customer is the only entity that knows the
private key of the coin, making him the \emph{owner} of the coin.
-The coin can be identified by the mint by its public key; however, due
-to the use of blind signatures, the mint does not learn the public key
-during the minting process. Knowledge of the private key of the coin
+The coin can be identified by the exchange by its public key; however, due
+to the use of blind signatures, the exchange does not learn the public key
+during the exchange process. Knowledge of the private key of the coin
enables the owner to spent the coin. If the private key is shared
with others, they also become owners of the coin.
@@ -579,10 +579,10 @@ To spend a coin, the coin's owner needs to sign a {\em deposit
request} specifying the amount, the merchant's account information
and a {\em business transaction-specific hash} using the coin's
private key. A merchant can then transfer this permission of the
-coin's owner to the mint to obtain the amount in traditional currency.
-If the customer is cheating and the coin was already spent, the mint
+coin's owner to the exchange to obtain the amount in traditional currency.
+If the customer is cheating and the coin was already spent, the exchange
provides cryptographic proof of the fraud to the merchant, who will
-then refuse the transaction. The mint is typically expected to
+then refuse the transaction. The exchange is typically expected to
transfer the funds to the merchant using a wire transfer or by
crediting the merchant's individual account, depending on what is
appropriate to the domain of the traditional currency.
@@ -591,7 +591,7 @@ To allow exact payments without requiring the customer to keep a large
amount of ``change'' in stock and possibly perform thousands of
signatures for larger transactions, the payment systems allows partial
spending where just a fraction of a coin's total value is transferred.
-Consequently, the mint the must not only store the identifiers of
+Consequently, the exchange the must not only store the identifiers of
spent coins, but also the fraction of the coin that has been spent.
@@ -601,7 +601,7 @@ In this and other scenarios it is thus possible that a customer has
revealed the public key of a coin to a merchant, but not ultimately
signed over the full value of the coin. If the customer then
continues to directly use the coin in other transactions, merchants
-and the mint could link the various transactions as they all share the
+and the exchange could link the various transactions as they all share the
same public key for the coin.
The owner of such a {\em dirty} coin might therefore want to exchange it
@@ -620,21 +620,21 @@ must assure that owner stays the same.
% Meh, this paragraph sucks :
We therefore demand two main properties from the refresh protocol:
-First, the mint must not be able to link the fresh coin's public key to
-the public key of the dirty coin. Second, the mint can ensure that the
+First, the exchange must not be able to link the fresh coin's public key to
+the public key of the dirty coin. Second, the exchange can ensure that the
owner of the dirty coin can determine the private key of the
fresh coin, thereby preventing the refresh protocol from being used to
construct a transaction.
%As with other operations, the refreshing protocol must also protect
-%the mint from double-spending; similarly, the customer has to have
-%cryptographic evidence if there is any misbehavior by the mint.
-%Finally, the mint may choose to charge a transaction fee for
+%the exchange from double-spending; similarly, the customer has to have
+%cryptographic evidence if there is any misbehavior by the exchange.
+%Finally, the exchange may choose to charge a transaction fee for
%refreshing by reducing the value of the generated fresh coins
%in relation to the value of the melted coins.
%
%Naturally, all such transaction fees should be clearly stated as part
-%of the business contract offered by the mint to customers and
+%of the business contract offered by the exchange to customers and
%merchants.
@@ -642,7 +642,7 @@ construct a transaction.
% In this section, we describe the protocols for Taler in detail.
-We shall assume for the sake of brevity that a recipient of a signed
+We shall assume for the sake of brevity that a recipient of a signed
message always first checks that the signature is valid, aborting the
operation if not. Additionally, we assume that the receiver of a
signed message is either told the public key, or knows it from the
@@ -650,10 +650,10 @@ context, and that the signature contains additional identification as
to the purpose of the signature, making it impossible to use a signature
in a different context.
-The mint has an {\em online message signing key} used for signing
-messages, as opposed to coins. The mint's long-term offline key is used
+The exchange has an {\em online message signing key} used for signing
+messages, as opposed to coins. The exchange's long-term offline key is used
to certify both the coin signing keys and the online message signing key
-of the mint. The mint's long-term offline key is assumed to be known to
+of the exchange. The exchange's long-term offline key is assumed to be known to
both customers and merchants and is certified by the auditors.
As we are dealing with financial transactions, we explicitly describe
@@ -665,19 +665,19 @@ information. Keys and thus coins always have a well-known expiration
date; information committed to disk can be discarded after the
expiration date of the respective public key. Customers can also
discard information once the respective coins have been fully spent,
-and merchants may discard information once payments from the mint have
+and merchants may discard information once payments from the exchange have
been received, assuming the records are also no longer needed for tax
-purposes. The mint's bank transfers dealing in traditional currency
+purposes. The exchange's bank transfers dealing in traditional currency
are expected to be recorded for tax authorities to ensure taxability.
\subsection{Withdrawal}
Let $G$ be the generator of an elliptic curve. To withdraw anonymous
digital coins, the customer performs the following interaction with
-the mint:
+the exchange:
\begin{enumerate}
- \item The customer identifies a mint with an auditor-approved
+ \item The customer identifies a exchange with an auditor-approved
coin signing public-private key pair $K := (K_s, K_p)$
and randomly generates:
\begin{itemize}
@@ -685,19 +685,19 @@ the mint:
\item coin key $C := (c_s,C_p)$ with private key $c_s$ and public key $C_p := c_s G$,
\item blinding factor $b$, and commits $\langle W, C, b \rangle$ to disk.
\end{itemize}
- \item The customer transfers an amount of money corresponding to at least $K_p$ to the mint, with $W_p$ in the subject line of the transaction.
- \item The mint receives the transaction and credits the $W_p$ reserve with the respective amount in its database.
- \item The customer sends $S_W(B_b(C_p))$ to the mint to request withdrawal of $C$; here, $B_b$ denotes Chaum-style blinding with blinding factor $b$.
- \item The mint checks if the same withdrawal request was issued before; in this case, it sends $S_{K}(B_b(C_p))$ to the customer.\footnote{Here $S_K$
+ \item The customer transfers an amount of money corresponding to at least $K_p$ to the exchange, with $W_p$ in the subject line of the transaction.
+ \item The exchange receives the transaction and credits the $W_p$ reserve with the respective amount in its database.
+ \item The customer sends $S_W(B_b(C_p))$ to the exchange to request withdrawal of $C$; here, $B_b$ denotes Chaum-style blinding with blinding factor $b$.
+ \item The exchange checks if the same withdrawal request was issued before; in this case, it sends $S_{K}(B_b(C_p))$ to the customer.\footnote{Here $S_K$
denotes a Chaum-style blind signature with private key $K_s$.}
- If this is a fresh withdrawal request, the mint performs the following transaction:
+ If this is a fresh withdrawal request, the exchange performs the following transaction:
\begin{enumerate}
\item checks if the reserve $W_p$ has sufficient funds for a coin of value corresponding to $K_p$
\item stores the withdrawal request and response $\langle S_W(B_b(C_p)), S_K(B_b(C_p)) \rangle$ in its database for future reference,
\item deducts the amount corresponding to $K_p$ from the reserve,
\end{enumerate}
and then sends $S_{K}(B_b(C_p))$ to the customer.
- If the guards for the transaction fail, the mint sends a descriptive error back to the customer,
+ If the guards for the transaction fail, the exchange sends a descriptive error back to the customer,
with proof that it operated correctly.
Assuming the signature was valid, this would involve showing the transaction history for the reserve.
\item The customer computes and verifies the unblinded signature $S_K(C_p) = U_b(S_K(B_b(C_p)))$.
@@ -705,7 +705,7 @@ the mint:
\end{enumerate}
We note that the authorization to create and access a reserve using a
withdrawal key $W$ is just one way to establish that the customer is
-authorized to withdraw funds. If a mint has other ways to securely
+authorized to withdraw funds. If a exchange has other ways to securely
authenticate customers and establish that they are authorized to
withdraw funds, those can also be used with Taler.
@@ -713,19 +713,19 @@ withdraw funds, those can also be used with Taler.
\subsection{Exact and partial spending}
A customer can spend coins at a merchant, under the condition that the
-merchant trusts the specific mint that minted the coin. Merchants are
+merchant trusts the specific exchange that exchanged the coin. Merchants are
identified by their key $M := (m_s, M_p)$ where the public key $M_p$
must be known to the customer a priori.
-We now describe the protocol between the customer, merchant, and mint
+We now describe the protocol between the customer, merchant, and exchange
for a transaction in which the customer spends a coin $C := (c_s, C_p)$
with signature $\widetilde{C} := S_K(C_p)$
- where $K$ is the mint's demonination key.
+ where $K$ is the exchange's demonination key.
\begin{enumerate}
\item\label{contract}
- Let $\vec{D} := D_1, \ldots, D_n$ be the list of mints accepted by
- the merchant where each $D_j$ is a mint's public key.
+ Let $\vec{D} := D_1, \ldots, D_n$ be the list of exchanges accepted by
+ the merchant where each $D_j$ is a exchange's public key.
The merchant creates a digitally signed contract
$\mathcal{A} := S_M(m, f, a, H(p, r), \vec{D})$
where $m$ is an identifier for this transaction, $a$ is data relevant
@@ -734,40 +734,40 @@ with signature $\widetilde{C} := S_K(C_p)$
$p$ is the merchant's payment information (e.g. his IBAN number), and
$r$ is a random nonce. The merchant commits $\langle \mathcal{A} \rangle$
to disk and sends $\mathcal{A}$ to the customer.
-\item\label{deposit}
- The customer should already possess a coin minted by a mint that is
+\item\label{deposit}
+ The customer should already possess a coin exchanged by a exchange that is
accepted by the merchant, meaning $K$ should be publicly signed by
- some $D_j \in \{D_1, D_2, \ldots, D_n\}$, and has a value $\geq f$.
+ some $D_j \in \{D_1, D_2, \ldots, D_n\}$, and has a value $\geq f$.
\item The customer generates a \emph{deposit-permission} $\mathcal{D} :=
S_c(\widetilde{C}, m, f, H(a), H(p,r), M_p)$
and sends $\langle \mathcal{D}, D_j\rangle$ to the merchant,
- where $D_j$ is the mint which signed $K$.
-\item The merchant gives $(\mathcal{D}, p, r)$ to the mint, revealing $p$
- only to the mint.
-\item The mint validates $\mathcal{D}$ and checks for double spending.
+ where $D_j$ is the exchange which signed $K$.
+\item The merchant gives $(\mathcal{D}, p, r)$ to the exchange, revealing $p$
+ only to the exchange.
+\item The exchange validates $\mathcal{D}$ and checks for double spending.
If the coin has been involved in previous transactions and the new
one would exceed its remaining value, it sends an error
with the records from the previous transactions back to the merchant.
%
- If double spending is not found, the mint commits $\langle \mathcal{D} \rangle$ to disk
+ If double spending is not found, the exchange commits $\langle \mathcal{D} \rangle$ to disk
and notifies the merchant that the deposit operation was successful.
-\item The merchant commits and forwards the notification from the mint to the
+\item The merchant commits and forwards the notification from the exchange to the
customer, confirming the success or failure of the operation.
\end{enumerate}
We have simplified the exposition by assuming that one coin suffices, but
-in practice a customer can use multiple coins from the same mint where
+in practice a customer can use multiple coins from the same exchange where
the total value adds up to $f$ by running the following steps for
each of the coins. There is a risk of metadata leakage if a customer
acquires a coin in responce to the merchant, or if a customer uses
-coings issued by multiple mints together.
+coings issued by multiple exchanges together.
If a transaction is aborted after Step~\ref{deposit},
subsequent transactions with the same coin could be linked to the coin,
but not directly to the coin's owner. The same applies to partially
spent coins where $f$ is smaller than the actual value of the coin.
To unlink subsequent transactions from a coin, the customer has to
-execute the coin refreshing protocol with the mint.
+execute the coin refreshing protocol with the exchange.
%\begin{figure}[h]
%\centering
@@ -777,12 +777,12 @@ execute the coin refreshing protocol with the mint.
%\node (origin) at (0,0) {};
%\node (offer) [def,below=of origin]{make offer (merchant $\rightarrow$ customer)};
%\node (A) [def,below=of offer]{permit lock (customer $\rightarrow$ merchant)};
-%\node (B) [def,below=of A]{apply lock (merchant $\rightarrow$ mint)};
-%\node (C) [def,below=of B]{confirm (or refuse) lock (mint $\rightarrow$ merchant)};
+%\node (B) [def,below=of A]{apply lock (merchant $\rightarrow$ exchange)};
+%\node (C) [def,below=of B]{confirm (or refuse) lock (exchange $\rightarrow$ merchant)};
%\node (D) [def,below=of C]{sign contract (merchant $\rightarrow$ customer)};
%\node (E) [def,below=of D]{permit deposit (customer $\rightarrow$ merchant)};
-%\node (F) [def,below=of E]{make deposit (merchant $\rightarrow$ mint)};
-%\node (G) [def,below=of F]{transfer confirmation (mint $\rightarrow$ merchant)};
+%\node (F) [def,below=of E]{make deposit (merchant $\rightarrow$ exchange)};
+%\node (G) [def,below=of F]{transfer confirmation (exchange $\rightarrow$ merchant)};
%
%\tikzstyle{C} = [color=black, line width=1pt]
%\draw [->,C](offer) -- (A);
@@ -796,7 +796,7 @@ execute the coin refreshing protocol with the mint.
%\draw [->,C, bend right, shorten <=2mm] (E.east)
% to[out=-135,in=-45,distance=3.8cm] node[left] {aggregate} (D.east);
%\end{tikzpicture}
-%\caption{Interactions between a customer, merchant and mint in the coin spending
+%\caption{Interactions between a customer, merchant and exchange in the coin spending
% protocol}
%\label{fig:spending_protocol_interactions}
%\end{figure}
@@ -804,11 +804,11 @@ execute the coin refreshing protocol with the mint.
\subsection{Refreshing} \label{sec:refreshing}
-We now describe the refresh protocol whereby a dirty coin $C'$ of
+We now describe the refresh protocol whereby a dirty coin $C'$ of
denomination $K$ is melted to obtain a fresh coin $\widetilde{C}$
with the same denomination. In practice, Taler uses a natural
extension where multiple fresh coins are generated a the same time to
-enable giving precise change matching any amount.
+enable giving precise change matching any amount.
In the protocol, $\kappa \ge 3$ is a security parameter and $G$ is the
generator of the elliptic curve.
@@ -830,18 +830,18 @@ generator of the elliptic curve.
between the private key $c'_s$ of the original coin with
the public transfer key $T_p^{(i)}$.
\item The customer computes $B^{(i)} := B_{b^{(i)}}(C^{(i)}_p)$ for $i \in \{1,\ldots,\kappa\}$ and sends a commitment
- $S_{C'}(\vec{E}, \vec{B}, \vec{T_p})$ to the mint.
- \item The mint generates a random $\gamma$ with $1 \le \gamma \le \kappa$ and
+ $S_{C'}(\vec{E}, \vec{B}, \vec{T_p})$ to the exchange.
+ \item The exchange generates a random $\gamma$ with $1 \le \gamma \le \kappa$ and
marks $C'_p$ as spent by committing
$\langle C', \gamma, S_{C'}(\vec{E}, \vec{B}, \vec{T_p}) \rangle$ to disk.
Auditing processes should assure that $\gamma$ is unpredictable until
- this time to prevent the mint from assisting tax evasion.
- \item The mint sends $S_{K'}(C'_p, \gamma)$ to the customer where
- $K'$ is the mint's message signing key.
+ this time to prevent the exchange from assisting tax evasion.
+ \item The exchange sends $S_{K'}(C'_p, \gamma)$ to the customer where
+ $K'$ is the exchange's message signing key.
\item The customer commits $\langle C', S_K(C'_p, \gamma) \rangle$ to disk.
\item The customer computes $\mathfrak{R} := \left(t_s^{(i)}\right)_{i \ne \gamma}$
- and sends $S_{C'}(\mathfrak{R})$ to the mint.
- \item \label{step:refresh-ccheck} The mint checks whether $\mathfrak{R}$ is consistent with the commitments;
+ and sends $S_{C'}(\mathfrak{R})$ to the exchange.
+ \item \label{step:refresh-ccheck} The exchange checks whether $\mathfrak{R}$ is consistent with the commitments;
specifically, it computes for $i \not= \gamma$:
\vspace{-2ex}
@@ -864,8 +864,8 @@ generator of the elliptic curve.
\item \label{step:refresh-done} If the commitments were consistent,
- the mint sends the blind signature $\widetilde{C} :=
- S_{K}(B^{(\gamma)})$ to the customer. Otherwise, the mint responds
+ the exchange sends the blind signature $\widetilde{C} :=
+ S_{K}(B^{(\gamma)})$ to the customer. Otherwise, the exchange responds
with an error indicating the location of the failure.
\end{enumerate}
@@ -875,7 +875,7 @@ generator of the elliptic curve.
\subsection{Linking}
-For a coin that was successfully refreshed, the mint responds to a
+For a coin that was successfully refreshed, the exchange responds to a
request $S_{C'}(\mathtt{link})$ with $(T^{(\gamma)}_p$, $E^{(\gamma)},
\widetilde{C})$.
%
@@ -883,7 +883,7 @@ This allows the owner of the melted coin to also obtain the private
key of the new coin, even if the refreshing protocol was illicitly
executed with the help of another party who generated $\vec{c_s}$ and only
provided $\vec{C_p}$ and other required information to the old owner.
-As a result, linking ensures that access to the new coins minted by
+As a result, linking ensures that access to the new coins exchanged by
the refresh protocol is always {\em shared} with the owner of the
melted coins. This makes it impossible to abuse the refresh protocol
for {\em transactions}.
@@ -892,7 +892,7 @@ The linking request is not expected to be used at all during ordinary
operation of Taler. If the refresh protocol is used by Alice to
obtain change as designed, she already knows all of the information
and thus has little reason to request it via the linking protocol.
-The fundamental reason why the mint must provide the link protocol is
+The fundamental reason why the exchange must provide the link protocol is
simply to provide a threat: if Bob were to use the refresh protocol
for a transaction of funds from Alice to him, Alice may use a link
request to gain shared access to Bob's coins. Thus, this threat
@@ -903,8 +903,8 @@ exchanging the original private coin keys. This is permitted in our
taxation model as with such trust they are assumed to be the same
entity.
-The auditor can anonymously check if the mint correctly implements the
-link request, thus preventing the mint operator from legally disabling
+The auditor can anonymously check if the exchange correctly implements the
+link request, thus preventing the exchange operator from legally disabling
this protocol component. Without the link operation, Taler would
devolve into a payment system where both sides can be anonymous, and
thus no longer provide taxability.
@@ -926,7 +926,7 @@ server indicates that the client is violating the protocol, the
client should record the interaction and enable the user to file a
bug report.
-The second case is a faulty mint service provider. Such faults will
+The second case is a faulty exchange service provider. Such faults will
be detected because of protocol violations, such as providing
a faulty proof or no proof. In this case, the client is expected to
notify the auditor, providing a transcript of the interaction. The
@@ -935,11 +935,11 @@ provide the now correct response to the client or take appropriate
legal action against the faulty provider.
The third case are transient failures, such as network failures or
-temporary hardware failures at the mint service provider. Here, the
+temporary hardware failures at the exchange service provider. Here, the
client may receive an explicit protocol indication, such as an HTTP
response code 500 ``internal server error'' or simply no response.
The appropriate behavior for the client is to automatically retry
-after 1s, and twice more at randomized times within 1 minute.
+after 1s, and twice more at randomized times within 1 minute.
If those three attempts fail, the user should be informed about the
delay. The client should then retry another three times within the
next 24h, and after that time the auditor be informed about the outage.
@@ -947,7 +947,7 @@ next 24h, and after that time the auditor be informed about the outage.
Using this process, short term failures should be effectively obscured
from the user, while malicious behavior is reported to the auditor who
can then presumably rectify the situation, such as by shutting down
-the operator and helping customers to regain refunds for coins in
+the operator and helping customers to regain refunds for coins in
their wallets. To ensure that such refunds are possible, the operator
is expected to always provide adequate securities for the amount of
coins in circulation as part of the certification process.
@@ -961,14 +961,14 @@ details, and having the customer keep the private key of the spent
coins on file.
Given this, the merchant can simply sign a {\em refund confirmation}
-and share it with the mint and the customer. Assuming the mint has
+and share it with the exchange and the customer. Assuming the exchange has
a way to recover the funds from the merchant, or has not yet performed
-the wire transfer, the mint can simply add the value of the refunded
-transaction back to the original coin, re-enabling those funds to be
+the wire transfer, the exchange can simply add the value of the refunded
+transaction back to the original coin, re-enabling those funds to be
spent again by the original customer.
This anonymous customer can then use the refresh protocol to melt the
-refunded coin and create a fresh coin that is unlinkable to the
+refunded coin and create a fresh coin that is unlinkable to the
refunded transaction.
@@ -976,11 +976,11 @@ refunded transaction.
Taler's security is largely equivalent to that of Chaum's original
design without online checks or the cut-and-choose revelation of
-double-spending customers for offline spending.
-We specifically note that the digital equivalent of the ``Columbian
-Black Market Exchange''~\cite{fatf1997} is a theoretical problem for
+double-spending customers for offline spending.
+We specifically note that the digital equivalent of the ``Columbian
+Black Market Exchange''~\cite{fatf1997} is a theoretical problem for
both Chaum and Taler, as individuals with a strong mutual trust
-foundation can simply copy electronic coins and thereby establish a
+foundation can simply copy electronic coins and thereby establish a
limited form of black transfers. However, unlike the situation with
physical checks with blank recipients in the Columbian black market,
the transitivity is limited as each participant can deposit the electronic
@@ -990,11 +990,11 @@ check and not also all previous owners of the physical check.
As with any unconditionally anonymous payment system, the ``Perfect
Crime'' attack~\cite{solms1992perfect} where blackmail is used to
-force the mint to issue anonymous coins also continues to apply in
+force the exchange to issue anonymous coins also continues to apply in
principle. However, as mentioned Taler does facilitate limits on
withdrawals, which we believe is a better trade-off than the
problematic escrow systems where the necessary intransparency
-actually facilitates voluntary cooperation between the mint and
+actually facilitates voluntary cooperation between the exchange and
criminals~\cite{sander1999escrow} and where state can selectively
deanonymize activists to support the deep state's quest for absolute
security.
@@ -1002,12 +1002,12 @@ security.
\subsection{Offline Payments}
Chaum's original proposals for anonymous digital cash avoided the need
-for online interactions with the mint to detect double spending by
+for online interactions with the exchange to detect double spending by
providing a means to deanonymize customers involved in
-double-spending. We believe that this is problematic as the mint or
+double-spending. We believe that this is problematic as the exchange or
the merchant will then still need out-of-band means to recover funds
from the customer, which may be impossible in practice. In contrast,
-in our design only the mint may try to defraud the other participants
+in our design only the exchange may try to defraud the other participants
and disappear. While this is still a risk, and regular financial
audits are required to protect against it, this is more manageable and
significantly cheaper compared to recovering funds via the court
@@ -1017,12 +1017,12 @@ Chaum's method for offline payments would also be incompatible with
the refreshing protocol (Section~\ref{sec:refreshing}) which enables
the crucial feature of giving unlinkable change. The reason is that
if the owner's identity were embedded in coins, it would be leaked to
-the mint as part of the reveal operation in the cut-and-choose
+the exchange as part of the reveal operation in the cut-and-choose
operation of the refreshing protocol.
%\subsection{Merchant Tax Audits}
%
-%For a tax audit on the merchant, the mint includes the business
+%For a tax audit on the merchant, the exchange includes the business
%transaction-specific hash in the transfer of the traditional
%currency. A tax auditor can then request the merchant to reveal
%(meaningful) details about the business transaction ($\mathcal{D}$,
@@ -1048,13 +1048,13 @@ computing base (TCB) is public and free software.
%\subsection{System Performance}
%
%We performed some initial performance measurements for the various
-%operations on our mint implementation. The main conclusion was that
+%operations on our exchange implementation. The main conclusion was that
%the computational and bandwidth cost for transactions described in
%this paper is smaller than $10^{-3}$ cent/transaction, and thus
-%dwarfed by the other business costs for the mint. However, this
+%dwarfed by the other business costs for the exchange. However, this
%figure excludes the cost of currency transfers using traditional
-%banking, which a mint operator would ultimately have to interact with.
-%Here, mint operators should be able to reduce their expenses by
+%banking, which a exchange operator would ultimately have to interact with.
+%Here, exchange operators should be able to reduce their expenses by
%aggregating multiple transfers to the same merchant.
@@ -1065,8 +1065,8 @@ computing base (TCB) is public and free software.
%citizen's need for privacy and the state's need for taxation. The
%coin refreshing protocol makes the design flexible and enables a
%variety of payment methods. The current balance and profits of the
-%mint are also easily determined, thus audits can be used to ensure
-%that the mint operates correctly. The libre implementation and open
+%exchange are also easily determined, thus audits can be used to ensure
+%that the exchange operates correctly. The libre implementation and open
%protocol may finally enable modern society to upgrade to proper
%electronic wallets with efficient, secure and privacy-preserving
%transactions.
@@ -1097,17 +1097,17 @@ certain interactions.
However, we note that Taler's transaction costs are expected to be so
low that these features are likely not particularly useful in
practice: When we performed some initial performance measurements for
-the various operations on our mint implementation, the main conclusion
+the various operations on our exchange implementation, the main conclusion
was that the computational and bandwidth cost for transactions
described in this paper is smaller than $10^{-3}$ cent/transaction,
-and thus dwarfed by the other business costs for the mint. We note
+and thus dwarfed by the other business costs for the exchange. We note
that the $10^{-3}$ cent/transaction estimate excludes the cost of wire
-transfers using traditional banking, which a mint operator would
-ultimately have to interact with. Here, mint operators should be able
+transfers using traditional banking, which a exchange operator would
+ultimately have to interact with. Here, exchange operators should be able
to reduce their expenses by aggregating multiple transfers to the same
merchant.
-As a result of the low cost of the interaction with the mint in Taler
+As a result of the low cost of the interaction with the exchange in Taler
today, we expect that transactions with amounts below Taler's internal
transaction costs to be economically meaningless. Nevertheless, we
document various ways how such transactions could be achieved within
@@ -1120,7 +1120,7 @@ Taler.
For services that include pay-as-you-go billing, customers can over
time sign deposit permissions for an increasing fraction of the value
of a coin to be paid to a particular merchant. As checking with the
-mint for each increment might be expensive, the coin's owner can
+exchange for each increment might be expensive, the coin's owner can
instead sign a {\em lock permission}, which allows the merchant to get
an exclusive right to redeem deposit permissions for the coin for a
limited duration. The merchant uses the lock permission to determine
@@ -1128,41 +1128,41 @@ if the coin has already been spent and to ensure that it cannot be
spent by another merchant for the {\em duration} of the lock as
specified in the lock permission. If the coin has insufficient funds
because too much has been spent or is
-already locked, the mint provides the owner's deposit or locking
+already locked, the exchange provides the owner's deposit or locking
request and signature to prove the attempted fraud by the customer.
-Otherwise, the mint locks the coin for the expected duration of the
+Otherwise, the exchange locks the coin for the expected duration of the
transaction (and remembers the lock permission). The merchant and the
customer can then finalize the business transaction, possibly
exchanging a series of incremental payment permissions for services.
-Finally, the merchant then redeems the coin at the mint before the
+Finally, the merchant then redeems the coin at the exchange before the
lock permission expires to ensure that no other merchant redeems the
coin first.
\begin{enumerate}
\item\label{offer2} The merchant sends an \emph{offer:} $\langle S_M(m, f),
\vec{D} \rangle$ containing the price of the offer $f$, a transaction
- ID $m$ and the list of mints $D_1, \ldots, D_n$ accepted by the merchant
- where each $D_j$ is a mint's public key.
+ ID $m$ and the list of exchanges $D_1, \ldots, D_n$ accepted by the merchant
+ where each $D_j$ is a exchange's public key.
\item\label{lock2} The customer must possess or acquire a coin $\widetilde{C}$
- signed by a mint that is
+ signed by a exchange that is
accepted by the merchant, i.e. $K$ should be signed by some $D_j
\in \{D_1, D_2, \ldots, D_n\}$, and has a value $\geq f$.
Customer then generates a \emph{lock-permission} $\mathcal{L} :=
S_c(\widetilde{C}, t, m, f, M_p)$ where $t$ specifies the time until which the
lock is valid and sends $\langle \mathcal{L}, D_j\rangle$ to the merchant,
- where $D_j$ is the mint which signed $K$.
-\item The merchant asks the mint to apply the lock by sending $\langle
- \mathcal{L} \rangle$ to the mint.
-\item The mint validates $\widetilde{C}$ and detects double spending
+ where $D_j$ is the exchange which signed $K$.
+\item The merchant asks the exchange to apply the lock by sending $\langle
+ \mathcal{L} \rangle$ to the exchange.
+\item The exchange validates $\widetilde{C}$ and detects double spending
in the form of existing \emph{deposit-permission} or
lock-permission records for $\widetilde{C}$. If such records exist
- and indicate that insufficient funds are left, the mint sends those
+ and indicate that insufficient funds are left, the exchange sends those
records to the merchant, who can then use the records to prove the double
spending to the customer.
If double spending is not found,
- the mint commits $\langle \mathcal{L} \rangle$ to disk
+ the exchange commits $\langle \mathcal{L} \rangle$ to disk
and notifies the merchant that locking was successful.
\item\label{contract2} The merchant creates a digitally signed contract
$\mathcal{A} := S_M(m, f, a, H(p, r))$ where $a$ is data relevant to the contract
@@ -1173,23 +1173,23 @@ coin first.
\emph{deposit-permission} $\mathcal{D} := S_c(\widetilde{C}, \widetilde{L}, f, m, M_p, H(a), H(p, r))$, commits
$\langle \mathcal{A}, \mathcal{D} \rangle$ to disk and sends $\mathcal{D}$ to the merchant.
\item\label{invoice_paid2} The merchant commits the received $\langle \mathcal{D} \rangle$ to disk.
-\item The merchant gives $(\mathcal{D}, p, r)$ to the mint, revealing his
+\item The merchant gives $(\mathcal{D}, p, r)$ to the exchange, revealing his
payment information.
-\item The mint verifies $(\mathcal{D}, p, r)$ for its validity and
+\item The exchange verifies $(\mathcal{D}, p, r)$ for its validity and
checks against double spending, while of
course permitting the merchant to withdraw funds from the amount that
had been locked for this merchant.
\item If $\widetilde{C}$ is valid and no equivalent \emph{deposit-permission} for $\widetilde{C}$ and $\widetilde{L}$ exists on disk, the
- mint performs the following transaction:
+ exchange performs the following transaction:
\begin{enumerate}
\item $\langle \mathcal{D}, p, r \rangle$ is committed to disk.
\item\label{transfer2} transfers an amount of $f$ to the merchant's bank account
given in $p$. The subject line of the transaction to $p$ must contain
$H(\mathcal{D})$.
\end{enumerate}
- Finally, the mint sends a confirmation to the merchant.
+ Finally, the exchange sends a confirmation to the merchant.
\item If the deposit record $\langle \mathcal{D}, p, r \rangle$ already exists,
- the mint sends the confirmation to the merchant,
+ the exchange sends the confirmation to the merchant,
but does not transfer money to $p$ again.
\end{enumerate}
@@ -1223,7 +1223,7 @@ incremental amount up to $f_{max}$:
For transactions with multiple coins, the steps of the protocol are
executed in parallel for each coin. During the time a coin is locked,
the locked fraction may not be spent at a different merchant or via a
-deposit permission that does not contain $\mathcal{L}$. The mint will
+deposit permission that does not contain $\mathcal{L}$. The exchange will
release the locks when they expire or are used in a deposit operation.
Thus the coins can be used with other merchants once their locks
expire, even if the original merchant never executed any deposit for
@@ -1234,7 +1234,7 @@ Similarly, if a transaction is aborted after Step 2, subsequent
transactions with the same coin can be linked to the coin, but not
directly to the coin's owner. The same applies to partially spent
coins. Thus, to unlink subsequent transactions from a coin, the
-customer has to execute the coin refreshing protocol with the mint.
+customer has to execute the coin refreshing protocol with the exchange.
%\begin{figure}[h]
%\centering
@@ -1244,12 +1244,12 @@ customer has to execute the coin refreshing protocol with the mint.
%\node (origin) at (0,0) {};
%\node (offer) [def,below=of origin]{make offer (merchant $\rightarrow$ customer)};
%\node (A) [def,below=of offer]{permit lock (customer $\rightarrow$ merchant)};
-%\node (B) [def,below=of A]{apply lock (merchant $\rightarrow$ mint)};
-%\node (C) [def,below=of B]{confirm (or refuse) lock (mint $\rightarrow$ merchant)};
+%\node (B) [def,below=of A]{apply lock (merchant $\rightarrow$ exchange)};
+%\node (C) [def,below=of B]{confirm (or refuse) lock (exchange $\rightarrow$ merchant)};
%\node (D) [def,below=of C]{sign contract (merchant $\rightarrow$ customer)};
%\node (E) [def,below=of D]{permit deposit (customer $\rightarrow$ merchant)};
-%\node (F) [def,below=of E]{make deposit (merchant $\rightarrow$ mint)};
-%\node (G) [def,below=of F]{transfer confirmation (mint $\rightarrow$ merchant)};
+%\node (F) [def,below=of E]{make deposit (merchant $\rightarrow$ exchange)};
+%\node (G) [def,below=of F]{transfer confirmation (exchange $\rightarrow$ merchant)};
%
%\tikzstyle{C} = [color=black, line width=1pt]
%\draw [->,C](offer) -- (A);
@@ -1263,7 +1263,7 @@ customer has to execute the coin refreshing protocol with the mint.
%\draw [->,C, bend right, shorten <=2mm] (E.east)
% to[out=-135,in=-45,distance=3.8cm] node[left] {aggregate} (D.east);
%\end{tikzpicture}
-%\caption{Interactions between a customer, merchant and mint in the coin spending
+%\caption{Interactions between a customer, merchant and exchange in the coin spending
% protocol}
%\label{fig:spending_protocol_interactions}
%\end{figure}
@@ -1274,7 +1274,7 @@ customer has to execute the coin refreshing protocol with the mint.
Similar to Peppercoin, Taler supports probabilistic {\em micro}donations of coins to
support cost-effective transactions for small amounts. We consider
amounts to be ``micro'' if the value of the transaction is close or
-even below the business cost of an individual transaction to the mint.
+even below the business cost of an individual transaction to the exchange.
To support microdonations, an ordinary transaction is performed based
on the result of a biased coin flip with a probability related to the
@@ -1282,7 +1282,7 @@ desired transaction amount in relation to the value of the coin. More
specifically, a microdonation of value $\epsilon$ is upgraded to a
macropayment of value $m$ with a probability of $\frac{\epsilon}{m}$.
Here, $m$ is chosen such that the business transaction cost at the
-mint is small in relation to $m$. The mint is only involved in the
+exchange is small in relation to $m$. The exchange is only involved in the
tiny fraction of transactions that are upgraded. On average both
customers and merchants end up paying (or receiving) the expected
amount $\epsilon$ per microdonation.
@@ -1290,12 +1290,12 @@ amount $\epsilon$ per microdonation.
Unlike Peppercoin, in Taler either the merchant wins and the customer
looses the coin, or the merchant looses and the customer keeps the
coin. Thus, there is no opportunity for the merchant and the customer
-to conspire against the mint. To determine if the coin is to be
+to conspire against the exchange. To determine if the coin is to be
transferred, merchant and customer execute a secure coin flipping
protocol~\cite{blum1981}. The commit values are included in the
business contract and are revealed after the contract has been signed
using the private key of the coin. If the coin flip is decided in
-favor of the merchant, the merchant can redeem the coin at the mint.
+favor of the merchant, the merchant can redeem the coin at the exchange.
One issue in this protocol is that the customer may use a worthless
coin by offering a coin that has already been spent. This kind of
@@ -1306,9 +1306,9 @@ already spent coins until the coin flip is in his favor.
As with incremental spending, lock permissions could be used to ensure
that the customer cannot defraud the merchant by offering a coin that
-has already been spent. However, as this means involving the mint
+has already been spent. However, as this means involving the exchange
even if the merchant looses the coin flip, such a scheme is unsuitable
-for microdonations as the transaction costs from involving the mint
+for microdonations as the transaction costs from involving the exchange
might be disproportionate to the value of the transaction, and thus
with locking the probabilistic scheme has no advantage over simply
using fractional payments.
@@ -1366,7 +1366,7 @@ indicate the application of a function $f$ to one or more arguments. Records of
data being committed to disk are represented in between $\langle\rangle$.
\begin{description}
- \item[$K_s$]{Private (RSA) key of the mint used for coin signing}
+ \item[$K_s$]{Private (RSA) key of the exchange used for coin signing}
\item[$K_p$]{Public (RSA) key corresponding to $K_s$}
\item[$K$]{Public-priate (RSA) coin signing key pair $K := (K_s, K_p)$}
\item[$b$]{RSA blinding factor for RSA-style blind signatures}
@@ -1389,11 +1389,11 @@ data being committed to disk are represented in between $\langle\rangle$.
\item[$c_s'$]{Private key of a ``dirty'' coin (otherwise like $c_s$)}
\item[$C_p'$]{Public key of a ``dirty'' coin (otherwise like $C_p$)}
\item[$C'$]{Dirty coin (otherwise like $C$)}
- \item[$\widetilde{C}$]{Mint signature $S_K(C_p)$ indicating validity of a fresh coin (with key $C$)}
- \item[$n$]{Number of mints accepted by a merchant}
- \item[$j$]{Index into a set of accepted mints, $i \in \{1,\ldots,n\}$}
- \item[$D_j$]{Public key of a mint (not used to sign coins)}
- \item[$\vec{D}$]{Vector of $D_j$ signifying mints accepted by a merchant}
+ \item[$\widetilde{C}$]{Exchange signature $S_K(C_p)$ indicating validity of a fresh coin (with key $C$)}
+ \item[$n$]{Number of exchanges accepted by a merchant}
+ \item[$j$]{Index into a set of accepted exchanges, $i \in \{1,\ldots,n\}$}
+ \item[$D_j$]{Public key of a exchange (not used to sign coins)}
+ \item[$\vec{D}$]{Vector of $D_j$ signifying exchanges accepted by a merchant}
\item[$a$]{Complete text of a contract between customer and merchant}
\item[$f$]{Amount a customer agrees to pay to a merchant for a contract}
\item[$m$]{Unique transaction identifier chosen by the merchant}
diff --git a/doc/taler-auditor-sign.1 b/doc/taler-auditor-sign.1
index ed264a496..177d0df04 100644
--- a/doc/taler-auditor-sign.1
+++ b/doc/taler-auditor-sign.1
@@ -1,7 +1,7 @@
.TH TALER\-AUDITOR\-SIGN 1 "Sep 15, 2015" "GNU Taler"
.SH NAME
-taler\-auditor\-sign \- Sign mint denomination as auditor.
+taler\-auditor\-sign \- Sign exchange denomination as auditor.
.SH SYNOPSIS
.B taler\-auditor\-sign
@@ -9,7 +9,7 @@ taler\-auditor\-sign \- Sign mint denomination as auditor.
.br
.SH DESCRIPTION
-\fBtaler\-auditor\-sign\fP is a command line tool to be used by an auditor to sign that he is aware of certain keys being used by a mint. Using this signature, the auditor affirms that he will verify that the mint is properly accounting for those coins.
+\fBtaler\-auditor\-sign\fP is a command line tool to be used by an auditor to sign that he is aware of certain keys being used by a exchange. Using this signature, the auditor affirms that he will verify that the exchange is properly accounting for those coins.
.SH OPTIONS
.B
@@ -19,11 +19,11 @@ Location of the private EdDSA auditor key. If it does not exist, it will be cre
.IP "\-h, \-\-help"
Print short help on options.
.B
-.IP "\-m KEY, \-\-mint-key=KEY"
-Public key of the mint in Crockford base32 encoding, for example as generated by gnunet\-ecc \-p.
+.IP "\-m KEY, \-\-exchange-key=KEY"
+Public key of the exchange in Crockford base32 encoding, for example as generated by gnunet\-ecc \-p.
.B
-.IP "\-r FILE, \-\-mint-request=FILE"
-File with the mint's denomination key signing request as generated by taler\-mint\-keyup \-o.
+.IP "\-r FILE, \-\-exchange-request=FILE"
+File with the exchange's denomination key signing request as generated by taler\-exchange\-keyup \-o.
.B
.IP "\-o FILE, \-\-output=FILE"
File where the auditor should write the EdDSA signature.
@@ -32,4 +32,4 @@ File where the auditor should write the EdDSA signature.
Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
.SH "SEE ALSO"
-\fBtaler\-mint\-keyup\fP(1), \fBgnunet\-ecc\fP(1), \fBtaler.conf\fP(5)
+\fBtaler\-exchange\-keyup\fP(1), \fBgnunet\-ecc\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-exchange-dbinit.1 b/doc/taler-exchange-dbinit.1
new file mode 100644
index 000000000..456a85b0c
--- /dev/null
+++ b/doc/taler-exchange-dbinit.1
@@ -0,0 +1,29 @@
+.TH TALER\-EXCHANGE\-DBINIT 1 "Apr 22, 2015" "GNU Taler"
+
+.SH NAME
+taler\-exchange\-dbinit \- Initialize Taler exchange database.
+
+.SH SYNOPSIS
+.B taler\-exchange\-dbinit
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBtaler\-exchange\-dbinit\fP is a command line tool to initialize the Taler exchange database. It creates the necessary tables and indices for the Taler exchange to operate.
+
+.SH OPTIONS
+.B
+.IP "\-d DIRNAME, \-\-exchange-dir=DIRNAME"
+Use the configuration and other resources for the exchange to operate from DIRNAME.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-v, \-\-version"
+Print version information.
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
+
+.SH "SEE ALSO"
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-reservemod\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-exchange-httpd.1 b/doc/taler-exchange-httpd.1
new file mode 100644
index 000000000..959f1ec76
--- /dev/null
+++ b/doc/taler-exchange-httpd.1
@@ -0,0 +1,39 @@
+.TH TALER\-EXCHANGE\-HTTPD 1 "Apr 22, 2015" "GNU Taler"
+
+.SH NAME
+taler\-exchange\-httpd \- Run Taler exchange (with RESTful API)
+
+.SH SYNOPSIS
+.B taler\-exchange\-httpd
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBtaler\-exchange\-httpd\fP is a command line tool to run the Taler exchange (HTTP server). The required configuration, keys and database must exist before running this command.
+
+.SH OPTIONS
+.B
+.IP "\-C, \-\-connection-close"
+Force each HTTP connection to be closed after each request (useful in combination with \-f to avoid having to wait for nc to time out).
+.B
+.IP "\-d DIRNAME, \-\-exchange-dir=DIRNAME"
+Use the configuration and other resources for the exchange to operate from DIRNAME.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-v, \-\-version"
+Print version information.
+.B
+.IP "\-f FILENAME, \-\-file\-input=FILENAME"
+This option is only available if the exchange was compiled with the configure option
+\-\-enable\-developer\-mode. It is used for generating test cases against the exchange using AFL. When this option is present, the HTTP server will (1) terminate after the first client's HTTP connection is completed, and (2) automatically start such a client using a helper process based on the 'nc' or 'ncat' binary using FILENAME as the standard input to the helper process. As a result, the process will effectively run with FILENAME as the input from an HTTP client and then immediately exit. This is useful to test taler\-exchange\-httpd against many different possible inputs in a controlled way.
+.B
+.IP \"-t SECONDS, \-\-timeout=SECONDS"
+Specifies the number of SECONDS after which the HTTPD should close (idle) HTTP connections.
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
+
+.SH "SEE ALSO"
+\fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-reservemod\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-exchange-keycheck.1 b/doc/taler-exchange-keycheck.1
new file mode 100644
index 000000000..3f3382336
--- /dev/null
+++ b/doc/taler-exchange-keycheck.1
@@ -0,0 +1,29 @@
+.TH TALER\-EXCHANGE\-KEYCHECK 1 "Apr 22, 2015" "GNU Taler"
+
+.SH NAME
+taler\-exchange\-keycheck \- Check validity of Taler signing and denomination keys.
+
+.SH SYNOPSIS
+.B taler\-exchange\-keycheck
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBtaler\-exchange\-keycheck\fP can be used to check if the signing and denomination keys in the operation directory are well-formed. This can be useful after importing fresh keys from the offline system to ensure that the files are correct.
+
+.SH OPTIONS
+.B
+.IP "\-d DIRNAME, \-\-exchange-dir=DIRNAME"
+Use the configuration and other resources for the exchange to operate from DIRNAME.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-v, \-\-version"
+Print version information.
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
+
+.SH "SEE ALSO"
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-dbinit\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-exchange-keyup.1 b/doc/taler-exchange-keyup.1
new file mode 100644
index 000000000..541c10ec8
--- /dev/null
+++ b/doc/taler-exchange-keyup.1
@@ -0,0 +1,38 @@
+.TH TALER\-EXCHANGE\-KEYUP 1 "Apr 22, 2015" "GNU Taler"
+
+.SH NAME
+taler\-exchange\-keyup \- Setup Taler exchange denomination and signing keys.
+
+.SH SYNOPSIS
+.B taler\-exchange\-keyup
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBtaler\-exchange\-keyup\fP is a command line tool to setup Taler denomination and signing keys. This tool requires access to the exchange's long-term offline signing key and should be run in a secure (offline) environment under strict controls. The resulting keys can then be copied to the main online directory where the Taler HTTP server operates.
+
+.SH OPTIONS
+.B
+.IP "\-d DIRNAME, \-\-exchange-dir=DIRNAME"
+Use the configuration and other resources for the exchange to operate from DIRNAME.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-m FILE, \-\-master-key=FILE"
+Location of the private EdDSA offline master key of the exchange.
+.B
+.IP "\-o FILE, \-\-ouptut=FILE"
+Where to write a denomination key signing request file to be given to the auditor.
+.B
+.IP "\-t TIMESTAMP, \-\-time=TIMESTAMP"
+Operate as if the current time was TIMESTAMP.
+.B
+.IP "\-v, \-\-version"
+Print version information.
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
+
+.SH "SEE ALSO"
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-keycheck\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-exchange-reservemod.1 b/doc/taler-exchange-reservemod.1
new file mode 100644
index 000000000..7044a7c61
--- /dev/null
+++ b/doc/taler-exchange-reservemod.1
@@ -0,0 +1,35 @@
+.TH TALER\-EXCHANGE\-RESERVEMOD 1 "Apr 22, 2015" "GNU Taler"
+
+.SH NAME
+taler\-exchange\-reservemod \- Modify reserve balance in the Taler exchange database.
+
+.SH SYNOPSIS
+.B taler\-exchange\-reservemod
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBtaler\-exchange\-reservemod\fP is a command line tool to modify reserves in the Taler exchange database. Basically, it can be used to import deposits, either for testing or as part of the import from the list of incoming transactions.
+
+.SH OPTIONS
+.B
+.IP "\-a DENOM, \-\-add=DENOM"
+Amount to add to the reserve.
+.B
+.IP "\-d DIRNAME, \-\-exchange-dir=DIRNAME"
+Use the configuration and other resources for the exchange to operate from DIRNAME.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-R KEY, \-\-reserve=KEY"
+Public EdDSA key of the reserve to modify.
+.B
+.IP "\-v, \-\-version"
+Print version information.
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
+
+.SH "SEE ALSO"
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-dbinit\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-exchange-sepa.1 b/doc/taler-exchange-sepa.1
new file mode 100644
index 000000000..b24828d96
--- /dev/null
+++ b/doc/taler-exchange-sepa.1
@@ -0,0 +1,41 @@
+.TH TALER\-EXCHANGE\-SEPA 1 "Apr 22, 2015" "GNU Taler"
+
+.SH NAME
+taler\-exchange\-sepa \- Create the master-key signed response to /wire/sepa.
+
+.SH SYNOPSIS
+.B taler\-exchange\-sepa
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBtaler\-exchange\-sepa\fP is used to create the exchange's reply to a /wire/sepa request. It converts the bank details into the appropriate signed response. This needs to be done using the long-term offline master key.
+
+.SH OPTIONS
+.B
+.IP "\-b BIC, \-\-bic=BIC"
+Specifies the BIC code to use.
+.B
+.IP "\-i IBAN, \-\-iban=IBAN"
+Specifies the IBAN to use.
+.B
+.IP "\-n NAME, \-\-name=NAME"
+Specifies the name of the account holder.
+.B
+.IP "\-m MASTERKEYFILE, \-\-master=MASTERKEYFILE"
+Specifies the name of the file containing the exchange's master key.
+.B
+.IP "\-o FILENAME, \-\-output=FILENAME"
+Where to write the SEPA_RESPONSE_FILE.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-v, \-\-version"
+Print version information.
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
+
+.SH "SEE ALSO"
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-mint-dbinit.1 b/doc/taler-mint-dbinit.1
deleted file mode 100644
index c8678aed0..000000000
--- a/doc/taler-mint-dbinit.1
+++ /dev/null
@@ -1,29 +0,0 @@
-.TH TALER\-MINT\-DBINIT 1 "Apr 22, 2015" "GNU Taler"
-
-.SH NAME
-taler\-mint\-dbinit \- Initialize Taler mint database.
-
-.SH SYNOPSIS
-.B taler\-mint\-dbinit
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-mint\-dbinit\fP is a command line tool to initialize the Taler mint database. It creates the necessary tables and indices for the Taler mint to operate.
-
-.SH OPTIONS
-.B
-.IP "\-d DIRNAME, \-\-mint-dir=DIRNAME"
-Use the configuration and other resources for the mint to operate from DIRNAME.
-.B
-.IP "\-h, \-\-help"
-Print short help on options.
-.B
-.IP "\-v, \-\-version"
-Print version information.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
-
-.SH "SEE ALSO"
-\fBtaler\-mint\-httpd\fP(1), \fBtaler\-mint\-keyup\fP(1), \fBtaler\-mint\-reservemod\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-mint-httpd.1 b/doc/taler-mint-httpd.1
deleted file mode 100644
index 4f9c35292..000000000
--- a/doc/taler-mint-httpd.1
+++ /dev/null
@@ -1,39 +0,0 @@
-.TH TALER\-MINT\-HTTPD 1 "Apr 22, 2015" "GNU Taler"
-
-.SH NAME
-taler\-mint\-httpd \- Run Taler mint (with RESTful API)
-
-.SH SYNOPSIS
-.B taler\-mint\-httpd
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-mint\-httpd\fP is a command line tool to run the Taler mint (HTTP server). The required configuration, keys and database must exist before running this command.
-
-.SH OPTIONS
-.B
-.IP "\-C, \-\-connection-close"
-Force each HTTP connection to be closed after each request (useful in combination with \-f to avoid having to wait for nc to time out).
-.B
-.IP "\-d DIRNAME, \-\-mint-dir=DIRNAME"
-Use the configuration and other resources for the mint to operate from DIRNAME.
-.B
-.IP "\-h, \-\-help"
-Print short help on options.
-.B
-.IP "\-v, \-\-version"
-Print version information.
-.B
-.IP "\-f FILENAME, \-\-file\-input=FILENAME"
-This option is only available if the mint was compiled with the configure option
-\-\-enable\-developer\-mode. It is used for generating test cases against the mint using AFL. When this option is present, the HTTP server will (1) terminate after the first client's HTTP connection is completed, and (2) automatically start such a client using a helper process based on the 'nc' or 'ncat' binary using FILENAME as the standard input to the helper process. As a result, the process will effectively run with FILENAME as the input from an HTTP client and then immediately exit. This is useful to test taler\-mint\-httpd against many different possible inputs in a controlled way.
-.B
-.IP \"-t SECONDS, \-\-timeout=SECONDS"
-Specifies the number of SECONDS after which the HTTPD should close (idle) HTTP connections.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
-
-.SH "SEE ALSO"
-\fBtaler\-mint\-dbinit\fP(1), \fBtaler\-mint\-keyup\fP(1), \fBtaler\-mint\-reservemod\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-mint-keycheck.1 b/doc/taler-mint-keycheck.1
deleted file mode 100644
index a2c153244..000000000
--- a/doc/taler-mint-keycheck.1
+++ /dev/null
@@ -1,29 +0,0 @@
-.TH TALER\-MINT\-KEYCHECK 1 "Apr 22, 2015" "GNU Taler"
-
-.SH NAME
-taler\-mint\-keycheck \- Check validity of Taler signing and denomination keys.
-
-.SH SYNOPSIS
-.B taler\-mint\-keycheck
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-mint\-keycheck\fP can be used to check if the signing and denomination keys in the operation directory are well-formed. This can be useful after importing fresh keys from the offline system to ensure that the files are correct.
-
-.SH OPTIONS
-.B
-.IP "\-d DIRNAME, \-\-mint-dir=DIRNAME"
-Use the configuration and other resources for the mint to operate from DIRNAME.
-.B
-.IP "\-h, \-\-help"
-Print short help on options.
-.B
-.IP "\-v, \-\-version"
-Print version information.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
-
-.SH "SEE ALSO"
-\fBtaler\-mint\-httpd\fP(1), \fBtaler\-mint\-keyup\fP(1), \fBtaler\-mint\-dbinit\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-mint-keyup.1 b/doc/taler-mint-keyup.1
deleted file mode 100644
index 71135b36a..000000000
--- a/doc/taler-mint-keyup.1
+++ /dev/null
@@ -1,38 +0,0 @@
-.TH TALER\-MINT\-KEYUP 1 "Apr 22, 2015" "GNU Taler"
-
-.SH NAME
-taler\-mint\-keyup \- Setup Taler mint denomination and signing keys.
-
-.SH SYNOPSIS
-.B taler\-mint\-keyup
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-mint\-keyup\fP is a command line tool to setup Taler denomination and signing keys. This tool requires access to the mint's long-term offline signing key and should be run in a secure (offline) environment under strict controls. The resulting keys can then be copied to the main online directory where the Taler HTTP server operates.
-
-.SH OPTIONS
-.B
-.IP "\-d DIRNAME, \-\-mint-dir=DIRNAME"
-Use the configuration and other resources for the mint to operate from DIRNAME.
-.B
-.IP "\-h, \-\-help"
-Print short help on options.
-.B
-.IP "\-m FILE, \-\-master-key=FILE"
-Location of the private EdDSA offline master key of the mint.
-.B
-.IP "\-o FILE, \-\-ouptut=FILE"
-Where to write a denomination key signing request file to be given to the auditor.
-.B
-.IP "\-t TIMESTAMP, \-\-time=TIMESTAMP"
-Operate as if the current time was TIMESTAMP.
-.B
-.IP "\-v, \-\-version"
-Print version information.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
-
-.SH "SEE ALSO"
-\fBtaler\-mint\-httpd\fP(1), \fBtaler\-mint\-keyup\fP(1), \fBtaler\-mint\-keycheck\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-mint-reservemod.1 b/doc/taler-mint-reservemod.1
deleted file mode 100644
index 1d8270458..000000000
--- a/doc/taler-mint-reservemod.1
+++ /dev/null
@@ -1,35 +0,0 @@
-.TH TALER\-MINT\-RESERVEMOD 1 "Apr 22, 2015" "GNU Taler"
-
-.SH NAME
-taler\-mint\-reservemod \- Modify reserve balance in the Taler mint database.
-
-.SH SYNOPSIS
-.B taler\-mint\-reservemod
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-mint\-reservemod\fP is a command line tool to modify reserves in the Taler mint database. Basically, it can be used to import deposits, either for testing or as part of the import from the list of incoming transactions.
-
-.SH OPTIONS
-.B
-.IP "\-a DENOM, \-\-add=DENOM"
-Amount to add to the reserve.
-.B
-.IP "\-d DIRNAME, \-\-mint-dir=DIRNAME"
-Use the configuration and other resources for the mint to operate from DIRNAME.
-.B
-.IP "\-h, \-\-help"
-Print short help on options.
-.B
-.IP "\-R KEY, \-\-reserve=KEY"
-Public EdDSA key of the reserve to modify.
-.B
-.IP "\-v, \-\-version"
-Print version information.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
-
-.SH "SEE ALSO"
-\fBtaler\-mint\-httpd\fP(1), \fBtaler\-mint\-keyup\fP(1), \fBtaler\-mint\-dbinit\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler-mint-sepa.1 b/doc/taler-mint-sepa.1
deleted file mode 100644
index 62d75a667..000000000
--- a/doc/taler-mint-sepa.1
+++ /dev/null
@@ -1,41 +0,0 @@
-.TH TALER\-MINT\-SEPA 1 "Apr 22, 2015" "GNU Taler"
-
-.SH NAME
-taler\-mint\-sepa \- Create the master-key signed response to /wire/sepa.
-
-.SH SYNOPSIS
-.B taler\-mint\-sepa
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-mint\-sepa\fP is used to create the mint's reply to a /wire/sepa request. It converts the bank details into the appropriate signed response. This needs to be done using the long-term offline master key.
-
-.SH OPTIONS
-.B
-.IP "\-b BIC, \-\-bic=BIC"
-Specifies the BIC code to use.
-.B
-.IP "\-i IBAN, \-\-iban=IBAN"
-Specifies the IBAN to use.
-.B
-.IP "\-n NAME, \-\-name=NAME"
-Specifies the name of the account holder.
-.B
-.IP "\-m MASTERKEYFILE, \-\-master=MASTERKEYFILE"
-Specifies the name of the file containing the mint's master key.
-.B
-.IP "\-o FILENAME, \-\-output=FILENAME"
-Where to write the SEPA_RESPONSE_FILE.
-.B
-.IP "\-h, \-\-help"
-Print short help on options.
-.B
-.IP "\-v, \-\-version"
-Print version information.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
-
-.SH "SEE ALSO"
-\fBtaler\-mint\-httpd\fP(1), \fBtaler.conf\fP(5)
diff --git a/doc/taler.conf.5 b/doc/taler.conf.5
index 87f216913..f9d9d6312 100644
--- a/doc/taler.conf.5
+++ b/doc/taler.conf.5
@@ -10,9 +10,9 @@ taler.conf \- Taler configuration file.
The basic structure of the configuration file is the following. The file is split into sections. Every section begins with "[SECTIONNAME]" and contains a number of options of the form "OPTION=VALUE". Empty lines and lines beginning with a "#" are treated as comments.
-.SH MINT OPTIONS
+.SH EXCHANGE OPTIONS
-The following options are from the "[mint]" section and used by most mint tools:
+The following options are from the "[exchange]" section and used by most exchange tools:
.IP CURRENCY
Name of the currency, i.e. "EUR" for Euro.
@@ -23,32 +23,32 @@ The following options are from the "[mint]" section and used by most mint tools:
.IP PORT
Port on which the HTTP server listens, i.e. 8080.
.IP MASTER_PUBLIC_KEY
- Crockford Base32-encoded master public key, public version of the mint\'s long\-time offline signing key.
+ Crockford Base32-encoded master public key, public version of the exchange\'s long\-time offline signing key.
.SH WIRE transfer details
-The following options must be in section "[mint-wire-test]":
+The following options must be in section "[exchange-wire-test]":
.IP REDIRECT_URL
URL to redirect /wire/test to. Should contain a Web form the user can use to charge his wallet with coins in a "test" currency for testing. If this option is not provided, /wire/test will return "501 NOT IMPLEMENTED".
-The following options must be in section "[mint-wire-sepa]":
+The following options must be in section "[exchange-wire-sepa]":
.IP SEPA_RESPONSE_FILE
- Filename with the JSON body for the /wire/sepa response, signed using the mint's long-term offline master key. If this option is not provided, /wire/test will return "501 NOT IMPLEMENTED". Use "taler-mint-sepa" to create the SEPA_RESPONSE_FILE.
+ Filename with the JSON body for the /wire/sepa response, signed using the exchange's long-term offline master key. If this option is not provided, /wire/test will return "501 NOT IMPLEMENTED". Use "taler-exchange-sepa" to create the SEPA_RESPONSE_FILE.
.SH Postgres database options
-The following options must be in section "[mintdb-postgres]":
+The following options must be in section "[exchangedb-postgres]":
.IP DB_CONN_STR
How to access the database, i.e. "postgres:///taler" to use the "taler" database. Testcases use "talercheck".
.SH COIN OPTIONS
-The following options must be in sections starting with "[coin_]" and are used by taler\-mint\-keyup to create denomination keys:
+The following options must be in sections starting with "[coin_]" and are used by taler\-exchange\-keyup to create denomination keys:
.IP VALUE
Value of the coin, i.e. "EUR:1.50" for 1 Euro and 50 Cents (per coin).
@@ -69,7 +69,7 @@ The following options must be in sections starting with "[coin_]" and are used b
.SH KEY OPTIONS
-The following options are from the "[mint_keys]" section and used by most taler\-mint\-keyup to create keys:
+The following options are from the "[exchange_keys]" section and used by most taler\-exchange\-keyup to create keys:
.IP SIGNKEY_DURATION
For how long is a signing key valid?
@@ -85,5 +85,5 @@ The following options are from the "[mint_keys]" section and used by most taler\
Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
.SH "SEE ALSO"
-\fBtaler\-mint\-httpd\fP(1), \fBtaler\-mint\-keyup\fP(1), \fBtaler\-mint\-reservemod\fP(1), \fBtaler\-mint\-dbinit\fP(1), \fBtaler\-mint\-sepa(1)
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-reservemod\fP(1), \fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-sepa(1)
diff --git a/src/Makefile.am b/src/Makefile.am
index ac839d52a..37c902e65 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,16 +3,24 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include
if HAVE_POSTGRESQL
PQ_DIR = pq
endif
+if HAVE_LIBCURL
+ BANK_LIB = bank-lib
+else
+if HAVE_LIBGNURL
+ BANK_LIB = bank-lib
+endif
+endif
+
if WALLET_ONLY
SUBDIRS = include util
else
-SUBDIRS = include util $(PQ_DIR) bank-lib wire mintdb mint mint-tools
+SUBDIRS = include util $(PQ_DIR) $(BANK_LIB) wire exchangedb exchange exchange-tools
if HAVE_LIBCURL
- SUBDIRS += mint-lib
+ SUBDIRS += exchange-lib
else
if HAVE_LIBGNURL
- SUBDIRS += mint-lib
+ SUBDIRS += exchange-lib
endif
endif
diff --git a/src/bank-lib/bank_api_context.c b/src/bank-lib/bank_api_context.c
index a47b4072a..2e4083cae 100644
--- a/src/bank-lib/bank_api_context.c
+++ b/src/bank-lib/bank_api_context.c
@@ -390,7 +390,7 @@ TALER_BANK_fini (struct TALER_BANK_Context *ctx)
/**
* Obtain the URL to use for an API request.
*
- * @param h the mint handle to query
+ * @param h the exchange handle to query
* @param path Taler API path (i.e. "/reserve/withdraw")
* @return the full URI to use with cURL
*/
diff --git a/src/bank-lib/bank_api_json.h b/src/bank-lib/bank_api_json.h
index 2ecaf8ef1..92fe0b1d4 100644
--- a/src/bank-lib/bank_api_json.h
+++ b/src/bank-lib/bank_api_json.h
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file mint-lib/mint_api_json.h
+ * @file exchange-lib/exchange_api_json.h
* @brief functions to parse incoming requests (JSON snippets)
* @author Florian Dold
* @author Benedikt Mueller
@@ -349,4 +349,4 @@ BAJ_spec_rsa_signature (const char *name,
-/* end of mint_api_json.h */
+/* end of exchange_api_json.h */
diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am
new file mode 100644
index 000000000..f5e58b401
--- /dev/null
+++ b/src/exchange-lib/Makefile.am
@@ -0,0 +1,62 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+lib_LTLIBRARIES = \
+ libtalerexchange.la
+
+libtalerexchange_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+
+libtalerexchange_la_SOURCES = \
+ exchange_api_common.c exchange_api_common.h \
+ exchange_api_context.c exchange_api_context.h \
+ exchange_api_json.c exchange_api_json.h \
+ exchange_api_handle.c exchange_api_handle.h \
+ exchange_api_admin.c \
+ exchange_api_deposit.c \
+ exchange_api_deposit_wtid.c \
+ exchange_api_refresh.c \
+ exchange_api_refresh_link.c \
+ exchange_api_reserve.c \
+ exchange_api_wire.c \
+ exchange_api_wire_deposits.c
+
+libtalerexchange_la_LIBADD = \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+if HAVE_LIBCURL
+libtalerexchange_la_LIBADD += -lcurl
+else
+if HAVE_LIBGNURL
+libtalerexchange_la_LIBADD += -lgnurl
+endif
+endif
+
+check_PROGRAMS = \
+ test_exchange_api
+
+TESTS = \
+ $(check_PROGRAMS)
+
+test_exchange_api_SOURCES = \
+ test_exchange_api.c
+test_exchange_api_LDADD = \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil \
+ -ljansson
+
+EXTRA_DIST = \
+ test-exchange-home/config/exchange-common.conf \
+ test-exchange-home/master.priv \
+ test-exchange-home/denomkeys/ \
+ test-exchange-home/signkeys/
diff --git a/src/exchange-lib/afl-generate.sh b/src/exchange-lib/afl-generate.sh
new file mode 100644
index 000000000..6ae833087
--- /dev/null
+++ b/src/exchange-lib/afl-generate.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# This file is part of TALER
+# Copyright (C) 2015 GNUnet e.V.
+#
+# TALER is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
+#
+# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License along with
+# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+#
+#
+# This will generate testcases in a directory 'afl-tests', which can then
+# be moved into src/exchange/afl-tests/ to be run during exchange-testing.
+#
+# This script uses American Fuzzy Loop (AFL) to fuzz the exchange to
+# automatically create tests with good coverage. You must install
+# AFL and set AFL_HOME to the directory where AFL is installed
+# before running. Also, a directory "baseline/" should exist with
+# templates for inputs for AFL to fuzz. These can be generated
+# by running wireshark on loopback while running 'make check' in
+# this directory. Save each HTTP request to a new file.
+#
+# Note that you want to switch 'TESTRUN = NO' and pre-init the
+# database before running this, otherwise it will be awfully slow.
+#
+# Must be run from this directory.
+#
+$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-exchange-httpd -f /tmp/afl-input -d test-exchange-home/ -C
diff --git a/src/mint-lib/baseline/admin_add_incoming.req b/src/exchange-lib/baseline/admin_add_incoming.req
index 677678b5d..677678b5d 100644
--- a/src/mint-lib/baseline/admin_add_incoming.req
+++ b/src/exchange-lib/baseline/admin_add_incoming.req
diff --git a/src/mint-lib/baseline/deposit.req b/src/exchange-lib/baseline/deposit.req
index f50d83e40..f50d83e40 100644
--- a/src/mint-lib/baseline/deposit.req
+++ b/src/exchange-lib/baseline/deposit.req
diff --git a/src/mint-lib/baseline/keys.req b/src/exchange-lib/baseline/keys.req
index a9503a864..a9503a864 100644
--- a/src/mint-lib/baseline/keys.req
+++ b/src/exchange-lib/baseline/keys.req
diff --git a/src/mint-lib/baseline/refresh_link.req b/src/exchange-lib/baseline/refresh_link.req
index acf3dff51..acf3dff51 100644
--- a/src/mint-lib/baseline/refresh_link.req
+++ b/src/exchange-lib/baseline/refresh_link.req
diff --git a/src/mint-lib/baseline/refresh_melt.req b/src/exchange-lib/baseline/refresh_melt.req
index 98b5b6389..98b5b6389 100644
--- a/src/mint-lib/baseline/refresh_melt.req
+++ b/src/exchange-lib/baseline/refresh_melt.req
diff --git a/src/mint-lib/baseline/refresh_reveal.req b/src/exchange-lib/baseline/refresh_reveal.req
index 3fb143960..3fb143960 100644
--- a/src/mint-lib/baseline/refresh_reveal.req
+++ b/src/exchange-lib/baseline/refresh_reveal.req
diff --git a/src/mint-lib/baseline/reserve_status.req b/src/exchange-lib/baseline/reserve_status.req
index 4f988f669..4f988f669 100644
--- a/src/mint-lib/baseline/reserve_status.req
+++ b/src/exchange-lib/baseline/reserve_status.req
diff --git a/src/mint-lib/baseline/reserve_withdraw.req b/src/exchange-lib/baseline/reserve_withdraw.req
index 484950250..484950250 100644
--- a/src/mint-lib/baseline/reserve_withdraw.req
+++ b/src/exchange-lib/baseline/reserve_withdraw.req
diff --git a/src/mint-lib/baseline/wire.req b/src/exchange-lib/baseline/wire.req
index a4f1d0749..a4f1d0749 100644
--- a/src/mint-lib/baseline/wire.req
+++ b/src/exchange-lib/baseline/wire.req
diff --git a/src/mint-lib/baseline/wire_sepa.req b/src/exchange-lib/baseline/wire_sepa.req
index 80d3d4619..80d3d4619 100644
--- a/src/mint-lib/baseline/wire_sepa.req
+++ b/src/exchange-lib/baseline/wire_sepa.req
diff --git a/src/mint-lib/baseline/wire_test.req b/src/exchange-lib/baseline/wire_test.req
index 684352c96..684352c96 100644
--- a/src/mint-lib/baseline/wire_test.req
+++ b/src/exchange-lib/baseline/wire_test.req
diff --git a/src/exchange-lib/exchange_api_admin.c b/src/exchange-lib/exchange_api_admin.c
new file mode 100644
index 000000000..3dcbb80e9
--- /dev/null
+++ b/src/exchange-lib/exchange_api_admin.c
@@ -0,0 +1,254 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_admin.c
+ * @brief Implementation of the /admin/ requests of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief An admin/add/incoming Handle
+ */
+struct TALER_EXCHANGE_AdminAddIncomingHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * HTTP headers for the request.
+ */
+ struct curl_slist *headers;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_AdminAddIncomingResultCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /admin/add/incoming request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_AdminAddIncomingHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_admin_add_incoming_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_AdminAddIncomingHandle *aai = cls;
+ long response_code;
+ json_t *json;
+
+ aai->job = NULL;
+ json = MAC_download_get_result (&aai->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ /* Access denied */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, exchange says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ aai->cb (aai->cb_cls,
+ response_code,
+ json);
+ json_decref (json);
+ TALER_EXCHANGE_admin_add_incoming_cancel (aai);
+}
+
+
+/**
+ * Notify the exchange that we have received an incoming transaction
+ * which fills a reserve. Note that this API is an administrative
+ * API and thus not accessible to typical exchange clients, but only
+ * to the operators of the exchange.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param reserve_pub public key of the reserve
+ * @param amount amount that was deposited
+ * @param execution_date when did we receive the amount
+ * @param wire wire details
+ * @param res_cb the callback to call when the final result for this request is available
+ * @param res_cb_cls closure for the above callback
+ * @return NULL
+ * if the inputs are invalid (i.e. invalid amount).
+ * In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_AdminAddIncomingHandle *
+TALER_EXCHANGE_admin_add_incoming (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute execution_date,
+ const json_t *wire,
+ TALER_EXCHANGE_AdminAddIncomingResultCallback res_cb,
+ void *res_cb_cls)
+{
+ struct TALER_EXCHANGE_AdminAddIncomingHandle *aai;
+ struct TALER_EXCHANGE_Context *ctx;
+ json_t *admin_obj;
+ CURL *eh;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_round_abs_time (&execution_date));
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */
+ " s:o, s:O}", /* execution_Date/wire */
+ "reserve_pub", TALER_json_from_data (reserve_pub,
+ sizeof (*reserve_pub)),
+ "amount", TALER_json_from_amount (amount),
+ "execution_date", TALER_json_from_abs (execution_date),
+ "wire", wire);
+ aai = GNUNET_new (struct TALER_EXCHANGE_AdminAddIncomingHandle);
+ aai->exchange = exchange;
+ aai->cb = res_cb;
+ aai->cb_cls = res_cb_cls;
+ aai->url = MAH_path_to_url (exchange, "/admin/add/incoming");
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (aai->json_enc =
+ json_dumps (admin_obj,
+ JSON_COMPACT)));
+ json_decref (admin_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ aai->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ aai->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (aai->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &aai->db));
+ ctx = MAH_handle_to_context (exchange);
+ aai->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_admin_add_incoming_finished,
+ aai);
+ return aai;
+}
+
+
+/**
+ * Cancel an add incoming. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param aai the admin add incoming request handle
+ */
+void
+TALER_EXCHANGE_admin_add_incoming_cancel (struct TALER_EXCHANGE_AdminAddIncomingHandle *aai)
+{
+ if (NULL != aai->job)
+ {
+ MAC_job_cancel (aai->job);
+ aai->job = NULL;
+ }
+ curl_slist_free_all (aai->headers);
+ GNUNET_free_non_null (aai->db.buf);
+ GNUNET_free (aai->url);
+ GNUNET_free (aai->json_enc);
+ GNUNET_free (aai);
+}
+
+
+/* end of exchange_api_admin.c */
diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c
new file mode 100644
index 000000000..805c3fc4e
--- /dev/null
+++ b/src/exchange-lib/exchange_api_common.c
@@ -0,0 +1,194 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_common.c
+ * @brief common functions for the exchange API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "exchange_api_common.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * Verify a coins transaction history as returned by the exchange.
+ *
+ * @param currency expected currency for the coin
+ * @param coin_pub public key of the coin
+ * @param history history of the coin in json encoding
+ * @param[out] total how much of the coin has been spent according to @a history
+ * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
+ */
+int
+TALER_EXCHANGE_verify_coin_history_ (const char *currency,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ json_t *history,
+ struct TALER_Amount *total)
+{
+ size_t len;
+ size_t off;
+
+ if (NULL == history)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ len = json_array_size (history);
+ if (0 == len)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ TALER_amount_get_zero (currency,
+ total);
+ for (off=0;off<len;off++)
+ {
+ json_t *transaction;
+ struct TALER_Amount amount;
+ struct TALER_CoinSpendSignatureP sig;
+ void *details;
+ size_t details_size;
+ const char *type;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_amount ("amount",
+ &amount),
+ MAJ_spec_string ("type",
+ &type),
+ MAJ_spec_fixed_auto ("signature",
+ &sig),
+ MAJ_spec_varsize ("details",
+ &details,
+ &details_size),
+ MAJ_spec_end
+ };
+
+ transaction = json_array_get (history,
+ off);
+ if (GNUNET_OK !=
+ MAJ_parse_json (transaction,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 == strcasecmp (type,
+ "DEPOSIT"))
+ {
+ const struct TALER_DepositRequestPS *dr;
+ struct TALER_Amount dr_amount;
+
+ if (details_size != sizeof (struct TALER_DepositRequestPS))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ dr = (const struct TALER_DepositRequestPS *) details;
+ if (details_size != ntohl (dr->purpose.size))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
+ &dr->purpose,
+ &sig.eddsa_signature,
+ &coin_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+
+ // FIXME: check sig!
+ TALER_amount_ntoh (&dr_amount,
+ &dr->amount_with_fee);
+ if (0 != TALER_amount_cmp (&dr_amount,
+ &amount))
+ {
+ GNUNET_break (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ }
+ else if (0 == strcasecmp (type,
+ "MELT"))
+ {
+ const struct TALER_RefreshMeltCoinAffirmationPS *rm;
+ struct TALER_Amount rm_amount;
+
+ if (details_size != sizeof (struct TALER_RefreshMeltCoinAffirmationPS))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details;
+ if (details_size != ntohl (rm->purpose.size))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
+ &rm->purpose,
+ &sig.eddsa_signature,
+ &coin_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ TALER_amount_ntoh (&rm_amount,
+ &rm->amount_with_fee);
+ if (0 != TALER_amount_cmp (&rm_amount,
+ &amount))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ /* signature not supported, new version on server? */
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_add (total,
+ total,
+ &amount))
+ {
+ /* overflow in history already!? inconceivable! Bad exchange! */
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ MAJ_parse_free (spec);
+ }
+ return GNUNET_OK;
+}
+
+
+/* end of exchange_api_common.c */
diff --git a/src/exchange-lib/exchange_api_common.h b/src/exchange-lib/exchange_api_common.h
new file mode 100644
index 000000000..49f486b00
--- /dev/null
+++ b/src/exchange-lib/exchange_api_common.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_common.h
+ * @brief common functions for the exchange API
+ * @author Christian Grothoff
+ */
+#include <jansson.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+
+/**
+ * Verify a coins transaction history as returned by the exchange.
+ *
+ * @param currency expected currency for the coin
+ * @param coin_pub public key of the coin
+ * @param history history of the coin in json encoding
+ * @param[out] total how much of the coin has been spent according to @a history
+ * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
+ */
+int
+TALER_EXCHANGE_verify_coin_history_ (const char *currency,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ json_t *history,
+ struct TALER_Amount *total);
+
+/* end of exchange_api_common.h */
diff --git a/src/exchange-lib/exchange_api_context.c b/src/exchange-lib/exchange_api_context.c
new file mode 100644
index 000000000..544719001
--- /dev/null
+++ b/src/exchange-lib/exchange_api_context.c
@@ -0,0 +1,537 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_context.c
+ * @brief Implementation of the context part of the exchange's HTTP API
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_context.h"
+
+
+/**
+ * Log error related to CURL operations.
+ *
+ * @param type log level
+ * @param function which function failed to run
+ * @param code what was the curl error code
+ */
+#define CURL_STRERROR(type, function, code) \
+ GNUNET_log (type, \
+ "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
+ function, __FILE__, __LINE__, curl_easy_strerror (code));
+
+/**
+ * Print JSON parsing related error information
+ */
+#define JSON_WARN(error) \
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
+ "JSON parsing failed at %s:%u: %s (%s)\n", \
+ __FILE__, __LINE__, error.text, error.source)
+
+
+/**
+ * Failsafe flag. Raised if our constructor fails to initialize
+ * the Curl library.
+ */
+static int TALER_EXCHANGE_curl_fail;
+
+
+/**
+ * Jobs are CURL requests running within a `struct TALER_EXCHANGE_Context`.
+ */
+struct MAC_Job
+{
+
+ /**
+ * We keep jobs in a DLL.
+ */
+ struct MAC_Job *next;
+
+ /**
+ * We keep jobs in a DLL.
+ */
+ struct MAC_Job *prev;
+
+ /**
+ * Easy handle of the job.
+ */
+ CURL *easy_handle;
+
+ /**
+ * Context this job runs in.
+ */
+ struct TALER_EXCHANGE_Context *ctx;
+
+ /**
+ * Function to call upon completion.
+ */
+ MAC_JobCompletionCallback jcc;
+
+ /**
+ * Closure for @e jcc.
+ */
+ void *jcc_cls;
+
+};
+
+
+/**
+ * Context
+ */
+struct TALER_EXCHANGE_Context
+{
+ /**
+ * Curl multi handle
+ */
+ CURLM *multi;
+
+ /**
+ * Curl share handle
+ */
+ CURLSH *share;
+
+ /**
+ * We keep jobs in a DLL.
+ */
+ struct MAC_Job *jobs_head;
+
+ /**
+ * We keep jobs in a DLL.
+ */
+ struct MAC_Job *jobs_tail;
+
+ /**
+ * HTTP header "application/json", created once and used
+ * for all requests that need it.
+ */
+ struct curl_slist *json_header;
+
+};
+
+
+/**
+ * Initialise this library. This function should be called before using any of
+ * the following functions.
+ *
+ * @return library context
+ */
+struct TALER_EXCHANGE_Context *
+TALER_EXCHANGE_init ()
+{
+ struct TALER_EXCHANGE_Context *ctx;
+ CURLM *multi;
+ CURLSH *share;
+
+ if (TALER_EXCHANGE_curl_fail)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Curl was not initialised properly\n");
+ return NULL;
+ }
+ if (NULL == (multi = curl_multi_init ()))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to create a Curl multi handle\n");
+ return NULL;
+ }
+ if (NULL == (share = curl_share_init ()))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to create a Curl share handle\n");
+ return NULL;
+ }
+ ctx = GNUNET_new (struct TALER_EXCHANGE_Context);
+ ctx->multi = multi;
+ ctx->share = share;
+ GNUNET_assert (NULL != (ctx->json_header =
+ curl_slist_append (NULL,
+ "Content-Type: application/json")));
+ return ctx;
+}
+
+
+/**
+ * Schedule a CURL request to be executed and call the given @a jcc
+ * upon its completion. Note that the context will make use of the
+ * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can
+ * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument
+ * from a valid @a eh afterwards.
+ *
+ * This function modifies the CURL handle to add the
+ * "Content-Type: application/json" header if @a add_json is set.
+ *
+ * @param ctx context to execute the job in
+ * @param eh curl easy handle for the request, will
+ * be executed AND cleaned up
+ * @param add_json add "application/json" content type header
+ * @param jcc callback to invoke upon completion
+ * @param jcc_cls closure for @a jcc
+ */
+struct MAC_Job *
+MAC_job_add (struct TALER_EXCHANGE_Context *ctx,
+ CURL *eh,
+ int add_json,
+ MAC_JobCompletionCallback jcc,
+ void *jcc_cls)
+{
+ struct MAC_Job *job;
+
+ if (GNUNET_YES == add_json)
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HTTPHEADER,
+ ctx->json_header));
+
+ job = GNUNET_new (struct MAC_Job);
+ job->easy_handle = eh;
+ job->ctx = ctx;
+ job->jcc = jcc;
+ job->jcc_cls = jcc_cls;
+ GNUNET_CONTAINER_DLL_insert (ctx->jobs_head,
+ ctx->jobs_tail,
+ job);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_PRIVATE,
+ job));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_SHARE,
+ ctx->share));
+ GNUNET_assert (CURLM_OK ==
+ curl_multi_add_handle (ctx->multi,
+ eh));
+ return job;
+}
+
+
+/**
+ * Obtain the `jcc_cls` argument from an `eh` that was
+ * given to #MAC_job_add().
+ *
+ * @param eh easy handle that was used
+ * @return the `jcc_cls` that was given to #MAC_job_add().
+ */
+void *
+MAC_easy_to_closure (CURL *eh)
+{
+ struct MAC_Job *job;
+
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_getinfo (eh,
+ CURLINFO_PRIVATE,
+ (char **) &job));
+ return job->jcc_cls;
+}
+
+
+/**
+ * Cancel a job. Must only be called before the job completion
+ * callback is called for the respective job.
+ *
+ * @param job job to cancel
+ */
+void
+MAC_job_cancel (struct MAC_Job *job)
+{
+ struct TALER_EXCHANGE_Context *ctx = job->ctx;
+
+ GNUNET_CONTAINER_DLL_remove (ctx->jobs_head,
+ ctx->jobs_tail,
+ job);
+ GNUNET_assert (CURLM_OK ==
+ curl_multi_remove_handle (ctx->multi,
+ job->easy_handle));
+ curl_easy_cleanup (job->easy_handle);
+ GNUNET_free (job);
+}
+
+
+/**
+ * Run the main event loop for the Taler interaction.
+ *
+ * @param ctx the library context
+ */
+void
+TALER_EXCHANGE_perform (struct TALER_EXCHANGE_Context *ctx)
+{
+ CURLMsg *cmsg;
+ struct MAC_Job *job;
+ int n_running;
+ int n_completed;
+
+ (void) curl_multi_perform (ctx->multi,
+ &n_running);
+ while (NULL != (cmsg = curl_multi_info_read (ctx->multi,
+ &n_completed)))
+ {
+ /* Only documented return value is CURLMSG_DONE */
+ GNUNET_break (CURLMSG_DONE == cmsg->msg);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_getinfo (cmsg->easy_handle,
+ CURLINFO_PRIVATE,
+ (char **) &job));
+ GNUNET_assert (job->ctx == ctx);
+ job->jcc (job->jcc_cls,
+ cmsg->easy_handle);
+ MAC_job_cancel (job);
+ }
+}
+
+
+/**
+ * Obtain the information for a select() call to wait until
+ * #TALER_EXCHANGE_perform() is ready again. Note that calling
+ * any other TALER_EXCHANGE-API may also imply that the library
+ * is again ready for #TALER_EXCHANGE_perform().
+ *
+ * Basically, a client should use this API to prepare for select(),
+ * then block on select(), then call #TALER_EXCHANGE_perform() and then
+ * start again until the work with the context is done.
+ *
+ * This function will NOT zero out the sets and assumes that @a max_fd
+ * and @a timeout are already set to minimal applicable values. It is
+ * safe to give this API FD-sets and @a max_fd and @a timeout that are
+ * already initialized to some other descriptors that need to go into
+ * the select() call.
+ *
+ * @param ctx context to get the event loop information for
+ * @param read_fd_set will be set for any pending read operations
+ * @param write_fd_set will be set for any pending write operations
+ * @param except_fd_set is here because curl_multi_fdset() has this argument
+ * @param max_fd set to the highest FD included in any set;
+ * if the existing sets have no FDs in it, the initial
+ * value should be "-1". (Note that `max_fd + 1` will need
+ * to be passed to select().)
+ * @param timeout set to the timeout in milliseconds (!); -1 means
+ * no timeout (NULL, blocking forever is OK), 0 means to
+ * proceed immediately with #TALER_EXCHANGE_perform().
+ */
+void
+TALER_EXCHANGE_get_select_info (struct TALER_EXCHANGE_Context *ctx,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *except_fd_set,
+ int *max_fd,
+ long *timeout)
+{
+ long to;
+ int m;
+
+ m = -1;
+ GNUNET_assert (CURLM_OK ==
+ curl_multi_fdset (ctx->multi,
+ read_fd_set,
+ write_fd_set,
+ except_fd_set,
+ &m));
+ to = *timeout;
+ *max_fd = GNUNET_MAX (m, *max_fd);
+ GNUNET_assert (CURLM_OK ==
+ curl_multi_timeout (ctx->multi,
+ &to));
+
+ /* Only if what we got back from curl is smaller than what we
+ already had (-1 == infinity!), then update timeout */
+ if ( (to < *timeout) &&
+ (-1 != to) )
+ *timeout = to;
+ if ( (-1 == (*timeout)) &&
+ (NULL != ctx->jobs_head) )
+ *timeout = to;
+}
+
+
+/**
+ * Cleanup library initialisation resources. This function should be called
+ * after using this library to cleanup the resources occupied during library's
+ * initialisation.
+ *
+ * @param ctx the library context
+ */
+void
+TALER_EXCHANGE_fini (struct TALER_EXCHANGE_Context *ctx)
+{
+ /* all jobs must have been cancelled at this time, assert this */
+ GNUNET_assert (NULL == ctx->jobs_head);
+ curl_share_cleanup (ctx->share);
+ curl_multi_cleanup (ctx->multi);
+ curl_slist_free_all (ctx->json_header);
+ GNUNET_free (ctx);
+}
+
+
+/**
+ * Callback used when downloading the reply to an HTTP request.
+ * Just appends all of the data to the `buf` in the
+ * `struct MAC_DownloadBuffer` for further processing. The size of
+ * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if
+ * the download exceeds this size, we abort with an error.
+ *
+ * @param bufptr data downloaded via HTTP
+ * @param size size of an item in @a bufptr
+ * @param nitems number of items in @a bufptr
+ * @param cls the `struct KeysRequest`
+ * @return number of bytes processed from @a bufptr
+ */
+size_t
+MAC_download_cb (char *bufptr,
+ size_t size,
+ size_t nitems,
+ void *cls)
+{
+ struct MAC_DownloadBuffer *db = cls;
+ size_t msize;
+ void *buf;
+
+ if (0 == size * nitems)
+ {
+ /* Nothing (left) to do */
+ return 0;
+ }
+ msize = size * nitems;
+ if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
+ {
+ db->eno = ENOMEM;
+ return 0; /* signals an error to curl */
+ }
+ db->buf = GNUNET_realloc (db->buf,
+ db->buf_size + msize);
+ buf = db->buf + db->buf_size;
+ memcpy (buf, bufptr, msize);
+ db->buf_size += msize;
+ return msize;
+}
+
+
+/**
+ * Obtain information about the final result about the
+ * HTTP download. If the download was successful, parses
+ * the JSON in the @a db and returns it. Also returns
+ * the HTTP @a response_code. If the download failed,
+ * the return value is NULL. The response code is set
+ * in any case, on download errors to zero.
+ *
+ * Calling this function also cleans up @a db.
+ *
+ * @param db download buffer
+ * @param eh CURL handle (to get the response code)
+ * @param[out] response_code set to the HTTP response code
+ * (or zero if we aborted the download, i.e.
+ * because the response was too big, or if
+ * the JSON we received was malformed).
+ * @return NULL if downloading a JSON reply failed
+ */
+json_t *
+MAC_download_get_result (struct MAC_DownloadBuffer *db,
+ CURL *eh,
+ long *response_code)
+{
+ json_t *json;
+ json_error_t error;
+ char *ct;
+
+ if ( (CURLE_OK !=
+ curl_easy_getinfo (eh,
+ CURLINFO_CONTENT_TYPE,
+ &ct)) ||
+ (NULL == ct) ||
+ (0 != strcasecmp (ct,
+ "application/json")) )
+ {
+ /* No content type or explicitly not JSON, refuse to parse
+ (but keep response code) */
+ if (CURLE_OK !=
+ curl_easy_getinfo (eh,
+ CURLINFO_RESPONSE_CODE,
+ response_code))
+ {
+ /* unexpected error... */
+ GNUNET_break (0);
+ *response_code = 0;
+ }
+ return NULL;
+ }
+
+ json = NULL;
+ if (0 == db->eno)
+ {
+ json = json_loadb (db->buf,
+ db->buf_size,
+ JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
+ &error);
+ if (NULL == json)
+ {
+ JSON_WARN (error);
+ *response_code = 0;
+ }
+ }
+ GNUNET_free_non_null (db->buf);
+ db->buf = NULL;
+ db->buf_size = 0;
+ if (NULL != json)
+ {
+ if (CURLE_OK !=
+ curl_easy_getinfo (eh,
+ CURLINFO_RESPONSE_CODE,
+ response_code))
+ {
+ /* unexpected error... */
+ GNUNET_break (0);
+ *response_code = 0;
+ }
+ }
+ return json;
+}
+
+
+/**
+ * Initial global setup logic, specifically runs the Curl setup.
+ */
+__attribute__ ((constructor))
+void
+TALER_EXCHANGE_constructor__ (void)
+{
+ CURLcode ret;
+
+ if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
+ {
+ CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "curl_global_init",
+ ret);
+ TALER_EXCHANGE_curl_fail = 1;
+ }
+}
+
+
+/**
+ * Cleans up after us, specifically runs the Curl cleanup.
+ */
+__attribute__ ((destructor))
+void
+TALER_EXCHANGE_destructor__ (void)
+{
+ if (TALER_EXCHANGE_curl_fail)
+ return;
+ curl_global_cleanup ();
+}
+
+/* end of exchange_api_context.c */
diff --git a/src/exchange-lib/exchange_api_context.h b/src/exchange-lib/exchange_api_context.h
new file mode 100644
index 000000000..3c54bfe07
--- /dev/null
+++ b/src/exchange-lib/exchange_api_context.h
@@ -0,0 +1,169 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_context.h
+ * @brief Internal interface to the context part of the exchange's HTTP API
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_signatures.h"
+
+
+/**
+ * Entry in the context's job queue.
+ */
+struct MAC_Job;
+
+/**
+ * Function to call upon completion of a job.
+ *
+ * @param cls closure
+ * @param eh original easy handle (for inspection)
+ */
+typedef void
+(*MAC_JobCompletionCallback)(void *cls,
+ CURL *eh);
+
+
+/**
+ * Schedule a CURL request to be executed and call the given @a jcc
+ * upon its completion. Note that the context will make use of the
+ * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can
+ * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument
+ * from a valid @a eh afterwards.
+ *
+ * This function modifies the CURL handle to add the
+ * "Content-Type: application/json" header if @a add_json is set.
+ *
+ * @param ctx context to execute the job in
+ * @param eh curl easy handle for the request, will
+ * be executed AND cleaned up
+ * @param add_json add "application/json" content type header
+ * @param jcc callback to invoke upon completion
+ * @param jcc_cls closure for @a jcc
+ */
+struct MAC_Job *
+MAC_job_add (struct TALER_EXCHANGE_Context *ctx,
+ CURL *eh,
+ int add_json,
+ MAC_JobCompletionCallback jcc,
+ void *jcc_cls);
+
+
+/**
+ * Obtain the `jcc_cls` argument from an `eh` that was
+ * given to #MAC_job_add().
+ *
+ * @param eh easy handle that was used
+ * @return the `jcc_cls` that was given to #MAC_job_add().
+ */
+void *
+MAC_easy_to_closure (CURL *eh);
+
+
+/**
+ * Cancel a job. Must only be called before the job completion
+ * callback is called for the respective job.
+ *
+ * @param job job to cancel
+ */
+void
+MAC_job_cancel (struct MAC_Job *job);
+
+
+/**
+ * @brief Buffer data structure we use to buffer the HTTP download
+ * before giving it to the JSON parser.
+ */
+struct MAC_DownloadBuffer
+{
+
+ /**
+ * Download buffer
+ */
+ void *buf;
+
+ /**
+ * The size of the download buffer
+ */
+ size_t buf_size;
+
+ /**
+ * Error code (based on libc errno) if we failed to download
+ * (i.e. response too large).
+ */
+ int eno;
+
+};
+
+
+/**
+ * Callback used when downloading the reply to an HTTP request.
+ * Just appends all of the data to the `buf` in the
+ * `struct MAC_DownloadBuffer` for further processing. The size of
+ * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if
+ * the download exceeds this size, we abort with an error.
+ *
+ * Should be used by the various routines as the
+ * CURLOPT_WRITEFUNCTION. A `struct MAC_DownloadBuffer` needs to be
+ * passed to the CURLOPT_WRITEDATA.
+ *
+ * Afterwards, `eno` needs to be checked to ensure that the download
+ * completed correctly.
+ *
+ * @param bufptr data downloaded via HTTP
+ * @param size size of an item in @a bufptr
+ * @param nitems number of items in @a bufptr
+ * @param cls the `struct KeysRequest`
+ * @return number of bytes processed from @a bufptr
+ */
+size_t
+MAC_download_cb (char *bufptr,
+ size_t size,
+ size_t nitems,
+ void *cls);
+
+
+/**
+ * Obtain information about the final result about the
+ * HTTP download. If the download was successful, parses
+ * the JSON in the @a db and returns it. Also returns
+ * the HTTP @a response_code. If the download failed,
+ * the return value is NULL. The response code is set
+ * in any case, on download errors to zero.
+ *
+ * Calling this function also cleans up @a db.
+ *
+ * @param db download buffer
+ * @param eh CURL handle (to get the response code)
+ * @param[out] response_code set to the HTTP response code
+ * (or zero if we aborted the download, i.e.
+ * because the response was too big, or if
+ * the JSON we received was malformed).
+ * @return NULL if downloading a JSON reply failed
+ */
+json_t *
+MAC_download_get_result (struct MAC_DownloadBuffer *db,
+ CURL *eh,
+ long *response_code);
+
+
+/* end of exchange_api_context.h */
diff --git a/src/exchange-lib/exchange_api_deposit.c b/src/exchange-lib/exchange_api_deposit.c
new file mode 100644
index 000000000..deba4877d
--- /dev/null
+++ b/src/exchange-lib/exchange_api_deposit.c
@@ -0,0 +1,569 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_deposit.c
+ * @brief Implementation of the /deposit request of the exchange's HTTP API
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A Deposit Handle
+ */
+struct TALER_EXCHANGE_DepositHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_DepositResultCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Information the exchange should sign in response.
+ */
+ struct TALER_DepositConfirmationPS depconf;
+
+ /**
+ * Value of the /deposit transaction, including fee.
+ */
+ struct TALER_Amount amount_with_fee;
+
+ /**
+ * Total value of the coin being transacted with.
+ */
+ struct TALER_Amount coin_value;
+
+};
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * from the exchange is valid.
+ *
+ * @param dh deposit handle
+ * @param json json reply with the signature
+ * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
+ */
+static int
+verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh,
+ json_t *json)
+{
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("sig", &exchange_sig),
+ MAJ_spec_fixed_auto ("pub", &exchange_pub),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ key_state = TALER_EXCHANGE_get_keys (dh->exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &exchange_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT,
+ &dh->depconf.purpose,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify that the signatures on the "403 FORBIDDEN" response from the
+ * exchange demonstrating customer double-spending are valid.
+ *
+ * @param dh deposit handle
+ * @param json json reply with the signature(s) and transaction history
+ * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
+ */
+static int
+verify_deposit_signature_forbidden (const struct TALER_EXCHANGE_DepositHandle *dh,
+ json_t *json)
+{
+ json_t *history;
+ struct TALER_Amount total;
+
+ history = json_object_get (json,
+ "history");
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_verify_coin_history_ (dh->coin_value.currency,
+ &dh->depconf.coin_pub,
+ history,
+ &total))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_add (&total,
+ &total,
+ &dh->amount_with_fee))
+ {
+ /* clearly not OK if our transaction would have caused
+ the overflow... */
+ return GNUNET_OK;
+ }
+
+ if (0 >= TALER_amount_cmp (&total,
+ &dh->coin_value))
+ {
+ /* transaction should have still fit */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* everything OK, proof of double-spending was provided */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /deposit request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_DepositHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_deposit_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_DepositHandle *dh = cls;
+ long response_code;
+ json_t *json;
+
+ dh->job = NULL;
+ json = MAC_download_get_result (&dh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ if (GNUNET_OK !=
+ verify_deposit_signature_ok (dh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ /* Double spending; check signatures on transaction history */
+ if (GNUNET_OK !=
+ verify_deposit_signature_forbidden (dh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, exchange says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ dh->cb (dh->cb_cls,
+ response_code,
+ json);
+ json_decref (json);
+ TALER_EXCHANGE_deposit_cancel (dh);
+}
+
+
+/**
+ * Verify signature information about the deposit.
+ *
+ * @param dki public key information
+ * @param amount the amount to be deposited
+ * @param h_wire hash of the merchant’s account details
+ * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
+ * @param coin_pub coin’s public key
+ * @param denom_pub denomination key with which the coin is signed
+ * @param denom_sig exchange’s unblinded signature of the coin
+ * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the exchange
+ * @param transaction_id transaction id for the transaction between merchant and customer
+ * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
+ * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed)
+ * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
+ * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
+ */
+static int
+verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
+ const struct TALER_Amount *amount,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_DenominationSignature *denom_sig,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ struct GNUNET_TIME_Absolute timestamp,
+ uint64_t transaction_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ const struct TALER_CoinSpendSignatureP *coin_sig)
+{
+ struct TALER_DepositRequestPS dr;
+ struct TALER_CoinPublicInfo coin_info;
+
+ dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
+ dr.h_contract = *h_contract;
+ dr.h_wire = *h_wire;
+ dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
+ dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
+ dr.transaction_id = GNUNET_htonll (transaction_id);
+ TALER_amount_hton (&dr.amount_with_fee,
+ amount);
+ TALER_amount_hton (&dr.deposit_fee,
+ &dki->fee_deposit);
+ dr.merchant = *merchant_pub;
+ dr.coin_pub = *coin_pub;
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
+ &dr.purpose,
+ &coin_sig->eddsa_signature,
+ &coin_pub->eddsa_pub))
+ {
+ TALER_LOG_WARNING ("Invalid coin signature on /deposit request\n");
+ {
+ char *s;
+ s = TALER_amount_to_string (amount);
+ TALER_LOG_DEBUG ("... amount_with_fee was %s\n", s);
+ GNUNET_free (s);
+ s = TALER_amount_to_string (&dki->fee_deposit);
+ TALER_LOG_DEBUG ("... deposit_fee was %s\n", s);
+ GNUNET_free (s);
+ }
+
+ return GNUNET_SYSERR;
+ }
+
+ /* check coin signature */
+ coin_info.coin_pub = *coin_pub;
+ coin_info.denom_pub = *denom_pub;
+ coin_info.denom_sig = *denom_sig;
+ if (GNUNET_YES !=
+ TALER_test_coin_valid (&coin_info))
+ {
+ TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
+ return GNUNET_SYSERR;
+ }
+ if (0 < TALER_amount_cmp (&dki->fee_deposit,
+ amount))
+ {
+ TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Submit a deposit permission to the exchange and get the exchange's response.
+ * Note that while we return the response verbatim to the caller for
+ * further processing, we do already verify that the response is
+ * well-formed (i.e. that signatures included in the response are all
+ * valid). If the exchange's reply is not well-formed, we return an
+ * HTTP status code of zero to @a cb.
+ *
+ * We also verify that the @a coin_sig is valid for this deposit
+ * request, and that the @a ub_sig is a valid signature for @a
+ * coin_pub. Also, the @a exchange must be ready to operate (i.e. have
+ * finished processing the /keys reply). If either check fails, we do
+ * NOT initiate the transaction with the exchange and instead return NULL.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param amount the amount to be deposited
+ * @param wire_deadline date until which the merchant would like the exchange to settle the balance (advisory, the exchange cannot be
+ * forced to settle in the past or upon very short notice, but of course a well-behaved exchange will limit aggregation based on the advice received)
+ * @param wire_details the merchant’s account details, in a format supported by the exchange
+ * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
+ * @param coin_pub coin’s public key
+ * @param denom_pub denomination key with which the coin is signed
+ * @param denom_sig exchange’s unblinded signature of the coin
+ * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the exchange
+ * @param transaction_id transaction id for the transaction between merchant and customer
+ * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
+ * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed)
+ * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the inputs are invalid (i.e.
+ * signatures fail to verify). In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_DepositHandle *
+TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ json_t *wire_details,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_DenominationSignature *denom_sig,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ struct GNUNET_TIME_Absolute timestamp,
+ uint64_t transaction_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ TALER_EXCHANGE_DepositResultCallback cb,
+ void *cb_cls)
+{
+ const struct TALER_EXCHANGE_Keys *key_state;
+ const struct TALER_EXCHANGE_DenomPublicKey *dki;
+ struct TALER_EXCHANGE_DepositHandle *dh;
+ struct TALER_EXCHANGE_Context *ctx;
+ json_t *deposit_obj;
+ CURL *eh;
+ struct GNUNET_HashCode h_wire;
+ struct TALER_Amount amount_without_fee;
+
+ (void) TALER_round_abs_time (&wire_deadline);
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ /* initialize h_wire */
+ if (GNUNET_OK !=
+ TALER_hash_json (wire_details,
+ &h_wire))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ key_state = TALER_EXCHANGE_get_keys (exchange);
+ dki = TALER_EXCHANGE_get_denomination_key (key_state,
+ denom_pub);
+ if (NULL == dki)
+ {
+ TALER_LOG_WARNING ("Denomination key unknown to exchange\n");
+ return NULL;
+ }
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&amount_without_fee,
+ amount,
+ &dki->fee_deposit))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ if (GNUNET_OK !=
+ verify_signatures (dki,
+ amount,
+ &h_wire,
+ h_contract,
+ coin_pub,
+ denom_sig,
+ denom_pub,
+ timestamp,
+ transaction_id,
+ merchant_pub,
+ refund_deadline,
+ coin_sig))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+
+ deposit_obj = json_pack ("{s:o, s:O," /* f/wire */
+ " s:o, s:o," /* H_wire, H_contract */
+ " s:o, s:o," /* coin_pub, denom_pub */
+ " s:o, s:o," /* ub_sig, timestamp */
+ " s:I, s:o," /* transaction id, merchant_pub */
+ " s:o, s:o," /* refund_deadline, wire_deadline */
+ " s:o}", /* coin_sig */
+ "f", TALER_json_from_amount (amount),
+ "wire", wire_details,
+ "H_wire", TALER_json_from_data (&h_wire,
+ sizeof (h_wire)),
+ "H_contract", TALER_json_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "coin_pub", TALER_json_from_data (coin_pub,
+ sizeof (*coin_pub)),
+ "denom_pub", TALER_json_from_rsa_public_key (denom_pub->rsa_public_key),
+ "ub_sig", TALER_json_from_rsa_signature (denom_sig->rsa_signature),
+ "timestamp", TALER_json_from_abs (timestamp),
+ "transaction_id", (json_int_t) transaction_id,
+ "merchant_pub", TALER_json_from_data (merchant_pub,
+ sizeof (*merchant_pub)),
+ "refund_deadline", TALER_json_from_abs (refund_deadline),
+ "edate", TALER_json_from_abs (wire_deadline),
+ "coin_sig", TALER_json_from_data (coin_sig,
+ sizeof (*coin_sig))
+ );
+
+ dh = GNUNET_new (struct TALER_EXCHANGE_DepositHandle);
+ dh->exchange = exchange;
+ dh->cb = cb;
+ dh->cb_cls = cb_cls;
+ dh->url = MAH_path_to_url (exchange, "/deposit");
+ dh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
+ dh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
+ dh->depconf.h_contract = *h_contract;
+ dh->depconf.h_wire = h_wire;
+ dh->depconf.transaction_id = GNUNET_htonll (transaction_id);
+ dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp);
+ dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
+ TALER_amount_hton (&dh->depconf.amount_without_fee,
+ &amount_without_fee);
+ dh->depconf.coin_pub = *coin_pub;
+ dh->depconf.merchant = *merchant_pub;
+ dh->amount_with_fee = *amount;
+ dh->coin_value = dki->value;
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (dh->json_enc =
+ json_dumps (deposit_obj,
+ JSON_COMPACT)));
+ json_decref (deposit_obj);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "URL for deposit: `%s'\n",
+ dh->url);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ dh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ dh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (dh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &dh->db));
+ ctx = MAH_handle_to_context (exchange);
+ dh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_deposit_finished,
+ dh);
+ return dh;
+}
+
+
+/**
+ * Cancel a deposit permission request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param deposit the deposit permission request handle
+ */
+void
+TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit)
+{
+ if (NULL != deposit->job)
+ {
+ MAC_job_cancel (deposit->job);
+ deposit->job = NULL;
+ }
+ GNUNET_free_non_null (deposit->db.buf);
+ GNUNET_free (deposit->url);
+ GNUNET_free (deposit->json_enc);
+ GNUNET_free (deposit);
+}
+
+
+/* end of exchange_api_deposit.c */
diff --git a/src/exchange-lib/exchange_api_deposit_wtid.c b/src/exchange-lib/exchange_api_deposit_wtid.c
new file mode 100644
index 000000000..83beb03ae
--- /dev/null
+++ b/src/exchange-lib/exchange_api_deposit_wtid.c
@@ -0,0 +1,379 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_deposit_wtid.c
+ * @brief Implementation of the /deposit/wtid request of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A Deposit Wtid Handle
+ */
+struct TALER_EXCHANGE_DepositWtidHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_DepositWtidCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Information the exchange should sign in response.
+ * (with pre-filled fields from the request).
+ */
+ struct TALER_ConfirmWirePS depconf;
+
+};
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * from the exchange is valid.
+ *
+ * @param dwh deposit wtid handle
+ * @param json json reply with the signature
+ * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
+ */
+static int
+verify_deposit_wtid_signature_ok (const struct TALER_EXCHANGE_DepositWtidHandle *dwh,
+ json_t *json)
+{
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("exchange_sig", &exchange_sig),
+ MAJ_spec_fixed_auto ("exchange_pub", &exchange_pub),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ key_state = TALER_EXCHANGE_get_keys (dwh->exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &exchange_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE,
+ &dwh->depconf.purpose,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /deposit/wtid request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_DepositWtidHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_deposit_wtid_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_DepositWtidHandle *dwh = cls;
+ long response_code;
+ json_t *json;
+ const struct TALER_WireTransferIdentifierRawP *wtid = NULL;
+ struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS;
+ const struct TALER_Amount *coin_contribution = NULL;
+ struct TALER_Amount coin_contribution_s;
+
+ dwh->job = NULL;
+ json = MAC_download_get_result (&dwh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
+ MAJ_spec_absolute_time ("execution_time", &execution_time),
+ MAJ_spec_amount ("coin_contribution", &coin_contribution_s),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ wtid = &dwh->depconf.wtid;
+ dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time);
+ TALER_amount_hton (&dwh->depconf.coin_contribution,
+ &coin_contribution_s);
+ coin_contribution = &coin_contribution_s;
+ if (GNUNET_OK !=
+ verify_deposit_wtid_signature_ok (dwh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ }
+ break;
+ case MHD_HTTP_ACCEPTED:
+ {
+ /* Transaction known, but not executed yet */
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_absolute_time ("execution_time", &execution_time),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, exchange says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Exchange does not know about transaction;
+ we should pass the reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ dwh->cb (dwh->cb_cls,
+ response_code,
+ json,
+ wtid,
+ execution_time,
+ coin_contribution);
+ json_decref (json);
+ TALER_EXCHANGE_deposit_wtid_cancel (dwh);
+}
+
+
+/**
+ * Obtain wire transfer details about an existing deposit operation.
+ *
+ * @param exchange the exchange to query
+ * @param merchant_priv the merchant's private key
+ * @param h_wire hash of merchant's wire transfer details
+ * @param h_contract hash of the contract
+ * @param coin_pub public key of the coin
+ * @param transaction_id transaction identifier
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return handle to abort request
+ */
+struct TALER_EXCHANGE_DepositWtidHandle *
+TALER_EXCHANGE_deposit_wtid (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t transaction_id,
+ TALER_EXCHANGE_DepositWtidCallback cb,
+ void *cb_cls)
+{
+ struct TALER_DepositTrackPS dtp;
+ struct TALER_MerchantSignatureP merchant_sig;
+ struct TALER_EXCHANGE_DepositWtidHandle *dwh;
+ struct TALER_EXCHANGE_Context *ctx;
+ json_t *deposit_wtid_obj;
+ CURL *eh;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID);
+ dtp.purpose.size = htonl (sizeof (dtp));
+ dtp.h_contract = *h_contract;
+ dtp.h_wire = *h_wire;
+ dtp.transaction_id = GNUNET_htonll (transaction_id);
+ GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
+ &dtp.merchant.eddsa_pub);
+
+ dtp.coin_pub = *coin_pub;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
+ &dtp.purpose,
+ &merchant_sig.eddsa_sig));
+ deposit_wtid_obj = json_pack ("{s:o, s:o," /* H_wire, H_contract */
+ " s:o, s:I," /* coin_pub, transaction_id */
+ " s:o, s:o}", /* merchant_pub, merchant_sig */
+ "H_wire", TALER_json_from_data (h_wire,
+ sizeof (struct GNUNET_HashCode)),
+ "H_contract", TALER_json_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "coin_pub", TALER_json_from_data (coin_pub,
+ sizeof (*coin_pub)),
+ "transaction_id", (json_int_t) transaction_id,
+ "merchant_pub", TALER_json_from_data (&dtp.merchant,
+ sizeof (struct TALER_MerchantPublicKeyP)),
+ "merchant_sig", TALER_json_from_data (&merchant_sig,
+ sizeof (merchant_sig)));
+
+ dwh = GNUNET_new (struct TALER_EXCHANGE_DepositWtidHandle);
+ dwh->exchange = exchange;
+ dwh->cb = cb;
+ dwh->cb_cls = cb_cls;
+ dwh->url = MAH_path_to_url (exchange, "/deposit/wtid");
+ dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
+ dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE);
+ dwh->depconf.h_wire = *h_wire;
+ dwh->depconf.h_contract = *h_contract;
+ dwh->depconf.coin_pub = *coin_pub;
+ dwh->depconf.transaction_id = GNUNET_htonll (transaction_id);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (dwh->json_enc =
+ json_dumps (deposit_wtid_obj,
+ JSON_COMPACT)));
+ json_decref (deposit_wtid_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ dwh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ dwh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (dwh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &dwh->db));
+ ctx = MAH_handle_to_context (exchange);
+ dwh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_deposit_wtid_finished,
+ dwh);
+ return dwh;
+}
+
+
+/**
+ * Cancel deposit wtid request. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param dwh the wire deposits request handle
+ */
+void
+TALER_EXCHANGE_deposit_wtid_cancel (struct TALER_EXCHANGE_DepositWtidHandle *dwh)
+{
+ if (NULL != dwh->job)
+ {
+ MAC_job_cancel (dwh->job);
+ dwh->job = NULL;
+ }
+ GNUNET_free_non_null (dwh->db.buf);
+ GNUNET_free (dwh->url);
+ GNUNET_free (dwh->json_enc);
+ GNUNET_free (dwh);
+}
+
+
+/* end of exchange_api_deposit_wtid.c */
diff --git a/src/exchange-lib/exchange_api_handle.c b/src/exchange-lib/exchange_api_handle.c
new file mode 100644
index 000000000..d4b3e4deb
--- /dev/null
+++ b/src/exchange-lib/exchange_api_handle.c
@@ -0,0 +1,902 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_handle.c
+ * @brief Implementation of the "handle" component of the exchange's HTTP API
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_exchange_service.h"
+#include "taler_signatures.h"
+#include "exchange_api_context.h"
+#include "exchange_api_json.h"
+#include "exchange_api_handle.h"
+
+
+/**
+ * Log error related to CURL operations.
+ *
+ * @param type log level
+ * @param function which function failed to run
+ * @param code what was the curl error code
+ */
+#define CURL_STRERROR(type, function, code) \
+ GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
+ function, __FILE__, __LINE__, curl_easy_strerror (code));
+
+
+/**
+ * Stages of initialization for the `struct TALER_EXCHANGE_Handle`
+ */
+enum ExchangeHandleState
+{
+ /**
+ * Just allocated.
+ */
+ MHS_INIT = 0,
+
+ /**
+ * Obtained the exchange's certification data and keys.
+ */
+ MHS_CERT = 1,
+
+ /**
+ * Failed to initialize (fatal).
+ */
+ MHS_FAILED = 2
+};
+
+
+/**
+ * Data for the request to get the /keys of a exchange.
+ */
+struct KeysRequest;
+
+
+/**
+ * Handle to the exchange
+ */
+struct TALER_EXCHANGE_Handle
+{
+ /**
+ * The context of this handle
+ */
+ struct TALER_EXCHANGE_Context *ctx;
+
+ /**
+ * The URL of the exchange (i.e. "http://exchange.taler.net/")
+ */
+ char *url;
+
+ /**
+ * Function to call with the exchange's certification data,
+ * NULL if this has already been done.
+ */
+ TALER_EXCHANGE_CertificationCallback cert_cb;
+
+ /**
+ * Closure to pass to @e cert_cb.
+ */
+ void *cert_cb_cls;
+
+ /**
+ * Data for the request to get the /keys of a exchange,
+ * NULL once we are past stage #MHS_INIT.
+ */
+ struct KeysRequest *kr;
+
+ /**
+ * Key data of the exchange, only valid if
+ * @e handshake_complete is past stage #MHS_CERT.
+ */
+ struct TALER_EXCHANGE_Keys key_data;
+
+ /**
+ * Stage of the exchange's initialization routines.
+ */
+ enum ExchangeHandleState state;
+
+};
+
+
+/* ***************** Internal /keys fetching ************* */
+
+/**
+ * Data for the request to get the /keys of a exchange.
+ */
+struct KeysRequest
+{
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this handle
+ */
+ char *url;
+
+ /**
+ * Entry for this request with the `struct TALER_EXCHANGE_Context`.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Data structure for the download.
+ */
+ struct MAC_DownloadBuffer db;
+
+};
+
+
+/**
+ * Release memory occupied by a keys request.
+ * Note that this does not cancel the request
+ * itself.
+ *
+ * @param kr request to free
+ */
+static void
+free_keys_request (struct KeysRequest *kr)
+{
+ GNUNET_free_non_null (kr->db.buf);
+ GNUNET_free (kr->url);
+ GNUNET_free (kr);
+}
+
+
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+
+/**
+ * Parse a exchange's signing key encoded in JSON.
+ *
+ * @param[out] sign_key where to return the result
+ * @param[in] sign_key_obj json to parse
+ * @param master_key master key to use to verify signature
+ * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
+ * invalid or the json malformed.
+ */
+static int
+parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
+ json_t *sign_key_obj,
+ const struct TALER_MasterPublicKeyP *master_key)
+{
+ struct TALER_ExchangeSigningKeyValidityPS sign_key_issue;
+ struct GNUNET_CRYPTO_EddsaSignature sig;
+ struct GNUNET_TIME_Absolute valid_from;
+ struct GNUNET_TIME_Absolute valid_until;
+ struct GNUNET_TIME_Absolute valid_legal;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("master_sig",
+ &sig),
+ MAJ_spec_fixed_auto ("key",
+ &sign_key_issue.signkey_pub),
+ MAJ_spec_absolute_time ("stamp_start",
+ &valid_from),
+ MAJ_spec_absolute_time ("stamp_expire",
+ &valid_until),
+ MAJ_spec_absolute_time ("stamp_end",
+ &valid_legal),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (sign_key_obj,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
+ sign_key_issue.purpose.size =
+ htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS)
+ - offsetof (struct TALER_ExchangeSigningKeyValidityPS,
+ purpose));
+ sign_key_issue.master_public_key = *master_key;
+ sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
+ sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until);
+ sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
+ &sign_key_issue.purpose,
+ &sig,
+ &master_key->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ sign_key->valid_from = valid_from;
+ sign_key->valid_until = valid_until;
+ sign_key->key = sign_key_issue.signkey_pub;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse a exchange's denomination key encoded in JSON.
+ *
+ * @param[out] denom_key where to return the result
+ * @param[in] denom_key_obj json to parse
+ * @param master_key master key to use to verify signature
+ * @param hash_context where to accumulate data for signature verification
+ * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
+ * invalid or the json malformed.
+ */
+static int
+parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
+ json_t *denom_key_obj,
+ struct TALER_MasterPublicKeyP *master_key,
+ struct GNUNET_HashContext *hash_context)
+{
+ struct GNUNET_TIME_Absolute valid_from;
+ struct GNUNET_TIME_Absolute withdraw_valid_until;
+ struct GNUNET_TIME_Absolute deposit_valid_until;
+ struct GNUNET_TIME_Absolute expire_legal;
+ struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_Amount fee_deposit;
+ struct TALER_Amount fee_refresh;
+ struct TALER_DenominationKeyValidityPS denom_key_issue;
+ struct GNUNET_CRYPTO_rsa_PublicKey *pk;
+ struct GNUNET_CRYPTO_EddsaSignature sig;
+
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("master_sig",
+ &sig),
+ MAJ_spec_absolute_time ("stamp_expire_deposit",
+ &deposit_valid_until),
+ MAJ_spec_absolute_time ("stamp_expire_withdraw",
+ &withdraw_valid_until),
+ MAJ_spec_absolute_time ("stamp_start",
+ &valid_from),
+ MAJ_spec_absolute_time ("stamp_expire_legal",
+ &expire_legal),
+ MAJ_spec_amount ("value",
+ &value),
+ MAJ_spec_amount ("fee_withdraw",
+ &fee_withdraw),
+ MAJ_spec_amount ("fee_deposit",
+ &fee_deposit),
+ MAJ_spec_amount ("fee_refresh",
+ &fee_refresh),
+ MAJ_spec_rsa_public_key ("denom_pub",
+ &pk),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (denom_key_obj,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ memset (&denom_key_issue, 0, sizeof (denom_key_issue));
+ GNUNET_CRYPTO_rsa_public_key_hash (pk,
+ &denom_key_issue.denom_hash);
+ denom_key_issue.purpose.purpose
+ = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
+ denom_key_issue.purpose.size
+ = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
+ denom_key_issue.master = *master_key;
+ denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
+ denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
+ denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until);
+ denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (expire_legal);
+ TALER_amount_hton (&denom_key_issue.value,
+ &value);
+ TALER_amount_hton (&denom_key_issue.fee_withdraw,
+ &fee_withdraw);
+ TALER_amount_hton (&denom_key_issue.fee_deposit,
+ &fee_deposit);
+ TALER_amount_hton (&denom_key_issue.fee_refresh,
+ &fee_refresh);
+ EXITIF (GNUNET_SYSERR ==
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
+ &denom_key_issue.purpose,
+ &sig,
+ &master_key->eddsa_pub));
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &denom_key_issue.denom_hash,
+ sizeof (struct GNUNET_HashCode));
+ denom_key->key.rsa_public_key = pk;
+ denom_key->h_key = denom_key_issue.denom_hash;
+ denom_key->valid_from = valid_from;
+ denom_key->withdraw_valid_until = withdraw_valid_until;
+ denom_key->deposit_valid_until = deposit_valid_until;
+ denom_key->expire_legal = expire_legal;
+ denom_key->value = value;
+ denom_key->fee_withdraw = fee_withdraw;
+ denom_key->fee_deposit = fee_deposit;
+ denom_key->fee_refresh = fee_refresh;
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Parse a exchange's auditor information encoded in JSON.
+ *
+ * @param[out] auditor where to return the result
+ * @param[in] auditor_obj json to parse
+ * @param key_data information about denomination keys
+ * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
+ * invalid or the json malformed.
+ */
+static int
+parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
+ json_t *auditor_obj,
+ const struct TALER_EXCHANGE_Keys *key_data)
+{
+ json_t *keys;
+ json_t *key;
+ unsigned int len;
+ unsigned int off;
+ unsigned int i;
+ struct TALER_ExchangeKeyValidityPS kv;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("auditor_pub",
+ &auditor->auditor_pub),
+ MAJ_spec_json ("denomination_keys",
+ &keys),
+ MAJ_spec_end
+ };
+
+ auditor->auditor_url = NULL; /* #3987 */
+ if (GNUNET_OK !=
+ MAJ_parse_json (auditor_obj,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS);
+ kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS));
+ kv.master = key_data->master_pub;
+ len = json_array_size (keys);
+ auditor->denom_keys = GNUNET_new_array (len,
+ const struct TALER_EXCHANGE_DenomPublicKey *);
+ i = 0;
+ off = 0;
+ json_array_foreach (keys, i, key) {
+ struct TALER_AuditorSignatureP auditor_sig;
+ struct GNUNET_HashCode denom_h;
+ const struct TALER_EXCHANGE_DenomPublicKey *dk;
+ unsigned int j;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("denom_pub_h",
+ &denom_h),
+ MAJ_spec_fixed_auto ("auditor_sig",
+ &auditor_sig),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (key,
+ spec))
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ dk = NULL;
+ for (j=0;j<key_data->num_denom_keys;j++)
+ {
+ if (0 == memcmp (&denom_h,
+ &key_data->denom_keys[j].h_key,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ dk = &key_data->denom_keys[j];
+ break;
+ }
+ }
+ if (NULL == dk)
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
+ kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until);
+ kv.expire_spend = GNUNET_TIME_absolute_hton (dk->deposit_valid_until);
+ kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
+ TALER_amount_hton (&kv.value,
+ &dk->value);
+ TALER_amount_hton (&kv.fee_withdraw,
+ &dk->fee_withdraw);
+ TALER_amount_hton (&kv.fee_deposit,
+ &dk->fee_deposit);
+ TALER_amount_hton (&kv.fee_refresh,
+ &dk->fee_refresh);
+ kv.denom_hash = dk->h_key;
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS,
+ &kv.purpose,
+ &auditor_sig.eddsa_sig,
+ &auditor->auditor_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ auditor->denom_keys[off] = dk;
+ off++;
+ }
+ auditor->num_denom_keys = off;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Decode the JSON in @a resp_obj from the /keys response and store the data
+ * in the @a key_data.
+ *
+ * @param[in] resp_obj JSON object to parse
+ * @param[out] key_data where to store the results we decoded
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
+ */
+static int
+decode_keys_json (json_t *resp_obj,
+ struct TALER_EXCHANGE_Keys *key_data)
+{
+ struct GNUNET_TIME_Absolute list_issue_date;
+ struct TALER_ExchangeSignatureP sig;
+ struct TALER_ExchangeKeySetPS ks;
+ struct GNUNET_HashContext *hash_context;
+ struct TALER_ExchangePublicKeyP pub;
+
+ if (JSON_OBJECT != json_typeof (resp_obj))
+ return GNUNET_SYSERR;
+
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
+ /* parse the master public key and issue date of the response */
+ {
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("master_public_key",
+ &key_data->master_pub),
+ MAJ_spec_fixed_auto ("eddsa_sig",
+ &sig),
+ MAJ_spec_fixed_auto ("eddsa_pub",
+ &pub),
+ MAJ_spec_absolute_time ("list_issue_date",
+ &list_issue_date),
+ MAJ_spec_end
+ };
+
+ EXITIF (GNUNET_OK !=
+ MAJ_parse_json (resp_obj,
+ spec));
+ }
+
+ /* parse the signing keys */
+ {
+ json_t *sign_keys_array;
+ json_t *sign_key_obj;
+ unsigned int index;
+
+ EXITIF (NULL == (sign_keys_array =
+ json_object_get (resp_obj,
+ "signkeys")));
+ EXITIF (JSON_ARRAY != json_typeof (sign_keys_array));
+ EXITIF (0 == (key_data->num_sign_keys =
+ json_array_size (sign_keys_array)));
+ key_data->sign_keys
+ = GNUNET_new_array (key_data->num_sign_keys,
+ struct TALER_EXCHANGE_SigningPublicKey);
+ index = 0;
+ json_array_foreach (sign_keys_array, index, sign_key_obj) {
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_signkey (&key_data->sign_keys[index],
+ sign_key_obj,
+ &key_data->master_pub));
+ }
+ }
+
+ /* parse the denomination keys */
+ {
+ json_t *denom_keys_array;
+ json_t *denom_key_obj;
+ unsigned int index;
+
+ EXITIF (NULL == (denom_keys_array =
+ json_object_get (resp_obj, "denoms")));
+ EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
+ EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array)));
+ key_data->denom_keys = GNUNET_new_array (key_data->num_denom_keys,
+ struct TALER_EXCHANGE_DenomPublicKey);
+ index = 0;
+ json_array_foreach (denom_keys_array, index, denom_key_obj) {
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_denomkey (&key_data->denom_keys[index],
+ denom_key_obj,
+ &key_data->master_pub,
+ hash_context));
+ }
+ }
+
+ /* parse the auditor information */
+ {
+ json_t *auditors_array;
+ json_t *auditor_info;
+ unsigned int len;
+ unsigned int index;
+
+ EXITIF (NULL == (auditors_array =
+ json_object_get (resp_obj, "auditors")));
+ EXITIF (JSON_ARRAY != json_typeof (auditors_array));
+ len = json_array_size (auditors_array);
+ if (0 != len)
+ {
+ key_data->auditors = GNUNET_new_array (len,
+ struct TALER_EXCHANGE_AuditorInformation);
+ index = 0;
+ json_array_foreach (auditors_array, index, auditor_info) {
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_auditor (&key_data->auditors[index],
+ auditor_info,
+ key_data));
+ }
+ }
+ }
+
+ /* Validate signature... */
+ ks.purpose.size = htonl (sizeof (ks));
+ ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
+ ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date);
+ GNUNET_CRYPTO_hash_context_finish (hash_context,
+ &ks.hc);
+ hash_context = NULL;
+ EXITIF (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_data,
+ &pub));
+ EXITIF (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET,
+ &ks.purpose,
+ &sig.eddsa_signature,
+ &pub.eddsa_pub));
+ return GNUNET_OK;
+ EXITIF_exit:
+
+ if (NULL != hash_context)
+ GNUNET_CRYPTO_hash_context_abort (hash_context);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Callback used when downloading the reply to a /keys request
+ * is complete.
+ *
+ * @param cls the `struct KeysRequest`
+ * @param eh easy handle of the original request
+ */
+static void
+keys_completed_cb (void *cls,
+ CURL *eh)
+{
+ struct KeysRequest *kr = cls;
+ struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
+ json_t *resp_obj;
+ long response_code;
+ TALER_EXCHANGE_CertificationCallback cb;
+
+ resp_obj = MAC_download_get_result (&kr->db,
+ eh,
+ &response_code);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received keys from URL `%s' with status %ld.\n",
+ kr->url,
+ response_code);
+ switch (response_code) {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ if ( (NULL == resp_obj) ||
+ (GNUNET_OK !=
+ decode_keys_json (resp_obj,
+ &kr->exchange->key_data)) )
+ response_code = 0;
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ break;
+ }
+ if (NULL != resp_obj)
+ json_decref (resp_obj);
+
+ if (MHD_HTTP_OK != response_code)
+ {
+ exchange->kr = NULL;
+ free_keys_request (kr);
+ exchange->state = MHS_FAILED;
+ /* notify application that we failed */
+ if (NULL != (cb = exchange->cert_cb))
+ {
+ exchange->cert_cb = NULL;
+ cb (exchange->cert_cb_cls,
+ NULL);
+ }
+ return;
+ }
+ exchange->kr = NULL;
+ free_keys_request (kr);
+ exchange->state = MHS_CERT;
+ /* notify application about the key information */
+ if (NULL != (cb = exchange->cert_cb))
+ {
+ exchange->cert_cb = NULL;
+ cb (exchange->cert_cb_cls,
+ &exchange->key_data);
+ }
+}
+
+
+/* ********************* library internal API ********* */
+
+
+/**
+ * Get the context of a exchange.
+ *
+ * @param h the exchange handle to query
+ * @return ctx context to execute jobs in
+ */
+struct TALER_EXCHANGE_Context *
+MAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
+{
+ return h->ctx;
+}
+
+
+/**
+ * Check if the handle is ready to process requests.
+ *
+ * @param h the exchange handle to query
+ * @return #GNUNET_YES if we are ready, #GNUNET_NO if not
+ */
+int
+MAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
+{
+ return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
+}
+
+
+/**
+ * Obtain the URL to use for an API request.
+ *
+ * @param h the exchange handle to query
+ * @param path Taler API path (i.e. "/reserve/withdraw")
+ * @return the full URI to use with cURL
+ */
+char *
+MAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
+ const char *path)
+{
+ char *url;
+
+ if ( ('/' == path[0]) &&
+ (0 < strlen (h->url)) &&
+ ('/' == h->url[strlen (h->url) - 1]) )
+ path++; /* avoid generating URL with "//" from concat */
+ GNUNET_asprintf (&url,
+ "%s%s",
+ h->url,
+ path);
+ return url;
+}
+
+
+/* ********************* public API ******************* */
+
+/**
+ * Initialise a connection to the exchange. Will connect to the
+ * exchange and obtain information about the exchange's master public
+ * key and the exchange's auditor. The respective information will
+ * be passed to the @a cert_cb once available, and all future
+ * interactions with the exchange will be checked to be signed
+ * (where appropriate) by the respective master key.
+ *
+ * @param ctx the context
+ * @param url HTTP base URL for the exchange
+ * @param cert_cb function to call with the exchange's certification information
+ * @param cert_cb_cls closure for @a cert_cb
+ * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END.
+ * @return the exchange handle; NULL upon error
+ */
+struct TALER_EXCHANGE_Handle *
+TALER_EXCHANGE_connect (struct TALER_EXCHANGE_Context *ctx,
+ const char *url,
+ TALER_EXCHANGE_CertificationCallback cert_cb,
+ void *cert_cb_cls,
+ ...)
+{
+ struct TALER_EXCHANGE_Handle *exchange;
+ struct KeysRequest *kr;
+ CURL *c;
+
+ exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
+ exchange->ctx = ctx;
+ exchange->url = GNUNET_strdup (url);
+ exchange->cert_cb = cert_cb;
+ exchange->cert_cb_cls = cert_cb_cls;
+ kr = GNUNET_new (struct KeysRequest);
+ kr->exchange = exchange;
+ kr->url = MAH_path_to_url (exchange, "/keys");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting keys with URL `%s'.\n",
+ kr->url);
+ c = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_VERBOSE,
+ 0));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_STDERR,
+ stdout));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_URL,
+ kr->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_WRITEDATA,
+ &kr->db));
+ kr->job = MAC_job_add (exchange->ctx,
+ c,
+ GNUNET_NO,
+ &keys_completed_cb,
+ kr);
+ exchange->kr = kr;
+ return exchange;
+}
+
+
+/**
+ * Disconnect from the exchange
+ *
+ * @param exchange the exchange handle
+ */
+void
+TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
+{
+ unsigned int i;
+
+ if (NULL != exchange->kr)
+ {
+ MAC_job_cancel (exchange->kr->job);
+ free_keys_request (exchange->kr);
+ exchange->kr = NULL;
+ }
+ GNUNET_array_grow (exchange->key_data.sign_keys,
+ exchange->key_data.num_sign_keys,
+ 0);
+ for (i=0;i<exchange->key_data.num_denom_keys;i++)
+ GNUNET_CRYPTO_rsa_public_key_free (exchange->key_data.denom_keys[i].key.rsa_public_key);
+ GNUNET_array_grow (exchange->key_data.denom_keys,
+ exchange->key_data.num_denom_keys,
+ 0);
+ GNUNET_array_grow (exchange->key_data.auditors,
+ exchange->key_data.num_auditors,
+ 0);
+ GNUNET_free (exchange->url);
+ GNUNET_free (exchange);
+}
+
+
+/**
+ * Test if the given @a pub is a the current signing key from the exchange
+ * according to @a keys.
+ *
+ * @param keys the exchange's key set
+ * @param pub claimed current online signing key for the exchange
+ * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key
+ */
+int
+TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_ExchangePublicKeyP *pub)
+{
+ struct GNUNET_TIME_Absolute now;
+ unsigned int i;
+
+ /* we will check using a tolerance of 1h for the time */
+ now = GNUNET_TIME_absolute_get ();
+ for (i=0;i<keys->num_sign_keys;i++)
+ if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) &&
+ (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) &&
+ (0 == memcmp (pub,
+ &keys->sign_keys[i].key,
+ sizeof (struct TALER_ExchangePublicKeyP))) )
+ return GNUNET_OK;
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Obtain the denomination key details from the exchange.
+ *
+ * @param keys the exchange's key set
+ * @param pk public key of the denomination to lookup
+ * @return details about the given denomination key, NULL if the key is
+ * not found
+ */
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_DenominationPublicKey *pk)
+{
+ unsigned int i;
+
+ for (i=0;i<keys->num_denom_keys;i++)
+ if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key,
+ keys->denom_keys[i].key.rsa_public_key))
+ return &keys->denom_keys[i];
+ return NULL;
+}
+
+
+/**
+ * Obtain the denomination key details from the exchange.
+ *
+ * @param keys the exchange's key set
+ * @param hc hash of the public key of the denomination to lookup
+ * @return details about the given denomination key
+ */
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys,
+ const struct GNUNET_HashCode *hc)
+{
+ unsigned int i;
+
+ for (i=0;i<keys->num_denom_keys;i++)
+ if (0 == memcmp (hc,
+ &keys->denom_keys[i].h_key,
+ sizeof (struct GNUNET_HashCode)))
+ return &keys->denom_keys[i];
+ return NULL;
+}
+
+
+/**
+ * Obtain the keys from the exchange.
+ *
+ * @param exchange the exchange handle
+ * @return the exchange's key set
+ */
+const struct TALER_EXCHANGE_Keys *
+TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange)
+{
+ return &exchange->key_data;
+}
+
+
+/* end of exchange_api_handle.c */
diff --git a/src/exchange-lib/exchange_api_handle.h b/src/exchange-lib/exchange_api_handle.h
new file mode 100644
index 000000000..48423a7b8
--- /dev/null
+++ b/src/exchange-lib/exchange_api_handle.h
@@ -0,0 +1,59 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_handle.h
+ * @brief Internal interface to the handle part of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include "taler_exchange_service.h"
+
+
+/**
+ * Get the context of a exchange.
+ *
+ * @param h the exchange handle to query
+ * @return ctx context to execute jobs in
+ */
+struct TALER_EXCHANGE_Context *
+MAH_handle_to_context (struct TALER_EXCHANGE_Handle *h);
+
+
+/**
+ * Check if the handle is ready to process requests.
+ *
+ * @param h the exchange handle to query
+ * @return #GNUNET_YES if we are ready, #GNUNET_NO if not
+ */
+int
+MAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);
+
+
+/**
+ * Obtain the URL to use for an API request.
+ *
+ * @param h the exchange handle to query
+ * @param path Taler API path (i.e. "/reserve/withdraw")
+ * @return the full URI to use with cURL
+ */
+char *
+MAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
+ const char *path);
+
+
+/* end of exchange_api_handle.h */
diff --git a/src/exchange-lib/exchange_api_json.c b/src/exchange-lib/exchange_api_json.c
new file mode 100644
index 000000000..d91feba0e
--- /dev/null
+++ b/src/exchange-lib/exchange_api_json.c
@@ -0,0 +1,525 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_json.c
+ * @brief functions to parse incoming requests (JSON snippets)
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "exchange_api_json.h"
+
+/**
+ * Navigate and parse data in a JSON tree.
+ *
+ * @param root the JSON node to start the navigation at.
+ * @param spec parse specification array
+ * @return offset in @a spec where parsing failed, -1 on success (!)
+ */
+static int
+parse_json (json_t *root,
+ struct MAJ_Specification *spec)
+{
+ int i;
+ json_t *pos; /* what's our current position? */
+
+ pos = root;
+ for (i=0;MAJ_CMD_END != spec[i].cmd;i++)
+ {
+ pos = json_object_get (root,
+ spec[i].field);
+ if (NULL == pos)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ switch (spec[i].cmd)
+ {
+ case MAJ_CMD_END:
+ GNUNET_assert (0);
+ return i;
+ case MAJ_CMD_AMOUNT:
+ if (GNUNET_OK !=
+ TALER_json_to_amount (pos,
+ spec[i].details.amount))
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ break;
+ case MAJ_CMD_TIME_ABSOLUTE:
+ if (GNUNET_OK !=
+ TALER_json_to_abs (pos,
+ spec[i].details.abs_time))
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ break;
+
+ case MAJ_CMD_STRING:
+ {
+ const char *str;
+
+ str = json_string_value (pos);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ *spec[i].details.strptr = str;
+ }
+ break;
+
+ case MAJ_CMD_BINARY_FIXED:
+ {
+ const char *str;
+ int res;
+
+ str = json_string_value (pos);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ res = GNUNET_STRINGS_string_to_data (str, strlen (str),
+ spec[i].details.fixed_data.dest,
+ spec[i].details.fixed_data.dest_size);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ }
+ break;
+
+ case MAJ_CMD_BINARY_VARIABLE:
+ {
+ const char *str;
+ size_t size;
+ void *data;
+ int res;
+
+ str = json_string_value (pos);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ size = (strlen (str) * 5) / 8;
+ if (size >= 1024)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ data = GNUNET_malloc (size);
+ res = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ data,
+ size);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (data);
+ return i;
+ }
+ *spec[i].details.variable_data.dest_p = data;
+ *spec[i].details.variable_data.dest_size_p = size;
+ }
+ break;
+
+ case MAJ_CMD_RSA_PUBLIC_KEY:
+ {
+ size_t size;
+ const char *str;
+ int res;
+ void *buf;
+
+ str = json_string_value (pos);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ size = (strlen (str) * 5) / 8;
+ buf = GNUNET_malloc (size);
+ res = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ buf,
+ size);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_free (buf);
+ GNUNET_break_op (0);
+ return i;
+ }
+ *spec[i].details.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_decode (buf,
+ size);
+ GNUNET_free (buf);
+ if (NULL == spec[i].details.rsa_public_key)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ }
+ break;
+
+ case MAJ_CMD_RSA_SIGNATURE:
+ {
+ size_t size;
+ const char *str;
+ int res;
+ void *buf;
+
+ str = json_string_value (pos);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ size = (strlen (str) * 5) / 8;
+ buf = GNUNET_malloc (size);
+ res = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ buf,
+ size);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_free (buf);
+ GNUNET_break_op (0);
+ return i;
+ }
+ *spec[i].details.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_decode (buf,
+ size);
+ GNUNET_free (buf);
+ if (NULL == spec[i].details.rsa_signature)
+ return i;
+ }
+ break;
+
+ case MAJ_CMD_UINT16:
+ {
+ json_int_t val;
+
+ if (! json_is_integer (pos))
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ val = json_integer_value (pos);
+ if ( (0 > val) || (val > UINT16_MAX) )
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ *spec[i].details.u16 = (uint16_t) val;
+ }
+ break;
+
+ case MAJ_CMD_UINT64:
+ {
+ json_int_t val;
+
+ if (! json_is_integer (pos))
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ val = json_integer_value (pos);
+ *spec[i].details.u64 = (uint64_t) val;
+ }
+ break;
+
+ case MAJ_CMD_JSON_OBJECT:
+ {
+ if (! (json_is_object (pos) || json_is_array (pos)) )
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ json_incref (pos);
+ *spec[i].details.obj = pos;
+ }
+ break;
+
+ default:
+ GNUNET_break (0);
+ return i;
+ }
+ }
+ return -1; /* all OK! */
+}
+
+
+/**
+ * Free all elements allocated during a
+ * #MAJ_parse_json() operation.
+ *
+ * @param spec specification of the parse operation
+ * @param end number of elements in @a spec to process
+ */
+static void
+parse_free (struct MAJ_Specification *spec,
+ int end)
+{
+ int i;
+
+ for (i=0;i<end;i++)
+ {
+ switch (spec[i].cmd)
+ {
+ case MAJ_CMD_END:
+ GNUNET_assert (0);
+ return;
+ case MAJ_CMD_AMOUNT:
+ break;
+ case MAJ_CMD_TIME_ABSOLUTE:
+ break;
+ case MAJ_CMD_BINARY_FIXED:
+ break;
+ case MAJ_CMD_STRING:
+ break;
+ case MAJ_CMD_BINARY_VARIABLE:
+ GNUNET_free (*spec[i].details.variable_data.dest_p);
+ *spec[i].details.variable_data.dest_p = NULL;
+ *spec[i].details.variable_data.dest_size_p = 0;
+ break;
+ case MAJ_CMD_RSA_PUBLIC_KEY:
+ GNUNET_CRYPTO_rsa_public_key_free (*spec[i].details.rsa_public_key);
+ *spec[i].details.rsa_public_key = NULL;
+ break;
+ case MAJ_CMD_RSA_SIGNATURE:
+ GNUNET_CRYPTO_rsa_signature_free (*spec[i].details.rsa_signature);
+ *spec[i].details.rsa_signature = NULL;
+ break;
+ case MAJ_CMD_JSON_OBJECT:
+ json_decref (*spec[i].details.obj);
+ *spec[i].details.obj = NULL;
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ }
+}
+
+
+/**
+ * Navigate and parse data in a JSON tree.
+ *
+ * @param root the JSON node to start the navigation at.
+ * @param spec parse specification array
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+MAJ_parse_json (const json_t *root,
+ struct MAJ_Specification *spec)
+{
+ int ret;
+
+ ret = parse_json ((json_t *) root,
+ spec);
+ if (-1 == ret)
+ return GNUNET_OK;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "JSON field `%s` (%d) had unexpected value\n",
+ spec[ret].field,
+ ret);
+ parse_free (spec, ret);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Free all elements allocated during a
+ * #MAJ_parse_json() operation.
+ *
+ * @param spec specification of the parse operation
+ */
+void
+MAJ_parse_free (struct MAJ_Specification *spec)
+{
+ int i;
+
+ for (i=0;MAJ_CMD_END != spec[i].cmd;i++) ;
+ parse_free (spec, i);
+}
+
+
+/**
+ * The expected field stores a string.
+ *
+ * @param name name of the JSON field
+ * @param strptr where to store a pointer to the field
+ */
+struct MAJ_Specification
+MAJ_spec_string (const char *name,
+ const char **strptr)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_STRING,
+ .field = name,
+ .details.strptr = strptr
+ };
+ return ret;
+}
+
+
+/**
+ * Specification for parsing an absolute time value.
+ *
+ * @param name name of the JSON field
+ * @param at where to store the absolute time found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_absolute_time (const char *name,
+ struct GNUNET_TIME_Absolute *at)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_TIME_ABSOLUTE,
+ .field = name,
+ .details.abs_time = at
+ };
+ return ret;
+}
+
+
+/**
+ * Specification for parsing an amount value.
+ *
+ * @param name name of the JSON field
+ * @param amount where to store the amount found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_amount (const char *name,
+ struct TALER_Amount *amount)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_AMOUNT,
+ .field = name,
+ .details.amount = amount
+ };
+ return ret;
+}
+
+
+/**
+ * 16-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u16 where to store the integer found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_uint16 (const char *name,
+ uint16_t *u16)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_UINT16,
+ .field = name,
+ .details.u16 = u16
+ };
+ return ret;
+}
+
+
+/**
+ * 64-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u64 where to store the integer found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_uint64 (const char *name,
+ uint64_t *u64)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_UINT64,
+ .field = name,
+ .details.u64 = u64
+ };
+ return ret;
+}
+
+
+/**
+ * JSON object.
+ *
+ * @param name name of the JSON field
+ * @param[out] jsonp where to store the JSON found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_json (const char *name,
+ json_t **jsonp)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_JSON_OBJECT,
+ .field = name,
+ .details.obj = jsonp
+ };
+ return ret;
+}
+
+
+/**
+ * Specification for parsing an RSA public key.
+ *
+ * @param name name of the JSON field
+ * @param pk where to store the RSA key found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_rsa_public_key (const char *name,
+ struct GNUNET_CRYPTO_rsa_PublicKey **pk)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_RSA_PUBLIC_KEY,
+ .field = name,
+ .details.rsa_public_key = pk
+ };
+ return ret;
+}
+
+
+/**
+ * Specification for parsing an RSA signature.
+ *
+ * @param name name of the JSON field
+ * @param sig where to store the RSA signature found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_rsa_signature (const char *name,
+ struct GNUNET_CRYPTO_rsa_Signature **sig)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_RSA_SIGNATURE,
+ .field = name,
+ .details.rsa_signature = sig
+ };
+ return ret;
+}
+
+
+/* end of exchange_api_json.c */
diff --git a/src/exchange-lib/exchange_api_json.h b/src/exchange-lib/exchange_api_json.h
new file mode 100644
index 000000000..41efcea68
--- /dev/null
+++ b/src/exchange-lib/exchange_api_json.h
@@ -0,0 +1,352 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_json.h
+ * @brief functions to parse incoming requests (JSON snippets)
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_util.h"
+#include <jansson.h>
+
+
+/**
+ * Enumeration with the various commands for the
+ * #MAJ_parse_json interpreter.
+ */
+enum MAJ_Command
+{
+
+ /**
+ * End of command list.
+ */
+ MAJ_CMD_END,
+
+ /**
+ * Parse amount at current position.
+ */
+ MAJ_CMD_AMOUNT,
+
+ /**
+ * Parse absolute time at current position.
+ */
+ MAJ_CMD_TIME_ABSOLUTE,
+
+ /**
+ * Parse fixed binary value at current position.
+ */
+ MAJ_CMD_BINARY_FIXED,
+
+ /**
+ * Parse variable-size binary value at current position.
+ */
+ MAJ_CMD_BINARY_VARIABLE,
+
+ /**
+ * Parse RSA public key at current position.
+ */
+ MAJ_CMD_RSA_PUBLIC_KEY,
+
+ /**
+ * Parse RSA signature at current position.
+ */
+ MAJ_CMD_RSA_SIGNATURE,
+
+ /**
+ * Parse `const char *` JSON string at current position.
+ */
+ MAJ_CMD_STRING,
+
+ /**
+ * Parse `uint16_t` integer at the current position.
+ */
+ MAJ_CMD_UINT16,
+
+ /**
+ * Parse `uint64_t` integer at the current position.
+ */
+ MAJ_CMD_UINT64,
+
+ /**
+ * Parse JSON object at the current position.
+ */
+ MAJ_CMD_JSON_OBJECT,
+
+ /**
+ * Parse ??? at current position.
+ */
+ MAJ_CMD_C
+
+};
+
+
+/**
+ * @brief Entry in parser specification for #MAJ_parse_json.
+ */
+struct MAJ_Specification
+{
+
+ /**
+ * Command to execute.
+ */
+ enum MAJ_Command cmd;
+
+ /**
+ * Name of the field to access.
+ */
+ const char *field;
+
+ /**
+ * Further details for the command.
+ */
+ union {
+
+ /**
+ * Where to store amount for #MAJ_CMD_AMOUNT.
+ */
+ struct TALER_Amount *amount;
+
+ /**
+ * Where to store time, for #MAJ_CMD_TIME_ABSOLUTE.
+ */
+ struct GNUNET_TIME_Absolute *abs_time;
+
+ /**
+ * Where to write binary data, for #MAJ_CMD_BINARY_FIXED.
+ */
+ struct {
+ /**
+ * Where to write the data.
+ */
+ void *dest;
+
+ /**
+ * How many bytes to write to @e dest.
+ */
+ size_t dest_size;
+
+ } fixed_data;
+
+ /**
+ * Where to write binary data, for #MAJ_CMD_BINARY_VARIABLE.
+ */
+ struct {
+ /**
+ * Where to store the pointer with the data (is allocated).
+ */
+ void **dest_p;
+
+ /**
+ * Where to store the number of bytes allocated at `*dest`.
+ */
+ size_t *dest_size_p;
+
+ } variable_data;
+
+ /**
+ * Where to store the RSA public key for #MAJ_CMD_RSA_PUBLIC_KEY
+ */
+ struct GNUNET_CRYPTO_rsa_PublicKey **rsa_public_key;
+
+ /**
+ * Where to store the RSA signature for #MAJ_CMD_RSA_SIGNATURE
+ */
+ struct GNUNET_CRYPTO_rsa_Signature **rsa_signature;
+
+ /**
+ * Details for #MAJ_CMD_EDDSA_SIGNATURE
+ */
+ struct {
+
+ /**
+ * Where to store the purpose.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose **purpose_p;
+
+ /**
+ * Key to verify the signature against.
+ */
+ const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key;
+
+ } eddsa_signature;
+
+ /**
+ * Where to store a pointer to the string.
+ */
+ const char **strptr;
+
+ /**
+ * Where to store 16-bit integer.
+ */
+ uint16_t *u16;
+
+ /**
+ * Where to store 64-bit integer.
+ */
+ uint64_t *u64;
+
+ /**
+ * Where to store a JSON object.
+ */
+ json_t **obj;
+
+ } details;
+
+};
+
+
+/**
+ * Navigate and parse data in a JSON tree.
+ *
+ * @param root the JSON node to start the navigation at.
+ * @param spec parse specification array
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+MAJ_parse_json (const json_t *root,
+ struct MAJ_Specification *spec);
+
+
+/**
+ * Free all elements allocated during a
+ * #MAJ_parse_json() operation.
+ *
+ * @param spec specification of the parse operation
+ */
+void
+MAJ_parse_free (struct MAJ_Specification *spec);
+
+
+/**
+ * End of a parser specification.
+ */
+#define MAJ_spec_end { .cmd = MAJ_CMD_END }
+
+/**
+ * Fixed size object (in network byte order, encoded using Crockford
+ * Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param obj pointer where to write the data (type of `*obj` will determine size)
+ */
+#define MAJ_spec_fixed_auto(name,obj) { .cmd = MAJ_CMD_BINARY_FIXED, .field = name, .details.fixed_data.dest = obj, .details.fixed_data.dest_size = sizeof (*obj) }
+
+
+/**
+ * Variable size object (in network byte order, encoded using Crockford
+ * Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param obj pointer where to write the data (a `void **`)
+ * @param size where to store the number of bytes allocated for @a obj (of type `size_t *`
+ */
+#define MAJ_spec_varsize(name,obj,size) { .cmd = MAJ_CMD_BINARY_VARIABLE, .field = name, .details.variable_data.dest_p = obj, .details.variable_data.dest_size_p = size }
+
+
+/**
+ * The expected field stores a string.
+ *
+ * @param name name of the JSON field
+ * @param strptr where to store a pointer to the field
+ */
+struct MAJ_Specification
+MAJ_spec_string (const char *name,
+ const char **strptr);
+
+
+/**
+ * Absolute time.
+ *
+ * @param name name of the JSON field
+ * @param[out] at where to store the absolute time found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_absolute_time (const char *name,
+ struct GNUNET_TIME_Absolute *at);
+
+
+/**
+ * 16-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u16 where to store the integer found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_uint16 (const char *name,
+ uint16_t *u16);
+
+
+/**
+ * 64-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u64 where to store the integer found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_uint64 (const char *name,
+ uint64_t *u64);
+
+
+/**
+ * JSON object.
+ *
+ * @param name name of the JSON field
+ * @param[out] jsonp where to store the JSON found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_json (const char *name,
+ json_t **jsonp);
+
+
+/**
+ * Specification for parsing an amount value.
+ *
+ * @param name name of the JSON field
+ * @param amount where to store the amount under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_amount (const char *name,
+ struct TALER_Amount *amount);
+
+
+/**
+ * Specification for parsing an RSA public key.
+ *
+ * @param name name of the JSON field
+ * @param pk where to store the RSA key found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_rsa_public_key (const char *name,
+ struct GNUNET_CRYPTO_rsa_PublicKey **pk);
+
+
+/**
+ * Specification for parsing an RSA signature.
+ *
+ * @param name name of the JSON field
+ * @param sig where to store the RSA signature found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_rsa_signature (const char *name,
+ struct GNUNET_CRYPTO_rsa_Signature **sig);
+
+
+
+
+/* end of exchange_api_json.h */
diff --git a/src/exchange-lib/exchange_api_refresh.c b/src/exchange-lib/exchange_api_refresh.c
new file mode 100644
index 000000000..03d59ea3b
--- /dev/null
+++ b/src/exchange-lib/exchange_api_refresh.c
@@ -0,0 +1,2061 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_refresh.c
+ * @brief Implementation of the /refresh/melt+reveal requests of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/* ********************* /refresh/ common ***************************** */
+
+/* structures for committing refresh data to disk before doing the
+ network interaction(s) */
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Header of serialized information about a coin we are melting.
+ */
+struct MeltedCoinP
+{
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Amount this coin contributes to the melt, including fee.
+ */
+ struct TALER_AmountNBO melt_amount_with_fee;
+
+ /**
+ * The applicable fee for withdrawing a coin of this denomination
+ */
+ struct TALER_AmountNBO fee_melt;
+
+ /**
+ * The original value of the coin.
+ */
+ struct TALER_AmountNBO original_value;
+
+ /**
+ * Transfer private keys for each cut-and-choose dimension.
+ */
+ struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
+
+ /**
+ * Timestamp indicating when coins of this denomination become invalid.
+ */
+ struct GNUNET_TIME_AbsoluteNBO deposit_valid_until;
+
+ /**
+ * Size of the encoded public key that follows.
+ */
+ uint16_t pbuf_size;
+
+ /**
+ * Size of the encoded signature that follows.
+ */
+ uint16_t sbuf_size;
+
+ /* Followed by serializations of:
+ 1) struct TALER_DenominationPublicKey pub_key;
+ 2) struct TALER_DenominationSignature sig;
+ */
+};
+
+
+/**
+ * Header for serializations of coin-specific information about the
+ * fresh coins we generate during a melt.
+ */
+struct FreshCoinP
+{
+
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Size of the encoded blinding key that follows.
+ */
+ uint32_t bbuf_size;
+
+ /* Followed by serialization of:
+ - struct TALER_DenominationBlindingKey blinding_key;
+ */
+
+};
+
+
+/**
+ * Header of serialized data about a melt operation, suitable for
+ * persisting it on disk.
+ */
+struct MeltDataP
+{
+
+ /**
+ * Hash over the melting session.
+ */
+ struct GNUNET_HashCode melt_session_hash;
+
+ /**
+ * Link secret used to encrypt the @a coin_priv and the blinding
+ * key in the linkage data for the respective cut-and-choose dimension.
+ */
+ struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA];
+
+ /**
+ * Number of coins we are melting, in NBO
+ */
+ uint16_t num_melted_coins GNUNET_PACKED;
+
+ /**
+ * Number of coins we are creating, in NBO
+ */
+ uint16_t num_fresh_coins GNUNET_PACKED;
+
+ /* Followed by serializations of:
+ 1) struct MeltedCoinP melted_coins[num_melted_coins];
+ 2) struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins];
+ 3) TALER_CNC_KAPPA times:
+ 3a) struct FreshCoinP fresh_coins[num_fresh_coins];
+ */
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * Information about a coin we are melting.
+ */
+struct MeltedCoin
+{
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Amount this coin contributes to the melt, including fee.
+ */
+ struct TALER_Amount melt_amount_with_fee;
+
+ /**
+ * The applicable fee for melting a coin of this denomination
+ */
+ struct TALER_Amount fee_melt;
+
+ /**
+ * The original value of the coin.
+ */
+ struct TALER_Amount original_value;
+
+ /**
+ * Transfer private keys for each cut-and-choose dimension.
+ */
+ struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
+
+ /**
+ * Timestamp indicating when coins of this denomination become invalid.
+ */
+ struct GNUNET_TIME_Absolute deposit_valid_until;
+
+ /**
+ * Denomination key of the original coin.
+ */
+ struct TALER_DenominationPublicKey pub_key;
+
+ /**
+ * Exchange's signature over the coin.
+ */
+ struct TALER_DenominationSignature sig;
+
+};
+
+
+/**
+ * Coin-specific information about the fresh coins we generate during
+ * a melt.
+ */
+struct FreshCoin
+{
+
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Blinding key used for blinding during blind signing.
+ */
+ struct TALER_DenominationBlindingKey blinding_key;
+
+};
+
+
+/**
+ * Melt data in non-serialized format for convenient processing.
+ */
+struct MeltData
+{
+
+ /**
+ * Hash over the melting session.
+ */
+ struct GNUNET_HashCode melt_session_hash;
+
+ /**
+ * Link secrets for each cut-and-choose dimension.
+ */
+ struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA];
+
+ /**
+ * Number of coins we are melting
+ */
+ uint16_t num_melted_coins;
+
+ /**
+ * Number of coins we are creating
+ */
+ uint16_t num_fresh_coins;
+
+ /**
+ * Information about the melted coins in an array of length @e
+ * num_melted_coins.
+ */
+ struct MeltedCoin *melted_coins;
+
+ /**
+ * Array of @e num_fresh_coins denomination keys for the coins to be
+ * freshly exchangeed.
+ */
+ struct TALER_DenominationPublicKey *fresh_pks;
+
+ /**
+ * Arrays of @e num_fresh_coins with information about the fresh
+ * coins to be created, for each cut-and-choose dimension.
+ */
+ struct FreshCoin *fresh_coins[TALER_CNC_KAPPA];
+};
+
+
+/**
+ * Free all information associated with a melted coin session.
+ *
+ * @param mc melted coin to release, the pointer itself is NOT
+ * freed (as it is typically not allocated by itself)
+ */
+static void
+free_melted_coin (struct MeltedCoin *mc)
+{
+ if (NULL == mc)
+ return;
+ if (NULL != mc->pub_key.rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (mc->pub_key.rsa_public_key);
+ if (NULL != mc->sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (mc->sig.rsa_signature);
+}
+
+
+/**
+ * Free all information associated with a fresh coin.
+ *
+ * @param fc fresh coin to release, the pointer itself is NOT
+ * freed (as it is typically not allocated by itself)
+ */
+static void
+free_fresh_coin (struct FreshCoin *fc)
+{
+ if (NULL == fc)
+ return;
+ if (NULL != fc->blinding_key.rsa_blinding_key)
+ GNUNET_CRYPTO_rsa_blinding_key_free (fc->blinding_key.rsa_blinding_key);
+}
+
+
+/**
+ * Free all information associated with a melting session. Note
+ * that we allow the melting session to be only partially initialized,
+ * as we use this function also when freeing melt data that was not
+ * fully initialized (i.e. due to failures in #deserialize_melt_data()).
+ *
+ * @param md melting data to release, the pointer itself is NOT
+ * freed (as it is typically not allocated by itself)
+ */
+static void
+free_melt_data (struct MeltData *md)
+{
+ unsigned int i;
+ unsigned int j;
+
+ if (NULL != md->melted_coins)
+ {
+ for (i=0;i<md->num_melted_coins;i++)
+ free_melted_coin (&md->melted_coins[i]);
+ GNUNET_free (md->melted_coins);
+ }
+ if (NULL != md->fresh_pks)
+ {
+ for (i=0;i<md->num_fresh_coins;i++)
+ if (NULL != md->fresh_pks[i].rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (md->fresh_pks[i].rsa_public_key);
+ GNUNET_free (md->fresh_pks);
+ }
+
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ {
+ for (j=0;j<md->num_fresh_coins;j++)
+ free_fresh_coin (&md->fresh_coins[i][j]);
+ GNUNET_free (md->fresh_coins[i]);
+ }
+ /* Finally, clean up a bit...
+ (NOTE: compilers might optimize this away, so this is
+ not providing any strong assurances that the key material
+ is purged.) */
+ memset (md,
+ 0,
+ sizeof (struct MeltData));
+}
+
+
+/**
+ * Serialize information about a coin we are melting.
+ *
+ * @param mc information to serialize
+ * @param buf buffer to write data in, NULL to just compute
+ * required size
+ * @param off offeset at @a buf to use
+ * @return number of bytes written to @a buf at @a off, or if
+ * @a buf is NULL, number of bytes required; 0 on error
+ */
+static size_t
+serialize_melted_coin (const struct MeltedCoin *mc,
+ char *buf,
+ size_t off)
+{
+ struct MeltedCoinP mcp;
+ unsigned int i;
+ char *pbuf;
+ size_t pbuf_size;
+ char *sbuf;
+ size_t sbuf_size;
+
+ sbuf_size = GNUNET_CRYPTO_rsa_signature_encode (mc->sig.rsa_signature,
+ &sbuf);
+ pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (mc->pub_key.rsa_public_key,
+ &pbuf);
+ if (NULL == buf)
+ {
+ GNUNET_free (sbuf);
+ GNUNET_free (pbuf);
+ return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size;
+ }
+ if ( (sbuf_size > UINT16_MAX) ||
+ (pbuf_size > UINT16_MAX) )
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ mcp.coin_priv = mc->coin_priv;
+ TALER_amount_hton (&mcp.melt_amount_with_fee,
+ &mc->melt_amount_with_fee);
+ TALER_amount_hton (&mcp.fee_melt,
+ &mc->fee_melt);
+ TALER_amount_hton (&mcp.original_value,
+ &mc->original_value);
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ mcp.transfer_priv[i] = mc->transfer_priv[i];
+ mcp.deposit_valid_until = GNUNET_TIME_absolute_hton (mc->deposit_valid_until);
+ mcp.pbuf_size = htons ((uint16_t) pbuf_size);
+ mcp.sbuf_size = htons ((uint16_t) sbuf_size);
+ memcpy (&buf[off],
+ &mcp,
+ sizeof (struct MeltedCoinP));
+ memcpy (&buf[off + sizeof (struct MeltedCoinP)],
+ pbuf,
+ pbuf_size);
+ memcpy (&buf[off + sizeof (struct MeltedCoinP) + pbuf_size],
+ sbuf,
+ sbuf_size);
+ GNUNET_free (sbuf);
+ GNUNET_free (pbuf);
+ return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size;
+}
+
+
+/**
+ * Deserialize information about a coin we are melting.
+ *
+ * @param[out] mc information to deserialize
+ * @param buf buffer to read data from
+ * @param size number of bytes available at @a buf to use
+ * @param[out] ok set to #GNUNET_NO to report errors
+ * @return number of bytes read from @a buf, 0 on error
+ */
+static size_t
+deserialize_melted_coin (struct MeltedCoin *mc,
+ const char *buf,
+ size_t size,
+ int *ok)
+{
+ struct MeltedCoinP mcp;
+ unsigned int i;
+ size_t pbuf_size;
+ size_t sbuf_size;
+ size_t off;
+
+ if (size < sizeof (struct MeltedCoinP))
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ memcpy (&mcp,
+ buf,
+ sizeof (struct MeltedCoinP));
+ pbuf_size = ntohs (mcp.pbuf_size);
+ sbuf_size = ntohs (mcp.sbuf_size);
+ if (size < sizeof (struct MeltedCoinP) + pbuf_size + sbuf_size)
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ off = sizeof (struct MeltedCoinP);
+ mc->pub_key.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_decode (&buf[off],
+ pbuf_size);
+ off += pbuf_size;
+ mc->sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_decode (&buf[off],
+ sbuf_size);
+ off += sbuf_size;
+ if ( (NULL == mc->pub_key.rsa_public_key) ||
+ (NULL == mc->sig.rsa_signature) )
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+
+ mc->coin_priv = mcp.coin_priv;
+ TALER_amount_ntoh (&mc->melt_amount_with_fee,
+ &mcp.melt_amount_with_fee);
+ TALER_amount_ntoh (&mc->fee_melt,
+ &mcp.fee_melt);
+ TALER_amount_ntoh (&mc->original_value,
+ &mcp.original_value);
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ mc->transfer_priv[i] = mcp.transfer_priv[i];
+ mc->deposit_valid_until = GNUNET_TIME_absolute_ntoh (mcp.deposit_valid_until);
+ return off;
+}
+
+
+/**
+ * Serialize information about a denomination key.
+ *
+ * @param dk information to serialize
+ * @param buf buffer to write data in, NULL to just compute
+ * required size
+ * @param off offeset at @a buf to use
+ * @return number of bytes written to @a buf at @a off, or if
+ * @a buf is NULL, number of bytes required
+ */
+static size_t
+serialize_denomination_key (const struct TALER_DenominationPublicKey *dk,
+ char *buf,
+ size_t off)
+{
+ char *pbuf;
+ size_t pbuf_size;
+ uint32_t be;
+
+ pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key,
+ &pbuf);
+ if (NULL == buf)
+ {
+ GNUNET_free (pbuf);
+ return pbuf_size + sizeof (uint32_t);
+ }
+ be = htonl ((uint32_t) pbuf_size);
+ memcpy (&buf[off],
+ &be,
+ sizeof (uint32_t));
+ memcpy (&buf[off + sizeof (uint32_t)],
+ pbuf,
+ pbuf_size);
+ GNUNET_free (pbuf);
+ return pbuf_size + sizeof (uint32_t);
+}
+
+
+/**
+ * Deserialize information about a denomination key.
+ *
+ * @param[out] dk information to deserialize
+ * @param buf buffer to read data from
+ * @param size number of bytes available at @a buf to use
+ * @param[out] ok set to #GNUNET_NO to report errors
+ * @return number of bytes read from @a buf, 0 on error
+ */
+static size_t
+deserialize_denomination_key (struct TALER_DenominationPublicKey *dk,
+ const char *buf,
+ size_t size,
+ int *ok)
+{
+ size_t pbuf_size;
+ uint32_t be;
+
+ if (size < sizeof (uint32_t))
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ memcpy (&be,
+ buf,
+ sizeof (uint32_t));
+ pbuf_size = ntohl (be);
+ if (size < sizeof (uint32_t) + pbuf_size)
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ dk->rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (uint32_t)],
+ pbuf_size);
+
+ if (NULL == dk->rsa_public_key)
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ return sizeof (uint32_t) + pbuf_size;
+}
+
+
+/**
+ * Serialize information about a fresh coin we are generating.
+ *
+ * @param fc information to serialize
+ * @param buf buffer to write data in, NULL to just compute
+ * required size
+ * @param off offeset at @a buf to use
+ * @return number of bytes written to @a buf at @a off, or if
+ * @a buf is NULL, number of bytes required
+ */
+static size_t
+serialize_fresh_coin (const struct FreshCoin *fc,
+ char *buf,
+ size_t off)
+{
+ struct FreshCoinP fcp;
+ char *bbuf;
+ size_t bbuf_size;
+
+ bbuf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (fc->blinding_key.rsa_blinding_key,
+ &bbuf);
+ if (NULL == buf)
+ {
+ GNUNET_free (bbuf);
+ return sizeof (struct FreshCoinP) + bbuf_size;
+ }
+ fcp.coin_priv = fc->coin_priv;
+ fcp.bbuf_size = htonl ((uint32_t) bbuf_size);
+ memcpy (&buf[off],
+ &fcp,
+ sizeof (struct FreshCoinP));
+ memcpy (&buf[off + sizeof (struct FreshCoinP)],
+ bbuf,
+ bbuf_size);
+ GNUNET_free (bbuf);
+ return sizeof (struct FreshCoinP) + bbuf_size;
+}
+
+
+/**
+ * Deserialize information about a fresh coin we are generating.
+ *
+ * @param[out] fc information to deserialize
+ * @param buf buffer to read data from
+ * @param size number of bytes available at @a buf to use
+ * @param[out] ok set to #GNUNET_NO to report errors
+ * @return number of bytes read from @a buf, 0 on error
+ */
+static size_t
+deserialize_fresh_coin (struct FreshCoin *fc,
+ const char *buf,
+ size_t size,
+ int *ok)
+{
+ struct FreshCoinP fcp;
+ size_t bbuf_size;
+
+ if (size < sizeof (struct FreshCoinP))
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ memcpy (&fcp,
+ buf,
+ sizeof (struct FreshCoinP));
+ bbuf_size = ntohl (fcp.bbuf_size);
+ if (size < sizeof (struct FreshCoinP) + bbuf_size)
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ fc->blinding_key.rsa_blinding_key
+ = GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct FreshCoinP)],
+ bbuf_size);
+ if (NULL == fc->blinding_key.rsa_blinding_key)
+ {
+ GNUNET_break (0);
+ *ok = GNUNET_NO;
+ return 0;
+ }
+ fc->coin_priv = fcp.coin_priv;
+ return sizeof (struct FreshCoinP) + bbuf_size;
+}
+
+
+/**
+ * Serialize melt data.
+ *
+ * @param md data to serialize
+ * @param[out] res_size size of buffer returned
+ * @return serialized melt data
+ */
+static char *
+serialize_melt_data (const struct MeltData *md,
+ size_t *res_size)
+{
+ size_t size;
+ size_t asize;
+ char *buf;
+ unsigned int i;
+ unsigned int j;
+
+ size = 0;
+ asize = (size_t) -1; /* make the compiler happy */
+ buf = NULL;
+ /* we do 2 iterations, #1 to determine total size, #2 to
+ actually construct the buffer */
+ do {
+ if (0 == size)
+ {
+ size = sizeof (struct MeltDataP);
+ }
+ else
+ {
+ struct MeltDataP *mdp;
+
+ buf = GNUNET_malloc (size);
+ asize = size; /* just for invariant check later */
+ size = sizeof (struct MeltDataP);
+ mdp = (struct MeltDataP *) buf;
+ mdp->melt_session_hash = md->melt_session_hash;
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ mdp->link_secrets[i] = md->link_secrets[i];
+ mdp->num_melted_coins = htons (md->num_melted_coins);
+ mdp->num_fresh_coins = htons (md->num_fresh_coins);
+ }
+ for (i=0;i<md->num_melted_coins;i++)
+ size += serialize_melted_coin (&md->melted_coins[i],
+ buf,
+ size);
+ for (i=0;i<md->num_fresh_coins;i++)
+ size += serialize_denomination_key (&md->fresh_pks[i],
+ buf,
+ size);
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ for(j=0;j<md->num_fresh_coins;j++)
+ size += serialize_fresh_coin (&md->fresh_coins[i][j],
+ buf,
+ size);
+ } while (NULL == buf);
+ GNUNET_assert (size == asize);
+ *res_size = size;
+ return buf;
+}
+
+
+/**
+ * Deserialize melt data.
+ *
+ * @param buf serialized data
+ * @param buf_size size of @a buf
+ * @return deserialized melt data, NULL on error
+ */
+static struct MeltData *
+deserialize_melt_data (const char *buf,
+ size_t buf_size)
+{
+ struct MeltData *md;
+ struct MeltDataP mdp;
+ unsigned int i;
+ unsigned int j;
+ size_t off;
+ int ok;
+
+ if (buf_size < sizeof (struct MeltDataP))
+ return NULL;
+ memcpy (&mdp,
+ buf,
+ sizeof (struct MeltDataP));
+ md = GNUNET_new (struct MeltData);
+ md->melt_session_hash = mdp.melt_session_hash;
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ md->link_secrets[i] = mdp.link_secrets[i];
+ md->num_melted_coins = ntohs (mdp.num_melted_coins);
+ md->num_fresh_coins = ntohs (mdp.num_fresh_coins);
+ md->melted_coins = GNUNET_new_array (md->num_melted_coins,
+ struct MeltedCoin);
+ md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
+ struct TALER_DenominationPublicKey);
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins,
+ struct FreshCoin);
+ off = sizeof (struct MeltDataP);
+ ok = GNUNET_YES;
+ for (i=0;(i<md->num_melted_coins)&&(GNUNET_YES == ok);i++)
+ off += deserialize_melted_coin (&md->melted_coins[i],
+ &buf[off],
+ buf_size - off,
+ &ok);
+ for (i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++)
+ off += deserialize_denomination_key (&md->fresh_pks[i],
+ &buf[off],
+ buf_size - off,
+ &ok);
+
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ for(j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++)
+ off += deserialize_fresh_coin (&md->fresh_coins[i][j],
+ &buf[off],
+ buf_size - off,
+ &ok);
+ if (off != buf_size)
+ {
+ GNUNET_break (0);
+ ok = GNUNET_NO;
+ }
+ if (GNUNET_YES != ok)
+ {
+ free_melt_data (md);
+ GNUNET_free (md);
+ return NULL;
+ }
+ return md;
+}
+
+
+/**
+ * Setup information for a fresh coin.
+ *
+ * @param[out] fc value to initialize
+ * @param pk denomination information for the fresh coin
+ */
+static void
+setup_fresh_coin (struct FreshCoin *fc,
+ const struct TALER_EXCHANGE_DenomPublicKey *pk)
+{
+ struct GNUNET_CRYPTO_EddsaPrivateKey *epk;
+ unsigned int len;
+
+ epk = GNUNET_CRYPTO_eddsa_key_create ();
+ fc->coin_priv.eddsa_priv = *epk;
+ GNUNET_free (epk);
+ len = GNUNET_CRYPTO_rsa_public_key_len (pk->key.rsa_public_key);
+ fc->blinding_key.rsa_blinding_key
+ = GNUNET_CRYPTO_rsa_blinding_key_create (len);
+}
+
+
+/**
+ * Melt (partially spent) coins to obtain fresh coins that are
+ * unlinkable to the original coin(s). Note that melting more
+ * than one coin in a single request will make those coins linkable,
+ * so the safest operation only melts one coin at a time.
+ *
+ * This API is typically used by a wallet. Note that to ensure that
+ * no money is lost in case of hardware failures, is operation does
+ * not actually initiate the request. Instead, it generates a buffer
+ * which the caller must store before proceeding with the actual call
+ * to #TALER_EXCHANGE_refresh_melt() that will generate the request.
+ *
+ * This function does verify that the given request data is internally
+ * consistent. However, the @a melts_sigs are only verified if
+ * @a check_sigs is set to #GNUNET_YES, as this may be relatively
+ * expensive and should be redundant.
+ *
+ * Aside from some non-trivial cryptographic operations that might
+ * take a bit of CPU time to complete, this function returns
+ * its result immediately and does not start any asynchronous
+ * processing. This function is also thread-safe.
+ *
+ * @param num_melts number of coins that are being melted (typically 1)
+ * @param melt_privs array of @a num_melts private keys of the coins to melt
+ * @param melt_amounts array of @a num_melts amounts specifying how much
+ * each coin will contribute to the melt (including fee)
+ * @param melt_sigs array of @a num_melts signatures affirming the
+ * validity of the public keys corresponding to the
+ * @a melt_privs private keys
+ * @param melt_pks array of @a num_melts denomination key information
+ * records corresponding to the @a melt_sigs
+ * validity of the keys
+ * @param check_sigs verify the validity of the signatures of @a melt_sigs
+ * @param fresh_pks_len length of the @a pks array
+ * @param fresh_pks array of @a pks_len denominations of fresh coins to create
+ * @param[out] res_size set to the size of the return value, or 0 on error
+ * @return NULL
+ * if the inputs are invalid (i.e. denomination key not with this exchange).
+ * Otherwise, pointer to a buffer of @a res_size to store persistently
+ * before proceeding to #TALER_EXCHANGE_refresh_melt().
+ * Non-null results should be freed using #GNUNET_free().
+ */
+char *
+TALER_EXCHANGE_refresh_prepare (unsigned int num_melts,
+ const struct TALER_CoinSpendPrivateKeyP *melt_privs,
+ const struct TALER_Amount *melt_amounts,
+ const struct TALER_DenominationSignature *melt_sigs,
+ const struct TALER_EXCHANGE_DenomPublicKey *melt_pks,
+ int check_sigs,
+ unsigned int fresh_pks_len,
+ const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks,
+ size_t *res_size)
+{
+ struct MeltData md;
+ char *buf;
+ unsigned int i;
+ unsigned int j;
+ struct GNUNET_HashContext *hash_context;
+
+ /* build up melt data structure */
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ &md.link_secrets[i],
+ sizeof (struct TALER_LinkSecretP));
+ md.num_melted_coins = num_melts;
+ md.num_fresh_coins = fresh_pks_len;
+ md.melted_coins = GNUNET_new_array (num_melts,
+ struct MeltedCoin);
+ for (i=0;i<num_melts;i++)
+ {
+ md.melted_coins[i].coin_priv = melt_privs[i];
+ md.melted_coins[i].melt_amount_with_fee = melt_amounts[i];
+ md.melted_coins[i].fee_melt = melt_pks[i].fee_refresh;
+ md.melted_coins[i].original_value = melt_pks[i].value;
+ for (j=0;j<TALER_CNC_KAPPA;j++)
+ {
+ struct GNUNET_CRYPTO_EcdhePrivateKey *tpk;
+
+ tpk = GNUNET_CRYPTO_ecdhe_key_create ();
+ md.melted_coins[i].transfer_priv[j].ecdhe_priv = *tpk;
+ GNUNET_free (tpk);
+ }
+ md.melted_coins[i].deposit_valid_until
+ = melt_pks[i].deposit_valid_until;
+ md.melted_coins[i].pub_key.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_dup (melt_pks[i].key.rsa_public_key);
+ md.melted_coins[i].sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_dup (melt_sigs[i].rsa_signature);
+ }
+ md.fresh_pks = GNUNET_new_array (fresh_pks_len,
+ struct TALER_DenominationPublicKey);
+ for (i=0;i<fresh_pks_len;i++)
+ md.fresh_pks[i].rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key);
+ for (i=0;i<TALER_CNC_KAPPA;i++)
+ {
+ md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
+ struct FreshCoin);
+ for (j=0;j<fresh_pks_len;j++)
+ setup_fresh_coin (&md.fresh_coins[i][j],
+ &fresh_pks[j]);
+ }
+
+ /* now compute melt session hash */
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
+ for (i=0;i<fresh_pks_len;i++)
+ {
+ char *buf;
+ size_t buf_size;
+
+ buf_size = GNUNET_CRYPTO_rsa_public_key_encode (fresh_pks[i].key.rsa_public_key,
+ &buf);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ buf,
+ buf_size);
+ GNUNET_free (buf);
+ }
+ for (i=0;i<num_melts;i++)
+ {
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_AmountNBO melt_amount;
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&melt_privs[i].eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP));
+ TALER_amount_hton (&melt_amount,
+ &melt_amounts[i]);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &melt_amount,
+ sizeof (struct TALER_AmountNBO));
+
+ }
+ for (i = 0; i < TALER_CNC_KAPPA; i++)
+ {
+ for (j = 0; j < fresh_pks_len; j++)
+ {
+ const struct FreshCoin *fc; /* coin this is about */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode coin_hash;
+ char *coin_ev; /* blinded message to be signed (in envelope) for each coin */
+ size_t coin_ev_size;
+ struct TALER_RefreshLinkDecrypted rld;
+ struct TALER_RefreshLinkEncrypted *rle;
+ char *link_enc; /* encrypted link data */
+ size_t link_enc_size;
+
+ fc = &md.fresh_coins[i][j];
+ GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ &coin_hash);
+ coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash,
+ fc->blinding_key.rsa_blinding_key,
+ md.fresh_pks[j].rsa_public_key,
+ &coin_ev);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ coin_ev,
+ coin_ev_size);
+ GNUNET_free (coin_ev);
+
+ rld.coin_priv = fc->coin_priv;
+ rld.blinding_key = fc->blinding_key;
+ rle = TALER_refresh_encrypt (&rld,
+ &md.link_secrets[i]);
+ link_enc = TALER_refresh_link_encrypted_encode (rle,
+ &link_enc_size);
+
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ link_enc,
+ link_enc_size);
+ GNUNET_free (link_enc);
+ }
+ }
+ for (i = 0; i < TALER_CNC_KAPPA; i++)
+ {
+ for (j = 0; j < num_melts; j++)
+ {
+ struct TALER_RefreshCommitLinkP rcl;
+ struct TALER_TransferSecretP trans_sec;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (&md.melted_coins[j].transfer_priv[i].ecdhe_priv,
+ &rcl.transfer_pub.ecdhe_pub);
+ TALER_link_derive_transfer_secret (&melt_privs[j],
+ &md.melted_coins[j].transfer_priv[i],
+ &trans_sec);
+ TALER_transfer_encrypt (&md.link_secrets[i],
+ &trans_sec,
+ &rcl.shared_secret_enc);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &rcl,
+ sizeof (struct TALER_RefreshCommitLinkP));
+ }
+ }
+
+ GNUNET_CRYPTO_hash_context_finish (hash_context,
+ &md.melt_session_hash);
+
+ /* finally, serialize everything */
+ buf = serialize_melt_data (&md,
+ res_size);
+ free_melt_data (&md);
+ return buf;
+}
+
+
+/* ********************* /refresh/melt ***************************** */
+
+
+/**
+ * @brief A /refresh/melt Handle
+ */
+struct TALER_EXCHANGE_RefreshMeltHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with refresh melt failure results.
+ */
+ TALER_EXCHANGE_RefreshMeltCallback melt_cb;
+
+ /**
+ * Closure for @e result_cb and @e melt_failure_cb.
+ */
+ void *melt_cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Actual information about the melt operation.
+ */
+ struct MeltData *md;
+};
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * from the exchange is valid.
+ *
+ * @param rmh melt handle
+ * @param json json reply with the signature
+ * @param[out] noreveal_index set to the noreveal index selected by the exchange
+ * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
+ */
+static int
+verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh,
+ json_t *json,
+ uint16_t *noreveal_index)
+{
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("exchange_sig", &exchange_sig),
+ MAJ_spec_fixed_auto ("exchange_pub", &exchange_pub),
+ MAJ_spec_uint16 ("noreveal_index", noreveal_index),
+ MAJ_spec_end
+ };
+ struct TALER_RefreshMeltConfirmationPS confirm;
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* check that exchange signing key is permitted */
+ key_state = TALER_EXCHANGE_get_keys (rmh->exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &exchange_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* check that noreveal index is in permitted range */
+ if (TALER_CNC_KAPPA <= *noreveal_index)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* verify signature by exchange */
+ confirm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT);
+ confirm.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
+ confirm.session_hash = rmh->md->melt_session_hash;
+ confirm.noreveal_index = htons (*noreveal_index);
+ confirm.reserved = htons (0);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT,
+ &confirm.purpose,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify that the signatures on the "403 FORBIDDEN" response from the
+ * exchange demonstrating customer double-spending are valid.
+ *
+ * @param rmh melt handle
+ * @param json json reply with the signature(s) and transaction history
+ * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
+ */
+static int
+verify_refresh_melt_signature_forbidden (struct TALER_EXCHANGE_RefreshMeltHandle *rmh,
+ json_t *json)
+{
+ json_t *history;
+ struct TALER_Amount original_value;
+ struct TALER_Amount melt_value_with_fee;
+ struct TALER_Amount total;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ unsigned int i;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_json ("history", &history),
+ MAJ_spec_fixed_auto ("coin_pub", &coin_pub),
+ MAJ_spec_amount ("original_value", &original_value),
+ MAJ_spec_amount ("requested_value", &melt_value_with_fee),
+ MAJ_spec_end
+ };
+ const struct MeltedCoin *mc;
+
+ /* parse JSON reply */
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* Find out which coin was deemed problematic by the exchange */
+ mc = NULL;
+ for (i=0;i<rmh->md->num_melted_coins;i++)
+ {
+ if (0 == TALER_amount_cmp (&melt_value_with_fee,
+ &rmh->md->melted_coins[i].melt_amount_with_fee))
+ {
+ struct TALER_CoinSpendPublicKeyP mc_pub;
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&rmh->md->melted_coins[i].coin_priv.eddsa_priv,
+ &mc_pub.eddsa_pub);
+ if (0 == memcmp (&mc_pub,
+ &coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP)))
+ {
+ mc = &rmh->md->melted_coins[i];
+ break;
+ }
+ }
+ }
+ if (NULL == mc)
+ {
+ /* coin not found in our original request */
+ GNUNET_break_op (0);
+ json_decref (history);
+ return GNUNET_SYSERR;
+ }
+
+ /* check basic coin properties */
+ if (0 != TALER_amount_cmp (&original_value,
+ &mc->original_value))
+ {
+ /* We disagree on the value of the coin */
+ GNUNET_break_op (0);
+ json_decref (history);
+ return GNUNET_SYSERR;
+ }
+ if (0 != TALER_amount_cmp (&melt_value_with_fee,
+ &mc->melt_amount_with_fee))
+ {
+ /* We disagree on the value of the coin */
+ GNUNET_break_op (0);
+ json_decref (history);
+ return GNUNET_SYSERR;
+ }
+
+ /* verify coin history */
+ history = json_object_get (json,
+ "history");
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_verify_coin_history_ (original_value.currency,
+ &coin_pub,
+ history,
+ &total))
+ {
+ GNUNET_break_op (0);
+ json_decref (history);
+ return GNUNET_SYSERR;
+ }
+ json_decref (history);
+
+ /* check if melt operation was really too expensive given history */
+ if (GNUNET_OK !=
+ TALER_amount_add (&total,
+ &total,
+ &melt_value_with_fee))
+ {
+ /* clearly not OK if our transaction would have caused
+ the overflow... */
+ return GNUNET_OK;
+ }
+
+ if (0 >= TALER_amount_cmp (&total,
+ &original_value))
+ {
+ /* transaction should have still fit */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* everything OK, valid proof of double-spending was provided */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /refresh/melt request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_RefreshMeltHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_refresh_melt_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_RefreshMeltHandle *rmh = cls;
+ long response_code;
+ json_t *json;
+ uint16_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */
+
+ rmh->job = NULL;
+ json = MAC_download_get_result (&rmh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ if (GNUNET_OK !=
+ verify_refresh_melt_signature_ok (rmh,
+ json,
+ &noreveal_index))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ if (NULL != rmh->melt_cb)
+ {
+ rmh->melt_cb (rmh->melt_cb_cls,
+ response_code,
+ noreveal_index,
+ json);
+ rmh->melt_cb = NULL;
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ /* Double spending; check signatures on transaction history */
+ if (GNUNET_OK !=
+ verify_refresh_melt_signature_forbidden (rmh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, exchange says one of the signatures is
+ invalid; assuming we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (NULL != rmh->melt_cb)
+ rmh->melt_cb (rmh->melt_cb_cls,
+ response_code,
+ UINT16_MAX,
+ json);
+ json_decref (json);
+ TALER_EXCHANGE_refresh_melt_cancel (rmh);
+}
+
+
+/**
+ * Convert a coin to be melted to the respective JSON encoding.
+ *
+ * @param melt_session_hash session hash to use
+ * @param mc coin to be melted
+ * @return JSON encoding of the melting request
+ */
+static json_t *
+melted_coin_to_json (const struct GNUNET_HashCode *melt_session_hash,
+ const struct MeltedCoin *mc)
+{
+ struct TALER_CoinSpendSignatureP confirm_sig;
+ struct TALER_RefreshMeltCoinAffirmationPS melt;
+
+ melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
+ melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
+ melt.session_hash = *melt_session_hash;
+ TALER_amount_hton (&melt.amount_with_fee,
+ &mc->melt_amount_with_fee);
+ TALER_amount_hton (&melt.melt_fee,
+ &mc->fee_melt);
+ GNUNET_CRYPTO_eddsa_key_get_public (&mc->coin_priv.eddsa_priv,
+ &melt.coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_sign (&mc->coin_priv.eddsa_priv,
+ &melt.purpose,
+ &confirm_sig.eddsa_signature);
+ return json_pack ("{s:o, s:o, s:o, s:o, s:o}",
+ "coin_pub",
+ TALER_json_from_data (&melt.coin_pub,
+ sizeof (melt.coin_pub)),
+ "denom_pub",
+ TALER_json_from_rsa_public_key (mc->pub_key.rsa_public_key),
+ "denom_sig",
+ TALER_json_from_rsa_signature (mc->sig.rsa_signature),
+ "confirm_sig",
+ TALER_json_from_data (&confirm_sig,
+ sizeof (confirm_sig)),
+ "value_with_fee",
+ TALER_json_from_amount (&mc->melt_amount_with_fee));
+}
+
+
+/**
+ * Submit a melt request to the exchange and get the exchange's
+ * response.
+ *
+ * This API is typically used by a wallet. Note that to ensure that
+ * no money is lost in case of hardware failures, the provided
+ * argument should have been constructed using
+ * #TALER_EXCHANGE_refresh_prepare and committed to persistent storage
+ * prior to calling this function.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param refresh_data_length size of the @a refresh_data (returned
+ * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare())
+ * @param refresh_data the refresh data as returned from
+ #TALER_EXCHANGE_refresh_prepare())
+ * @param melt_cb the callback to call with the result
+ * @param melt_cb_cls closure for @a melt_cb
+ * @return a handle for this request; NULL if the argument was invalid.
+ * In this case, neither callback will be called.
+ */
+struct TALER_EXCHANGE_RefreshMeltHandle *
+TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange,
+ size_t refresh_data_length,
+ const char *refresh_data,
+ TALER_EXCHANGE_RefreshMeltCallback melt_cb,
+ void *melt_cb_cls)
+{
+ json_t *melt_obj;
+ json_t *new_denoms;
+ json_t *melt_coins;
+ json_t *coin_evs;
+ json_t *transfer_pubs;
+ json_t *secret_encs;
+ json_t *link_encs;
+ json_t *tmp;
+ struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
+ CURL *eh;
+ struct TALER_EXCHANGE_Context *ctx;
+ struct MeltData *md;
+ unsigned int i;
+ unsigned int j;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ md = deserialize_melt_data (refresh_data,
+ refresh_data_length);
+ if (NULL == md)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ /* build JSON request, each of the 6 arrays first */
+ new_denoms = json_array ();
+ melt_coins = json_array ();
+ coin_evs = json_array ();
+ transfer_pubs = json_array ();
+ secret_encs = json_array ();
+ link_encs = json_array ();
+ for (i=0;i<md->num_melted_coins;i++)
+ {
+ const struct MeltedCoin *mc = &md->melted_coins[i];
+
+ /* now melt_coins */
+ json_array_append (melt_coins,
+ melted_coin_to_json (&md->melt_session_hash,
+ mc));
+ }
+
+ /* now transfer_pubs */
+ for (j=0;j<TALER_CNC_KAPPA;j++)
+ {
+ tmp = json_array ();
+ for (i=0;i<md->num_melted_coins;i++)
+ {
+ const struct MeltedCoin *mc = &md->melted_coins[i];
+ struct TALER_TransferPublicKeyP transfer_pub;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (&mc->transfer_priv[j].ecdhe_priv,
+ &transfer_pub.ecdhe_pub);
+ json_array_append (tmp,
+ TALER_json_from_data (&transfer_pub,
+ sizeof (transfer_pub)));
+ }
+ json_array_append (transfer_pubs,
+ tmp);
+ }
+
+ /* now secret_encs */
+ for (j=0;j<TALER_CNC_KAPPA;j++)
+ {
+ tmp = json_array ();
+ for (i=0;i<md->num_melted_coins;i++)
+ {
+ const struct MeltedCoin *mc = &md->melted_coins[i];
+ struct TALER_EncryptedLinkSecretP els;
+ struct TALER_TransferSecretP trans_sec;
+
+ TALER_link_derive_transfer_secret (&mc->coin_priv,
+ &mc->transfer_priv[j],
+ &trans_sec);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_transfer_encrypt (&md->link_secrets[j],
+ &trans_sec,
+ &els));
+ json_array_append (tmp,
+ TALER_json_from_data (&els,
+ sizeof (els)));
+ }
+ json_array_append (secret_encs,
+ tmp);
+ }
+
+ /* now new_denoms */
+ for (i=0;i<md->num_fresh_coins;i++)
+ {
+ json_array_append (new_denoms,
+ TALER_json_from_rsa_public_key
+ (md->fresh_pks[i].rsa_public_key));
+ }
+
+ /* now link_encs */
+ for (j=0;j<TALER_CNC_KAPPA;j++)
+ {
+ tmp = json_array ();
+ for (i=0;i<md->num_fresh_coins;i++)
+ {
+ const struct FreshCoin *fc = &md->fresh_coins[j][i];
+ struct TALER_RefreshLinkDecrypted rld;
+ struct TALER_RefreshLinkEncrypted *rle;
+ char *buf;
+ size_t buf_len;
+
+ rld.coin_priv = fc->coin_priv;
+ rld.blinding_key = fc->blinding_key;
+ rle = TALER_refresh_encrypt (&rld,
+ &md->link_secrets[j]);
+ GNUNET_assert (NULL != rle);
+ buf = TALER_refresh_link_encrypted_encode (rle,
+ &buf_len);
+ GNUNET_assert (NULL != buf);
+ json_array_append (tmp,
+ TALER_json_from_data (buf,
+ buf_len));
+ GNUNET_free (buf);
+ GNUNET_free (rle);
+ }
+ json_array_append (link_encs,
+ tmp);
+ }
+
+ /* now coin_evs */
+ for (j=0;j<TALER_CNC_KAPPA;j++)
+ {
+ tmp = json_array ();
+ for (i=0;i<md->num_fresh_coins;i++)
+ {
+ const struct FreshCoin *fc = &md->fresh_coins[j][i];
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode coin_hash;
+ char *coin_ev; /* blinded message to be signed (in envelope) for each coin */
+ size_t coin_ev_size;
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ &coin_hash);
+ coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash,
+ fc->blinding_key.rsa_blinding_key,
+ md->fresh_pks[i].rsa_public_key,
+ &coin_ev);
+ json_array_append (tmp,
+ TALER_json_from_data (coin_ev,
+ coin_ev_size));
+ GNUNET_free (coin_ev);
+ }
+ json_array_append (coin_evs,
+ tmp);
+ }
+
+ /* finally, assemble main JSON request from constitutent arrays */
+ melt_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}",
+ "new_denoms", new_denoms,
+ "melt_coins", melt_coins,
+ "coin_evs", coin_evs,
+ "transfer_pubs", transfer_pubs,
+ "secret_encs", secret_encs,
+ "link_encs", link_encs);
+
+ /* and now we can at last begin the actual request handling */
+ rmh = GNUNET_new (struct TALER_EXCHANGE_RefreshMeltHandle);
+ rmh->exchange = exchange;
+ rmh->melt_cb = melt_cb;
+ rmh->melt_cb_cls = melt_cb_cls;
+ rmh->md = md;
+ rmh->url = MAH_path_to_url (exchange,
+ "/refresh/melt");
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (rmh->json_enc =
+ json_dumps (melt_obj,
+ JSON_COMPACT)));
+ json_decref (melt_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ rmh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ rmh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (rmh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &rmh->db));
+ ctx = MAH_handle_to_context (exchange);
+ rmh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_refresh_melt_finished,
+ rmh);
+ return rmh;
+}
+
+
+/**
+ * Cancel a refresh execute request. This function cannot be used
+ * on a request handle if either callback was already invoked.
+ *
+ * @param rmh the refresh melt handle
+ */
+void
+TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh)
+{
+ if (NULL != rmh->job)
+ {
+ MAC_job_cancel (rmh->job);
+ rmh->job = NULL;
+ }
+ GNUNET_free_non_null (rmh->db.buf);
+ free_melt_data (rmh->md); /* does not free 'md' itself */
+ GNUNET_free (rmh->md);
+ GNUNET_free (rmh->url);
+ GNUNET_free (rmh->json_enc);
+ GNUNET_free (rmh);
+}
+
+
+/* ********************* /refresh/reveal ***************************** */
+
+
+/**
+ * @brief A /refresh/reveal Handle
+ */
+struct TALER_EXCHANGE_RefreshRevealHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_RefreshRevealCallback reveal_cb;
+
+ /**
+ * Closure for @e reveal_cb.
+ */
+ void *reveal_cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Actual information about the melt operation.
+ */
+ struct MeltData *md;
+
+ /**
+ * The index selected by the exchange in cut-and-choose to not be revealed.
+ */
+ uint16_t noreveal_index;
+
+};
+
+
+/**
+ * We got a 200 OK response for the /refresh/reveal operation.
+ * Extract the coin signatures and return them to the caller.
+ * The signatures we get from the exchange is for the blinded value.
+ * Thus, we first must unblind them and then should verify their
+ * validity.
+ *
+ * If everything checks out, we return the unblinded signatures
+ * to the application via the callback.
+ *
+ * @param rrh operation handle
+ * @param json reply from the exchange
+ * @param[out] coin_privs array of length `num_fresh_coins`, initialized to contain private keys
+ * @param[out] sigs array of length `num_fresh_coins`, initialized to cointain RSA signatures
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
+ */
+static int
+refresh_reveal_ok (struct TALER_EXCHANGE_RefreshRevealHandle *rrh,
+ json_t *json,
+ struct TALER_CoinSpendPrivateKeyP *coin_privs,
+ struct TALER_DenominationSignature *sigs)
+{
+ unsigned int i;
+ json_t *jsona;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_json ("ev_sigs", &jsona),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! json_is_array (jsona))
+ {
+ /* We expected an array of coins */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (rrh->md->num_fresh_coins != json_array_size (jsona))
+ {
+ /* Number of coins generated does not match our expectation */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ for (i=0;i<rrh->md->num_fresh_coins;i++)
+ {
+ const struct FreshCoin *fc;
+ struct TALER_DenominationPublicKey *pk;
+ json_t *jsonai;
+ struct GNUNET_CRYPTO_rsa_Signature *blind_sig;
+ struct GNUNET_CRYPTO_rsa_Signature *sig;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode coin_hash;
+
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_rsa_signature ("ev_sig", &blind_sig),
+ MAJ_spec_end
+ };
+
+ fc = &rrh->md->fresh_coins[rrh->noreveal_index][i];
+ pk = &rrh->md->fresh_pks[i];
+ jsonai = json_array_get (jsona, i);
+ GNUNET_assert (NULL != jsonai);
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (jsonai,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* unblind the signature */
+ sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
+ fc->blinding_key.rsa_blinding_key,
+ pk->rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (blind_sig);
+
+ /* verify the signature */
+ GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ &coin_hash);
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (&coin_hash,
+ sig,
+ pk->rsa_public_key))
+ {
+ GNUNET_break_op (0);
+ GNUNET_CRYPTO_rsa_signature_free (sig);
+ return GNUNET_SYSERR;
+ }
+ coin_privs[i] = fc->coin_priv;
+ sigs[i].rsa_signature = sig;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /refresh/reveal request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_RefreshHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_refresh_reveal_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_RefreshRevealHandle *rrh = cls;
+ long response_code;
+ json_t *json;
+
+ rrh->job = NULL;
+ json = MAC_download_get_result (&rrh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins];
+ struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
+ unsigned int i;
+ int ret;
+
+ memset (sigs, 0, sizeof (sigs));
+ ret = refresh_reveal_ok (rrh,
+ json,
+ coin_privs,
+ sigs);
+ if (GNUNET_OK != ret)
+ {
+ response_code = 0;
+ }
+ else
+ {
+ rrh->reveal_cb (rrh->reveal_cb_cls,
+ MHD_HTTP_OK,
+ rrh->md->num_fresh_coins,
+ coin_privs,
+ sigs,
+ json);
+ rrh->reveal_cb = NULL;
+ }
+ for (i=0;i<rrh->md->num_fresh_coins;i++)
+ if (NULL != sigs[i].rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_CONFLICT:
+ /* Nothing really to verify, exchange says our reveal is inconsitent
+ with our commitment, so either side is buggy; we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (NULL != rrh->reveal_cb)
+ rrh->reveal_cb (rrh->reveal_cb_cls,
+ response_code,
+ 0, NULL, NULL,
+ json);
+ json_decref (json);
+ TALER_EXCHANGE_refresh_reveal_cancel (rrh);
+}
+
+
+/**
+ * Submit a /refresh/reval request to the exchange and get the exchange's
+ * response.
+ *
+ * This API is typically used by a wallet. Note that to ensure that
+ * no money is lost in case of hardware failures, the provided
+ * arguments should have been committed to persistent storage
+ * prior to calling this function.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param refresh_data_length size of the @a refresh_data (returned
+ * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare())
+ * @param refresh_data the refresh data as returned from
+ #TALER_EXCHANGE_refresh_prepare())
+ * @param noreveal_index response from the exchange to the
+ * #TALER_EXCHANGE_refresh_melt() invocation
+ * @param reveal_cb the callback to call with the final result of the
+ * refresh operation
+ * @param reveal_cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the argument was invalid.
+ * In this case, neither callback will be called.
+ */
+struct TALER_EXCHANGE_RefreshRevealHandle *
+TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
+ size_t refresh_data_length,
+ const char *refresh_data,
+ uint16_t noreveal_index,
+ TALER_EXCHANGE_RefreshRevealCallback reveal_cb,
+ void *reveal_cb_cls)
+{
+ struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
+ json_t *transfer_privs;
+ json_t *reveal_obj;
+ json_t *tmp;
+ CURL *eh;
+ struct TALER_EXCHANGE_Context *ctx;
+ struct MeltData *md;
+ unsigned int i;
+ unsigned int j;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ md = deserialize_melt_data (refresh_data,
+ refresh_data_length);
+ if (NULL == md)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (noreveal_index >= TALER_CNC_KAPPA)
+ {
+ /* We check this here, as it would be really bad to below just
+ disclose all the transfer keys. Note that this error should
+ have been caught way earlier when the exchange replied, but maybe
+ we had some internal corruption that changed the value... */
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ /* build array of transfer private keys */
+ transfer_privs = json_array ();
+ for (j=0;j<TALER_CNC_KAPPA;j++)
+ {
+ if (j == noreveal_index)
+ {
+ /* This is crucial: exclude the transfer key for the
+ noreval index! */
+ continue;
+ }
+ tmp = json_array ();
+ for (i=0;i<md->num_melted_coins;i++)
+ {
+ const struct MeltedCoin *mc = &md->melted_coins[i];
+
+ json_array_append (tmp,
+ TALER_json_from_data (&mc->transfer_priv[j],
+ sizeof (struct TALER_TransferPrivateKeyP)));
+ }
+ json_array_append (transfer_privs,
+ tmp);
+ }
+
+ /* build main JSON request */
+ reveal_obj = json_pack ("{s:o, s:o}",
+ "session_hash",
+ TALER_json_from_data (&md->melt_session_hash,
+ sizeof (struct GNUNET_HashCode)),
+ "transfer_privs",
+ transfer_privs);
+
+ /* finally, we can actually issue the request */
+ rrh = GNUNET_new (struct TALER_EXCHANGE_RefreshRevealHandle);
+ rrh->exchange = exchange;
+ rrh->noreveal_index = noreveal_index;
+ rrh->reveal_cb = reveal_cb;
+ rrh->reveal_cb_cls = reveal_cb_cls;
+ rrh->md = md;
+ rrh->url = MAH_path_to_url (rrh->exchange,
+ "/refresh/reveal");
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (rrh->json_enc =
+ json_dumps (reveal_obj,
+ JSON_COMPACT)));
+ json_decref (reveal_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ rrh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ rrh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (rrh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &rrh->db));
+ ctx = MAH_handle_to_context (rrh->exchange);
+ rrh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_refresh_reveal_finished,
+ rrh);
+ return rrh;
+}
+
+
+/**
+ * Cancel a refresh reveal request. This function cannot be used
+ * on a request handle if the callback was already invoked.
+ *
+ * @param rrh the refresh reval handle
+ */
+void
+TALER_EXCHANGE_refresh_reveal_cancel (struct TALER_EXCHANGE_RefreshRevealHandle *rrh)
+{
+ if (NULL != rrh->job)
+ {
+ MAC_job_cancel (rrh->job);
+ rrh->job = NULL;
+ }
+ GNUNET_free_non_null (rrh->db.buf);
+ GNUNET_free (rrh->url);
+ GNUNET_free (rrh->json_enc);
+ free_melt_data (rrh->md); /* does not free 'md' itself */
+ GNUNET_free (rrh->md);
+ GNUNET_free (rrh);
+}
+
+
+/* end of exchange_api_refresh.c */
diff --git a/src/exchange-lib/exchange_api_refresh_link.c b/src/exchange-lib/exchange_api_refresh_link.c
new file mode 100644
index 000000000..9576916bc
--- /dev/null
+++ b/src/exchange-lib/exchange_api_refresh_link.c
@@ -0,0 +1,482 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_refresh_link.c
+ * @brief Implementation of the /refresh/link request of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A /refresh/link Handle
+ */
+struct TALER_EXCHANGE_RefreshLinkHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_RefreshLinkCallback link_cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *link_cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Private key of the coin, required to decode link information.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+};
+
+
+/**
+ * Parse the provided linkage data from the "200 OK" response
+ * for one of the coins.
+ *
+ * @param rlh refresh link handle
+ * @param json json reply with the data for one coin
+ * @param trans_pub our transfer public key
+ * @param secret_enc encrypted key to decrypt link data
+ * @param[out] coin_priv where to return private coin key
+ * @param[out] sig where to return private coin signature
+ * @param[out] pub where to return the public key for the coin
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+parse_refresh_link_coin (const struct TALER_EXCHANGE_RefreshLinkHandle *rlh,
+ json_t *json,
+ const struct TALER_TransferPublicKeyP *trans_pub,
+ const struct TALER_EncryptedLinkSecretP *secret_enc,
+ struct TALER_CoinSpendPrivateKeyP *coin_priv,
+ struct TALER_DenominationSignature *sig,
+ struct TALER_DenominationPublicKey *pub)
+{
+ void *link_enc;
+ size_t link_enc_size;
+ struct GNUNET_CRYPTO_rsa_Signature *bsig;
+ struct GNUNET_CRYPTO_rsa_PublicKey *rpub;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_varsize ("link_enc", &link_enc, &link_enc_size),
+ MAJ_spec_rsa_public_key ("denom_pub", &rpub),
+ MAJ_spec_rsa_signature ("ev_sig", &bsig),
+ MAJ_spec_end
+ };
+ struct TALER_RefreshLinkEncrypted *rle;
+ struct TALER_RefreshLinkDecrypted *rld;
+ struct TALER_LinkSecretP secret;
+
+ /* parse reply */
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* decode and decrypt link data */
+ rle = TALER_refresh_link_encrypted_decode (link_enc,
+ link_enc_size);
+ if (NULL == rle)
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_link_decrypt_secret2 (secret_enc,
+ trans_pub,
+ &rlh->coin_priv,
+ &secret))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ rld = TALER_refresh_decrypt (rle,
+ &secret);
+ if (NULL == rld)
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+
+ /* extract coin and signature */
+ *coin_priv = rld->coin_priv;
+ sig->rsa_signature
+ = GNUNET_CRYPTO_rsa_unblind (bsig,
+ rld->blinding_key.rsa_blinding_key,
+ rpub);
+
+ /* clean up */
+ GNUNET_free (rld);
+ pub->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (rpub);
+ MAJ_parse_free (spec);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse the provided linkage data from the "200 OK" response
+ * for one of the coins.
+ *
+ * @param[in,out] rlh refresh link handle (callback may be zero'ed out)
+ * @param json json reply with the data for one coin
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+parse_refresh_link_ok (struct TALER_EXCHANGE_RefreshLinkHandle *rlh,
+ json_t *json)
+{
+ unsigned int session;
+ unsigned int num_coins;
+ int ret;
+
+ if (! json_is_array (json))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ num_coins = 0;
+ /* Theoretically, a coin may have been melted repeatedly
+ into different sessions; so the response is an array
+ which contains information by melting session. That
+ array contains another array. However, our API returns
+ a single 1d array, so we flatten the 2d array that is
+ returned into a single array. Note that usually a coin
+ is melted at most once, and so we'll only run this
+ loop once for 'session=0' in most cases.
+
+ num_coins tracks the size of the 1d array we return,
+ whilst 'i' and 'session' track the 2d array. */
+ for (session=0;session<json_array_size (json); session++)
+ {
+ json_t *jsona;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_json ("new_coins", &jsona),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json_array_get (json,
+ session),
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! json_is_array (jsona))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+
+ /* count all coins over all sessions */
+ num_coins += json_array_size (jsona);
+ MAJ_parse_free (spec);
+ }
+ /* Now that we know how big the 1d array is, allocate
+ and fill it. */
+ {
+ unsigned int off_coin; /* index into 1d array */
+ unsigned int i;
+ struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins];
+ struct TALER_DenominationSignature sigs[num_coins];
+ struct TALER_DenominationPublicKey pubs[num_coins];
+
+ memset (sigs, 0, sizeof (sigs));
+ memset (pubs, 0, sizeof (pubs));
+ off_coin = 0;
+ for (session=0;session<json_array_size (json); session++)
+ {
+ json_t *jsona;
+ struct TALER_TransferPublicKeyP trans_pub;
+ struct TALER_EncryptedLinkSecretP secret_enc;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_json ("new_coins", &jsona),
+ MAJ_spec_fixed_auto ("transfer_pub", &trans_pub),
+ MAJ_spec_fixed_auto ("secret_enc", &secret_enc),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json_array_get (json,
+ session),
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! json_is_array (jsona))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+
+ /* decode all coins */
+ for (i=0;i<json_array_size (jsona);i++)
+ {
+ if (GNUNET_OK !=
+ parse_refresh_link_coin (rlh,
+ json_array_get (jsona,
+ i),
+ &trans_pub,
+ &secret_enc,
+ &coin_privs[i+off_coin],
+ &sigs[i+off_coin],
+ &pubs[i+off_coin]))
+ {
+ GNUNET_break_op (0);
+ break;
+ }
+ }
+ /* check if we really got all, then invoke callback */
+ off_coin += i;
+ if (i != json_array_size (jsona))
+ {
+ GNUNET_break_op (0);
+ ret = GNUNET_SYSERR;
+ MAJ_parse_free (spec);
+ break;
+ }
+ MAJ_parse_free (spec);
+ } /* end of for (session) */
+
+ if (off_coin == num_coins)
+ {
+ rlh->link_cb (rlh->link_cb_cls,
+ MHD_HTTP_OK,
+ num_coins,
+ coin_privs,
+ sigs,
+ pubs,
+ json);
+ rlh->link_cb = NULL;
+ ret = GNUNET_OK;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ ret = GNUNET_SYSERR;
+ }
+
+ /* clean up */
+ for (i=0;i<off_coin;i++)
+ {
+ if (NULL != sigs[i].rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
+ if (NULL != pubs[i].rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (pubs[i].rsa_public_key);
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /refresh/link request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_RefreshLinkHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_refresh_link_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_RefreshLinkHandle *rlh = cls;
+ long response_code;
+ json_t *json;
+
+ rlh->job = NULL;
+ json = MAC_download_get_result (&rlh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ if (GNUNET_OK !=
+ parse_refresh_link_ok (rlh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, exchange says this coin was not melted; we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (NULL != rlh->link_cb)
+ rlh->link_cb (rlh->link_cb_cls,
+ response_code,
+ 0, NULL, NULL, NULL,
+ json);
+ json_decref (json);
+ TALER_EXCHANGE_refresh_link_cancel (rlh);
+}
+
+
+/**
+ * Submit a link request to the exchange and get the exchange's response.
+ *
+ * This API is typically not used by anyone, it is more a threat
+ * against those trying to receive a funds transfer by abusing the
+ * /refresh protocol.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param coin_priv private key to request link data for
+ * @param link_cb the callback to call with the useful result of the
+ * refresh operation the @a coin_priv was involved in (if any)
+ * @param link_cb_cls closure for @a link_cb
+ * @return a handle for this request
+ */
+struct TALER_EXCHANGE_RefreshLinkHandle *
+TALER_EXCHANGE_refresh_link (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+ TALER_EXCHANGE_RefreshLinkCallback link_cb,
+ void *link_cb_cls)
+{
+ struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
+ CURL *eh;
+ struct TALER_EXCHANGE_Context *ctx;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ char *pub_str;
+ char *arg_str;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pub.eddsa_pub);
+ pub_str = GNUNET_STRINGS_data_to_string_alloc (&coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP));
+ GNUNET_asprintf (&arg_str,
+ "/refresh/link?coin_pub=%s",
+ pub_str);
+ GNUNET_free (pub_str);
+
+ rlh = GNUNET_new (struct TALER_EXCHANGE_RefreshLinkHandle);
+ rlh->exchange = exchange;
+ rlh->link_cb = link_cb;
+ rlh->link_cb_cls = link_cb_cls;
+ rlh->coin_priv = *coin_priv;
+ rlh->url = MAH_path_to_url (exchange, arg_str);
+ GNUNET_free (arg_str);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ rlh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &rlh->db));
+ ctx = MAH_handle_to_context (exchange);
+ rlh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_refresh_link_finished,
+ rlh);
+ return rlh;
+}
+
+
+/**
+ * Cancel a refresh link request. This function cannot be used
+ * on a request handle if the callback was already invoked.
+ *
+ * @param rlh the refresh link handle
+ */
+void
+TALER_EXCHANGE_refresh_link_cancel (struct TALER_EXCHANGE_RefreshLinkHandle *rlh)
+{
+ if (NULL != rlh->job)
+ {
+ MAC_job_cancel (rlh->job);
+ rlh->job = NULL;
+ }
+ GNUNET_free_non_null (rlh->db.buf);
+ GNUNET_free (rlh->url);
+ GNUNET_free (rlh);
+}
+
+
+/* end of exchange_api_refresh_link.c */
diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c
new file mode 100644
index 000000000..e694b8d95
--- /dev/null
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -0,0 +1,930 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_reserve.c
+ * @brief Implementation of the /reserve requests of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/* ********************** /reserve/status ********************** */
+
+/**
+ * @brief A Withdraw Status Handle
+ */
+struct TALER_EXCHANGE_ReserveStatusHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_ReserveStatusResultCallback cb;
+
+ /**
+ * Public key of the reserve we are querying.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+};
+
+
+/**
+ * Parse history given in JSON format and return it in binary
+ * format.
+ *
+ * @param[in] history JSON array with the history
+ * @param reserve_pub public key of the reserve to inspect
+ * @param currency currency we expect the balance to be in
+ * @param[out] balance final balance
+ * @param history_length number of entries in @a history
+ * @param[out] rhistory array of length @a history_length, set to the
+ * parsed history entries
+ * @return #GNUNET_OK if history was valid and @a rhistory and @a balance
+ * were set,
+ * #GNUNET_SYSERR if there was a protocol violation in @a history
+ */
+static int
+parse_reserve_history (json_t *history,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const char *currency,
+ struct TALER_Amount *balance,
+ unsigned int history_length,
+ struct TALER_EXCHANGE_ReserveHistory *rhistory)
+{
+ struct GNUNET_HashCode uuid[history_length];
+ unsigned int uuid_off;
+ struct TALER_Amount total_in;
+ struct TALER_Amount total_out;
+ size_t off;
+
+ TALER_amount_get_zero (currency,
+ &total_in);
+ TALER_amount_get_zero (currency,
+ &total_out);
+ uuid_off = 0;
+ for (off=0;off<history_length;off++)
+ {
+ json_t *transaction;
+ struct TALER_Amount amount;
+ const char *type;
+ struct MAJ_Specification hist_spec[] = {
+ MAJ_spec_string ("type", &type),
+ MAJ_spec_amount ("amount",
+ &amount),
+ /* 'wire' and 'signature' are optional depending on 'type'! */
+ MAJ_spec_end
+ };
+
+ transaction = json_array_get (history,
+ off);
+ if (GNUNET_OK !=
+ MAJ_parse_json (transaction,
+ hist_spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ rhistory[off].amount = amount;
+
+ if (0 == strcasecmp (type,
+ "DEPOSIT"))
+ {
+ json_t *wire;
+
+ rhistory[off].type = TALER_EXCHANGE_RTT_DEPOSIT;
+ if (GNUNET_OK !=
+ TALER_amount_add (&total_in,
+ &total_in,
+ &amount))
+ {
+ /* overflow in history already!? inconceivable! Bad exchange! */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ wire = json_object_get (transaction,
+ "wire");
+ /* check 'wire' is a JSON object (no need to check wireformat,
+ but we do at least expect "some" JSON object here) */
+ if ( (NULL == wire) ||
+ (! json_is_object (wire)) )
+ {
+ /* not even a JSON 'wire' specification, not acceptable */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ rhistory[off].details.wire_in_details = wire;
+ /* end type==DEPOSIT */
+ }
+ else if (0 == strcasecmp (type,
+ "WITHDRAW"))
+ {
+ struct TALER_ReserveSignatureP sig;
+ struct TALER_WithdrawRequestPS withdraw_purpose;
+ struct TALER_Amount amount_from_purpose;
+ struct MAJ_Specification withdraw_spec[] = {
+ MAJ_spec_fixed_auto ("signature",
+ &sig),
+ MAJ_spec_fixed_auto ("details",
+ &withdraw_purpose),
+ MAJ_spec_end
+ };
+ unsigned int i;
+
+ rhistory[off].type = TALER_EXCHANGE_RTT_WITHDRAWAL;
+ if (GNUNET_OK !=
+ MAJ_parse_json (transaction,
+ withdraw_spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ /* Check that the signature is a valid withdraw request */
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
+ &withdraw_purpose.purpose,
+ &sig.eddsa_signature,
+ &reserve_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (withdraw_spec);
+ return GNUNET_SYSERR;
+ }
+ TALER_amount_ntoh (&amount_from_purpose,
+ &withdraw_purpose.amount_with_fee);
+ if (0 != TALER_amount_cmp (&amount,
+ &amount_from_purpose))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (withdraw_spec);
+ return GNUNET_SYSERR;
+ }
+ rhistory[off].details.out_authorization_sig = json_object_get (transaction,
+ "signature");
+ /* Check check that the same withdraw transaction
+ isn't listed twice by the exchange. We use the
+ "uuid" array to remember the hashes of all
+ purposes, and compare the hashes to find
+ duplicates. */
+ GNUNET_CRYPTO_hash (&withdraw_purpose,
+ ntohl (withdraw_purpose.purpose.size),
+ &uuid[uuid_off]);
+ for (i=0;i<uuid_off;i++)
+ {
+ if (0 == memcmp (&uuid[uuid_off],
+ &uuid[i],
+ sizeof (struct GNUNET_HashCode)))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (withdraw_spec);
+ return GNUNET_SYSERR;
+ }
+ }
+ uuid_off++;
+
+ if (GNUNET_OK !=
+ TALER_amount_add (&total_out,
+ &total_out,
+ &amount))
+ {
+ /* overflow in history already!? inconceivable! Bad exchange! */
+ GNUNET_break_op (0);
+ MAJ_parse_free (withdraw_spec);
+ return GNUNET_SYSERR;
+ }
+ /* end type==WITHDRAW */
+ }
+ else
+ {
+ /* unexpected 'type', protocol incompatibility, complain! */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ /* check balance = total_in - total_out < withdraw-amount */
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (balance,
+ &total_in,
+ &total_out))
+ {
+ /* total_in < total_out, why did the exchange ever allow this!? */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /reserve/status request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_ReserveStatusHandle`
+ * @param eh curl handle of the request that finished
+ */
+static void
+handle_reserve_status_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_ReserveStatusHandle *wsh = cls;
+ long response_code;
+ json_t *json;
+
+ wsh->job = NULL;
+ json = MAC_download_get_result (&wsh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ /* TODO: move into separate function... */
+ json_t *history;
+ unsigned int len;
+ struct TALER_Amount balance;
+ struct TALER_Amount balance_from_history;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_amount ("balance", &balance),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ history = json_object_get (json,
+ "history");
+ if (NULL == history)
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ len = json_array_size (history);
+ {
+ struct TALER_EXCHANGE_ReserveHistory rhistory[len];
+
+ if (GNUNET_OK !=
+ parse_reserve_history (history,
+ &wsh->reserve_pub,
+ balance.currency,
+ &balance_from_history,
+ len,
+ rhistory))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ if (0 !=
+ TALER_amount_cmp (&balance_from_history,
+ &balance))
+ {
+ /* exchange cannot add up balances!? */
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ wsh->cb (wsh->cb_cls,
+ response_code,
+ json,
+ &balance,
+ len,
+ rhistory);
+ wsh->cb = NULL;
+ }
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (NULL != wsh->cb)
+ wsh->cb (wsh->cb_cls,
+ response_code,
+ json,
+ NULL,
+ 0, NULL);
+ json_decref (json);
+ TALER_EXCHANGE_reserve_status_cancel (wsh);
+}
+
+
+/**
+ * Submit a request to obtain the transaction history of a reserve
+ * from the exchange. Note that while we return the full response to the
+ * caller for further processing, we do already verify that the
+ * response is well-formed (i.e. that signatures included in the
+ * response are all valid and add up to the balance). If the exchange's
+ * reply is not well-formed, we return an HTTP status code of zero to
+ * @a cb.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param reserve_pub public key of the reserve to inspect
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the inputs are invalid (i.e.
+ * signatures fail to verify). In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_ReserveStatusHandle *
+TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ TALER_EXCHANGE_ReserveStatusResultCallback cb,
+ void *cb_cls)
+{
+ struct TALER_EXCHANGE_ReserveStatusHandle *wsh;
+ struct TALER_EXCHANGE_Context *ctx;
+ CURL *eh;
+ char *pub_str;
+ char *arg_str;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ pub_str = GNUNET_STRINGS_data_to_string_alloc (reserve_pub,
+ sizeof (struct TALER_ReservePublicKeyP));
+ GNUNET_asprintf (&arg_str,
+ "/reserve/status?reserve_pub=%s",
+ pub_str);
+ GNUNET_free (pub_str);
+ wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveStatusHandle);
+ wsh->exchange = exchange;
+ wsh->cb = cb;
+ wsh->cb_cls = cb_cls;
+ wsh->reserve_pub = *reserve_pub;
+ wsh->url = MAH_path_to_url (exchange,
+ arg_str);
+ GNUNET_free (arg_str);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ wsh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &wsh->db));
+ ctx = MAH_handle_to_context (exchange);
+ wsh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_NO,
+ &handle_reserve_status_finished,
+ wsh);
+ return wsh;
+}
+
+
+/**
+ * Cancel a withdraw status request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param wsh the withdraw status request handle
+ */
+void
+TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *wsh)
+{
+ if (NULL != wsh->job)
+ {
+ MAC_job_cancel (wsh->job);
+ wsh->job = NULL;
+ }
+ GNUNET_free_non_null (wsh->db.buf);
+ GNUNET_free (wsh->url);
+ GNUNET_free (wsh);
+}
+
+
+/* ********************** /reserve/withdraw ********************** */
+
+/**
+ * @brief A Withdraw Sign Handle
+ */
+struct TALER_EXCHANGE_ReserveWithdrawHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_ReserveWithdrawResultCallback cb;
+
+ /**
+ * Key used to blind the value.
+ */
+ const struct TALER_DenominationBlindingKey *blinding_key;
+
+ /**
+ * Denomination key we are withdrawing.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Hash of the public key of the coin we are signing.
+ */
+ struct GNUNET_HashCode c_hash;
+
+ /**
+ * Public key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+};
+
+
+/**
+ * We got a 200 OK response for the /reserve/withdraw operation.
+ * Extract the coin's signature and return it to the caller.
+ * The signature we get from the exchange is for the blinded value.
+ * Thus, we first must unblind it and then should verify its
+ * validity against our coin's hash.
+ *
+ * If everything checks out, we return the unblinded signature
+ * to the application via the callback.
+ *
+ * @param wsh operation handle
+ * @param json reply from the exchange
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
+ */
+static int
+reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
+ json_t *json)
+{
+ struct GNUNET_CRYPTO_rsa_Signature *blind_sig;
+ struct GNUNET_CRYPTO_rsa_Signature *sig;
+ struct TALER_DenominationSignature dsig;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_rsa_signature ("ev_sig", &blind_sig),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
+ wsh->blinding_key->rsa_blinding_key,
+ wsh->pk->key.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (blind_sig);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (&wsh->c_hash,
+ sig,
+ wsh->pk->key.rsa_public_key))
+ {
+ GNUNET_break_op (0);
+ GNUNET_CRYPTO_rsa_signature_free (sig);
+ return GNUNET_SYSERR;
+ }
+ /* signature is valid, return it to the application */
+ dsig.rsa_signature = sig;
+ wsh->cb (wsh->cb_cls,
+ MHD_HTTP_OK,
+ &dsig,
+ json);
+ /* make sure callback isn't called again after return */
+ wsh->cb = NULL;
+ GNUNET_CRYPTO_rsa_signature_free (sig);
+ return GNUNET_OK;
+}
+
+
+/**
+ * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation.
+ * Check the signatures on the withdraw transactions in the provided
+ * history and that the balances add up. We don't do anything directly
+ * with the information, as the JSON will be returned to the application.
+ * However, our job is ensuring that the exchange followed the protocol, and
+ * this in particular means checking all of the signatures in the history.
+ *
+ * @param wsh operation handle
+ * @param json reply from the exchange
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
+ */
+static int
+reserve_withdraw_payment_required (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh,
+ json_t *json)
+{
+ struct TALER_Amount balance;
+ struct TALER_Amount balance_from_history;
+ struct TALER_Amount requested_amount;
+ json_t *history;
+ size_t len;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_amount ("balance", &balance),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ history = json_object_get (json,
+ "history");
+ if (NULL == history)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* go over transaction history and compute
+ total incoming and outgoing amounts */
+ len = json_array_size (history);
+ {
+ struct TALER_EXCHANGE_ReserveHistory rhistory[len];
+
+ if (GNUNET_OK !=
+ parse_reserve_history (history,
+ &wsh->reserve_pub,
+ balance.currency,
+ &balance_from_history,
+ len,
+ rhistory))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ if (0 !=
+ TALER_amount_cmp (&balance_from_history,
+ &balance))
+ {
+ /* exchange cannot add up balances!? */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ /* Compute how much we expected to charge to the reserve */
+ if (GNUNET_OK !=
+ TALER_amount_add (&requested_amount,
+ &wsh->pk->value,
+ &wsh->pk->fee_withdraw))
+ {
+ /* Overflow here? Very strange, our CPU must be fried... */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* Check that funds were really insufficient */
+ if (0 >= TALER_amount_cmp (&requested_amount,
+ &balance))
+ {
+ /* Requested amount is smaller or equal to reported balance,
+ so this should not have failed. */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /reserve/withdraw request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_ReserveWithdrawHandle`
+ * @param eh curl handle of the request that finished
+ */
+static void
+handle_reserve_withdraw_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh = cls;
+ long response_code;
+ json_t *json;
+
+ wsh->job = NULL;
+ json = MAC_download_get_result (&wsh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ if (GNUNET_OK !=
+ reserve_withdraw_ok (wsh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_PAYMENT_REQUIRED:
+ /* The exchange says that the reserve has insufficient funds;
+ check the signatures in the history... */
+ if (GNUNET_OK !=
+ reserve_withdraw_payment_required (wsh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ GNUNET_break (0);
+ /* Nothing really to verify, exchange says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, the exchange basically just says
+ that it doesn't know this reserve. Can happen if we
+ query before the wire transfer went through.
+ We should simply pass the JSON reply to the application. */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (NULL != wsh->cb)
+ wsh->cb (wsh->cb_cls,
+ response_code,
+ NULL,
+ json);
+ json_decref (json);
+ TALER_EXCHANGE_reserve_withdraw_cancel (wsh);
+}
+
+
+/**
+ * Withdraw a coin from the exchange using a /reserve/withdraw request. Note
+ * that to ensure that no money is lost in case of hardware failures,
+ * the caller must have committed (most of) the arguments to disk
+ * before calling, and be ready to repeat the request with the same
+ * arguments in case of failures.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param pk kind of coin to create
+ * @param reserve_priv private key of the reserve to withdraw from
+ * @param coin_priv where to store the coin's private key,
+ * caller must have committed this value to disk before the call (with @a pk)
+ * @param blinding_key where to store the coin's blinding key
+ * caller must have committed this value to disk before the call (with @a pk)
+ * @param res_cb the callback to call when the final result for this request is available
+ * @param res_cb_cls closure for the above callback
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR
+ * if the inputs are invalid (i.e. denomination key not with this exchange).
+ * In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_ReserveWithdrawHandle *
+TALER_EXCHANGE_reserve_withdraw (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_EXCHANGE_DenomPublicKey *pk,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+ const struct TALER_DenominationBlindingKey *blinding_key,
+ TALER_EXCHANGE_ReserveWithdrawResultCallback res_cb,
+ void *res_cb_cls)
+{
+ struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
+ struct TALER_WithdrawRequestPS req;
+ struct TALER_ReserveSignatureP reserve_sig;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_EXCHANGE_Context *ctx;
+ struct TALER_Amount amount_with_fee;
+ char *coin_ev;
+ size_t coin_ev_size;
+ json_t *withdraw_obj;
+ CURL *eh;
+
+ wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveWithdrawHandle);
+ wsh->exchange = exchange;
+ wsh->cb = res_cb;
+ wsh->cb_cls = res_cb_cls;
+ wsh->pk = pk;
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ &wsh->c_hash);
+ coin_ev_size = GNUNET_CRYPTO_rsa_blind (&wsh->c_hash,
+ blinding_key->rsa_blinding_key,
+ pk->key.rsa_public_key,
+ &coin_ev);
+ GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
+ &wsh->reserve_pub.eddsa_pub);
+ req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
+ req.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
+ req.reserve_pub = wsh->reserve_pub;
+ if (GNUNET_OK !=
+ TALER_amount_add (&amount_with_fee,
+ &pk->fee_withdraw,
+ &pk->value))
+ {
+ /* exchange gave us denomination keys that overflow like this!? */
+ GNUNET_break_op (0);
+ GNUNET_free (coin_ev);
+ GNUNET_free (wsh);
+ return NULL;
+ }
+ TALER_amount_hton (&req.amount_with_fee,
+ &amount_with_fee);
+ TALER_amount_hton (&req.withdraw_fee,
+ &pk->fee_withdraw);
+ GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
+ &req.h_denomination_pub);
+ GNUNET_CRYPTO_hash (coin_ev,
+ coin_ev_size,
+ &req.h_coin_envelope);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
+ &req.purpose,
+ &reserve_sig.eddsa_signature));
+ withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub and coin_ev */
+ " s:o, s:o}",/* reserve_pub and reserve_sig */
+ "denom_pub", TALER_json_from_rsa_public_key (pk->key.rsa_public_key),
+ "coin_ev", TALER_json_from_data (coin_ev,
+ coin_ev_size),
+ "reserve_pub", TALER_json_from_data (&wsh->reserve_pub,
+ sizeof (struct TALER_ReservePublicKeyP)),
+ "reserve_sig", TALER_json_from_data (&reserve_sig,
+ sizeof (reserve_sig)));
+ GNUNET_free (coin_ev);
+
+ wsh->blinding_key = blinding_key;
+ wsh->url = MAH_path_to_url (exchange, "/reserve/withdraw");
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (wsh->json_enc =
+ json_dumps (withdraw_obj,
+ JSON_COMPACT)));
+ json_decref (withdraw_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ wsh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ wsh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (wsh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &wsh->db));
+ ctx = MAH_handle_to_context (exchange);
+ wsh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_reserve_withdraw_finished,
+ wsh);
+ return wsh;
+}
+
+
+/**
+ * Cancel a withdraw status request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param sign the withdraw sign request handle
+ */
+void
+TALER_EXCHANGE_reserve_withdraw_cancel (struct TALER_EXCHANGE_ReserveWithdrawHandle *sign)
+{
+ if (NULL != sign->job)
+ {
+ MAC_job_cancel (sign->job);
+ sign->job = NULL;
+ }
+ GNUNET_free_non_null (sign->db.buf);
+ GNUNET_free (sign->url);
+ GNUNET_free (sign->json_enc);
+ GNUNET_free (sign);
+}
+
+
+/* end of exchange_api_reserve.c */
diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c
new file mode 100644
index 000000000..fd40230c7
--- /dev/null
+++ b/src/exchange-lib/exchange_api_wire.c
@@ -0,0 +1,620 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_wire.c
+ * @brief Implementation of the /wire request of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A Wire Handle
+ */
+struct TALER_EXCHANGE_WireHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_WireResultCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Set to the "methods" JSON array returned by the
+ * /wire request.
+ */
+ json_t *methods;
+
+ /**
+ * Current iteration offset in the @e methods array.
+ */
+ unsigned int methods_off;
+
+};
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * for /wire/sepa from the exchange is valid.
+ *
+ * @param wh wire handle
+ * @param json json reply with the signature
+ * @return #GNUNET_SYSERR if @a json is invalid,
+ * #GNUNET_NO if the method is unknown,
+ * #GNUNET_OK if the json is valid
+ */
+static int
+verify_wire_sepa_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh,
+ json_t *json)
+{
+ struct TALER_MasterSignatureP exchange_sig;
+ struct TALER_MasterWireSepaDetailsPS mp;
+ const char *receiver_name;
+ const char *iban;
+ const char *bic;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct GNUNET_HashContext *hc;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("sig", &exchange_sig),
+ MAJ_spec_string ("receiver_name", &receiver_name),
+ MAJ_spec_string ("iban", &iban),
+ MAJ_spec_string ("bic", &bic),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ key_state = TALER_EXCHANGE_get_keys (wh->exchange);
+ mp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
+ mp.purpose.size = htonl (sizeof (struct TALER_MasterWireSepaDetailsPS));
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ receiver_name,
+ strlen (receiver_name) + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ iban,
+ strlen (iban) + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ bic,
+ strlen (bic) + 1);
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &mp.h_sepa_details);
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
+ &mp.purpose,
+ &exchange_sig.eddsa_signature,
+ &key_state->master_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ MAJ_parse_free (spec);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * for /wire/METHOD from the exchange is valid.
+ *
+ * @param wh wire handle with key material
+ * @param method method to verify the reply for
+ * @param json json reply with the signature
+ * @return #GNUNET_SYSERR if @a json is invalid,
+ * #GNUNET_NO if the method is unknown,
+ * #GNUNET_OK if the json is valid
+ */
+static int
+verify_wire_method_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh,
+ const char *method,
+ json_t *json)
+{
+ struct
+ {
+ /**
+ * Name fo the method.
+ */
+ const char *method;
+
+ /**
+ * Handler to invoke to verify signature.
+ *
+ * @param wh wire handle with key material
+ * @param json json reply with signature to verify
+ */
+ int (*handler)(const struct TALER_EXCHANGE_WireHandle *wh,
+ json_t *json);
+ } handlers[] = {
+ { "sepa", &verify_wire_sepa_signature_ok },
+ { NULL, NULL }
+ };
+ unsigned int i;
+
+ for (i=0;NULL != handlers[i].method; i++)
+ if (0 == strcasecmp (handlers[i].method,
+ method))
+ return handlers[i].handler (wh,
+ json);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Wire transfer method `%s' not supported\n",
+ method);
+ return GNUNET_NO;
+}
+
+
+/**
+ * Perform the next /wire/method request or signal
+ * the end of the iteration.
+ *
+ * @param wh the wire handle
+ * @return a handle for this request
+ */
+static void
+request_wire_method (struct TALER_EXCHANGE_WireHandle *wh);
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /wire/METHOD request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_WireHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_wire_method_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_WireHandle *wh = cls;
+ long response_code;
+ json_t *json;
+
+ wh->job = NULL;
+ json = MAC_download_get_result (&wh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ const char *method;
+
+ method = json_string_value (json_array_get (wh->methods,
+ wh->methods_off - 1));
+ if (GNUNET_OK !=
+ verify_wire_method_signature_ok (wh,
+ method,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ break;
+ }
+ case MHD_HTTP_FOUND:
+ /* /wire/test returns a 302 redirect, we should just give
+ this information back to the callback below */
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (0 == response_code)
+ {
+ /* signal end of iteration */
+ wh->cb (wh->cb_cls,
+ 0,
+ NULL,
+ NULL);
+ json_decref (json);
+ TALER_EXCHANGE_wire_cancel (wh);
+ return;
+ }
+ /* pass on successful reply */
+ wh->cb (wh->cb_cls,
+ response_code,
+ json_string_value (json_array_get (wh->methods,
+ wh->methods_off-1)),
+ json);
+ /* trigger request for the next /wire/method */
+ request_wire_method (wh);
+}
+
+
+/**
+ * Perform the next /wire/method request or signal
+ * the end of the iteration.
+ *
+ * @param wh the wire handle
+ * @return a handle for this request
+ */
+static void
+request_wire_method (struct TALER_EXCHANGE_WireHandle *wh)
+{
+ struct TALER_EXCHANGE_Context *ctx;
+ CURL *eh;
+ char *path;
+
+ if (json_array_size (wh->methods) <= wh->methods_off)
+ {
+ /* we are done, signal end of iteration */
+ wh->cb (wh->cb_cls,
+ 0,
+ NULL,
+ NULL);
+ TALER_EXCHANGE_wire_cancel (wh);
+ return;
+ }
+ GNUNET_free_non_null (wh->db.buf);
+ wh->db.buf = NULL;
+ wh->db.buf_size = 0;
+ wh->db.eno = 0;
+ GNUNET_free_non_null (wh->url);
+ GNUNET_asprintf (&path,
+ "/wire/%s",
+ json_string_value (json_array_get (wh->methods,
+ wh->methods_off++)));
+ wh->url = MAH_path_to_url (wh->exchange,
+ path);
+ GNUNET_free (path);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ wh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &wh->db));
+ /* The default is 'disabled', but let's be sure */
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_FOLLOWLOCATION,
+ (long) 0));
+ ctx = MAH_handle_to_context (wh->exchange);
+ wh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_wire_method_finished,
+ wh);
+ TALER_EXCHANGE_perform (ctx);
+}
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * for /wire from the exchange is valid.
+ *
+ * @param wh wire handle
+ * @param json json reply with the signature
+ * @return NULL if @a json is invalid, otherwise the
+ * "methods" array (with an RC of 1)
+ */
+static json_t *
+verify_wire_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh,
+ json_t *json)
+{
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeWireSupportMethodsPS mp;
+ json_t *methods;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct GNUNET_HashContext *hc;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("sig", &exchange_sig),
+ MAJ_spec_fixed_auto ("pub", &exchange_pub),
+ MAJ_spec_json ("methods", &methods),
+ MAJ_spec_end
+ };
+ unsigned int i;
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+ if (! json_is_array (methods))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return NULL;
+ }
+
+ key_state = TALER_EXCHANGE_get_keys (wh->exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &exchange_pub))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ for (i=0;i<json_array_size (methods);i++)
+ {
+ const json_t *element = json_array_get (methods, i);
+ const char *method;
+
+ if (! json_is_string (element))
+ {
+ GNUNET_CRYPTO_hash_context_abort (hc);
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return NULL;
+ }
+ method = json_string_value (element);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ method,
+ strlen (method) + 1);
+ }
+ mp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_WIRE_TYPES);
+ mp.purpose.size = htonl (sizeof (struct TALER_ExchangeWireSupportMethodsPS));
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &mp.h_wire_types);
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_WIRE_TYPES,
+ &mp.purpose,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ MAJ_parse_free (spec);
+ return NULL;
+ }
+ return methods;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /wire request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_WireHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_wire_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_WireHandle *wh = cls;
+ long response_code;
+ json_t *json;
+
+ wh->job = NULL;
+ json = MAC_download_get_result (&wh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ json_t *methods;
+
+ if (NULL ==
+ (methods = verify_wire_signature_ok (wh,
+ json)))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ wh->methods = methods;
+ request_wire_method (wh);
+ return;
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ if (0 != response_code)
+ {
+ /* pass on successful reply */
+ wh->cb (wh->cb_cls,
+ response_code,
+ NULL,
+ json);
+ }
+ /* signal end of iteration */
+ wh->cb (wh->cb_cls,
+ 0,
+ NULL,
+ NULL);
+ if (NULL != json)
+ json_decref (json);
+ TALER_EXCHANGE_wire_cancel (wh);
+}
+
+
+/**
+ * Obtain information about a exchange's wire instructions.
+ * A exchange may provide wire instructions for creating
+ * a reserve. The wire instructions also indicate
+ * which wire formats merchants may use with the exchange.
+ * This API is typically used by a wallet for wiring
+ * funds, and possibly by a merchant to determine
+ * supported wire formats.
+ *
+ * Note that while we return the (main) response verbatim to the
+ * caller for further processing, we do already verify that the
+ * response is well-formed (i.e. that signatures included in the
+ * response are all valid). If the exchange's reply is not well-formed,
+ * we return an HTTP status code of zero to @a cb.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param wire_cb the callback to call when a reply for this request is available
+ * @param wire_cb_cls closure for the above callback
+ * @return a handle for this request
+ */
+struct TALER_EXCHANGE_WireHandle *
+TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange,
+ TALER_EXCHANGE_WireResultCallback wire_cb,
+ void *wire_cb_cls)
+{
+ struct TALER_EXCHANGE_WireHandle *wh;
+ struct TALER_EXCHANGE_Context *ctx;
+ CURL *eh;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ wh = GNUNET_new (struct TALER_EXCHANGE_WireHandle);
+ wh->exchange = exchange;
+ wh->cb = wire_cb;
+ wh->cb_cls = wire_cb_cls;
+ wh->url = MAH_path_to_url (exchange, "/wire");
+
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ wh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &wh->db));
+ ctx = MAH_handle_to_context (exchange);
+ wh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_wire_finished,
+ wh);
+ return wh;
+}
+
+
+/**
+ * Cancel a wire information request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param wh the wire information request handle
+ */
+void
+TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh)
+{
+ if (NULL != wh->job)
+ {
+ MAC_job_cancel (wh->job);
+ wh->job = NULL;
+ }
+ if (NULL != wh->methods)
+ {
+ json_decref (wh->methods);
+ wh->methods = NULL;
+ }
+ GNUNET_free_non_null (wh->db.buf);
+ GNUNET_free (wh->url);
+ GNUNET_free (wh);
+}
+
+
+/* end of exchange_api_wire.c */
diff --git a/src/exchange-lib/exchange_api_wire_deposits.c b/src/exchange-lib/exchange_api_wire_deposits.c
new file mode 100644
index 000000000..281ae2097
--- /dev/null
+++ b/src/exchange-lib/exchange_api_wire_deposits.c
@@ -0,0 +1,284 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-lib/exchange_api_wire_deposits.c
+ * @brief Implementation of the /wire/deposits request of the exchange's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
+#include "exchange_api_json.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A /wire/deposits Handle
+ */
+struct TALER_EXCHANGE_WireDepositsHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_WireDepositsCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /wire/deposits request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_WireDepositsHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_wire_deposits_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_EXCHANGE_WireDepositsHandle *wdh = cls;
+ long response_code;
+ json_t *json;
+
+ wdh->job = NULL;
+ json = MAC_download_get_result (&wdh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ json_t *details_j;
+ struct GNUNET_HashCode h_wire;
+ struct TALER_Amount total_amount;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ unsigned int num_details;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("H_wire", &h_wire),
+ MAJ_spec_fixed_auto ("merchant_pub", &merchant_pub),
+ MAJ_spec_amount ("total_amount", &total_amount),
+ MAJ_spec_json ("details", &details_j),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ num_details = json_array_size (details_j);
+ {
+ struct TALER_WireDepositDetails details[num_details];
+ unsigned int i;
+
+ for (i=0;i<num_details;i++)
+ {
+ struct TALER_WireDepositDetails *detail = &details[i];
+ struct json_t *detail_j = json_array_get (details_j, i);
+ struct MAJ_Specification spec_detail[] = {
+ MAJ_spec_fixed_auto ("H_contract", &detail->h_contract),
+ MAJ_spec_amount ("deposit_value", &detail->coin_value),
+ MAJ_spec_amount ("deposit_fee", &detail->coin_fee),
+ MAJ_spec_uint64 ("transaction_id", &detail->transaction_id),
+ MAJ_spec_fixed_auto ("coin_pub", &detail->coin_pub),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (detail_j,
+ spec_detail))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ }
+ if (0 == response_code)
+ break;
+ wdh->cb (wdh->cb_cls,
+ response_code,
+ json,
+ &h_wire,
+ &total_amount,
+ num_details,
+ details);
+ json_decref (json);
+ TALER_EXCHANGE_wire_deposits_cancel (wdh);
+ return;
+ }
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, exchange says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Exchange does not know about transaction;
+ we should pass the reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ wdh->cb (wdh->cb_cls,
+ response_code,
+ json,
+ NULL, NULL, 0, NULL);
+ json_decref (json);
+ TALER_EXCHANGE_wire_deposits_cancel (wdh);
+}
+
+
+/**
+ * Query the exchange about which transactions were combined
+ * to create a wire transfer.
+ *
+ * @param exchange exchange to query
+ * @param wtid raw wire transfer identifier to get information about
+ * @param cb callback to call
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel operation
+ */
+struct TALER_EXCHANGE_WireDepositsHandle *
+TALER_EXCHANGE_wire_deposits (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_EXCHANGE_WireDepositsCallback cb,
+ void *cb_cls)
+{
+ struct TALER_EXCHANGE_WireDepositsHandle *wdh;
+ struct TALER_EXCHANGE_Context *ctx;
+ char *buf;
+ char *path;
+ CURL *eh;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ wdh = GNUNET_new (struct TALER_EXCHANGE_WireDepositsHandle);
+ wdh->exchange = exchange;
+ wdh->cb = cb;
+ wdh->cb_cls = cb_cls;
+
+ buf = GNUNET_STRINGS_data_to_string_alloc (wtid,
+ sizeof (struct TALER_WireTransferIdentifierRawP));
+ GNUNET_asprintf (&path,
+ "/wire/deposits?wtid=%s",
+ buf);
+ wdh->url = MAH_path_to_url (wdh->exchange,
+ path);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ wdh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &wdh->db));
+ ctx = MAH_handle_to_context (exchange);
+ wdh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_wire_deposits_finished,
+ wdh);
+ return wdh;
+}
+
+
+/**
+ * Cancel wire deposits request. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param wdh the wire deposits request handle
+ */
+void
+TALER_EXCHANGE_wire_deposits_cancel (struct TALER_EXCHANGE_WireDepositsHandle *wdh)
+{
+ if (NULL != wdh->job)
+ {
+ MAC_job_cancel (wdh->job);
+ wdh->job = NULL;
+ }
+ GNUNET_free_non_null (wdh->db.buf);
+ GNUNET_free (wdh->url);
+ GNUNET_free (wdh);
+}
+
+
+/* end of exchange_api_wire_deposits.c */
diff --git a/src/exchange-lib/test-exchange-home/config/exchange-common.conf b/src/exchange-lib/test-exchange-home/config/exchange-common.conf
new file mode 100644
index 000000000..806046588
--- /dev/null
+++ b/src/exchange-lib/test-exchange-home/config/exchange-common.conf
@@ -0,0 +1,31 @@
+[exchange]
+# Currency supported by the exchange (can only be one)
+CURRENCY = EUR
+
+# Wire format supported by the exchange
+# We use 'test' for testing of the actual
+# coin operations, and 'sepa' to test SEPA-specific routines.
+WIREFORMAT = test sepa
+
+# 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
+
+# Is this is a testcase, use transient DB actions?
+TESTRUN = YES
+
+[exchangedb-postgres]
+DB_CONN_STR = "postgres:///talercheck"
+
+[wire-sepa]
+SEPA_RESPONSE_FILE = "test-exchange-home/sepa.json"
+
+[wire-test]
+REDIRECT_URL = "http://www.taler.net/"
+BANK_URI = "http://localhost/"
+BANK_ACCOUNT_NO = 2
diff --git a/src/exchange-lib/test-exchange-home/config/exchange-keyup.conf b/src/exchange-lib/test-exchange-home/config/exchange-keyup.conf
new file mode 100644
index 000000000..4a80da7e9
--- /dev/null
+++ b/src/exchange-lib/test-exchange-home/config/exchange-keyup.conf
@@ -0,0 +1,86 @@
+[exchange_keys]
+
+# how long is one signkey valid?
+signkey_duration = 4 weeks
+
+# how long are the signatures with the signkey valid?
+legal_duration = 2 years
+
+# how long do we generate denomination and signing keys
+# ahead of time?
+lookahead_sign = 32 weeks 1 day
+
+# how long do we provide to clients denomination and signing keys
+# ahead of time?
+lookahead_provide = 4 weeks 1 day
+
+
+# Coin definitions are detected because the section
+# name begins with "coin_". The rest of the
+# name is free, but of course following the convention
+# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense.
+[coin_eur_ct_1]
+value = EUR:0.01
+duration_overlap = 5 minutes
+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
+rsa_keysize = 1024
+
+[coin_eur_ct_10]
+value = EUR:0.10
+duration_overlap = 5 minutes
+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
+rsa_keysize = 1024
+
+[coin_eur_1]
+value = EUR:1
+duration_overlap = 5 minutes
+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
+rsa_keysize = 1024
+
+[coin_eur_5]
+value = EUR:5
+duration_overlap = 5 minutes
+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
+rsa_keysize = 1024
+
+[coin_eur_10]
+value = EUR:10
+duration_overlap = 5 minutes
+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
+rsa_keysize = 1024
+
+[coin_eur_1000]
+value = EUR:1000
+duration_overlap = 5 minutes
+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
+rsa_keysize = 2048
diff --git a/src/mint-lib/test-mint-home/master.priv b/src/exchange-lib/test-exchange-home/master.priv
index 394926938..394926938 100644
--- a/src/mint-lib/test-mint-home/master.priv
+++ b/src/exchange-lib/test-exchange-home/master.priv
diff --git a/src/mint-lib/test-mint-home/sepa.json b/src/exchange-lib/test-exchange-home/sepa.json
index 36d12f661..36d12f661 100644
--- a/src/mint-lib/test-mint-home/sepa.json
+++ b/src/exchange-lib/test-exchange-home/sepa.json
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c
new file mode 100644
index 000000000..80e2c6add
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api.c
@@ -0,0 +1,2599 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange/test_exchange_api.c
+ * @brief testcase to test exchange's HTTP API interface
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+
+/**
+ * Is the configuration file is set to include wire format 'test'?
+ */
+#define WIRE_TEST 1
+
+/**
+ * Is the configuration file is set to include wire format 'sepa'?
+ */
+#define WIRE_SEPA 1
+
+/**
+ * Main execution context for the main loop.
+ */
+static struct TALER_EXCHANGE_Context *ctx;
+
+/**
+ * Handle to access the exchange.
+ */
+static struct TALER_EXCHANGE_Handle *exchange;
+
+/**
+ * Task run on shutdown.
+ */
+static struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+/**
+ * Task that runs the main event loop.
+ */
+static struct GNUNET_SCHEDULER_Task *ctx_task;
+
+/**
+ * Result of the testcases, #GNUNET_OK on success
+ */
+static int result;
+
+
+/**
+ * Opcodes for the interpreter.
+ */
+enum OpCode
+{
+ /**
+ * Termination code, stops the interpreter loop (with success).
+ */
+ OC_END = 0,
+
+ /**
+ * Add funds to a reserve by (faking) incoming wire transfer.
+ */
+ OC_ADMIN_ADD_INCOMING,
+
+ /**
+ * Check status of a reserve.
+ */
+ OC_WITHDRAW_STATUS,
+
+ /**
+ * Withdraw a coin from a reserve.
+ */
+ OC_WITHDRAW_SIGN,
+
+ /**
+ * Deposit a coin (pay with it).
+ */
+ OC_DEPOSIT,
+
+ /**
+ * Melt a (set of) coins.
+ */
+ OC_REFRESH_MELT,
+
+ /**
+ * Complete melting session by withdrawing melted coins.
+ */
+ OC_REFRESH_REVEAL,
+
+ /**
+ * Verify exchange's /refresh/link by linking original private key to
+ * results from #OC_REFRESH_REVEAL step.
+ */
+ OC_REFRESH_LINK,
+
+ /**
+ * Verify the exchange's /wire-method.
+ */
+ OC_WIRE,
+
+ /**
+ * Verify exchange's /wire/deposits method.
+ */
+ OC_WIRE_DEPOSITS,
+
+ /**
+ * Verify exchange's /deposit/wtid method.
+ */
+ OC_DEPOSIT_WTID
+
+};
+
+
+/**
+ * Structure specifying details about a coin to be melted.
+ * Used in a NULL-terminated array as part of command
+ * specification.
+ */
+struct MeltDetails
+{
+
+ /**
+ * Amount to melt (including fee).
+ */
+ const char *amount;
+
+ /**
+ * Reference to reserve_withdraw operations for coin to
+ * be used for the /refresh/melt operation.
+ */
+ const char *coin_ref;
+
+};
+
+
+/**
+ * Information about a fresh coin generated by the refresh operation.
+ */
+struct FreshCoin
+{
+
+ /**
+ * If @e amount is NULL, this specifies the denomination key to
+ * use. Otherwise, this will be set (by the interpreter) to the
+ * denomination PK matching @e amount.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+ /**
+ * Set (by the interpreter) to the exchange's signature over the
+ * coin's public key.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Set (by the interpreter) to the coin's private key.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+};
+
+
+/**
+ * Details for a exchange operation to execute.
+ */
+struct Command
+{
+ /**
+ * Opcode of the command.
+ */
+ enum OpCode oc;
+
+ /**
+ * Label for the command, can be NULL.
+ */
+ const char *label;
+
+ /**
+ * Which response code do we expect for this command?
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Details about the command.
+ */
+ union
+ {
+
+ /**
+ * Information for a #OC_ADMIN_ADD_INCOMING command.
+ */
+ struct
+ {
+
+ /**
+ * Label to another admin_add_incoming command if we
+ * should deposit into an existing reserve, NULL if
+ * a fresh reserve should be created.
+ */
+ const char *reserve_reference;
+
+ /**
+ * String describing the amount to add to the reserve.
+ */
+ const char *amount;
+
+ /**
+ * Wire details (JSON).
+ */
+ const char *wire;
+
+ /**
+ * Set (by the interpreter) to the reserve's private key
+ * we used to fill the reserve.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Set to the API's handle during the operation.
+ */
+ struct TALER_EXCHANGE_AdminAddIncomingHandle *aih;
+
+ } admin_add_incoming;
+
+ /**
+ * Information for a #OC_WITHDRAW_STATUS command.
+ */
+ struct
+ {
+
+ /**
+ * Label to the #OC_ADMIN_ADD_INCOMING command which
+ * created the reserve.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Set to the API's handle during the operation.
+ */
+ struct TALER_EXCHANGE_ReserveStatusHandle *wsh;
+
+ /**
+ * Expected reserve balance.
+ */
+ const char *expected_balance;
+
+ } reserve_status;
+
+ /**
+ * Information for a #OC_WITHDRAW_SIGN command.
+ */
+ struct
+ {
+
+ /**
+ * Which reserve should we withdraw from?
+ */
+ const char *reserve_reference;
+
+ /**
+ * String describing the denomination value we should withdraw.
+ * A corresponding denomination key must exist in the exchange's
+ * offerings. Can be NULL if @e pk is set instead.
+ */
+ const char *amount;
+
+ /**
+ * If @e amount is NULL, this specifies the denomination key to
+ * use. Otherwise, this will be set (by the interpreter) to the
+ * denomination PK matching @e amount.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+ /**
+ * Set (by the interpreter) to the exchange's signature over the
+ * coin's public key.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Set (by the interpreter) to the coin's private key.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Blinding key used for the operation.
+ */
+ struct TALER_DenominationBlindingKey blinding_key;
+
+ /**
+ * Withdraw handle (while operation is running).
+ */
+ struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
+
+ } reserve_withdraw;
+
+ /**
+ * Information for a #OC_DEPOSIT command.
+ */
+ struct
+ {
+
+ /**
+ * Amount to deposit.
+ */
+ const char *amount;
+
+ /**
+ * Reference to a reserve_withdraw operation for a coin to
+ * be used for the /deposit operation.
+ */
+ const char *coin_ref;
+
+ /**
+ * If this @e coin_ref refers to an operation that generated
+ * an array of coins, this value determines which coin to use.
+ */
+ unsigned int coin_idx;
+
+ /**
+ * JSON string describing the merchant's "wire details".
+ */
+ const char *wire_details;
+
+ /**
+ * JSON string describing the contract between the two parties.
+ */
+ const char *contract;
+
+ /**
+ * Transaction ID to use.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * Relative time (to add to 'now') to compute the refund deadline.
+ * Zero for no refunds.
+ */
+ struct GNUNET_TIME_Relative refund_deadline;
+
+ /**
+ * Set (by the interpreter) to a fresh private key of the merchant,
+ * if @e refund_deadline is non-zero.
+ */
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+
+ /**
+ * Deposit handle while operation is running.
+ */
+ struct TALER_EXCHANGE_DepositHandle *dh;
+
+ } deposit;
+
+ /**
+ * Information for a #OC_REFRESH_MELT command.
+ */
+ struct
+ {
+
+ /**
+ * Information about coins to be melted.
+ */
+ struct MeltDetails *melted_coins;
+
+ /**
+ * Denominations of the fresh coins to withdraw.
+ */
+ const char **fresh_amounts;
+
+ /**
+ * Array of the public keys corresponding to
+ * the @e fresh_amounts, set by the interpreter.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey **fresh_pks;
+
+ /**
+ * Melt handle while operation is running.
+ */
+ struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
+
+ /**
+ * Data used in the refresh operation, set by the interpreter.
+ */
+ char *refresh_data;
+
+ /**
+ * Number of bytes in @e refresh_data, set by the interpreter.
+ */
+ size_t refresh_data_length;
+
+ /**
+ * Set by the interpreter (upon completion) to the noreveal
+ * index selected by the exchange.
+ */
+ uint16_t noreveal_index;
+
+ } refresh_melt;
+
+ /**
+ * Information for a #OC_REFRESH_REVEAL command.
+ */
+ struct
+ {
+
+ /**
+ * Melt operation this is the matching reveal for.
+ */
+ const char *melt_ref;
+
+ /**
+ * Reveal handle while operation is running.
+ */
+ struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
+
+ /**
+ * Number of fresh coins withdrawn, set by the interpreter.
+ * Length of the @e fresh_coins array.
+ */
+ unsigned int num_fresh_coins;
+
+ /**
+ * Information about coins withdrawn, set by the interpreter.
+ */
+ struct FreshCoin *fresh_coins;
+
+ } refresh_reveal;
+
+ /**
+ * Information for a #OC_REFRESH_LINK command.
+ */
+ struct
+ {
+
+ /**
+ * Reveal operation this is the matching link for.
+ */
+ const char *reveal_ref;
+
+ /**
+ * Link handle while operation is running.
+ */
+ struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
+
+ /**
+ * Which of the melted coins should be used for the linkage?
+ */
+ unsigned int coin_idx;
+
+ } refresh_link;
+
+ /**
+ * Information for the /wire command.
+ */
+ struct {
+
+ /**
+ * Handle to the wire request.
+ */
+ struct TALER_EXCHANGE_WireHandle *wh;
+
+ /**
+ * Format we expect to see, others will be *ignored*.
+ */
+ const char *format;
+
+ } wire;
+
+ /**
+ * Information for the /wire/deposits's command.
+ */
+ struct {
+
+ /**
+ * Handle to the wire deposits request.
+ */
+ struct TALER_EXCHANGE_WireDepositsHandle *wdh;
+
+ /**
+ * Reference to a /deposit/wtid command. If set, we use the
+ * WTID from that command.
+ */
+ const char *wtid_ref;
+
+ /**
+ * WTID to use (used if @e wtid_ref is NULL).
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /* TODO: may want to add list of deposits we expected
+ to see aggregated here in the future. */
+
+ } wire_deposits;
+
+ /**
+ * Information for the /deposit/wtid command.
+ */
+ struct {
+
+ /**
+ * Handle to the deposit wtid request.
+ */
+ struct TALER_EXCHANGE_DepositWtidHandle *dwh;
+
+ /**
+ * Which /deposit operation should we obtain WTID data for?
+ */
+ const char *deposit_ref;
+
+ /**
+ * What is the expected total amount? Only used if
+ * @e expected_response_code was #MHD_HTTP_OK.
+ */
+ struct TALER_Amount total_amount_expected;
+
+ /**
+ * Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ } deposit_wtid;
+
+ } details;
+
+};
+
+
+/**
+ * State of the interpreter loop.
+ */
+struct InterpreterState
+{
+ /**
+ * Keys from the exchange.
+ */
+ const struct TALER_EXCHANGE_Keys *keys;
+
+ /**
+ * Commands the interpreter will run.
+ */
+ struct Command *commands;
+
+ /**
+ * Interpreter task (if one is scheduled).
+ */
+ struct GNUNET_SCHEDULER_Task *task;
+
+ /**
+ * Instruction pointer. Tells #interpreter_run() which
+ * instruction to run next.
+ */
+ unsigned int ip;
+
+};
+
+
+/**
+ * Task that runs the context's event loop with the GNUnet scheduler.
+ *
+ * @param cls unused
+ * @param tc scheduler context (unused)
+ */
+static void
+context_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Run the context task, the working set has changed.
+ */
+static void
+trigger_context_task ()
+{
+ GNUNET_SCHEDULER_cancel (ctx_task);
+ ctx_task = GNUNET_SCHEDULER_add_now (&context_task,
+ NULL);
+}
+
+
+/**
+ * The testcase failed, return with an error code.
+ *
+ * @param is interpreter state to clean up
+ */
+static void
+fail (struct InterpreterState *is)
+{
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Find a command by label.
+ *
+ * @param is interpreter state to search
+ * @param label label to look for
+ * @return NULL if command was not found
+ */
+static const struct Command *
+find_command (const struct InterpreterState *is,
+ const char *label)
+{
+ unsigned int i;
+ const struct Command *cmd;
+
+ if (NULL == label)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Attempt to lookup command for empty label\n");
+ return NULL;
+ }
+ for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
+ if ( (NULL != cmd->label) &&
+ (0 == strcmp (cmd->label,
+ label)) )
+ return cmd;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command not found: %s\n",
+ label);
+ return NULL;
+}
+
+
+/**
+ * Run the main interpreter loop that performs exchange operations.
+ *
+ * @param cls contains the `struct InterpreterState`
+ * @param tc scheduler context
+ */
+static void
+interpreter_run (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Function called upon completion of our /admin/add/incoming request.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+static void
+add_incoming_cb (void *cls,
+ unsigned int http_status,
+ json_t *full_response)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.admin_add_incoming.aih = NULL;
+ if (MHD_HTTP_OK != http_status)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Check if the given historic event @a h corresponds to the given
+ * command @a cmd.
+ *
+ * @param h event in history
+ * @param cmd an #OC_ADMIN_ADD_INCOMING command
+ * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
+ */
+static int
+compare_admin_add_incoming_history (const struct TALER_EXCHANGE_ReserveHistory *h,
+ const struct Command *cmd)
+{
+ struct TALER_Amount amount;
+
+ if (TALER_EXCHANGE_RTT_DEPOSIT != h->type)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
+ &amount));
+ if (0 != TALER_amount_cmp (&amount,
+ &h->amount))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check if the given historic event @a h corresponds to the given
+ * command @a cmd.
+ *
+ * @param h event in history
+ * @param cmd an #OC_WITHDRAW_SIGN command
+ * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
+ */
+static int
+compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h,
+ const struct Command *cmd)
+{
+ struct TALER_Amount amount;
+ struct TALER_Amount amount_with_fee;
+
+ if (TALER_EXCHANGE_RTT_WITHDRAWAL != h->type)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
+ &amount));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_add (&amount_with_fee,
+ &amount,
+ &cmd->details.reserve_withdraw.pk->fee_withdraw));
+ if (0 != TALER_amount_cmp (&amount_with_fee,
+ &h->amount))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with the result of a /reserve/status request.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param[in] json original response in JSON format (useful only for diagnostics)
+ * @param balance current balance in the reserve, NULL on error
+ * @param history_length number of entries in the transaction history, 0 on error
+ * @param history detailed transaction history, NULL on error
+ */
+static void
+reserve_status_cb (void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct TALER_Amount *balance,
+ unsigned int history_length,
+ const struct TALER_EXCHANGE_ReserveHistory *history)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+ struct Command *rel;
+ unsigned int i;
+ unsigned int j;
+ struct TALER_Amount amount;
+
+ cmd->details.reserve_status.wsh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ GNUNET_break (0);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ /* FIXME: note that history events may come in a different
+ order than the commands. However, for now this works... */
+ j = 0;
+ for (i=0;i<is->ip;i++)
+ {
+ switch ((rel = &is->commands[i])->oc)
+ {
+ case OC_ADMIN_ADD_INCOMING:
+ if ( ( (NULL != rel->label) &&
+ (0 == strcmp (cmd->details.reserve_status.reserve_reference,
+ rel->label) ) ) ||
+ ( (NULL != rel->details.admin_add_incoming.reserve_reference) &&
+ (0 == strcmp (cmd->details.reserve_status.reserve_reference,
+ rel->details.admin_add_incoming.reserve_reference) ) ) )
+ {
+ if (GNUNET_OK !=
+ compare_admin_add_incoming_history (&history[j],
+ rel))
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ j++;
+ }
+ break;
+ case OC_WITHDRAW_SIGN:
+ if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
+ rel->details.reserve_withdraw.reserve_reference))
+ {
+ if (GNUNET_OK !=
+ compare_reserve_withdraw_history (&history[j],
+ rel))
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ j++;
+ }
+ break;
+ default:
+ /* unreleated, just skip */
+ break;
+ }
+ }
+ if (j != history_length)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ if (NULL != cmd->details.reserve_status.expected_balance)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (cmd->details.reserve_status.expected_balance,
+ &amount));
+ if (0 != TALER_amount_cmp (&amount,
+ balance))
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ }
+ break;
+ default:
+ /* Unsupported status code (by test harness) */
+ GNUNET_break (0);
+ break;
+ }
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called upon completion of our /reserve/withdraw request.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param sig signature over the coin, NULL on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+static void
+reserve_withdraw_cb (void *cls,
+ unsigned int http_status,
+ const struct TALER_DenominationSignature *sig,
+ json_t *full_response)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.reserve_withdraw.wsh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (full_response, stderr, 0);
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ if (NULL == sig)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ cmd->details.reserve_withdraw.sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
+ break;
+ case MHD_HTTP_PAYMENT_REQUIRED:
+ /* nothing to check */
+ break;
+ default:
+ /* Unsupported status code (by test harness) */
+ GNUNET_break (0);
+ break;
+ }
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called with the result of a /deposit operation.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param obj the received JSON reply, should be kept as proof (and, in case of errors,
+ * be forwarded to the customer)
+ */
+static void
+deposit_cb (void *cls,
+ unsigned int http_status,
+ json_t *obj)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.deposit.dh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (obj, stderr, 0);
+ fail (is);
+ return;
+ }
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called with the result of the /refresh/melt operation.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
+ * UINT16_MAX on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+static void
+melt_cb (void *cls,
+ unsigned int http_status,
+ uint16_t noreveal_index,
+ json_t *full_response)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.refresh_melt.rmh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (full_response, stderr, 0);
+ fail (is);
+ return;
+ }
+ cmd->details.refresh_melt.noreveal_index = noreveal_index;
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called with the result of the /refresh/reveal operation.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
+ * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
+ * @param sigs array of signature over @a num_coins coins, NULL on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+static void
+reveal_cb (void *cls,
+ unsigned int http_status,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPrivateKeyP *coin_privs,
+ const struct TALER_DenominationSignature *sigs,
+ json_t *full_response)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+ const struct Command *ref;
+ unsigned int i;
+
+ cmd->details.refresh_reveal.rrh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (full_response, stderr, 0);
+ fail (is);
+ return;
+ }
+ ref = find_command (is,
+ cmd->details.refresh_reveal.melt_ref);
+ cmd->details.refresh_reveal.num_fresh_coins = num_coins;
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ cmd->details.refresh_reveal.fresh_coins
+ = GNUNET_new_array (num_coins,
+ struct FreshCoin);
+ for (i=0;i<num_coins;i++)
+ {
+ struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i];
+
+ fc->pk = ref->details.refresh_melt.fresh_pks[i];
+ fc->coin_priv = coin_privs[i];
+ fc->sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature);
+ }
+ break;
+ default:
+ break;
+ }
+
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called with the result of a /refresh/link operation.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
+ * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
+ * @param sigs array of signature over @a num_coins coins, NULL on error
+ * @param pubs array of public keys for the @a sigs, NULL on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+static void
+link_cb (void *cls,
+ unsigned int http_status,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPrivateKeyP *coin_privs,
+ const struct TALER_DenominationSignature *sigs,
+ const struct TALER_DenominationPublicKey *pubs,
+ json_t *full_response)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+ const struct Command *ref;
+ unsigned int i;
+ unsigned int j;
+ unsigned int found;
+
+ cmd->details.refresh_link.rlh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (full_response, stderr, 0);
+ fail (is);
+ return;
+ }
+ ref = find_command (is,
+ cmd->details.refresh_link.reveal_ref);
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ /* check that number of coins returned matches */
+ if (num_coins != ref->details.refresh_reveal.num_fresh_coins)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ /* check that the coins match */
+ for (i=0;i<num_coins;i++)
+ for (j=i+1;j<num_coins;j++)
+ if (0 == memcmp (&coin_privs[i],
+ &coin_privs[j],
+ sizeof (struct TALER_CoinSpendPrivateKeyP)))
+ GNUNET_break (0);
+ /* Note: coins might be legitimately permutated in here... */
+ found = 0;
+ for (i=0;i<num_coins;i++)
+ for (j=0;j<num_coins;j++)
+ {
+ const struct FreshCoin *fc;
+
+ fc = &ref->details.refresh_reveal.fresh_coins[j];
+ if ( (0 == memcmp (&coin_privs[i],
+ &fc->coin_priv,
+ sizeof (struct TALER_CoinSpendPrivateKeyP))) &&
+ (0 == GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature,
+ sigs[i].rsa_signature)) &&
+ (0 == GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key,
+ pubs[i].rsa_public_key)) )
+ {
+ found++;
+ break;
+ }
+ }
+ if (found != num_coins)
+ {
+ fprintf (stderr,
+ "Only %u/%u coins match expectations\n",
+ found,
+ num_coins);
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Find denomination key matching the given amount.
+ *
+ * @param keys array of keys to search
+ * @param amount coin value to look for
+ * @return NULL if no matching key was found
+ */
+static const struct TALER_EXCHANGE_DenomPublicKey *
+find_pk (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_Amount *amount)
+{
+ unsigned int i;
+ struct GNUNET_TIME_Absolute now;
+ struct TALER_EXCHANGE_DenomPublicKey *pk;
+ char *str;
+
+ now = GNUNET_TIME_absolute_get ();
+ for (i=0;i<keys->num_denom_keys;i++)
+ {
+ pk = &keys->denom_keys[i];
+ if ( (0 == TALER_amount_cmp (amount,
+ &pk->value)) &&
+ (now.abs_value_us >= pk->valid_from.abs_value_us) &&
+ (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) )
+ return pk;
+ }
+ /* do 2nd pass to check if expiration times are to blame for failure */
+ str = TALER_amount_to_string (amount);
+ for (i=0;i<keys->num_denom_keys;i++)
+ {
+ pk = &keys->denom_keys[i];
+ if ( (0 == TALER_amount_cmp (amount,
+ &pk->value)) &&
+ ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
+ (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n",
+ str,
+ now.abs_value_us,
+ pk->valid_from.abs_value_us,
+ pk->withdraw_valid_until.abs_value_us);
+ GNUNET_free (str);
+ return NULL;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No denomination key for amount %s found\n",
+ str);
+ GNUNET_free (str);
+ return NULL;
+}
+
+
+/**
+ * Callbacks called with the result(s) of a
+ * wire format inquiry request to the exchange.
+ *
+ * The callback is invoked multiple times, once for each supported @a
+ * method. Finally, it is invoked one more time with cls/0/NULL/NULL
+ * to indicate the end of the iteration. If any request fails to
+ * generate a valid response from the exchange, @a http_status will also
+ * be zero and the iteration will also end. Thus, the iteration
+ * always ends with a final call with an @a http_status of 0. If the
+ * @a http_status is already 0 on the first call, then the response to
+ * the /wire request was invalid. Later, clients can tell the
+ * difference between @a http_status of 0 indicating a failed
+ * /wire/method request and a regular end of the iteration by @a
+ * method being non-NULL. If the exchange simply correctly asserts that
+ * it does not support any methods, @a method will be NULL but the @a
+ * http_status will be #MHD_HTTP_OK for the first call (followed by a
+ * cls/0/NULL/NULL call to signal the end of the iteration).
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param method wire format method supported, i.e. "test" or "sepa", or NULL
+ * if already the /wire request failed.
+ * @param obj the received JSON reply, if successful this should be the wire
+ * format details as provided by /wire/METHOD/, or NULL if the
+ * reply was not in JSON format (in this case, the client might
+ * want to do an HTTP request to /wire/METHOD/ with a browser to
+ * provide more information to the user about the @a method).
+ */
+static void
+wire_cb (void *cls,
+ unsigned int http_status,
+ const char *method,
+ json_t *obj)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ if (0 == http_status)
+ {
+ /* 0 always signals the end of the iteration */
+ cmd->details.wire.wh = NULL;
+ }
+ else if ( (NULL != method) &&
+ (0 != strcasecmp (method,
+ cmd->details.wire.format)) )
+ {
+ /* not the method we care about, skip */
+ return;
+ }
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s/%s\n",
+ http_status,
+ cmd->label,
+ method);
+ json_dumpf (obj, stderr, 0);
+ fail (is);
+ return;
+ }
+ if (0 == http_status)
+ {
+ /* end of iteration, move to next command */
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+ return;
+ }
+ /* For now, we only support to be called only once
+ with a "positive" result; so we switch to an
+ expected value of 0 for the 2nd iteration */
+ cmd->expected_response_code = 0;
+}
+
+
+/**
+ * Function called with detailed wire transfer data, including all
+ * of the coin transactions that were combined into the wire transfer.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param json original json reply (may include signatures, those have then been
+ * validated already)
+ * @param wtid extracted wire transfer identifier, or NULL if the exchange could
+ * not provide any (set only if @a http_status is #MHD_HTTP_OK)
+ * @param total_amount total amount of the wire transfer, or NULL if the exchange could
+ * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ * @param details_length length of the @a details array
+ * @param details array with details about the combined transactions
+ */
+static void
+wire_deposits_cb (void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_Amount *total_amount,
+ unsigned int details_length,
+ const struct TALER_WireDepositDetails *details)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+ const struct Command *ref;
+
+ cmd->details.wire_deposits.wdh = NULL;
+ ref = find_command (is,
+ cmd->details.wire_deposits.wtid_ref);
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ if (0 != TALER_amount_cmp (total_amount,
+ &ref->details.deposit_wtid.total_amount_expected))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Total amount missmatch to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ if (NULL != ref->details.deposit_wtid.deposit_ref)
+ {
+ const struct Command *dep;
+ struct GNUNET_HashCode hw;
+
+ dep = find_command (is,
+ ref->details.deposit_wtid.deposit_ref);
+ GNUNET_CRYPTO_hash (dep->details.deposit.wire_details,
+ strlen (dep->details.deposit.wire_details),
+ &hw);
+ if (0 != memcmp (&hw,
+ h_wire,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire hash missmatch to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* move to next command */
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called with detailed wire transfer data.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param json original json reply (may include signatures, those have then been
+ * validated already)
+ * @param wtid wire transfer identifier used by the exchange, NULL if exchange did not
+ * yet execute the transaction
+ * @param execution_time actual or planned execution time for the wire transfer
+ * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
+ * @param total_amount total amount of the wire transfer, or NULL if the exchange could
+ * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ */
+static void
+deposit_wtid_cb (void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_Amount *coin_contribution)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.deposit_wtid.dwh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ cmd->details.deposit_wtid.wtid = *wtid;
+ break;
+ default:
+ break;
+ }
+
+ /* move to next command */
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Run the main interpreter loop that performs exchange operations.
+ *
+ * @param cls contains the `struct InterpreterState`
+ * @param tc scheduler context
+ */
+static void
+interpreter_run (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+ const struct Command *ref;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_Amount amount;
+ struct GNUNET_TIME_Absolute execution_date;
+ json_t *wire;
+
+ is->task = NULL;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+ fprintf (stderr,
+ "Test aborted by shutdown request\n");
+ fail (is);
+ return;
+ }
+ switch (cmd->oc)
+ {
+ case OC_END:
+ result = GNUNET_OK;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ case OC_ADMIN_ADD_INCOMING:
+ if (NULL !=
+ cmd->details.admin_add_incoming.reserve_reference)
+ {
+ ref = find_command (is,
+ cmd->details.admin_add_incoming.reserve_reference);
+ GNUNET_assert (NULL != ref);
+ GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
+ cmd->details.admin_add_incoming.reserve_priv
+ = ref->details.admin_add_incoming.reserve_priv;
+ }
+ else
+ {
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+
+ priv = GNUNET_CRYPTO_eddsa_key_create ();
+ cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv;
+ GNUNET_free (priv);
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv,
+ &reserve_pub.eddsa_pub);
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
+ &amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ cmd->details.admin_add_incoming.amount,
+ is->ip);
+ fail (is);
+ return;
+ }
+ wire = json_loads (cmd->details.admin_add_incoming.wire,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == wire)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse wire details `%s' at %u\n",
+ cmd->details.admin_add_incoming.wire,
+ is->ip);
+ fail (is);
+ return;
+ }
+ execution_date = GNUNET_TIME_absolute_get ();
+ TALER_round_abs_time (&execution_date);
+ cmd->details.admin_add_incoming.aih
+ = TALER_EXCHANGE_admin_add_incoming (exchange,
+ &reserve_pub,
+ &amount,
+ execution_date,
+ wire,
+ &add_incoming_cb,
+ is);
+ if (NULL == cmd->details.admin_add_incoming.aih)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ trigger_context_task ();
+ return;
+ case OC_WITHDRAW_STATUS:
+ GNUNET_assert (NULL !=
+ cmd->details.reserve_status.reserve_reference);
+ ref = find_command (is,
+ cmd->details.reserve_status.reserve_reference);
+ GNUNET_assert (NULL != ref);
+ GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
+ GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv,
+ &reserve_pub.eddsa_pub);
+ cmd->details.reserve_status.wsh
+ = TALER_EXCHANGE_reserve_status (exchange,
+ &reserve_pub,
+ &reserve_status_cb,
+ is);
+ trigger_context_task ();
+ return;
+ case OC_WITHDRAW_SIGN:
+ GNUNET_assert (NULL !=
+ cmd->details.reserve_withdraw.reserve_reference);
+ ref = find_command (is,
+ cmd->details.reserve_withdraw.reserve_reference);
+ GNUNET_assert (NULL != ref);
+ GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
+ if (NULL != cmd->details.reserve_withdraw.amount)
+ {
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
+ &amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ cmd->details.reserve_withdraw.amount,
+ is->ip);
+ fail (is);
+ return;
+ }
+ cmd->details.reserve_withdraw.pk = find_pk (is->keys,
+ &amount);
+ }
+ if (NULL == cmd->details.reserve_withdraw.pk)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to determine denomination key at %u\n",
+ is->ip);
+ fail (is);
+ return;
+ }
+
+ /* create coin's private key */
+ {
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+
+ priv = GNUNET_CRYPTO_eddsa_key_create ();
+ cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv;
+ GNUNET_free (priv);
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.reserve_withdraw.coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key
+ = GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.reserve_withdraw.pk->key.rsa_public_key));
+ cmd->details.reserve_withdraw.wsh
+ = TALER_EXCHANGE_reserve_withdraw (exchange,
+ cmd->details.reserve_withdraw.pk,
+ &ref->details.admin_add_incoming.reserve_priv,
+ &cmd->details.reserve_withdraw.coin_priv,
+ &cmd->details.reserve_withdraw.blinding_key,
+ &reserve_withdraw_cb,
+ is);
+ if (NULL == cmd->details.reserve_withdraw.wsh)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ trigger_context_task ();
+ return;
+ case OC_DEPOSIT:
+ {
+ struct GNUNET_HashCode h_contract;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_EXCHANGE_DenomPublicKey *coin_pk;
+ const struct TALER_DenominationSignature *coin_pk_sig;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct GNUNET_TIME_Absolute refund_deadline;
+ struct GNUNET_TIME_Absolute wire_deadline;
+ struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ json_t *contract;
+ json_t *wire;
+
+ GNUNET_assert (NULL !=
+ cmd->details.deposit.coin_ref);
+ ref = find_command (is,
+ cmd->details.deposit.coin_ref);
+ GNUNET_assert (NULL != ref);
+ switch (ref->oc)
+ {
+ case OC_WITHDRAW_SIGN:
+ coin_priv = &ref->details.reserve_withdraw.coin_priv;
+ coin_pk = ref->details.reserve_withdraw.pk;
+ coin_pk_sig = &ref->details.reserve_withdraw.sig;
+ break;
+ case OC_REFRESH_REVEAL:
+ {
+ const struct FreshCoin *fc;
+ unsigned int idx;
+
+ idx = cmd->details.deposit.coin_idx;
+ GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins);
+ fc = &ref->details.refresh_reveal.fresh_coins[idx];
+
+ coin_priv = &fc->coin_priv;
+ coin_pk = fc->pk;
+ coin_pk_sig = &fc->sig;
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.deposit.amount,
+ &amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ cmd->details.deposit.amount,
+ is->ip);
+ fail (is);
+ return;
+ }
+ contract = json_loads (cmd->details.deposit.contract,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == contract)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse contract details `%s' at %u/%s\n",
+ cmd->details.deposit.contract,
+ is->ip,
+ cmd->label);
+ fail (is);
+ return;
+ }
+ TALER_hash_json (contract,
+ &h_contract);
+ wire = json_loads (cmd->details.deposit.wire_details,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == wire)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse wire details `%s' at %u/%s\n",
+ cmd->details.deposit.wire_details,
+ is->ip,
+ cmd->label);
+ fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pub.eddsa_pub);
+
+ priv = GNUNET_CRYPTO_eddsa_key_create ();
+ cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
+ GNUNET_free (priv);
+ if (0 != cmd->details.deposit.refund_deadline.rel_value_us)
+ {
+ refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline);
+ }
+ else
+ {
+ refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
+ &merchant_pub.eddsa_pub);
+
+ wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
+ timestamp = GNUNET_TIME_absolute_get ();
+ TALER_round_abs_time (&timestamp);
+ {
+ struct TALER_DepositRequestPS dr;
+
+ memset (&dr, 0, sizeof (dr));
+ dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
+ dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ dr.h_contract = h_contract;
+ TALER_hash_json (wire,
+ &dr.h_wire);
+ dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
+ dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
+ dr.transaction_id = GNUNET_htonll (cmd->details.deposit.transaction_id);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &amount);
+ TALER_amount_hton (&dr.deposit_fee,
+ &coin_pk->fee_deposit);
+ dr.merchant = merchant_pub;
+ dr.coin_pub = coin_pub;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
+ &dr.purpose,
+ &coin_sig.eddsa_signature));
+ }
+ cmd->details.deposit.dh
+ = TALER_EXCHANGE_deposit (exchange,
+ &amount,
+ wire_deadline,
+ wire,
+ &h_contract,
+ &coin_pub,
+ coin_pk_sig,
+ &coin_pk->key,
+ timestamp,
+ cmd->details.deposit.transaction_id,
+ &merchant_pub,
+ refund_deadline,
+ &coin_sig,
+ &deposit_cb,
+ is);
+ if (NULL == cmd->details.deposit.dh)
+ {
+ GNUNET_break (0);
+ json_decref (wire);
+ fail (is);
+ return;
+ }
+ json_decref (wire);
+ trigger_context_task ();
+ return;
+ }
+ case OC_REFRESH_MELT:
+ {
+ unsigned int num_melted_coins;
+ unsigned int num_fresh_coins;
+
+ cmd->details.refresh_melt.noreveal_index = UINT16_MAX;
+ for (num_melted_coins=0;
+ NULL != cmd->details.refresh_melt.melted_coins[num_melted_coins].amount;
+ num_melted_coins++) ;
+ for (num_fresh_coins=0;
+ NULL != cmd->details.refresh_melt.fresh_amounts[num_fresh_coins];
+ num_fresh_coins++) ;
+
+ cmd->details.refresh_melt.fresh_pks
+ = GNUNET_new_array (num_fresh_coins,
+ const struct TALER_EXCHANGE_DenomPublicKey *);
+ {
+ struct TALER_CoinSpendPrivateKeyP melt_privs[num_melted_coins];
+ struct TALER_Amount melt_amounts[num_melted_coins];
+ struct TALER_DenominationSignature melt_sigs[num_melted_coins];
+ struct TALER_EXCHANGE_DenomPublicKey melt_pks[num_melted_coins];
+ struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins];
+ unsigned int i;
+
+ for (i=0;i<num_melted_coins;i++)
+ {
+ const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coins[i];
+ ref = find_command (is,
+ md->coin_ref);
+ GNUNET_assert (NULL != ref);
+ GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
+
+ melt_privs[i] = ref->details.reserve_withdraw.coin_priv;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (md->amount,
+ &melt_amounts[i]))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ md->amount,
+ is->ip);
+ fail (is);
+ return;
+ }
+ melt_sigs[i] = ref->details.reserve_withdraw.sig;
+ melt_pks[i] = *ref->details.reserve_withdraw.pk;
+ }
+ for (i=0;i<num_fresh_coins;i++)
+ {
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.refresh_melt.fresh_amounts[i],
+ &amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ cmd->details.reserve_withdraw.amount,
+ is->ip);
+ fail (is);
+ return;
+ }
+ cmd->details.refresh_melt.fresh_pks[i]
+ = find_pk (is->keys,
+ &amount);
+ fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i];
+ }
+ cmd->details.refresh_melt.refresh_data
+ = TALER_EXCHANGE_refresh_prepare (num_melted_coins,
+ melt_privs,
+ melt_amounts,
+ melt_sigs,
+ melt_pks,
+ GNUNET_YES,
+ num_fresh_coins,
+ fresh_pks,
+ &cmd->details.refresh_melt.refresh_data_length);
+ if (NULL == cmd->details.refresh_melt.refresh_data)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ cmd->details.refresh_melt.rmh
+ = TALER_EXCHANGE_refresh_melt (exchange,
+ cmd->details.refresh_melt.refresh_data_length,
+ cmd->details.refresh_melt.refresh_data,
+ &melt_cb,
+ is);
+ if (NULL == cmd->details.refresh_melt.rmh)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ }
+ }
+ trigger_context_task ();
+ return;
+ case OC_REFRESH_REVEAL:
+ ref = find_command (is,
+ cmd->details.refresh_reveal.melt_ref);
+ cmd->details.refresh_reveal.rrh
+ = TALER_EXCHANGE_refresh_reveal (exchange,
+ ref->details.refresh_melt.refresh_data_length,
+ ref->details.refresh_melt.refresh_data,
+ ref->details.refresh_melt.noreveal_index,
+ &reveal_cb,
+ is);
+ if (NULL == cmd->details.refresh_reveal.rrh)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ trigger_context_task ();
+ return;
+ case OC_REFRESH_LINK:
+ /* find reveal command */
+ ref = find_command (is,
+ cmd->details.refresh_link.reveal_ref);
+ /* find melt command */
+ ref = find_command (is,
+ ref->details.refresh_reveal.melt_ref);
+ /* find reserve_withdraw command */
+ {
+ unsigned int idx;
+ const struct MeltDetails *md;
+ unsigned int num_melted_coins;
+
+ for (num_melted_coins=0;
+ NULL != ref->details.refresh_melt.melted_coins[num_melted_coins].amount;
+ num_melted_coins++) ;
+ idx = cmd->details.refresh_link.coin_idx;
+ GNUNET_assert (idx < num_melted_coins);
+ md = &ref->details.refresh_melt.melted_coins[idx];
+ ref = find_command (is,
+ md->coin_ref);
+ }
+ GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
+ /* finally, use private key from withdraw sign command */
+ cmd->details.refresh_link.rlh
+ = TALER_EXCHANGE_refresh_link (exchange,
+ &ref->details.reserve_withdraw.coin_priv,
+ &link_cb,
+ is);
+ if (NULL == cmd->details.refresh_link.rlh)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ trigger_context_task ();
+ return;
+ case OC_WIRE:
+ cmd->details.wire.wh = TALER_EXCHANGE_wire (exchange,
+ &wire_cb,
+ is);
+ trigger_context_task ();
+ return;
+ case OC_WIRE_DEPOSITS:
+ if (NULL != cmd->details.wire_deposits.wtid_ref)
+ {
+ ref = find_command (is,
+ cmd->details.wire_deposits.wtid_ref);
+ GNUNET_assert (NULL != ref);
+ cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
+ }
+ cmd->details.wire_deposits.wdh
+ = TALER_EXCHANGE_wire_deposits (exchange,
+ &cmd->details.wire_deposits.wtid,
+ &wire_deposits_cb,
+ is);
+ trigger_context_task ();
+ return;
+ case OC_DEPOSIT_WTID:
+ {
+ struct GNUNET_HashCode h_wire;
+ struct GNUNET_HashCode h_contract;
+ json_t *wire;
+ json_t *contract;
+ const struct Command *coin;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ ref = find_command (is,
+ cmd->details.deposit_wtid.deposit_ref);
+ GNUNET_assert (NULL != ref);
+ coin = find_command (is,
+ ref->details.deposit.coin_ref);
+ GNUNET_assert (NULL != coin);
+ switch (coin->oc)
+ {
+ case OC_WITHDRAW_SIGN:
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ break;
+ case OC_REFRESH_REVEAL:
+ {
+ const struct FreshCoin *fc;
+ unsigned int idx;
+
+ idx = ref->details.deposit.coin_idx;
+ GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
+ fc = &coin->details.refresh_reveal.fresh_coins[idx];
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+
+ wire = json_loads (ref->details.deposit.wire_details,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_assert (NULL != wire);
+ TALER_hash_json (wire,
+ &h_wire);
+ json_decref (wire);
+ contract = json_loads (ref->details.deposit.contract,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_assert (NULL != contract);
+ TALER_hash_json (contract,
+ &h_contract);
+ json_decref (contract);
+ cmd->details.deposit_wtid.dwh
+ = TALER_EXCHANGE_deposit_wtid (exchange,
+ &ref->details.deposit.merchant_priv,
+ &h_wire,
+ &h_contract,
+ &coin_pub,
+ ref->details.deposit.transaction_id,
+ &deposit_wtid_cb,
+ is);
+ trigger_context_task ();
+ }
+ return;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unknown instruction %d at %u (%s)\n",
+ cmd->oc,
+ is->ip,
+ cmd->label);
+ fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Function run when the test terminates (good or bad).
+ * Cleans up our state.
+ *
+ * @param cls the interpreter state.
+ * @param tc unused
+ */
+static void
+do_shutdown (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd;
+ unsigned int i;
+
+ shutdown_task = NULL;
+ for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
+ {
+ switch (cmd->oc)
+ {
+ case OC_END:
+ GNUNET_assert (0);
+ break;
+ case OC_ADMIN_ADD_INCOMING:
+ if (NULL != cmd->details.admin_add_incoming.aih)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_admin_add_incoming_cancel (cmd->details.admin_add_incoming.aih);
+ cmd->details.admin_add_incoming.aih = NULL;
+ }
+ break;
+ case OC_WITHDRAW_STATUS:
+ if (NULL != cmd->details.reserve_status.wsh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_reserve_status_cancel (cmd->details.reserve_status.wsh);
+ cmd->details.reserve_status.wsh = NULL;
+ }
+ break;
+ case OC_WITHDRAW_SIGN:
+ if (NULL != cmd->details.reserve_withdraw.wsh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_reserve_withdraw_cancel (cmd->details.reserve_withdraw.wsh);
+ cmd->details.reserve_withdraw.wsh = NULL;
+ }
+ if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (cmd->details.reserve_withdraw.sig.rsa_signature);
+ cmd->details.reserve_withdraw.sig.rsa_signature = NULL;
+ }
+ if (NULL != cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key)
+ {
+ GNUNET_CRYPTO_rsa_blinding_key_free (cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key);
+ cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key = NULL;
+ }
+ break;
+ case OC_DEPOSIT:
+ if (NULL != cmd->details.deposit.dh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_deposit_cancel (cmd->details.deposit.dh);
+ cmd->details.deposit.dh = NULL;
+ }
+ break;
+ case OC_REFRESH_MELT:
+ if (NULL != cmd->details.refresh_melt.rmh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_refresh_melt_cancel (cmd->details.refresh_melt.rmh);
+ cmd->details.refresh_melt.rmh = NULL;
+ }
+ GNUNET_free_non_null (cmd->details.refresh_melt.fresh_pks);
+ cmd->details.refresh_melt.fresh_pks = NULL;
+ GNUNET_free_non_null (cmd->details.refresh_melt.refresh_data);
+ cmd->details.refresh_melt.refresh_data = NULL;
+ cmd->details.refresh_melt.refresh_data_length = 0;
+ break;
+ case OC_REFRESH_REVEAL:
+ if (NULL != cmd->details.refresh_reveal.rrh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_refresh_reveal_cancel (cmd->details.refresh_reveal.rrh);
+ cmd->details.refresh_reveal.rrh = NULL;
+ }
+ {
+ unsigned int j;
+ struct FreshCoin *fresh_coins;
+
+ fresh_coins = cmd->details.refresh_reveal.fresh_coins;
+ for (j=0;j<cmd->details.refresh_reveal.num_fresh_coins;j++)
+ GNUNET_CRYPTO_rsa_signature_free (fresh_coins[j].sig.rsa_signature);
+ }
+ GNUNET_free_non_null (cmd->details.refresh_reveal.fresh_coins);
+ cmd->details.refresh_reveal.fresh_coins = NULL;
+ cmd->details.refresh_reveal.num_fresh_coins = 0;
+ break;
+ case OC_REFRESH_LINK:
+ if (NULL != cmd->details.refresh_link.rlh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_refresh_link_cancel (cmd->details.refresh_link.rlh);
+ cmd->details.refresh_link.rlh = NULL;
+ }
+ break;
+ case OC_WIRE:
+ if (NULL != cmd->details.wire.wh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_wire_cancel (cmd->details.wire.wh);
+ cmd->details.wire.wh = NULL;
+ }
+ break;
+ case OC_WIRE_DEPOSITS:
+ if (NULL != cmd->details.wire_deposits.wdh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_wire_deposits_cancel (cmd->details.wire_deposits.wdh);
+ cmd->details.wire_deposits.wdh = NULL;
+ }
+ break;
+ case OC_DEPOSIT_WTID:
+ if (NULL != cmd->details.deposit_wtid.dwh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_deposit_wtid_cancel (cmd->details.deposit_wtid.dwh);
+ cmd->details.deposit_wtid.dwh = NULL;
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unknown instruction %d at %u (%s)\n",
+ cmd->oc,
+ i,
+ cmd->label);
+ break;
+ }
+ }
+ if (NULL != is->task)
+ {
+ GNUNET_SCHEDULER_cancel (is->task);
+ is->task = NULL;
+ }
+ GNUNET_free (is);
+ if (NULL != ctx_task)
+ {
+ GNUNET_SCHEDULER_cancel (ctx_task);
+ ctx_task = NULL;
+ }
+ if (NULL != exchange)
+ {
+ TALER_EXCHANGE_disconnect (exchange);
+ exchange = NULL;
+ }
+ if (NULL != ctx)
+ {
+ TALER_EXCHANGE_fini (ctx);
+ ctx = NULL;
+ }
+}
+
+
+/**
+ * Functions of this type are called to provide the retrieved signing and
+ * denomination keys of the exchange. No TALER_EXCHANGE_*() functions should be called
+ * in this callback.
+ *
+ * @param cls closure
+ * @param keys information about keys of the exchange
+ */
+static void
+cert_cb (void *cls,
+ const struct TALER_EXCHANGE_Keys *keys)
+{
+ struct InterpreterState *is = cls;
+
+ /* check that keys is OK */
+#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); GNUNET_SCHEDULER_shutdown(); return; } while (0)
+ ERR (NULL == keys);
+ ERR (0 == keys->num_sign_keys);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Read %u signing keys\n",
+ keys->num_sign_keys);
+ ERR (0 == keys->num_denom_keys);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Read %u denomination keys\n",
+ keys->num_denom_keys);
+#undef ERR
+
+ /* run actual tests via interpreter-loop */
+ is->keys = keys;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Task that runs the context's event loop with the GNUnet scheduler.
+ *
+ * @param cls unused
+ * @param tc scheduler context (unused)
+ */
+static void
+context_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ long timeout;
+ int max_fd;
+ fd_set read_fd_set;
+ fd_set write_fd_set;
+ fd_set except_fd_set;
+ struct GNUNET_NETWORK_FDSet *rs;
+ struct GNUNET_NETWORK_FDSet *ws;
+ struct GNUNET_TIME_Relative delay;
+
+ ctx_task = NULL;
+ TALER_EXCHANGE_perform (ctx);
+ max_fd = -1;
+ timeout = -1;
+ FD_ZERO (&read_fd_set);
+ FD_ZERO (&write_fd_set);
+ FD_ZERO (&except_fd_set);
+ TALER_EXCHANGE_get_select_info (ctx,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set,
+ &max_fd,
+ &timeout);
+ if (timeout >= 0)
+ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+ timeout);
+ else
+ delay = GNUNET_TIME_UNIT_FOREVER_REL;
+ rs = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (rs,
+ &read_fd_set,
+ max_fd + 1);
+ ws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (ws,
+ &write_fd_set,
+ max_fd + 1);
+ ctx_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ delay,
+ rs,
+ ws,
+ &context_task,
+ cls);
+ GNUNET_NETWORK_fdset_destroy (rs);
+ GNUNET_NETWORK_fdset_destroy (ws);
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param config configuration
+ */
+static void
+run (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct InterpreterState *is;
+ static struct MeltDetails melt_coins_1[] = {
+ { .amount = "EUR:4",
+ .coin_ref = "refresh-withdraw-coin-1" },
+ { NULL, NULL }
+ };
+ static const char *melt_fresh_amounts_1[] = {
+ "EUR:1",
+ "EUR:1",
+ "EUR:1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.1",
+ "EUR:0.01",
+ "EUR:0.01",
+ "EUR:0.01",
+ "EUR:0.01",
+ "EUR:0.01",
+ "EUR:0.01",
+ /* with 0.01 withdraw fees (except for 1ct coins),
+ this totals up to exactly EUR:3.97, and with
+ the 0.03 refresh fee, to EUR:4.0*/
+ NULL
+ };
+ static struct Command commands[] =
+ {
+ /* *************** start of /wire testing ************** */
+
+#if WIRE_TEST
+ { .oc = OC_WIRE,
+ .label = "wire-test",
+ /* /wire/test replies with a 302 redirect */
+ .expected_response_code = MHD_HTTP_FOUND,
+ .details.wire.format = "test" },
+#endif
+#if WIRE_SEPA
+ { .oc = OC_WIRE,
+ .label = "wire-sepa",
+ /* /wire/sepa replies with a 200 redirect */
+ .expected_response_code = MHD_HTTP_OK,
+ .details.wire.format = "sepa" },
+#endif
+ /* *************** end of /wire testing ************** */
+
+#if WIRE_TEST
+ /* None of this works if 'test' is not allowed as we do
+ /admin/add/incoming with format 'test' */
+
+ /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
+ { .oc = OC_ADMIN_ADD_INCOMING,
+ .label = "create-reserve-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account_number\":42 }",
+ .details.admin_add_incoming.amount = "EUR:5.01" },
+ /* Withdraw a 5 EUR coin, at fee of 1 ct */
+ { .oc = OC_WITHDRAW_SIGN,
+ .label = "withdraw-coin-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.reserve_withdraw.reserve_reference = "create-reserve-1",
+ .details.reserve_withdraw.amount = "EUR:5" },
+ /* Check that deposit and withdraw operation are in history, and
+ that the balance is now at zero */
+ { .oc = OC_WITHDRAW_STATUS,
+ .label = "withdraw-status-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.reserve_status.reserve_reference = "create-reserve-1",
+ .details.reserve_status.expected_balance = "EUR:0" },
+ /* Try to deposit the 5 EUR coin (in full) */
+ { .oc = OC_DEPOSIT,
+ .label = "deposit-simple",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.deposit.amount = "EUR:5",
+ .details.deposit.coin_ref = "withdraw-coin-1",
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":42 }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
+ .details.deposit.transaction_id = 1 },
+
+ /* Try to overdraw funds ... */
+ { .oc = OC_WITHDRAW_SIGN,
+ .label = "withdraw-coin-2",
+ .expected_response_code = MHD_HTTP_PAYMENT_REQUIRED,
+ .details.reserve_withdraw.reserve_reference = "create-reserve-1",
+ .details.reserve_withdraw.amount = "EUR:5" },
+
+ /* Try to double-spend the 5 EUR coin with different wire details */
+ { .oc = OC_DEPOSIT,
+ .label = "deposit-double-1",
+ .expected_response_code = MHD_HTTP_FORBIDDEN,
+ .details.deposit.amount = "EUR:5",
+ .details.deposit.coin_ref = "withdraw-coin-1",
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":43 }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
+ .details.deposit.transaction_id = 1 },
+ /* Try to double-spend the 5 EUR coin at the same merchant (but different
+ transaction ID) */
+ { .oc = OC_DEPOSIT,
+ .label = "deposit-double-2",
+ .expected_response_code = MHD_HTTP_FORBIDDEN,
+ .details.deposit.amount = "EUR:5",
+ .details.deposit.coin_ref = "withdraw-coin-1",
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":42 }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
+ .details.deposit.transaction_id = 2 },
+ /* Try to double-spend the 5 EUR coin at the same merchant (but different
+ contract) */
+ { .oc = OC_DEPOSIT,
+ .label = "deposit-double-3",
+ .expected_response_code = MHD_HTTP_FORBIDDEN,
+ .details.deposit.amount = "EUR:5",
+ .details.deposit.coin_ref = "withdraw-coin-1",
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":42 }",
+ .details.deposit.contract = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }",
+ .details.deposit.transaction_id = 1 },
+
+ /* ***************** /refresh testing ******************** */
+
+ /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct */
+ { .oc = OC_ADMIN_ADD_INCOMING,
+ .label = "refresh-create-reserve-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account_number\":424 }",
+ .details.admin_add_incoming.amount = "EUR:5.01" },
+ /* Withdraw a 5 EUR coin, at fee of 1 ct */
+ { .oc = OC_WITHDRAW_SIGN,
+ .label = "refresh-withdraw-coin-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.reserve_withdraw.reserve_reference = "refresh-create-reserve-1",
+ .details.reserve_withdraw.amount = "EUR:5" },
+ /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
+ (merchant would receive EUR:0.99 due to 1 ct deposit fee) */
+ { .oc = OC_DEPOSIT,
+ .label = "refresh-deposit-partial",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.deposit.amount = "EUR:1",
+ .details.deposit.coin_ref = "refresh-withdraw-coin-1",
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":42 }",
+ .details.deposit.contract = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }",
+ .details.deposit.transaction_id = 42421 },
+
+ /* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
+
+ { .oc = OC_REFRESH_MELT,
+ .label = "refresh-melt-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.refresh_melt.melted_coins = melt_coins_1,
+ .details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
+
+
+ /* Complete (successful) melt operation, and withdraw the coins */
+ { .oc = OC_REFRESH_REVEAL,
+ .label = "refresh-reveal-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.refresh_reveal.melt_ref = "refresh-melt-1" },
+
+ /* Test that /refresh/link works */
+ { .oc = OC_REFRESH_LINK,
+ .label = "refresh-link-1",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.refresh_link.reveal_ref = "refresh-reveal-1" },
+
+
+ /* Test successfully spending coins from the refresh operation:
+ first EUR:1 */
+ { .oc = OC_DEPOSIT,
+ .label = "refresh-deposit-refreshed-1a",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.deposit.amount = "EUR:1",
+ .details.deposit.coin_ref = "refresh-reveal-1",
+ .details.deposit.coin_idx = 0,
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":42 }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
+ .details.deposit.transaction_id = 2 },
+
+ /* Test successfully spending coins from the refresh operation:
+ finally EUR:0.1 */
+ { .oc = OC_DEPOSIT,
+ .label = "refresh-deposit-refreshed-1b",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.deposit.amount = "EUR:0.1",
+ .details.deposit.coin_ref = "refresh-reveal-1",
+ .details.deposit.coin_idx = 4,
+ .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account_number\":42 }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
+ .details.deposit.transaction_id = 2 },
+
+ /* Test running a failing melt operation (same operation again must fail) */
+ { .oc = OC_REFRESH_MELT,
+ .label = "refresh-melt-failing",
+ .expected_response_code = MHD_HTTP_FORBIDDEN,
+ .details.refresh_melt.melted_coins = melt_coins_1,
+ .details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
+
+ // FIXME: also test with coin that was already melted
+ // (signature differs from coin that was deposited...)
+ /* *************** end of /refresh testing ************** */
+
+ /* ************** Test tracking API ******************** */
+ /* Try resolving a deposit's WTID, as we never triggered
+ execution of transactions, the answer should be that
+ the exchange knows about the deposit, but has no WTID yet. */
+ { .oc = OC_DEPOSIT_WTID,
+ .label = "deposit-wtid-found",
+ .expected_response_code = MHD_HTTP_ACCEPTED,
+ .details.deposit_wtid.deposit_ref = "deposit-simple" },
+ /* Try resolving a deposit's WTID for a failed deposit.
+ As the deposit failed, the answer should be that
+ the exchange does NOT know about the deposit. */
+ { .oc = OC_DEPOSIT_WTID,
+ .label = "deposit-wtid-failing",
+ .expected_response_code = MHD_HTTP_NOT_FOUND,
+ .details.deposit_wtid.deposit_ref = "deposit-double-2" },
+ /* Try resolving an undefined (all zeros) WTID; this
+ should fail as obviously the exchange didn't use that
+ WTID value for any transaction. */
+ { .oc = OC_WIRE_DEPOSITS,
+ .label = "wire-deposit-failing",
+ .expected_response_code = MHD_HTTP_NOT_FOUND },
+
+ /* TODO: trigger aggregation logic and then check the
+ cases where tracking succeeds! */
+
+ /* ************** End of tracking API testing************* */
+
+
+#endif
+
+ { .oc = OC_END }
+ };
+
+ is = GNUNET_new (struct InterpreterState);
+ is->commands = commands;
+
+ ctx = TALER_EXCHANGE_init ();
+ GNUNET_assert (NULL != ctx);
+ ctx_task = GNUNET_SCHEDULER_add_now (&context_task,
+ ctx);
+ exchange = TALER_EXCHANGE_connect (ctx,
+ "http://localhost:8081",
+ &cert_cb, is,
+ TALER_EXCHANGE_OPTION_END);
+ GNUNET_assert (NULL != exchange);
+ shutdown_task
+ = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 150),
+ &do_shutdown, is);
+}
+
+
+/**
+ * Main function for the testcase for the exchange API.
+ *
+ * @param argc expected to be 1
+ * @param argv expected to only contain the program name
+ */
+int
+main (int argc,
+ char * const *argv)
+{
+ struct GNUNET_OS_Process *proc;
+ struct GNUNET_OS_Process *exchanged;
+
+ GNUNET_log_setup ("test-exchange-api",
+ "WARNING",
+ NULL);
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-d", "test-exchange-home",
+ "-m", "test-exchange-home/master.priv",
+ NULL);
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_destroy (proc);
+ exchanged = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-httpd",
+ "taler-exchange-httpd",
+ "-d", "test-exchange-home",
+ NULL);
+ /* give child time to start and bind against the socket */
+ fprintf (stderr, "Waiting for taler-exchange-httpd to be ready");
+ do
+ {
+ fprintf (stderr, ".");
+ sleep (1);
+ }
+ while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
+ fprintf (stderr, "\n");
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_run (&run, NULL);
+ GNUNET_OS_process_kill (exchanged,
+ SIGTERM);
+ GNUNET_OS_process_wait (exchanged);
+ GNUNET_OS_process_destroy (exchanged);
+ return (GNUNET_OK == result) ? 0 : 1;
+}
+
+/* end of test_exchange_api.c */
diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am
new file mode 100644
index 000000000..4ffabd15d
--- /dev/null
+++ b/src/exchange-tools/Makefile.am
@@ -0,0 +1,81 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+bin_PROGRAMS = \
+ taler-auditor-sign \
+ taler-exchange-keyup \
+ taler-exchange-keycheck \
+ taler-exchange-reservemod \
+ taler-exchange-sepa \
+ taler-exchange-dbinit
+
+taler_exchange_keyup_SOURCES = \
+ taler-exchange-keyup.c
+taler_exchange_keyup_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/pq/libtalerpq.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -lgnunetutil $(XLIB)
+taler_exchange_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS)
+
+taler_auditor_sign_SOURCES = \
+ taler-auditor-sign.c
+taler_auditor_sign_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -lgnunetutil $(XLIB)
+
+
+taler_exchange_sepa_SOURCES = \
+ taler-exchange-sepa.c
+taler_exchange_sepa_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil -ljansson $(XLIB)
+taler_exchange_sepa_LDFLAGS = $(POSTGRESQL_LDFLAGS)
+
+taler_exchange_keycheck_SOURCES = \
+ taler-exchange-keycheck.c
+taler_exchange_keycheck_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -lgnunetutil $(XLIB)
+taler_exchange_keycheck_LDFLAGS = $(POSTGRESQL_LDFLAGS)
+
+taler_exchange_reservemod_SOURCES = \
+ taler-exchange-reservemod.c
+taler_exchange_reservemod_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/pq/libtalerpq.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -lgnunetutil -ljansson $(XLIB)
+taler_exchange_reservemod_LDFLAGS = \
+ $(POSTGRESQL_LDFLAGS)
+taler_exchange_reservemod_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/pq/ \
+ $(POSTGRESQL_CPPFLAGS)
+
+taler_exchange_dbinit_SOURCES = \
+ taler-exchange-dbinit.c
+taler_exchange_dbinit_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/pq/libtalerpq.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -lgnunetutil $(XLIB)
+taler_exchange_dbinit_LDFLAGS = \
+ $(POSTGRESQL_LDFLAGS)
+taler_exchange_dbinit_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/pq/ \
+ $(POSTGRESQL_CPPFLAGS)
diff --git a/src/exchange-tools/taler-auditor-sign.c b/src/exchange-tools/taler-auditor-sign.c
new file mode 100644
index 000000000..e4821f411
--- /dev/null
+++ b/src/exchange-tools/taler-auditor-sign.c
@@ -0,0 +1,321 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-auditor-sign.c
+ * @brief Tool used by the auditor to sign the exchange's master key and the
+ * denomination key(s).
+ * @author Christian Grothoff
+ */
+#include <platform.h>
+#include "taler_exchangedb_lib.h"
+
+
+/**
+ * Are we running in verbose mode?
+ */
+static int verbose;
+
+/**
+ * Filename of the auditor's private key.
+ */
+static char *auditor_key_file;
+
+/**
+ * Exchange's public key (in Crockford base32 encoding).
+ */
+static char *exchange_public_key;
+
+/**
+ * File with the Exchange's denomination keys to sign, itself
+ * signed by the Exchange's public key.
+ */
+static char *exchange_request_file;
+
+/**
+ * Where should we write the auditor's signature?
+ */
+static char *output_file;
+
+/**
+ * Master public key of the exchange.
+ */
+static struct TALER_MasterPublicKeyP master_public_key;
+
+
+/**
+ * Print denomination key details for diagnostics.
+ *
+ * @param dk denomination key to print
+ */
+static void
+print_dk (const struct TALER_DenominationKeyValidityPS *dk)
+{
+ struct TALER_Amount a;
+ char *s;
+
+ fprintf (stdout,
+ "Denomination key hash: %s\n",
+ GNUNET_h2s_full (&dk->denom_hash));
+ TALER_amount_ntoh (&a,
+ &dk->value);
+ fprintf (stdout,
+ "Value: %s\n",
+ s = TALER_amount_to_string (&a));
+ GNUNET_free (s);
+ TALER_amount_ntoh (&a,
+ &dk->fee_withdraw);
+ fprintf (stdout,
+ "Withdraw fee: %s\n",
+ s = TALER_amount_to_string (&a));
+ GNUNET_free (s);
+ TALER_amount_ntoh (&a,
+ &dk->fee_deposit);
+ fprintf (stdout,
+ "Deposit fee: %s\n",
+ s = TALER_amount_to_string (&a));
+ GNUNET_free (s);
+ TALER_amount_ntoh (&a,
+ &dk->fee_refresh);
+ fprintf (stdout,
+ "Refresh fee: %s\n",
+ s = TALER_amount_to_string (&a));
+ GNUNET_free (s);
+
+ fprintf (stdout,
+ "Validity start time: %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->start)));
+ fprintf (stdout,
+ "Withdraw end time: %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_withdraw)));
+ fprintf (stdout,
+ "Deposit end time: %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_spend)));
+ fprintf (stdout,
+ "Legal dispute end time: %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_legal)));
+
+ fprintf (stdout,
+ "\n");
+}
+
+
+/**
+ * The main function of the taler-auditor-sign tool. This tool is used
+ * to sign a exchange's master and denomination keys, affirming that the
+ * auditor is aware of them and will validate the exchange's database with
+ * respect to these keys.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'a', "auditor-key", "FILE",
+ "file containing the private key of the auditor", 1,
+ &GNUNET_GETOPT_set_filename, &auditor_key_file},
+ TALER_GETOPT_OPTION_HELP ("Private key of the auditor to use for signing"),
+ {'m', "exchange-key", "KEY",
+ "public key of the exchange (Crockford base32 encoded)", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_public_key},
+ {'r', "exchange-request", "FILE",
+ "set of keys the exchange requested the auditor to sign", 1,
+ &GNUNET_GETOPT_set_string, &exchange_request_file},
+ {'o', "output", "FILE",
+ "where to write our signature", 1,
+ &GNUNET_GETOPT_set_string, &output_file},
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+ GNUNET_GETOPT_OPTION_END
+ };
+ struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
+ struct TALER_AuditorSignatureP *sigs;
+ struct TALER_AuditorPublicKeyP apub;
+ struct GNUNET_DISK_FileHandle *fh;
+ struct TALER_DenominationKeyValidityPS *dks;
+ unsigned int dks_len;
+ struct TALER_ExchangeKeyValidityPS kv;
+ off_t in_size;
+ unsigned int i;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-keyup",
+ "WARNING",
+ NULL));
+ if (GNUNET_GETOPT_run ("taler-exchange-keyup",
+ options,
+ argc, argv) < 0)
+ return 1;
+ if (NULL == auditor_key_file)
+ {
+ fprintf (stderr,
+ "Auditor key file not given\n");
+ return 1;
+ }
+ eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (auditor_key_file);
+ if (NULL == eddsa_priv)
+ {
+ fprintf (stderr,
+ "Failed to initialize auditor key from file `%s'\n",
+ auditor_key_file);
+ return 1;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (eddsa_priv,
+ &apub.eddsa_pub);
+ if (NULL == exchange_public_key)
+ {
+ fprintf (stderr,
+ "Exchange public key not given\n");
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (exchange_public_key,
+ strlen (exchange_public_key),
+ &master_public_key,
+ sizeof (master_public_key)))
+ {
+ fprintf (stderr,
+ "Public key `%s' malformed\n",
+ exchange_public_key);
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ if (NULL == exchange_request_file)
+ {
+ fprintf (stderr,
+ "Exchange signing request not given\n");
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ fh = GNUNET_DISK_file_open (exchange_request_file,
+ GNUNET_DISK_OPEN_READ,
+ GNUNET_DISK_PERM_NONE);
+ if (NULL == fh)
+ {
+ fprintf (stderr,
+ "Failed to open file `%s': %s\n",
+ exchange_request_file,
+ STRERROR (errno));
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_file_handle_size (fh,
+ &in_size))
+ {
+ fprintf (stderr,
+ "Failed to obtain input file size `%s': %s\n",
+ exchange_request_file,
+ STRERROR (errno));
+ GNUNET_DISK_file_close (fh);
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ if (0 != (in_size % sizeof (struct TALER_DenominationKeyValidityPS)))
+ {
+ fprintf (stderr,
+ "Input file size of file `%s' is invalid\n",
+ exchange_request_file);
+ GNUNET_DISK_file_close (fh);
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ dks_len = in_size / sizeof (struct TALER_DenominationKeyValidityPS);
+ kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS);
+ kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS));
+ kv.master = master_public_key;
+ dks = GNUNET_new_array (dks_len,
+ struct TALER_DenominationKeyValidityPS);
+ sigs = GNUNET_new_array (dks_len,
+ struct TALER_AuditorSignatureP);
+ if (in_size !=
+ GNUNET_DISK_file_read (fh,
+ dks,
+ in_size))
+ {
+ fprintf (stderr,
+ "Failed to read input file `%s': %s\n",
+ exchange_request_file,
+ STRERROR (errno));
+ GNUNET_DISK_file_close (fh);
+ GNUNET_free (sigs);
+ GNUNET_free (dks);
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+ GNUNET_DISK_file_close (fh);
+ for (i=0;i<dks_len;i++)
+ {
+ struct TALER_DenominationKeyValidityPS *dk = &dks[i];
+
+ if (verbose)
+ print_dk (dk);
+ kv.start = dk->start;
+ kv.expire_withdraw = dk->expire_withdraw;
+ kv.expire_spend = dk->expire_spend;
+ kv.expire_legal = dk->expire_legal;
+ kv.value = dk->value;
+ kv.fee_withdraw = dk->fee_withdraw;
+ kv.fee_deposit = dk->fee_deposit;
+ kv.fee_refresh = dk->fee_refresh;
+ kv.denom_hash = dk->denom_hash;
+
+ /* Finally sign ... */
+ GNUNET_CRYPTO_eddsa_sign (eddsa_priv,
+ &kv.purpose,
+ &sigs[i].eddsa_sig);
+
+
+ }
+
+ if (NULL == output_file)
+ {
+ fprintf (stderr,
+ "Output file not given\n");
+ GNUNET_free (dks);
+ GNUNET_free (sigs);
+ GNUNET_free (eddsa_priv);
+ return 1;
+ }
+
+ /* write result to disk */
+ if (GNUNET_OK !=
+ TALER_EXCHANGEDB_auditor_write (output_file,
+ &apub,
+ sigs,
+ &master_public_key,
+ dks_len,
+ dks))
+ {
+ fprintf (stderr,
+ "Failed to write to file `%s': %s\n",
+ output_file,
+ STRERROR (errno));
+ GNUNET_free (sigs);
+ GNUNET_free (dks);
+ return 1;
+ }
+ GNUNET_free (sigs);
+ GNUNET_free (dks);
+ GNUNET_free (eddsa_priv);
+ return 0;
+}
+
+/* end of taler-auditor-sign.c */
diff --git a/src/exchange-tools/taler-exchange-dbinit.c b/src/exchange-tools/taler-exchange-dbinit.c
new file mode 100644
index 000000000..43a070228
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-dbinit.c
@@ -0,0 +1,105 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange-tools/taler-exchange-dbinit.c
+ * @brief Create tables for the exchange database.
+ * @author Florian Dold
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <libpq-fe.h>
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Exchange directory with the keys.
+ */
+static char *exchange_base_dir;
+
+/**
+ * Our configuration.
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Our DB plugin.
+ */
+static struct TALER_EXCHANGEDB_Plugin *plugin;
+
+
+/**
+ * The main function of the database initialization tool.
+ * Used to initialize the Taler Exchange's database.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'d', "exchange-dir", "DIR",
+ "exchange directory", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_base_dir},
+ GNUNET_GETOPT_OPTION_HELP ("Initialize Taler Exchange database"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ if (GNUNET_GETOPT_run ("taler-exchange-dbinit",
+ options,
+ argc, argv) < 0)
+ return 1;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-dbinit",
+ "INFO",
+ NULL));
+ if (NULL == exchange_base_dir)
+ {
+ fprintf (stderr,
+ "Exchange base directory not given.\n");
+ return 1;
+ }
+ cfg = TALER_config_load (exchange_base_dir);
+ if (NULL == cfg)
+ {
+ fprintf (stderr,
+ "Failed to load exchange configuration.\n");
+ return 1;
+ }
+ if (NULL ==
+ (plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
+ {
+ fprintf (stderr,
+ "Failed to initialize database plugin.\n");
+ return 1;
+ }
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ GNUNET_NO))
+ {
+ fprintf (stderr,
+ "Failed to initialize database.\n");
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ return 1;
+ }
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ return 0;
+}
+
+/* end of taler-exchange-dbinit.c */
diff --git a/src/exchange-tools/taler-exchange-keycheck.c b/src/exchange-tools/taler-exchange-keycheck.c
new file mode 100644
index 000000000..d6566cd03
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-keycheck.c
@@ -0,0 +1,247 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-keycheck.c
+ * @brief Check exchange keys for validity. Reads the signing and denomination
+ * keys from the exchange directory and checks to make sure they are
+ * well-formed. This is purely a diagnostic tool.
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include <platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchangedb_lib.h"
+
+/**
+ * Exchange directory with the keys.
+ */
+static char *exchange_directory;
+
+/**
+ * Our configuration.
+ */
+static struct GNUNET_CONFIGURATION_Handle *kcfg;
+
+
+/**
+ * Function called on each signing key.
+ *
+ * @param cls closure (NULL)
+ * @param filename name of the file the key came from
+ * @param ski the sign key
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+signkeys_iter (void *cls,
+ const char *filename,
+ const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Iterating over key `%s' for start time %s\n",
+ filename,
+ GNUNET_STRINGS_absolute_time_to_string
+ (GNUNET_TIME_absolute_ntoh (ski->issue.start)));
+
+ if (ntohl (ski->issue.purpose.size) !=
+ (sizeof (struct TALER_ExchangeSigningKeyValidityPS) -
+ offsetof (struct TALER_ExchangeSigningKeyValidityPS,
+ purpose)))
+ {
+ fprintf (stderr,
+ "Signing key `%s' has invalid purpose size\n",
+ filename);
+ return GNUNET_SYSERR;
+ }
+ if ( (0 != GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us % 1000000) ||
+ (0 != GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us % 1000000) ||
+ (0 != GNUNET_TIME_absolute_ntoh (ski->issue.end).abs_value_us % 1000000) )
+ {
+ fprintf (stderr,
+ "Timestamps are not multiples of a round second\n");
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
+ &ski->issue.purpose,
+ &ski->issue.signature.eddsa_signature,
+ &ski->issue.master_public_key.eddsa_pub))
+ {
+ fprintf (stderr,
+ "Signing key `%s' has invalid signature\n",
+ filename);
+ return GNUNET_SYSERR;
+ }
+ printf ("Signing key `%s' valid\n",
+ filename);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check signing keys.
+ *
+ * @return #GNUNET_OK if the keys are OK
+ * #GNUNET_NO if not
+ */
+static int
+exchange_signkeys_check ()
+{
+ if (0 > TALER_EXCHANGEDB_signing_keys_iterate (exchange_directory,
+ &signkeys_iter,
+ NULL))
+ return GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called on each denomination key.
+ *
+ * @param cls closure (NULL)
+ * @param dki the denomination key
+ * @param alias coin alias
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+denomkeys_iter (void *cls,
+ const char *alias,
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ struct GNUNET_HashCode hc;
+
+ if (ntohl (dki->issue.properties.purpose.size) !=
+ sizeof (struct TALER_DenominationKeyValidityPS))
+ {
+ fprintf (stderr,
+ "Denomination key for `%s' has invalid purpose size\n",
+ alias);
+ return GNUNET_SYSERR;
+ }
+
+ if ( (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us % 1000000) ||
+ (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us % 1000000) ||
+ (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_legal).abs_value_us % 1000000) ||
+ (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us % 1000000) )
+ {
+ fprintf (stderr,
+ "Timestamps are not multiples of a round second\n");
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
+ &dki->issue.properties.purpose,
+ &dki->issue.signature.eddsa_signature,
+ &dki->issue.properties.master.eddsa_pub))
+ {
+ fprintf (stderr,
+ "Denomination key for `%s' has invalid signature\n",
+ alias);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+ &hc);
+ if (0 != memcmp (&hc,
+ &dki->issue.properties.denom_hash,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ fprintf (stderr,
+ "Public key for `%s' does not match signature\n",
+ alias);
+ return GNUNET_SYSERR;
+ }
+ printf ("Denomination key `%s' is valid\n",
+ alias);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check denomination keys.
+ *
+ * @return #GNUNET_OK if the keys are OK
+ * #GNUNET_NO if not
+ */
+static int
+exchange_denomkeys_check ()
+{
+ if (0 > TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory,
+ &denomkeys_iter,
+ NULL))
+ return GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
+/**
+ * The main function of the keyup tool
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_HELP ("gnunet-exchange-keycheck OPTIONS"),
+ {'d', "directory", "DIRECTORY",
+ "exchange directory with keys to check", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_directory},
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-keycheck",
+ "WARNING",
+ NULL));
+
+ if (GNUNET_GETOPT_run ("taler-exchange-keycheck",
+ options,
+ argc, argv) < 0)
+ return 1;
+ if (NULL == exchange_directory)
+ {
+ fprintf (stderr,
+ "Exchange directory not given\n");
+ return 1;
+ }
+
+ kcfg = TALER_config_load (exchange_directory);
+ if (NULL == kcfg)
+ {
+ fprintf (stderr,
+ "Failed to load exchange configuration\n");
+ return 1;
+ }
+ if ( (GNUNET_OK != exchange_signkeys_check ()) ||
+ (GNUNET_OK != exchange_denomkeys_check ()) )
+ {
+ GNUNET_CONFIGURATION_destroy (kcfg);
+ return 1;
+ }
+ GNUNET_CONFIGURATION_destroy (kcfg);
+ return 0;
+}
+
+/* end of taler-exchange-keycheck.c */
diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c
new file mode 100644
index 000000000..779e3a3d3
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -0,0 +1,1039 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-keyup.c
+ * @brief Update the exchange's keys for coins and signatures,
+ * using the exchange's offline master key.
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include <platform.h>
+#include "taler_exchangedb_lib.h"
+
+/**
+ * When generating filenames from a cryptographic hash, we do not use
+ * all 512 bits but cut off after this number of characters (in
+ * base32-encoding). Base32 is 5 bit per character, and given that we
+ * have very few coin types we hash, at 100 bits the chance of
+ * collision (by accident over tiny set -- birthday paradox does not
+ * apply here!) is negligible.
+ */
+#define HASH_CUTOFF 20
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Struct with all of the key information for a kind of coin. Hashed
+ * to generate a unique directory name per coin type.
+ */
+struct CoinTypeNBOP
+{
+ /**
+ * How long are the signatures legally valid?
+ */
+ struct GNUNET_TIME_RelativeNBO duration_legal;
+
+ /**
+ * How long can the coin be spend?
+ */
+ struct GNUNET_TIME_RelativeNBO duration_spend;
+
+ /**
+ * How long can the coin be withdrawn (generated)?
+ */
+ struct GNUNET_TIME_RelativeNBO duration_withdraw;
+
+ /**
+ * What is the value of the coin?
+ */
+ struct TALER_AmountNBO value;
+
+ /**
+ * What is the fee charged for withdrawl?
+ */
+ struct TALER_AmountNBO fee_withdraw;
+
+ /**
+ * What is the fee charged for deposits?
+ */
+ struct TALER_AmountNBO fee_deposit;
+
+ /**
+ * What is the fee charged for melting?
+ */
+ struct TALER_AmountNBO fee_refresh;
+
+ /**
+ * Key size in NBO.
+ */
+ uint32_t rsa_keysize;
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Set of all of the parameters that chracterize a coin.
+ */
+struct CoinTypeParams
+{
+
+ /**
+ * How long are the signatures legally valid? Should be
+ * significantly larger than @e duration_spend (i.e. years).
+ */
+ struct GNUNET_TIME_Relative duration_legal;
+
+
+ /**
+ * How long can the coin be spend? Should be significantly
+ * larger than @e duration_withdraw (i.e. years).
+ */
+ struct GNUNET_TIME_Relative duration_spend;
+
+ /**
+ * How long can the coin be withdrawn (generated)? Should be small
+ * enough to limit how many coins will be signed into existence with
+ * the same key, but large enough to still provide a reasonable
+ * anonymity set.
+ */
+ struct GNUNET_TIME_Relative duration_withdraw;
+
+ /**
+ * How much should coin creation (@e duration_withdraw) duration
+ * overlap with the next coin? Basically, the starting time of two
+ * coins is always @e duration_withdraw - @e duration_overlap apart.
+ */
+ struct GNUNET_TIME_Relative duration_overlap;
+
+ /**
+ * What is the value of the coin?
+ */
+ struct TALER_Amount value;
+
+ /**
+ * What is the fee charged for withdrawl?
+ */
+ struct TALER_Amount fee_withdraw;
+
+ /**
+ * What is the fee charged for deposits?
+ */
+ struct TALER_Amount fee_deposit;
+
+ /**
+ * What is the fee charged for melting?
+ */
+ struct TALER_Amount fee_refresh;
+
+ /**
+ * Time at which this coin is supposed to become valid.
+ */
+ struct GNUNET_TIME_Absolute anchor;
+
+ /**
+ * Length of the RSA key in bits.
+ */
+ uint32_t rsa_keysize;
+};
+
+
+/**
+ * Filename of the master private key.
+ */
+static char *masterkeyfile;
+
+/**
+ * Filename where to write denomination key signing
+ * requests for the auditor (optional, can be NULL).
+ */
+static char *auditorrequestfile;
+
+/**
+ * Handle for writing the output for the auditor.
+ */
+static FILE *auditor_output_file;
+
+/**
+ * Director of the exchange, containing the keys.
+ */
+static char *exchange_directory;
+
+/**
+ * Time to pretend when the key update is executed.
+ */
+static char *pretend_time_str;
+
+/**
+ * Handle to the exchange's configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *kcfg;
+
+/**
+ * Time when the key update is executed. Either the actual current time, or a
+ * pretended time.
+ */
+static struct GNUNET_TIME_Absolute now;
+
+/**
+ * Master private key of the exchange.
+ */
+static struct TALER_MasterPrivateKeyP master_priv;
+
+/**
+ * Master public key of the exchange.
+ */
+static struct TALER_MasterPublicKeyP master_public_key;
+
+/**
+ * Until what time do we provide keys?
+ */
+static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
+
+
+/**
+ * Obtain the name of the directory we use to store signing
+ * keys created at time @a start.
+ *
+ * @param start time at which we create the signing key
+ * @return name of the directory we should use, basically "$EXCHANGEDIR/$TIME/";
+ * (valid until next call to this function)
+ */
+static const char *
+get_signkey_file (struct GNUNET_TIME_Absolute start)
+{
+ static char dir[4096];
+
+ GNUNET_snprintf (dir,
+ sizeof (dir),
+ "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS DIR_SEPARATOR_STR "%llu",
+ exchange_directory,
+ (unsigned long long) start.abs_value_us);
+ return dir;
+}
+
+
+/**
+ * Hash the data defining the coin type. Exclude information that may
+ * not be the same for all instances of the coin type (i.e. the
+ * anchor, overlap).
+ *
+ * @param p coin parameters to convert to a hash
+ * @param[out] hash set to the hash matching @a p
+ */
+static void
+hash_coin_type (const struct CoinTypeParams *p,
+ struct GNUNET_HashCode *hash)
+{
+ struct CoinTypeNBOP p_nbo;
+
+ memset (&p_nbo,
+ 0,
+ sizeof (struct CoinTypeNBOP));
+ p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
+ p_nbo.duration_legal = GNUNET_TIME_relative_hton (p->duration_legal);
+ p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
+ TALER_amount_hton (&p_nbo.value,
+ &p->value);
+ TALER_amount_hton (&p_nbo.fee_withdraw,
+ &p->fee_withdraw);
+ TALER_amount_hton (&p_nbo.fee_deposit,
+ &p->fee_deposit);
+ TALER_amount_hton (&p_nbo.fee_refresh,
+ &p->fee_refresh);
+ p_nbo.rsa_keysize = htonl (p->rsa_keysize);
+ GNUNET_CRYPTO_hash (&p_nbo,
+ sizeof (struct CoinTypeNBOP),
+ hash);
+}
+
+
+/**
+ * Obtain the name of the directory we should use to store coins of
+ * the given type. The directory name has the format
+ * "$EXCHANGEDIR/$VALUE/$HASH/" where "$VALUE" represents the value of the
+ * coin and "$HASH" encodes all of the coin's parameters, generating a
+ * unique string for each type of coin. Note that the "$HASH"
+ * includes neither the absolute creation time nor the key of the
+ * coin, thus the files in the subdirectory really just refer to the
+ * same type of coins, not the same coin.
+ *
+ * @param p coin parameters to convert to a directory name
+ * @return directory name (valid until next call to this function)
+ */
+static const char *
+get_cointype_dir (const struct CoinTypeParams *p)
+{
+ static char dir[4096];
+ struct GNUNET_HashCode hash;
+ char *hash_str;
+ char *val_str;
+ size_t i;
+
+ hash_coin_type (p, &hash);
+ hash_str = GNUNET_STRINGS_data_to_string_alloc (&hash,
+ sizeof (struct GNUNET_HashCode));
+ GNUNET_assert (NULL != hash_str);
+ GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
+ hash_str[HASH_CUTOFF] = 0;
+
+ val_str = TALER_amount_to_string (&p->value);
+ for (i = 0; i < strlen (val_str); i++)
+ if ( (':' == val_str[i]) ||
+ ('.' == val_str[i]) )
+ val_str[i] = '_';
+
+ GNUNET_snprintf (dir,
+ sizeof (dir),
+ "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR "%s-%s",
+ exchange_directory,
+ val_str,
+ hash_str);
+ GNUNET_free (hash_str);
+ GNUNET_free (val_str);
+ return dir;
+}
+
+
+/**
+ * Obtain the name of the file we would use to store the key
+ * information for a coin of the given type @a p and validity
+ * start time @a start
+ *
+ * @param p parameters for the coin
+ * @param start when would the coin begin to be issued
+ * @return name of the file to use for this coin
+ * (valid until next call to this function)
+ */
+static const char *
+get_cointype_file (const struct CoinTypeParams *p,
+ struct GNUNET_TIME_Absolute start)
+{
+ static char filename[4096];
+ const char *dir;
+
+ dir = get_cointype_dir (p);
+ GNUNET_snprintf (filename,
+ sizeof (filename),
+ "%s" DIR_SEPARATOR_STR "%llu",
+ dir,
+ (unsigned long long) start.abs_value_us);
+ return filename;
+}
+
+
+/**
+ * Get the latest key file from a past run of the key generation
+ * tool. Used to calculate the starting time for the keys we
+ * generate during this invocation. This function is used to
+ * handle both signing keys and coin keys, as in both cases
+ * the filenames correspond to the timestamps we need.
+ *
+ * @param cls closure, a `struct GNUNET_TIME_Absolute *`, updated
+ * to contain the highest timestamp (below #now)
+ * that was found
+ * @param filename complete filename (absolute path)
+ * @return #GNUNET_OK (to continue to iterate)
+ */
+static int
+get_anchor_iter (void *cls,
+ const char *filename)
+{
+ struct GNUNET_TIME_Absolute *anchor = cls;
+ struct GNUNET_TIME_Absolute stamp;
+ const char *base;
+ char *end = NULL;
+
+ base = GNUNET_STRINGS_get_short_name (filename);
+ stamp.abs_value_us = strtol (base,
+ &end,
+ 10);
+ if ((NULL == end) || (0 != *end))
+ {
+ fprintf(stderr,
+ "Ignoring unexpected file `%s'.\n",
+ filename);
+ return GNUNET_OK;
+ }
+ *anchor = GNUNET_TIME_absolute_max (stamp,
+ *anchor);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Get the timestamp where the first new key should be generated.
+ * Relies on correctly named key files (as we do not parse them,
+ * but just look at the filenames to "guess" at their contents).
+ *
+ * @param dir directory that should contain the existing keys
+ * @param duration how long is one key valid (for signing)?
+ * @param overlap what's the overlap between the keys validity period?
+ * @param[out] anchor the timestamp where the first new key should be generated
+ */
+static void
+get_anchor (const char *dir,
+ struct GNUNET_TIME_Relative duration,
+ struct GNUNET_TIME_Relative overlap,
+ struct GNUNET_TIME_Absolute *anchor)
+{
+ GNUNET_assert (0 == duration.rel_value_us % 1000000);
+ GNUNET_assert (0 == overlap.rel_value_us % 1000000);
+ if (GNUNET_YES !=
+ GNUNET_DISK_directory_test (dir,
+ GNUNET_YES))
+ {
+ *anchor = now;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No existing keys found, starting with fresh key set.\n");
+ return;
+ }
+ *anchor = GNUNET_TIME_UNIT_ZERO_ABS;
+ if (-1 ==
+ GNUNET_DISK_directory_scan (dir,
+ &get_anchor_iter,
+ anchor))
+ {
+ *anchor = now;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No existing keys found, starting with fresh key set.\n");
+ return;
+ }
+
+ if ((GNUNET_TIME_absolute_add (*anchor,
+ duration)).abs_value_us < now.abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Existing keys are way too old, starting with fresh key set.\n");
+ *anchor = now;
+ }
+ else if (anchor->abs_value_us != now.abs_value_us)
+ {
+ /* Real starting time is the last start time + duration - overlap */
+ *anchor = GNUNET_TIME_absolute_add (*anchor,
+ duration);
+ *anchor = GNUNET_TIME_absolute_subtract (*anchor,
+ overlap);
+ }
+ /* anchor is now the stamp where we need to create a new key */
+}
+
+
+/**
+ * Create a exchange signing key (for signing exchange messages, not for coins)
+ * and assert its correctness by signing it with the master key.
+ *
+ * @param start start time of the validity period for the key
+ * @param duration how long should the key be valid
+ * @param end when do all signatures by this key expire
+ * @param[out] pi set to the signing key information
+ */
+static void
+create_signkey_issue_priv (struct GNUNET_TIME_Absolute start,
+ struct GNUNET_TIME_Relative duration,
+ struct GNUNET_TIME_Absolute end,
+ struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *pi)
+{
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+ struct TALER_ExchangeSigningKeyValidityPS *issue = &pi->issue;
+
+ priv = GNUNET_CRYPTO_eddsa_key_create ();
+ pi->signkey_priv.eddsa_priv = *priv;
+ GNUNET_free (priv);
+ issue->master_public_key = master_public_key;
+ issue->start = GNUNET_TIME_absolute_hton (start);
+ issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start,
+ duration));
+ issue->end = GNUNET_TIME_absolute_hton (end);
+ GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv.eddsa_priv,
+ &issue->signkey_pub.eddsa_pub);
+ issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
+ issue->purpose.size = htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS) -
+ offsetof (struct TALER_ExchangeSigningKeyValidityPS,
+ purpose));
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
+ &issue->purpose,
+ &issue->signature.eddsa_signature));
+}
+
+
+/**
+ * Generate signing keys starting from the last key found to
+ * the lookahead time.
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+exchange_keys_update_signkeys ()
+{
+ struct GNUNET_TIME_Relative signkey_duration;
+ struct GNUNET_TIME_Relative legal_duration;
+ struct GNUNET_TIME_Absolute anchor;
+ char *signkey_dir;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ "exchange_keys",
+ "signkey_duration",
+ &signkey_duration))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange_keys",
+ "signkey_duration");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ "exchange_keys",
+ "legal_duration",
+ &legal_duration))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange_keys",
+ "legal_duration",
+ "fails to specify valid timeframe");
+ return GNUNET_SYSERR;
+ }
+ if (signkey_duration.rel_value_us > legal_duration.rel_value_us)
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange_keys",
+ "legal_duration",
+ "must be longer than signkey_duration");
+ return GNUNET_SYSERR;
+ }
+ TALER_round_rel_time (&signkey_duration);
+ GNUNET_asprintf (&signkey_dir,
+ "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS,
+ exchange_directory);
+ /* make sure the directory exists */
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create (signkey_dir))
+ {
+ fprintf (stderr,
+ "Failed to create signing key directory\n");
+ return GNUNET_SYSERR;
+ }
+
+ get_anchor (signkey_dir,
+ signkey_duration,
+ GNUNET_TIME_UNIT_ZERO /* no overlap for signing keys */,
+ &anchor);
+
+ while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
+ {
+ const char *skf;
+ struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP signkey_issue;
+ ssize_t nwrite;
+ struct GNUNET_TIME_Absolute end;
+
+ skf = get_signkey_file (anchor);
+ end = GNUNET_TIME_absolute_add (anchor,
+ legal_duration);
+ GNUNET_break (GNUNET_YES !=
+ GNUNET_DISK_file_test (skf));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Generating signing key for %s.\n",
+ GNUNET_STRINGS_absolute_time_to_string (anchor));
+ create_signkey_issue_priv (anchor,
+ signkey_duration,
+ end,
+ &signkey_issue);
+ nwrite = GNUNET_DISK_fn_write (skf,
+ &signkey_issue,
+ sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP),
+ GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ);
+ if (sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP) != nwrite)
+ {
+ fprintf (stderr,
+ "Failed to write to file `%s': %s\n",
+ skf,
+ STRERROR (errno));
+ return GNUNET_SYSERR;
+ }
+ anchor = GNUNET_TIME_absolute_add (anchor,
+ signkey_duration);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse configuration for coin type parameters. Also determines
+ * our anchor by looking at the existing coins of the same type.
+ *
+ * @param ct section in the configuration file giving the coin type parameters
+ * @param[out] params set to the coin parameters from the configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
+ */
+static int
+get_cointype_params (const char *ct,
+ struct CoinTypeParams *params)
+{
+ const char *dir;
+ unsigned long long rsa_keysize;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_withdraw",
+ &params->duration_withdraw))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "duration_withdraw");
+ return GNUNET_SYSERR;
+ }
+ TALER_round_rel_time (&params->duration_withdraw);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_spend",
+ &params->duration_spend))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "duration_spend");
+ return GNUNET_SYSERR;
+ }
+ TALER_round_rel_time (&params->duration_spend);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_legal",
+ &params->duration_legal))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "duration_legal");
+ return GNUNET_SYSERR;
+ }
+ TALER_round_rel_time (&params->duration_legal);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_overlap",
+ &params->duration_overlap))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "exchange_denom_duration_overlap");
+ return GNUNET_SYSERR;
+ }
+ TALER_round_rel_time (&params->duration_overlap);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (kcfg,
+ ct,
+ "rsa_keysize",
+ &rsa_keysize))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "rsa_keysize");
+ return GNUNET_SYSERR;
+ }
+ if ( (rsa_keysize > 4 * 2048) ||
+ (rsa_keysize < 1024) )
+ {
+ fprintf (stderr,
+ "Given RSA keysize %llu outside of permitted range\n",
+ rsa_keysize);
+ return GNUNET_SYSERR;
+ }
+ params->rsa_keysize = (unsigned int) rsa_keysize;
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "value",
+ &params->value))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "value");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "fee_withdraw",
+ &params->fee_withdraw))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "fee_withdraw");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "fee_deposit",
+ &params->fee_deposit))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "fee_deposit");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "fee_refresh",
+ &params->fee_refresh))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "fee_refresh");
+ return GNUNET_SYSERR;
+ }
+
+ dir = get_cointype_dir (params);
+ get_anchor (dir,
+ params->duration_withdraw,
+ params->duration_overlap,
+ &params->anchor);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Initialize the private and public key information structure for
+ * signing coins into existence. Generates the private signing key
+ * and signes it together with the coin's meta data using the master
+ * signing key.
+ *
+ * @param params parameters used to initialize the @a dki
+ * @param[out] dki initialized according to @a params
+ */
+static void
+create_denomkey_issue (const struct CoinTypeParams *params,
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ dki->denom_priv.rsa_private_key
+ = GNUNET_CRYPTO_rsa_private_key_create (params->rsa_keysize);
+ GNUNET_assert (NULL != dki->denom_priv.rsa_private_key);
+ dki->denom_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_private_key_get_public (dki->denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+ &dki->issue.properties.denom_hash);
+ dki->issue.properties.master = master_public_key;
+ dki->issue.properties.start = GNUNET_TIME_absolute_hton (params->anchor);
+ dki->issue.properties.expire_withdraw =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
+ params->duration_withdraw));
+ dki->issue.properties.expire_spend =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
+ params->duration_spend));
+ dki->issue.properties.expire_legal =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
+ params->duration_legal));
+ TALER_amount_hton (&dki->issue.properties.value,
+ &params->value);
+ TALER_amount_hton (&dki->issue.properties.fee_withdraw,
+ &params->fee_withdraw);
+ TALER_amount_hton (&dki->issue.properties.fee_deposit,
+ &params->fee_deposit);
+ TALER_amount_hton (&dki->issue.properties.fee_refresh,
+ &params->fee_refresh);
+ dki->issue.properties.purpose.purpose
+ = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
+ dki->issue.properties.purpose.size
+ = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
+ &dki->issue.properties.purpose,
+ &dki->issue.signature.eddsa_signature));
+}
+
+
+/**
+ * Generate new coin signing keys for the coin type of the given @a
+ * coin_alias.
+ *
+ * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure
+ * @param coin_alias name of the coin's section in the configuration
+ */
+static void
+exchange_keys_update_cointype (void *cls,
+ const char *coin_alias)
+{
+ int *ret = cls;
+ struct CoinTypeParams p;
+ const char *dkf;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation denomkey_issue;
+
+ if (0 != strncasecmp (coin_alias,
+ "coin_",
+ strlen ("coin_")))
+ return; /* not a coin definition */
+ if (GNUNET_OK !=
+ get_cointype_params (coin_alias,
+ &p))
+ {
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create (get_cointype_dir (&p)))
+ {
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+
+ while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
+ {
+ dkf = get_cointype_file (&p,
+ p.anchor);
+ GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Generating denomination key for type `%s', start %s at %s\n",
+ coin_alias,
+ GNUNET_STRINGS_absolute_time_to_string (p.anchor),
+ dkf);
+ create_denomkey_issue (&p,
+ &denomkey_issue);
+ if (GNUNET_OK !=
+ TALER_EXCHANGEDB_denomination_key_write (dkf,
+ &denomkey_issue))
+ {
+ fprintf (stderr,
+ "Failed to write denomination key information to file `%s'.\n",
+ dkf);
+ *ret = GNUNET_SYSERR;
+ GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
+ return;
+ }
+ if ( (NULL != auditor_output_file) &&
+ (sizeof (denomkey_issue.issue.properties) !=
+ fwrite (&denomkey_issue.issue.properties,
+ sizeof (struct TALER_DenominationKeyValidityPS),
+ 1,
+ auditor_output_file)) )
+ {
+ fprintf (stderr,
+ "Failed to write denomination key information to %s: %s\n",
+ auditorrequestfile,
+ STRERROR (errno));
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
+ p.anchor = GNUNET_TIME_absolute_add (p.anchor,
+ p.duration_spend);
+ p.anchor = GNUNET_TIME_absolute_subtract (p.anchor,
+ p.duration_overlap);
+ }
+}
+
+
+/**
+ * Update all of the denomination keys of the exchange.
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+exchange_keys_update_denomkeys ()
+{
+ int ok;
+
+ ok = GNUNET_OK;
+ GNUNET_CONFIGURATION_iterate_sections (kcfg,
+ &exchange_keys_update_cointype,
+ &ok);
+ return ok;
+}
+
+
+/**
+ * The main function of the taler-exchange-keyup tool. This tool is used
+ * to create the signing and denomination keys for the exchange. It uses
+ * the long-term offline private key and writes the (additional) key
+ * files to the respective exchange directory (from where they can then be
+ * copied to the online server). Note that we need (at least) the
+ * most recent generated previous keys so as to align the validity
+ * periods.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'d', "exchange-dir", "DIR",
+ "exchange directory with keys to update", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_directory},
+ TALER_GETOPT_OPTION_HELP ("Setup signing and denomination keys for a Taler exchange"),
+ {'m', "master-key", "FILE",
+ "master key file (private key)", 1,
+ &GNUNET_GETOPT_set_filename, &masterkeyfile},
+ {'o', "output", "FILE",
+ "auditor denomination key signing request file to create", 1,
+ &GNUNET_GETOPT_set_filename, &auditorrequestfile},
+ {'t', "time", "TIMESTAMP",
+ "pretend it is a different time for the update", 0,
+ &GNUNET_GETOPT_set_string, &pretend_time_str},
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ struct GNUNET_TIME_Relative lookahead_sign;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-keyup",
+ "WARNING",
+ NULL));
+
+ if (GNUNET_GETOPT_run ("taler-exchange-keyup",
+ options,
+ argc, argv) < 0)
+ return 1;
+ if (NULL == exchange_directory)
+ {
+ fprintf (stderr,
+ "Exchange directory not given\n");
+ return 1;
+ }
+ if (NULL != pretend_time_str)
+ {
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str,
+ &now))
+ {
+ fprintf (stderr,
+ "timestamp `%s' invalid\n",
+ pretend_time_str);
+ return 1;
+ }
+ }
+ else
+ {
+ now = GNUNET_TIME_absolute_get ();
+ }
+ TALER_round_abs_time (&now);
+
+ kcfg = TALER_config_load (exchange_directory);
+ if (NULL == kcfg)
+ {
+ fprintf (stderr,
+ "Failed to load exchange configuration\n");
+ return 1;
+ }
+ if (NULL == masterkeyfile)
+ {
+ fprintf (stderr,
+ "Master key file not given\n");
+ return 1;
+ }
+ eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
+ if (NULL == eddsa_priv)
+ {
+ fprintf (stderr,
+ "Failed to initialize master key from file `%s'\n",
+ masterkeyfile);
+ return 1;
+ }
+ master_priv.eddsa_priv = *eddsa_priv;
+ GNUNET_free (eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
+ &master_public_key.eddsa_pub);
+
+ if (NULL != auditorrequestfile)
+ {
+ auditor_output_file = FOPEN (auditorrequestfile,
+ "w");
+ if (NULL == auditor_output_file)
+ {
+ fprintf (stderr,
+ "Failed to open `%s' for writing: %s\n",
+ auditorrequestfile,
+ STRERROR (errno));
+ return 1;
+ }
+ }
+
+ /* check if key from file matches the one from the configuration */
+ {
+ struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_data (kcfg,
+ "exchange",
+ "master_public_key",
+ &master_public_key_from_cfg,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "master_public_key");
+ return 1;
+ }
+ if (0 !=
+ memcmp (&master_public_key,
+ &master_public_key_from_cfg,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "master_public_key",
+ _("does not match with private key"));
+ return 1;
+ }
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ "exchange_keys",
+ "lookahead_sign",
+ &lookahead_sign))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange_keys",
+ "lookahead_sign");
+ return GNUNET_SYSERR;
+ }
+ if (0 == lookahead_sign.rel_value_us)
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange_keys",
+ "lookahead_sign",
+ _("must not be zero"));
+ return GNUNET_SYSERR;
+ }
+ TALER_round_rel_time (&lookahead_sign);
+ lookahead_sign_stamp = GNUNET_TIME_absolute_add (now,
+ lookahead_sign);
+
+
+ /* finally, do actual work */
+ if (GNUNET_OK != exchange_keys_update_signkeys ())
+ return 1;
+
+ if (GNUNET_OK != exchange_keys_update_denomkeys ())
+ return 1;
+ if (NULL != auditor_output_file)
+ {
+ FCLOSE (auditor_output_file);
+ auditor_output_file = NULL;
+ }
+ return 0;
+}
+
+/* end of taler-exchange-keyup.c */
diff --git a/src/exchange-tools/taler-exchange-reservemod.c b/src/exchange-tools/taler-exchange-reservemod.c
new file mode 100644
index 000000000..984b7f8ee
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-reservemod.c
@@ -0,0 +1,206 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-reservemod.c
+ * @brief Modify reserves. Allows manipulation of reserve balances.
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <libpq-fe.h>
+#include <jansson.h>
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Director of the exchange, containing the keys.
+ */
+static char *exchange_directory;
+
+/**
+ * Handle to the exchange's configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Our DB plugin.
+ */
+static struct TALER_EXCHANGEDB_Plugin *plugin;
+
+
+/**
+ * The main function of the reservemod tool
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ char *reserve_pub_str = NULL;
+ char *add_str = NULL;
+ struct TALER_Amount add_value;
+ char *details = NULL;
+ json_t *jdetails;
+ json_error_t error;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_EXCHANGEDB_Session *session;
+ const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'a', "add", "DENOM",
+ "value to add", 1,
+ &GNUNET_GETOPT_set_string, &add_str},
+ {'d', "exchange-dir", "DIR",
+ "exchange directory with keys to update", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_directory},
+ {'D', "details", "JSON",
+ "details about the bank transaction which justify why we add this amount", 1,
+ &GNUNET_GETOPT_set_string, &details},
+ TALER_GETOPT_OPTION_HELP ("Deposit funds into a Taler reserve"),
+ {'R', "reserve", "KEY",
+ "reserve (public key) to modify", 1,
+ &GNUNET_GETOPT_set_string, &reserve_pub_str},
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-reservemod",
+ "WARNING",
+ NULL));
+
+ if (GNUNET_GETOPT_run ("taler-exchange-reservemod",
+ options,
+ argc, argv) < 0)
+ return 1;
+ if (NULL == exchange_directory)
+ {
+ fprintf (stderr,
+ "Exchange directory not given\n");
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (details);
+ GNUNET_free_non_null (reserve_pub_str);
+ return 1;
+ }
+ if ((NULL == reserve_pub_str) ||
+ (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (reserve_pub_str,
+ strlen (reserve_pub_str),
+ &reserve_pub,
+ sizeof (struct TALER_ReservePublicKeyP))))
+ {
+ fprintf (stderr,
+ "Parsing reserve key invalid\n");
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (details);
+ GNUNET_free_non_null (reserve_pub_str);
+ return 1;
+ }
+ if ( (NULL == add_str) ||
+ (GNUNET_OK !=
+ TALER_string_to_amount (add_str,
+ &add_value)) )
+ {
+ fprintf (stderr,
+ "Failed to parse currency amount `%s'\n",
+ add_str);
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (details);
+ GNUNET_free_non_null (reserve_pub_str);
+ return 1;
+ }
+
+ if (NULL == details)
+ {
+ fprintf (stderr,
+ "No wiring details given (justification required)\n");
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (reserve_pub_str);
+ return 1;
+ }
+
+ cfg = TALER_config_load (exchange_directory);
+ if (NULL == cfg)
+ {
+ fprintf (stderr,
+ "Failed to load exchange configuration\n");
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (details);
+ GNUNET_free_non_null (reserve_pub_str);
+ return 1;
+ }
+ ret = 1;
+ if (NULL ==
+ (plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
+ {
+ fprintf (stderr,
+ "Failed to initialize database plugin.\n");
+ goto cleanup;
+ }
+
+ session = plugin->get_session (plugin->cls,
+ GNUNET_NO);
+ if (NULL == session)
+ {
+ fprintf (stderr,
+ "Failed to initialize DB session\n");
+ goto cleanup;
+ }
+ jdetails = json_loads (details,
+ JSON_REJECT_DUPLICATES,
+ &error);
+ if (NULL == jdetails)
+ {
+ fprintf (stderr,
+ "Failed to parse JSON transaction details `%s': %s (%s)\n",
+ details,
+ error.text,
+ error.source);
+ goto cleanup;
+ }
+ /* FIXME: maybe allow passing timestamp via command-line? */
+ ret = plugin->reserves_in_insert (plugin->cls,
+ session,
+ &reserve_pub,
+ &add_value,
+ GNUNET_TIME_absolute_get (),
+ jdetails);
+ json_decref (jdetails);
+ if (GNUNET_SYSERR == ret)
+ {
+ fprintf (stderr,
+ "Failed to update reserve.\n");
+ goto cleanup;
+ }
+ if (GNUNET_NO == ret)
+ {
+ fprintf (stderr,
+ "Record exists, reserve not updated.\n");
+ }
+ ret = 0;
+ cleanup:
+ if (NULL != plugin)
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ if (NULL != cfg)
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (details);
+ GNUNET_free_non_null (reserve_pub_str);
+ return ret;
+}
+
+/* end taler-exchange-reservemod.c */
diff --git a/src/exchange-tools/taler-exchange-sepa.c b/src/exchange-tools/taler-exchange-sepa.c
new file mode 100644
index 000000000..a3ac95436
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-sepa.c
@@ -0,0 +1,163 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-sepa.c
+ * @brief Create signed response for /wire/sepa requests.
+ * @author Christian Grothoff
+ */
+#include <platform.h>
+#include <jansson.h>
+#include "taler_crypto_lib.h"
+#include "taler_signatures.h"
+
+
+/**
+ * Filename of the master private key.
+ */
+static char *masterkeyfile;
+
+/**
+ * Account holder name.
+ */
+static char *sepa_name;
+
+/**
+ * IBAN number.
+ */
+static char *iban;
+
+/**
+ * BIC number.
+ */
+static char *bic;
+
+/**
+ * Where to write the result.
+ */
+static char *output_filename;
+
+
+/**
+ * The main function of the taler-exchange-sepa tool. This tool is used
+ * to sign the SEPA bank account details using the master key.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'b', "bic", "BICCODE",
+ "bank BIC code", 1,
+ &GNUNET_GETOPT_set_string, &bic},
+ {'i', "iban", "IBAN",
+ "IBAN number of the account", 1,
+ &GNUNET_GETOPT_set_string, &iban},
+ {'m', "master-key", "FILE",
+ "master key file (private key)", 1,
+ &GNUNET_GETOPT_set_filename, &masterkeyfile},
+ {'n', "name", "NAME",
+ "name of the account holder", 1,
+ &GNUNET_GETOPT_set_string, &sepa_name},
+ {'o', "output", "FILE",
+ "where to write the result", 1,
+ &GNUNET_GETOPT_set_filename, &output_filename},
+ TALER_GETOPT_OPTION_HELP ("Setup /wire/sepa response"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
+ struct TALER_MasterWireSepaDetailsPS wsd;
+ struct TALER_MasterSignatureP sig;
+ struct GNUNET_HashContext *hc;
+ json_t *reply;
+ char *json_str;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-sepa",
+ "WARNING",
+ NULL));
+
+ if (GNUNET_GETOPT_run ("taler-exchange-sepa",
+ options,
+ argc, argv) < 0)
+ return 1;
+ if (NULL == masterkeyfile)
+ {
+ fprintf (stderr,
+ "Master key file not given\n");
+ return 1;
+ }
+ eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
+ if (NULL == eddsa_priv)
+ {
+ fprintf (stderr,
+ "Failed to initialize master key from file `%s'\n",
+ masterkeyfile);
+ return 1;
+ }
+
+ /* Compute message to sign */
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ sepa_name,
+ strlen (sepa_name) + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ iban,
+ strlen (iban) + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ bic,
+ strlen (bic) + 1);
+ wsd.purpose.size = htonl (sizeof (wsd));
+ wsd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &wsd.h_sepa_details);
+ GNUNET_CRYPTO_eddsa_sign (eddsa_priv,
+ &wsd.purpose,
+ &sig.eddsa_signature);
+ GNUNET_free (eddsa_priv);
+
+ /* build JSON message */
+ reply = json_pack ("{s:s, s:s, s:s, s:o}",
+ "receiver_name", sepa_name,
+ "iban", iban,
+ "bic", bic,
+ "sig", TALER_json_from_data (&sig,
+ sizeof (sig)));
+ GNUNET_assert (NULL != reply);
+
+ /* dump result to stdout */
+ json_str = json_dumps (reply, JSON_INDENT(2));
+ GNUNET_assert (NULL != json_str);
+
+ if (NULL != output_filename)
+ {
+ fclose (stdout);
+ stdout = fopen (output_filename,
+ "w+");
+ }
+ fprintf (stdout,
+ "%s",
+ json_str);
+ fflush (stdout);
+ free (json_str);
+ return 0;
+}
+
+/* end of taler-exchange-sepa.c */
diff --git a/src/exchange/.gitignore b/src/exchange/.gitignore
new file mode 100644
index 000000000..a1e5e9aa7
--- /dev/null
+++ b/src/exchange/.gitignore
@@ -0,0 +1,6 @@
+taler-exchange-dbinit
+taler-exchange-keycheck
+taler-exchange-keyup
+taler-exchange-pursemod
+taler-exchange-reservemod
+taler-exchange-httpd \ No newline at end of file
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
new file mode 100644
index 000000000..443ac511a
--- /dev/null
+++ b/src/exchange/Makefile.am
@@ -0,0 +1,59 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+bin_PROGRAMS = \
+ taler-exchange-aggregator \
+ taler-exchange-httpd
+
+taler_exchange_aggregator_SOURCES = \
+ taler-exchange-aggregator.c
+taler_exchange_aggregator_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/wire/libtalerwire.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -ljansson \
+ -lgnunetutil
+
+taler_exchange_httpd_SOURCES = \
+ taler-exchange-httpd.c taler-exchange-httpd.h \
+ taler-exchange-httpd_admin.c taler-exchange-httpd_admin.h \
+ taler-exchange-httpd_db.c taler-exchange-httpd_db.h \
+ taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \
+ taler-exchange-httpd_keystate.c taler-exchange-httpd_keystate.h \
+ taler-exchange-httpd_mhd.c taler-exchange-httpd_mhd.h \
+ taler-exchange-httpd_parsing.c taler-exchange-httpd_parsing.h \
+ taler-exchange-httpd_refresh.c taler-exchange-httpd_refresh.h \
+ taler-exchange-httpd_reserve.c taler-exchange-httpd_reserve.h \
+ taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
+ taler-exchange-httpd_tracking.c taler-exchange-httpd_tracking.h \
+ taler-exchange-httpd_wire.c taler-exchange-httpd_wire.h \
+ taler-exchange-httpd_validation.c taler-exchange-httpd_validation.h
+taler_exchange_httpd_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ -lmicrohttpd \
+ -ljansson \
+ -lgnunetutil \
+ -lpthread
+
+if HAVE_DEVELOPER
+taler_exchange_httpd_SOURCES += \
+ taler-exchange-httpd_test.c taler-exchange-httpd_test.h
+endif
+
+check_SCRIPTS = \
+ test_taler_exchange_httpd.sh
+
+if HAVE_EXPENSIVE_TESTS
+check_SCRIPTS += \
+ test_taler_exchange_httpd_afl.sh
+endif
+
+TESTS = $(check_SCRIPTS)
diff --git a/src/mint/afl-tests/id:000000,orig:admin_add_incoming.req b/src/exchange/afl-tests/id:000000,orig:admin_add_incoming.req
index 677678b5d..677678b5d 100644
--- a/src/mint/afl-tests/id:000000,orig:admin_add_incoming.req
+++ b/src/exchange/afl-tests/id:000000,orig:admin_add_incoming.req
diff --git a/src/mint/afl-tests/id:000001,orig:deposit.req b/src/exchange/afl-tests/id:000001,orig:deposit.req
index ec490759e..ec490759e 100644
--- a/src/mint/afl-tests/id:000001,orig:deposit.req
+++ b/src/exchange/afl-tests/id:000001,orig:deposit.req
diff --git a/src/mint/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060 b/src/exchange/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060
index 6f317bf51..6f317bf51 100644
--- a/src/mint/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060
+++ b/src/exchange/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060
diff --git a/src/mint/afl-tests/id:000002,orig:keys.req b/src/exchange/afl-tests/id:000002,orig:keys.req
index a9503a864..a9503a864 100644
--- a/src/mint/afl-tests/id:000002,orig:keys.req
+++ b/src/exchange/afl-tests/id:000002,orig:keys.req
diff --git a/src/mint/afl-tests/id:000003,orig:refresh_link.req b/src/exchange/afl-tests/id:000003,orig:refresh_link.req
index acf3dff51..acf3dff51 100644
--- a/src/mint/afl-tests/id:000003,orig:refresh_link.req
+++ b/src/exchange/afl-tests/id:000003,orig:refresh_link.req
diff --git a/src/mint/afl-tests/id:000004,orig:refresh_melt.req b/src/exchange/afl-tests/id:000004,orig:refresh_melt.req
index 98b5b6389..98b5b6389 100644
--- a/src/mint/afl-tests/id:000004,orig:refresh_melt.req
+++ b/src/exchange/afl-tests/id:000004,orig:refresh_melt.req
diff --git a/src/mint/afl-tests/id:000005,orig:refresh_reveal.req b/src/exchange/afl-tests/id:000005,orig:refresh_reveal.req
index 3fb143960..3fb143960 100644
--- a/src/mint/afl-tests/id:000005,orig:refresh_reveal.req
+++ b/src/exchange/afl-tests/id:000005,orig:refresh_reveal.req
diff --git a/src/mint/afl-tests/id:000006,orig:reserve_status.req b/src/exchange/afl-tests/id:000006,orig:reserve_status.req
index 4f988f669..4f988f669 100644
--- a/src/mint/afl-tests/id:000006,orig:reserve_status.req
+++ b/src/exchange/afl-tests/id:000006,orig:reserve_status.req
diff --git a/src/mint/afl-tests/id:000007,orig:reserve_withdraw.req b/src/exchange/afl-tests/id:000007,orig:reserve_withdraw.req
index 484950250..484950250 100644
--- a/src/mint/afl-tests/id:000007,orig:reserve_withdraw.req
+++ b/src/exchange/afl-tests/id:000007,orig:reserve_withdraw.req
diff --git a/src/mint/afl-tests/id:000008,orig:wire.req b/src/exchange/afl-tests/id:000008,orig:wire.req
index a4f1d0749..a4f1d0749 100644
--- a/src/mint/afl-tests/id:000008,orig:wire.req
+++ b/src/exchange/afl-tests/id:000008,orig:wire.req
diff --git a/src/mint/afl-tests/id:000009,orig:wire_sepa.req b/src/exchange/afl-tests/id:000009,orig:wire_sepa.req
index 80d3d4619..80d3d4619 100644
--- a/src/mint/afl-tests/id:000009,orig:wire_sepa.req
+++ b/src/exchange/afl-tests/id:000009,orig:wire_sepa.req
diff --git a/src/mint/afl-tests/id:000010,orig:wire_test.req b/src/exchange/afl-tests/id:000010,orig:wire_test.req
index 684352c96..684352c96 100644
--- a/src/mint/afl-tests/id:000010,orig:wire_test.req
+++ b/src/exchange/afl-tests/id:000010,orig:wire_test.req
diff --git a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov
index 4cb4552ad..4cb4552ad 100644
--- a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov
+++ b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov
diff --git a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov
index ffb59d7f9..ffb59d7f9 100644
--- a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov
+++ b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov
diff --git a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov
index 801bf114d..801bf114d 100644
--- a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov
+++ b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov
diff --git a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov
index fd3daf4c7..fd3daf4c7 100644
--- a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov
+++ b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000013,src:000000,op:flip1,pos:4,+cov b/src/exchange/afl-tests/id:000013,src:000000,op:flip1,pos:4,+cov
index fd3daf4c7..fd3daf4c7 100644
--- a/src/mint/afl-tests/id:000013,src:000000,op:flip1,pos:4,+cov
+++ b/src/exchange/afl-tests/id:000013,src:000000,op:flip1,pos:4,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000013,src:000000,op:flip1,pos:5,+cov b/src/exchange/afl-tests/id:000013,src:000000,op:flip1,pos:5,+cov
index 20e0e33e4..20e0e33e4 100644
--- a/src/mint/afl-tests/id:000013,src:000000,op:flip1,pos:5,+cov
+++ b/src/exchange/afl-tests/id:000013,src:000000,op:flip1,pos:5,+cov
diff --git a/src/mint/afl-tests/id:000014,src:000000,op:flip1,pos:5,+cov b/src/exchange/afl-tests/id:000014,src:000000,op:flip1,pos:5,+cov
index 20e0e33e4..20e0e33e4 100644
--- a/src/mint/afl-tests/id:000014,src:000000,op:flip1,pos:5,+cov
+++ b/src/exchange/afl-tests/id:000014,src:000000,op:flip1,pos:5,+cov
diff --git a/src/mint/afl-tests/id:000015,src:000000,op:flip1,pos:5,+cov b/src/exchange/afl-tests/id:000015,src:000000,op:flip1,pos:5,+cov
index 25451a5bd..25451a5bd 100644
--- a/src/mint/afl-tests/id:000015,src:000000,op:flip1,pos:5,+cov
+++ b/src/exchange/afl-tests/id:000015,src:000000,op:flip1,pos:5,+cov
diff --git a/src/mint/afl-tests/id:000015,src:000000,op:flip1,pos:8,+cov b/src/exchange/afl-tests/id:000015,src:000000,op:flip1,pos:8,+cov
index 893951bb9..893951bb9 100644
--- a/src/mint/afl-tests/id:000015,src:000000,op:flip1,pos:8,+cov
+++ b/src/exchange/afl-tests/id:000015,src:000000,op:flip1,pos:8,+cov
diff --git a/src/mint/afl-tests/id:000016,src:000000,op:flip1,pos:11 b/src/exchange/afl-tests/id:000016,src:000000,op:flip1,pos:11
index dce84ef37..dce84ef37 100644
--- a/src/mint/afl-tests/id:000016,src:000000,op:flip1,pos:11
+++ b/src/exchange/afl-tests/id:000016,src:000000,op:flip1,pos:11
diff --git a/src/mint/afl-tests/id:000016,src:000000,op:flip1,pos:5,+cov b/src/exchange/afl-tests/id:000016,src:000000,op:flip1,pos:5,+cov
index afda51803..afda51803 100644
--- a/src/mint/afl-tests/id:000016,src:000000,op:flip1,pos:5,+cov
+++ b/src/exchange/afl-tests/id:000016,src:000000,op:flip1,pos:5,+cov
diff --git a/src/mint/afl-tests/id:000017,src:000000,op:flip1,pos:13,+cov b/src/exchange/afl-tests/id:000017,src:000000,op:flip1,pos:13,+cov
index 85a02f53f..85a02f53f 100644
--- a/src/mint/afl-tests/id:000017,src:000000,op:flip1,pos:13,+cov
+++ b/src/exchange/afl-tests/id:000017,src:000000,op:flip1,pos:13,+cov
diff --git a/src/mint/afl-tests/id:000017,src:000000,op:flip1,pos:7,+cov b/src/exchange/afl-tests/id:000017,src:000000,op:flip1,pos:7,+cov
index db763284c..db763284c 100644
--- a/src/mint/afl-tests/id:000017,src:000000,op:flip1,pos:7,+cov
+++ b/src/exchange/afl-tests/id:000017,src:000000,op:flip1,pos:7,+cov
diff --git a/src/mint/afl-tests/id:000018,src:000000,op:flip1,pos:13,+cov b/src/exchange/afl-tests/id:000018,src:000000,op:flip1,pos:13,+cov
index 91ae254fb..91ae254fb 100644
--- a/src/mint/afl-tests/id:000018,src:000000,op:flip1,pos:13,+cov
+++ b/src/exchange/afl-tests/id:000018,src:000000,op:flip1,pos:13,+cov
diff --git a/src/mint/afl-tests/id:000018,src:000000,op:flip1,pos:9,+cov b/src/exchange/afl-tests/id:000018,src:000000,op:flip1,pos:9,+cov
index 626bd149d..626bd149d 100644
--- a/src/mint/afl-tests/id:000018,src:000000,op:flip1,pos:9,+cov
+++ b/src/exchange/afl-tests/id:000018,src:000000,op:flip1,pos:9,+cov
diff --git a/src/mint/afl-tests/id:000019,src:000000,op:flip1,pos:11 b/src/exchange/afl-tests/id:000019,src:000000,op:flip1,pos:11
index dce84ef37..dce84ef37 100644
--- a/src/mint/afl-tests/id:000019,src:000000,op:flip1,pos:11
+++ b/src/exchange/afl-tests/id:000019,src:000000,op:flip1,pos:11
diff --git a/src/mint/afl-tests/id:000019,src:000000,op:flip1,pos:19,+cov b/src/exchange/afl-tests/id:000019,src:000000,op:flip1,pos:19,+cov
index fa104c258..fa104c258 100644
--- a/src/mint/afl-tests/id:000019,src:000000,op:flip1,pos:19,+cov
+++ b/src/exchange/afl-tests/id:000019,src:000000,op:flip1,pos:19,+cov
diff --git a/src/mint/afl-tests/id:000020,src:000000,op:flip1,pos:12,+cov b/src/exchange/afl-tests/id:000020,src:000000,op:flip1,pos:12,+cov
index c023761dd..c023761dd 100644
--- a/src/mint/afl-tests/id:000020,src:000000,op:flip1,pos:12,+cov
+++ b/src/exchange/afl-tests/id:000020,src:000000,op:flip1,pos:12,+cov
diff --git a/src/mint/afl-tests/id:000020,src:000000,op:flip1,pos:19,+cov b/src/exchange/afl-tests/id:000020,src:000000,op:flip1,pos:19,+cov
index 52cac8707..52cac8707 100644
--- a/src/mint/afl-tests/id:000020,src:000000,op:flip1,pos:19,+cov
+++ b/src/exchange/afl-tests/id:000020,src:000000,op:flip1,pos:19,+cov
diff --git a/src/mint/afl-tests/id:000021,src:000000,op:flip1,pos:13,+cov b/src/exchange/afl-tests/id:000021,src:000000,op:flip1,pos:13,+cov
index 85a02f53f..85a02f53f 100644
--- a/src/mint/afl-tests/id:000021,src:000000,op:flip1,pos:13,+cov
+++ b/src/exchange/afl-tests/id:000021,src:000000,op:flip1,pos:13,+cov
diff --git a/src/mint/afl-tests/id:000021,src:000000,op:flip1,pos:21,+cov b/src/exchange/afl-tests/id:000021,src:000000,op:flip1,pos:21,+cov
index a9673b600..a9673b600 100644
--- a/src/mint/afl-tests/id:000021,src:000000,op:flip1,pos:21,+cov
+++ b/src/exchange/afl-tests/id:000021,src:000000,op:flip1,pos:21,+cov
diff --git a/src/mint/afl-tests/id:000022,src:000000,op:flip1,pos:17,+cov b/src/exchange/afl-tests/id:000022,src:000000,op:flip1,pos:17,+cov
index 5331d9fc1..5331d9fc1 100644
--- a/src/mint/afl-tests/id:000022,src:000000,op:flip1,pos:17,+cov
+++ b/src/exchange/afl-tests/id:000022,src:000000,op:flip1,pos:17,+cov
diff --git a/src/mint/afl-tests/id:000022,src:000000,op:flip1,pos:23,+cov b/src/exchange/afl-tests/id:000022,src:000000,op:flip1,pos:23,+cov
index c9dbbaf21..c9dbbaf21 100644
--- a/src/mint/afl-tests/id:000022,src:000000,op:flip1,pos:23,+cov
+++ b/src/exchange/afl-tests/id:000022,src:000000,op:flip1,pos:23,+cov
diff --git a/src/mint/afl-tests/id:000023,src:000000,op:flip1,pos:22,+cov b/src/exchange/afl-tests/id:000023,src:000000,op:flip1,pos:22,+cov
index 9d97068e9..9d97068e9 100644
--- a/src/mint/afl-tests/id:000023,src:000000,op:flip1,pos:22,+cov
+++ b/src/exchange/afl-tests/id:000023,src:000000,op:flip1,pos:22,+cov
diff --git a/src/mint/afl-tests/id:000023,src:000000,op:flip1,pos:24,+cov b/src/exchange/afl-tests/id:000023,src:000000,op:flip1,pos:24,+cov
index 974be1c5d..974be1c5d 100644
--- a/src/mint/afl-tests/id:000023,src:000000,op:flip1,pos:24,+cov
+++ b/src/exchange/afl-tests/id:000023,src:000000,op:flip1,pos:24,+cov
diff --git a/src/mint/afl-tests/id:000024,src:000000,op:flip1,pos:24,+cov b/src/exchange/afl-tests/id:000024,src:000000,op:flip1,pos:24,+cov
index 974be1c5d..974be1c5d 100644
--- a/src/mint/afl-tests/id:000024,src:000000,op:flip1,pos:24,+cov
+++ b/src/exchange/afl-tests/id:000024,src:000000,op:flip1,pos:24,+cov
diff --git a/src/mint/afl-tests/id:000025,src:000000,op:flip1,pos:24,+cov b/src/exchange/afl-tests/id:000025,src:000000,op:flip1,pos:24,+cov
index 2e40ec2aa..2e40ec2aa 100644
--- a/src/mint/afl-tests/id:000025,src:000000,op:flip1,pos:24,+cov
+++ b/src/exchange/afl-tests/id:000025,src:000000,op:flip1,pos:24,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000026,src:000000,op:flip1,pos:25,+cov b/src/exchange/afl-tests/id:000026,src:000000,op:flip1,pos:25,+cov
index 5806f8864..5806f8864 100644
--- a/src/mint/afl-tests/id:000026,src:000000,op:flip1,pos:25,+cov
+++ b/src/exchange/afl-tests/id:000026,src:000000,op:flip1,pos:25,+cov
diff --git a/src/mint/afl-tests/id:000027,src:000000,op:flip1,pos:26,+cov b/src/exchange/afl-tests/id:000027,src:000000,op:flip1,pos:26,+cov
index e469d9e6e..e469d9e6e 100644
--- a/src/mint/afl-tests/id:000027,src:000000,op:flip1,pos:26,+cov
+++ b/src/exchange/afl-tests/id:000027,src:000000,op:flip1,pos:26,+cov
diff --git a/src/mint/afl-tests/id:000028,src:000000,op:flip1,pos:26,+cov b/src/exchange/afl-tests/id:000028,src:000000,op:flip1,pos:26,+cov
index 8cc9a7213..8cc9a7213 100644
--- a/src/mint/afl-tests/id:000028,src:000000,op:flip1,pos:26,+cov
+++ b/src/exchange/afl-tests/id:000028,src:000000,op:flip1,pos:26,+cov
diff --git a/src/mint/afl-tests/id:000029,src:000000,op:flip1,pos:26,+cov b/src/exchange/afl-tests/id:000029,src:000000,op:flip1,pos:26,+cov
index 3bdae2df4..3bdae2df4 100644
--- a/src/mint/afl-tests/id:000029,src:000000,op:flip1,pos:26,+cov
+++ b/src/exchange/afl-tests/id:000029,src:000000,op:flip1,pos:26,+cov
diff --git a/src/mint/afl-tests/id:000029,src:000000,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000029,src:000000,op:flip1,pos:27,+cov
index 8edf59d14..8edf59d14 100644
--- a/src/mint/afl-tests/id:000029,src:000000,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000029,src:000000,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000030,src:000000,op:flip1,pos:27 b/src/exchange/afl-tests/id:000030,src:000000,op:flip1,pos:27
index 49ca2a545..49ca2a545 100644
--- a/src/mint/afl-tests/id:000030,src:000000,op:flip1,pos:27
+++ b/src/exchange/afl-tests/id:000030,src:000000,op:flip1,pos:27
diff --git a/src/mint/afl-tests/id:000030,src:000000,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000030,src:000000,op:flip1,pos:27,+cov
index 741e93549..741e93549 100644
--- a/src/mint/afl-tests/id:000030,src:000000,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000030,src:000000,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000031,src:000000,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000031,src:000000,op:flip1,pos:27,+cov
index 66860c9d8..66860c9d8 100644
--- a/src/mint/afl-tests/id:000031,src:000000,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000031,src:000000,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000031,src:000000,op:flip1,pos:28,+cov b/src/exchange/afl-tests/id:000031,src:000000,op:flip1,pos:28,+cov
index 079159870..079159870 100644
--- a/src/mint/afl-tests/id:000031,src:000000,op:flip1,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000031,src:000000,op:flip1,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000032,src:000000,op:flip1,pos:28,+cov b/src/exchange/afl-tests/id:000032,src:000000,op:flip1,pos:28,+cov
index d8d7582bb..d8d7582bb 100644
--- a/src/mint/afl-tests/id:000032,src:000000,op:flip1,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000032,src:000000,op:flip1,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000032,src:000000,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000032,src:000000,op:flip1,pos:30,+cov
index 8795b682d..8795b682d 100644
--- a/src/mint/afl-tests/id:000032,src:000000,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000032,src:000000,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000033,src:000000,op:flip1,pos:28,+cov b/src/exchange/afl-tests/id:000033,src:000000,op:flip1,pos:28,+cov
index 079159870..079159870 100644
--- a/src/mint/afl-tests/id:000033,src:000000,op:flip1,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000033,src:000000,op:flip1,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000033,src:000000,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000033,src:000000,op:flip1,pos:30,+cov
index 4cd329de8..4cd329de8 100644
--- a/src/mint/afl-tests/id:000033,src:000000,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000033,src:000000,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000034,src:000000,op:flip1,pos:28,+cov b/src/exchange/afl-tests/id:000034,src:000000,op:flip1,pos:28,+cov
index 001dc6cd7..001dc6cd7 100644
--- a/src/mint/afl-tests/id:000034,src:000000,op:flip1,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000034,src:000000,op:flip1,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000034,src:000000,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000034,src:000000,op:flip1,pos:30,+cov
index d10865820..d10865820 100644
--- a/src/mint/afl-tests/id:000034,src:000000,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000034,src:000000,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000035,src:000000,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000035,src:000000,op:flip1,pos:30,+cov
index 0825eb253..0825eb253 100644
--- a/src/mint/afl-tests/id:000035,src:000000,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000035,src:000000,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000036,src:000000,op:flip1,pos:31,+cov b/src/exchange/afl-tests/id:000036,src:000000,op:flip1,pos:31,+cov
index ee5a5d37c..ee5a5d37c 100644
--- a/src/mint/afl-tests/id:000036,src:000000,op:flip1,pos:31,+cov
+++ b/src/exchange/afl-tests/id:000036,src:000000,op:flip1,pos:31,+cov
diff --git a/src/mint/afl-tests/id:000037,src:000000,op:flip1,pos:32,+cov b/src/exchange/afl-tests/id:000037,src:000000,op:flip1,pos:32,+cov
index da97248c8..da97248c8 100644
--- a/src/mint/afl-tests/id:000037,src:000000,op:flip1,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000037,src:000000,op:flip1,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000038,src:000000,op:flip1,pos:32 b/src/exchange/afl-tests/id:000038,src:000000,op:flip1,pos:32
index 118e79796..118e79796 100644
--- a/src/mint/afl-tests/id:000038,src:000000,op:flip1,pos:32
+++ b/src/exchange/afl-tests/id:000038,src:000000,op:flip1,pos:32
diff --git a/src/mint/afl-tests/id:000038,src:000000,op:flip1,pos:32,+cov b/src/exchange/afl-tests/id:000038,src:000000,op:flip1,pos:32,+cov
index b4394dc36..b4394dc36 100644
--- a/src/mint/afl-tests/id:000038,src:000000,op:flip1,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000038,src:000000,op:flip1,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000039,src:000000,op:flip1,pos:32,+cov b/src/exchange/afl-tests/id:000039,src:000000,op:flip1,pos:32,+cov
index 450ce2aa1..450ce2aa1 100644
--- a/src/mint/afl-tests/id:000039,src:000000,op:flip1,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000039,src:000000,op:flip1,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000039,src:000000,op:flip1,pos:34,+cov b/src/exchange/afl-tests/id:000039,src:000000,op:flip1,pos:34,+cov
index 4c6751fa1..4c6751fa1 100644
--- a/src/mint/afl-tests/id:000039,src:000000,op:flip1,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000039,src:000000,op:flip1,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000040,src:000000,op:flip1,pos:32,+cov b/src/exchange/afl-tests/id:000040,src:000000,op:flip1,pos:32,+cov
index 32d481622..32d481622 100644
--- a/src/mint/afl-tests/id:000040,src:000000,op:flip1,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000040,src:000000,op:flip1,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000040,src:000000,op:flip1,pos:34,+cov b/src/exchange/afl-tests/id:000040,src:000000,op:flip1,pos:34,+cov
index 67a5342b0..67a5342b0 100644
--- a/src/mint/afl-tests/id:000040,src:000000,op:flip1,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000040,src:000000,op:flip1,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000041,src:000000,op:flip1,pos:34,+cov b/src/exchange/afl-tests/id:000041,src:000000,op:flip1,pos:34,+cov
index 4c6751fa1..4c6751fa1 100644
--- a/src/mint/afl-tests/id:000041,src:000000,op:flip1,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000041,src:000000,op:flip1,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000041,src:000000,op:flip1,pos:36,+cov b/src/exchange/afl-tests/id:000041,src:000000,op:flip1,pos:36,+cov
index a647f780b..a647f780b 100644
--- a/src/mint/afl-tests/id:000041,src:000000,op:flip1,pos:36,+cov
+++ b/src/exchange/afl-tests/id:000041,src:000000,op:flip1,pos:36,+cov
diff --git a/src/mint/afl-tests/id:000042,src:000000,op:flip1,pos:36,+cov b/src/exchange/afl-tests/id:000042,src:000000,op:flip1,pos:36,+cov
index 3ec22972a..3ec22972a 100644
--- a/src/mint/afl-tests/id:000042,src:000000,op:flip1,pos:36,+cov
+++ b/src/exchange/afl-tests/id:000042,src:000000,op:flip1,pos:36,+cov
diff --git a/src/mint/afl-tests/id:000043,src:000000,op:flip1,pos:37,+cov b/src/exchange/afl-tests/id:000043,src:000000,op:flip1,pos:37,+cov
index a8dc5e751..a8dc5e751 100644
--- a/src/mint/afl-tests/id:000043,src:000000,op:flip1,pos:37,+cov
+++ b/src/exchange/afl-tests/id:000043,src:000000,op:flip1,pos:37,+cov
diff --git a/src/mint/afl-tests/id:000043,src:000000,op:flip1,pos:38 b/src/exchange/afl-tests/id:000043,src:000000,op:flip1,pos:38
index 7b596a2c7..7b596a2c7 100644
--- a/src/mint/afl-tests/id:000043,src:000000,op:flip1,pos:38
+++ b/src/exchange/afl-tests/id:000043,src:000000,op:flip1,pos:38
diff --git a/src/mint/afl-tests/id:000044,src:000000,op:flip1,pos:38 b/src/exchange/afl-tests/id:000044,src:000000,op:flip1,pos:38
index 7b596a2c7..7b596a2c7 100644
--- a/src/mint/afl-tests/id:000044,src:000000,op:flip1,pos:38
+++ b/src/exchange/afl-tests/id:000044,src:000000,op:flip1,pos:38
diff --git a/src/mint/afl-tests/id:000044,src:000000,op:flip1,pos:38,+cov b/src/exchange/afl-tests/id:000044,src:000000,op:flip1,pos:38,+cov
index 4ff51d8ef..4ff51d8ef 100644
--- a/src/mint/afl-tests/id:000044,src:000000,op:flip1,pos:38,+cov
+++ b/src/exchange/afl-tests/id:000044,src:000000,op:flip1,pos:38,+cov
diff --git a/src/mint/afl-tests/id:000045,src:000000,op:flip1,pos:38,+cov b/src/exchange/afl-tests/id:000045,src:000000,op:flip1,pos:38,+cov
index ef215ea3b..ef215ea3b 100644
--- a/src/mint/afl-tests/id:000045,src:000000,op:flip1,pos:38,+cov
+++ b/src/exchange/afl-tests/id:000045,src:000000,op:flip1,pos:38,+cov
diff --git a/src/mint/afl-tests/id:000045,src:000000,op:flip1,pos:39,+cov b/src/exchange/afl-tests/id:000045,src:000000,op:flip1,pos:39,+cov
index 0cee2b153..0cee2b153 100644
--- a/src/mint/afl-tests/id:000045,src:000000,op:flip1,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000045,src:000000,op:flip1,pos:39,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000046,src:000000,op:flip1,pos:39,+cov b/src/exchange/afl-tests/id:000046,src:000000,op:flip1,pos:39,+cov
index 0cee2b153..0cee2b153 100644
--- a/src/mint/afl-tests/id:000046,src:000000,op:flip1,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000046,src:000000,op:flip1,pos:39,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000047,src:000000,op:flip1,pos:39 b/src/exchange/afl-tests/id:000047,src:000000,op:flip1,pos:39
index efad51cd9..efad51cd9 100644
--- a/src/mint/afl-tests/id:000047,src:000000,op:flip1,pos:39
+++ b/src/exchange/afl-tests/id:000047,src:000000,op:flip1,pos:39
diff --git a/src/mint/afl-tests/id:000047,src:000000,op:flip1,pos:39,+cov b/src/exchange/afl-tests/id:000047,src:000000,op:flip1,pos:39,+cov
index 192ce6805..192ce6805 100644
--- a/src/mint/afl-tests/id:000047,src:000000,op:flip1,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000047,src:000000,op:flip1,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000048,src:000000,op:flip1,pos:39,+cov b/src/exchange/afl-tests/id:000048,src:000000,op:flip1,pos:39,+cov
index 192ce6805..192ce6805 100644
--- a/src/mint/afl-tests/id:000048,src:000000,op:flip1,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000048,src:000000,op:flip1,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000048,src:000000,op:flip1,pos:40,+cov b/src/exchange/afl-tests/id:000048,src:000000,op:flip1,pos:40,+cov
index eead8e8f8..eead8e8f8 100644
--- a/src/mint/afl-tests/id:000048,src:000000,op:flip1,pos:40,+cov
+++ b/src/exchange/afl-tests/id:000048,src:000000,op:flip1,pos:40,+cov
diff --git a/src/mint/afl-tests/id:000049,src:000000,op:flip1,pos:41,+cov b/src/exchange/afl-tests/id:000049,src:000000,op:flip1,pos:41,+cov
index cebfe49cc..cebfe49cc 100644
--- a/src/mint/afl-tests/id:000049,src:000000,op:flip1,pos:41,+cov
+++ b/src/exchange/afl-tests/id:000049,src:000000,op:flip1,pos:41,+cov
diff --git a/src/mint/afl-tests/id:000050,src:000000,op:flip1,pos:41,+cov b/src/exchange/afl-tests/id:000050,src:000000,op:flip1,pos:41,+cov
index b1b340511..b1b340511 100644
--- a/src/mint/afl-tests/id:000050,src:000000,op:flip1,pos:41,+cov
+++ b/src/exchange/afl-tests/id:000050,src:000000,op:flip1,pos:41,+cov
diff --git a/src/mint/afl-tests/id:000050,src:000000,op:flip1,pos:42,+cov b/src/exchange/afl-tests/id:000050,src:000000,op:flip1,pos:42,+cov
index a6ed1cc27..a6ed1cc27 100644
--- a/src/mint/afl-tests/id:000050,src:000000,op:flip1,pos:42,+cov
+++ b/src/exchange/afl-tests/id:000050,src:000000,op:flip1,pos:42,+cov
diff --git a/src/mint/afl-tests/id:000051,src:000000,op:flip1,pos:41,+cov b/src/exchange/afl-tests/id:000051,src:000000,op:flip1,pos:41,+cov
index 01a348c5a..01a348c5a 100644
--- a/src/mint/afl-tests/id:000051,src:000000,op:flip1,pos:41,+cov
+++ b/src/exchange/afl-tests/id:000051,src:000000,op:flip1,pos:41,+cov
diff --git a/src/mint/afl-tests/id:000051,src:000000,op:flip1,pos:47,+cov b/src/exchange/afl-tests/id:000051,src:000000,op:flip1,pos:47,+cov
index 8c63b4898..8c63b4898 100644
--- a/src/mint/afl-tests/id:000051,src:000000,op:flip1,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000051,src:000000,op:flip1,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000052,src:000000,op:flip1,pos:42,+cov b/src/exchange/afl-tests/id:000052,src:000000,op:flip1,pos:42,+cov
index 4fdb1b817..4fdb1b817 100644
--- a/src/mint/afl-tests/id:000052,src:000000,op:flip1,pos:42,+cov
+++ b/src/exchange/afl-tests/id:000052,src:000000,op:flip1,pos:42,+cov
diff --git a/src/mint/afl-tests/id:000052,src:000000,op:flip1,pos:47,+cov b/src/exchange/afl-tests/id:000052,src:000000,op:flip1,pos:47,+cov
index 8df30e7e2..8df30e7e2 100644
--- a/src/mint/afl-tests/id:000052,src:000000,op:flip1,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000052,src:000000,op:flip1,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000053,src:000000,op:flip1,pos:42,+cov b/src/exchange/afl-tests/id:000053,src:000000,op:flip1,pos:42,+cov
index f389ef560..f389ef560 100644
--- a/src/mint/afl-tests/id:000053,src:000000,op:flip1,pos:42,+cov
+++ b/src/exchange/afl-tests/id:000053,src:000000,op:flip1,pos:42,+cov
diff --git a/src/mint/afl-tests/id:000053,src:000000,op:flip1,pos:47,+cov b/src/exchange/afl-tests/id:000053,src:000000,op:flip1,pos:47,+cov
index 8b8be65ce..8b8be65ce 100644
--- a/src/mint/afl-tests/id:000053,src:000000,op:flip1,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000053,src:000000,op:flip1,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000054,src:000000,op:flip1,pos:43,+cov b/src/exchange/afl-tests/id:000054,src:000000,op:flip1,pos:43,+cov
index 786a4736f..786a4736f 100644
--- a/src/mint/afl-tests/id:000054,src:000000,op:flip1,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000054,src:000000,op:flip1,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000054,src:000000,op:flip1,pos:49,+cov b/src/exchange/afl-tests/id:000054,src:000000,op:flip1,pos:49,+cov
index b2c1febcb..b2c1febcb 100644
--- a/src/mint/afl-tests/id:000054,src:000000,op:flip1,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000054,src:000000,op:flip1,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000055,src:000000,op:flip1,pos:43,+cov b/src/exchange/afl-tests/id:000055,src:000000,op:flip1,pos:43,+cov
index 1f0070c32..1f0070c32 100644
--- a/src/mint/afl-tests/id:000055,src:000000,op:flip1,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000055,src:000000,op:flip1,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000055,src:000000,op:flip1,pos:52,+cov b/src/exchange/afl-tests/id:000055,src:000000,op:flip1,pos:52,+cov
index 16f5a9a23..16f5a9a23 100644
--- a/src/mint/afl-tests/id:000055,src:000000,op:flip1,pos:52,+cov
+++ b/src/exchange/afl-tests/id:000055,src:000000,op:flip1,pos:52,+cov
diff --git a/src/mint/afl-tests/id:000056,src:000000,op:flip1,pos:44,+cov b/src/exchange/afl-tests/id:000056,src:000000,op:flip1,pos:44,+cov
index 2c0c049af..2c0c049af 100644
--- a/src/mint/afl-tests/id:000056,src:000000,op:flip1,pos:44,+cov
+++ b/src/exchange/afl-tests/id:000056,src:000000,op:flip1,pos:44,+cov
diff --git a/src/mint/afl-tests/id:000056,src:000000,op:flip1,pos:52,+cov b/src/exchange/afl-tests/id:000056,src:000000,op:flip1,pos:52,+cov
index 5da12c78c..5da12c78c 100644
--- a/src/mint/afl-tests/id:000056,src:000000,op:flip1,pos:52,+cov
+++ b/src/exchange/afl-tests/id:000056,src:000000,op:flip1,pos:52,+cov
diff --git a/src/mint/afl-tests/id:000057,src:000000,op:flip1,pos:47,+cov b/src/exchange/afl-tests/id:000057,src:000000,op:flip1,pos:47,+cov
index 8c63b4898..8c63b4898 100644
--- a/src/mint/afl-tests/id:000057,src:000000,op:flip1,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000057,src:000000,op:flip1,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000057,src:000000,op:flip1,pos:54,+cov b/src/exchange/afl-tests/id:000057,src:000000,op:flip1,pos:54,+cov
index cf648c561..cf648c561 100644
--- a/src/mint/afl-tests/id:000057,src:000000,op:flip1,pos:54,+cov
+++ b/src/exchange/afl-tests/id:000057,src:000000,op:flip1,pos:54,+cov
diff --git a/src/mint/afl-tests/id:000058,src:000000,op:flip1,pos:47,+cov b/src/exchange/afl-tests/id:000058,src:000000,op:flip1,pos:47,+cov
index 9c4f77f1f..9c4f77f1f 100644
--- a/src/mint/afl-tests/id:000058,src:000000,op:flip1,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000058,src:000000,op:flip1,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000058,src:000000,op:flip1,pos:54,+cov b/src/exchange/afl-tests/id:000058,src:000000,op:flip1,pos:54,+cov
index 7c16c0071..7c16c0071 100644
--- a/src/mint/afl-tests/id:000058,src:000000,op:flip1,pos:54,+cov
+++ b/src/exchange/afl-tests/id:000058,src:000000,op:flip1,pos:54,+cov
diff --git a/src/mint/afl-tests/id:000059,src:000000,op:flip1,pos:48,+cov b/src/exchange/afl-tests/id:000059,src:000000,op:flip1,pos:48,+cov
index c830e88dc..c830e88dc 100644
--- a/src/mint/afl-tests/id:000059,src:000000,op:flip1,pos:48,+cov
+++ b/src/exchange/afl-tests/id:000059,src:000000,op:flip1,pos:48,+cov
diff --git a/src/mint/afl-tests/id:000059,src:000000,op:flip1,pos:55,+cov b/src/exchange/afl-tests/id:000059,src:000000,op:flip1,pos:55,+cov
index 456b76d8f..456b76d8f 100644
--- a/src/mint/afl-tests/id:000059,src:000000,op:flip1,pos:55,+cov
+++ b/src/exchange/afl-tests/id:000059,src:000000,op:flip1,pos:55,+cov
diff --git a/src/mint/afl-tests/id:000060,src:000000,op:flip1,pos:49,+cov b/src/exchange/afl-tests/id:000060,src:000000,op:flip1,pos:49,+cov
index a2b330a31..a2b330a31 100644
--- a/src/mint/afl-tests/id:000060,src:000000,op:flip1,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000060,src:000000,op:flip1,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000060,src:000000,op:flip1,pos:56,+cov b/src/exchange/afl-tests/id:000060,src:000000,op:flip1,pos:56,+cov
index ac1e30e4e..ac1e30e4e 100644
--- a/src/mint/afl-tests/id:000060,src:000000,op:flip1,pos:56,+cov
+++ b/src/exchange/afl-tests/id:000060,src:000000,op:flip1,pos:56,+cov
diff --git a/src/mint/afl-tests/id:000061,src:000000,op:flip1,pos:50,+cov b/src/exchange/afl-tests/id:000061,src:000000,op:flip1,pos:50,+cov
index 82aa47f06..82aa47f06 100644
--- a/src/mint/afl-tests/id:000061,src:000000,op:flip1,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000061,src:000000,op:flip1,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000061,src:000000,op:flip1,pos:59,+cov b/src/exchange/afl-tests/id:000061,src:000000,op:flip1,pos:59,+cov
index eb2ab1fd3..eb2ab1fd3 100644
--- a/src/mint/afl-tests/id:000061,src:000000,op:flip1,pos:59,+cov
+++ b/src/exchange/afl-tests/id:000061,src:000000,op:flip1,pos:59,+cov
diff --git a/src/mint/afl-tests/id:000062,src:000000,op:flip1,pos:51,+cov b/src/exchange/afl-tests/id:000062,src:000000,op:flip1,pos:51,+cov
index 494399d0f..494399d0f 100644
--- a/src/mint/afl-tests/id:000062,src:000000,op:flip1,pos:51,+cov
+++ b/src/exchange/afl-tests/id:000062,src:000000,op:flip1,pos:51,+cov
diff --git a/src/mint/afl-tests/id:000062,src:000000,op:flip1,pos:60,+cov b/src/exchange/afl-tests/id:000062,src:000000,op:flip1,pos:60,+cov
index 73523bbcc..73523bbcc 100644
--- a/src/mint/afl-tests/id:000062,src:000000,op:flip1,pos:60,+cov
+++ b/src/exchange/afl-tests/id:000062,src:000000,op:flip1,pos:60,+cov
diff --git a/src/mint/afl-tests/id:000063,src:000000,op:flip1,pos:54 b/src/exchange/afl-tests/id:000063,src:000000,op:flip1,pos:54
index cf648c561..cf648c561 100644
--- a/src/mint/afl-tests/id:000063,src:000000,op:flip1,pos:54
+++ b/src/exchange/afl-tests/id:000063,src:000000,op:flip1,pos:54
diff --git a/src/mint/afl-tests/id:000063,src:000000,op:flip1,pos:61,+cov b/src/exchange/afl-tests/id:000063,src:000000,op:flip1,pos:61,+cov
index 58032bd77..58032bd77 100644
--- a/src/mint/afl-tests/id:000063,src:000000,op:flip1,pos:61,+cov
+++ b/src/exchange/afl-tests/id:000063,src:000000,op:flip1,pos:61,+cov
diff --git a/src/mint/afl-tests/id:000064,src:000000,op:flip1,pos:55,+cov b/src/exchange/afl-tests/id:000064,src:000000,op:flip1,pos:55,+cov
index 456b76d8f..456b76d8f 100644
--- a/src/mint/afl-tests/id:000064,src:000000,op:flip1,pos:55,+cov
+++ b/src/exchange/afl-tests/id:000064,src:000000,op:flip1,pos:55,+cov
diff --git a/src/mint/afl-tests/id:000064,src:000000,op:flip1,pos:62,+cov b/src/exchange/afl-tests/id:000064,src:000000,op:flip1,pos:62,+cov
index 8f1e99ed4..8f1e99ed4 100644
--- a/src/mint/afl-tests/id:000064,src:000000,op:flip1,pos:62,+cov
+++ b/src/exchange/afl-tests/id:000064,src:000000,op:flip1,pos:62,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000065,src:000000,op:flip1,pos:55,+cov b/src/exchange/afl-tests/id:000065,src:000000,op:flip1,pos:55,+cov
index 54da3e6cf..54da3e6cf 100644
--- a/src/mint/afl-tests/id:000065,src:000000,op:flip1,pos:55,+cov
+++ b/src/exchange/afl-tests/id:000065,src:000000,op:flip1,pos:55,+cov
diff --git a/src/mint/afl-tests/id:000065,src:000000,op:flip1,pos:63,+cov b/src/exchange/afl-tests/id:000065,src:000000,op:flip1,pos:63,+cov
index 6601e27c8..6601e27c8 100644
--- a/src/mint/afl-tests/id:000065,src:000000,op:flip1,pos:63,+cov
+++ b/src/exchange/afl-tests/id:000065,src:000000,op:flip1,pos:63,+cov
diff --git a/src/mint/afl-tests/id:000066,src:000000,op:flip1,pos:56,+cov b/src/exchange/afl-tests/id:000066,src:000000,op:flip1,pos:56,+cov
index ac1e30e4e..ac1e30e4e 100644
--- a/src/mint/afl-tests/id:000066,src:000000,op:flip1,pos:56,+cov
+++ b/src/exchange/afl-tests/id:000066,src:000000,op:flip1,pos:56,+cov
diff --git a/src/mint/afl-tests/id:000066,src:000000,op:flip1,pos:63,+cov b/src/exchange/afl-tests/id:000066,src:000000,op:flip1,pos:63,+cov
index 02f7cc662..02f7cc662 100644
--- a/src/mint/afl-tests/id:000066,src:000000,op:flip1,pos:63,+cov
+++ b/src/exchange/afl-tests/id:000066,src:000000,op:flip1,pos:63,+cov
diff --git a/src/mint/afl-tests/id:000067,src:000000,op:flip1,pos:58,+cov b/src/exchange/afl-tests/id:000067,src:000000,op:flip1,pos:58,+cov
index 82b57e5f4..82b57e5f4 100644
--- a/src/mint/afl-tests/id:000067,src:000000,op:flip1,pos:58,+cov
+++ b/src/exchange/afl-tests/id:000067,src:000000,op:flip1,pos:58,+cov
diff --git a/src/mint/afl-tests/id:000067,src:000000,op:flip1,pos:65,+cov b/src/exchange/afl-tests/id:000067,src:000000,op:flip1,pos:65,+cov
index f032e2a47..f032e2a47 100644
--- a/src/mint/afl-tests/id:000067,src:000000,op:flip1,pos:65,+cov
+++ b/src/exchange/afl-tests/id:000067,src:000000,op:flip1,pos:65,+cov
diff --git a/src/mint/afl-tests/id:000068,src:000000,op:flip1,pos:60,+cov b/src/exchange/afl-tests/id:000068,src:000000,op:flip1,pos:60,+cov
index 73523bbcc..73523bbcc 100644
--- a/src/mint/afl-tests/id:000068,src:000000,op:flip1,pos:60,+cov
+++ b/src/exchange/afl-tests/id:000068,src:000000,op:flip1,pos:60,+cov
diff --git a/src/mint/afl-tests/id:000068,src:000000,op:flip1,pos:66,+cov b/src/exchange/afl-tests/id:000068,src:000000,op:flip1,pos:66,+cov
index 55e544a9e..55e544a9e 100644
--- a/src/mint/afl-tests/id:000068,src:000000,op:flip1,pos:66,+cov
+++ b/src/exchange/afl-tests/id:000068,src:000000,op:flip1,pos:66,+cov
diff --git a/src/mint/afl-tests/id:000069,src:000000,op:flip1,pos:61,+cov b/src/exchange/afl-tests/id:000069,src:000000,op:flip1,pos:61,+cov
index 58032bd77..58032bd77 100644
--- a/src/mint/afl-tests/id:000069,src:000000,op:flip1,pos:61,+cov
+++ b/src/exchange/afl-tests/id:000069,src:000000,op:flip1,pos:61,+cov
diff --git a/src/mint/afl-tests/id:000069,src:000000,op:flip1,pos:67,+cov b/src/exchange/afl-tests/id:000069,src:000000,op:flip1,pos:67,+cov
index 7576575c7..7576575c7 100644
--- a/src/mint/afl-tests/id:000069,src:000000,op:flip1,pos:67,+cov
+++ b/src/exchange/afl-tests/id:000069,src:000000,op:flip1,pos:67,+cov
diff --git a/src/mint/afl-tests/id:000070,src:000000,op:flip1,pos:62,+cov b/src/exchange/afl-tests/id:000070,src:000000,op:flip1,pos:62,+cov
index 7d09a8db2..7d09a8db2 100644
--- a/src/mint/afl-tests/id:000070,src:000000,op:flip1,pos:62,+cov
+++ b/src/exchange/afl-tests/id:000070,src:000000,op:flip1,pos:62,+cov
diff --git a/src/mint/afl-tests/id:000070,src:000000,op:flip1,pos:69,+cov b/src/exchange/afl-tests/id:000070,src:000000,op:flip1,pos:69,+cov
index c46483ddf..c46483ddf 100644
--- a/src/mint/afl-tests/id:000070,src:000000,op:flip1,pos:69,+cov
+++ b/src/exchange/afl-tests/id:000070,src:000000,op:flip1,pos:69,+cov
diff --git a/src/mint/afl-tests/id:000071,src:000000,op:flip1,pos:62,+cov b/src/exchange/afl-tests/id:000071,src:000000,op:flip1,pos:62,+cov
index 8f1e99ed4..8f1e99ed4 100644
--- a/src/mint/afl-tests/id:000071,src:000000,op:flip1,pos:62,+cov
+++ b/src/exchange/afl-tests/id:000071,src:000000,op:flip1,pos:62,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000071,src:000000,op:flip1,pos:74,+cov b/src/exchange/afl-tests/id:000071,src:000000,op:flip1,pos:74,+cov
index 83f03098e..83f03098e 100644
--- a/src/mint/afl-tests/id:000071,src:000000,op:flip1,pos:74,+cov
+++ b/src/exchange/afl-tests/id:000071,src:000000,op:flip1,pos:74,+cov
diff --git a/src/mint/afl-tests/id:000072,src:000000,op:flip1,pos:63,+cov b/src/exchange/afl-tests/id:000072,src:000000,op:flip1,pos:63,+cov
index 6601e27c8..6601e27c8 100644
--- a/src/mint/afl-tests/id:000072,src:000000,op:flip1,pos:63,+cov
+++ b/src/exchange/afl-tests/id:000072,src:000000,op:flip1,pos:63,+cov
diff --git a/src/mint/afl-tests/id:000072,src:000000,op:flip1,pos:76,+cov b/src/exchange/afl-tests/id:000072,src:000000,op:flip1,pos:76,+cov
index 9970eebf4..9970eebf4 100644
--- a/src/mint/afl-tests/id:000072,src:000000,op:flip1,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000072,src:000000,op:flip1,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000073,src:000000,op:flip1,pos:64,+cov b/src/exchange/afl-tests/id:000073,src:000000,op:flip1,pos:64,+cov
index f7dab72cf..f7dab72cf 100644
--- a/src/mint/afl-tests/id:000073,src:000000,op:flip1,pos:64,+cov
+++ b/src/exchange/afl-tests/id:000073,src:000000,op:flip1,pos:64,+cov
diff --git a/src/mint/afl-tests/id:000073,src:000000,op:flip1,pos:81,+cov b/src/exchange/afl-tests/id:000073,src:000000,op:flip1,pos:81,+cov
index 0e3095c5b..0e3095c5b 100644
--- a/src/mint/afl-tests/id:000073,src:000000,op:flip1,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000073,src:000000,op:flip1,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000074,src:000000,op:flip1,pos:65,+cov b/src/exchange/afl-tests/id:000074,src:000000,op:flip1,pos:65,+cov
index f032e2a47..f032e2a47 100644
--- a/src/mint/afl-tests/id:000074,src:000000,op:flip1,pos:65,+cov
+++ b/src/exchange/afl-tests/id:000074,src:000000,op:flip1,pos:65,+cov
diff --git a/src/mint/afl-tests/id:000074,src:000000,op:flip1,pos:82,+cov b/src/exchange/afl-tests/id:000074,src:000000,op:flip1,pos:82,+cov
index 22e96e268..22e96e268 100644
--- a/src/mint/afl-tests/id:000074,src:000000,op:flip1,pos:82,+cov
+++ b/src/exchange/afl-tests/id:000074,src:000000,op:flip1,pos:82,+cov
diff --git a/src/mint/afl-tests/id:000075,src:000000,op:flip1,pos:71,+cov b/src/exchange/afl-tests/id:000075,src:000000,op:flip1,pos:71,+cov
index a6c721364..a6c721364 100644
--- a/src/mint/afl-tests/id:000075,src:000000,op:flip1,pos:71,+cov
+++ b/src/exchange/afl-tests/id:000075,src:000000,op:flip1,pos:71,+cov
diff --git a/src/mint/afl-tests/id:000075,src:000000,op:flip1,pos:82,+cov b/src/exchange/afl-tests/id:000075,src:000000,op:flip1,pos:82,+cov
index eda09494e..eda09494e 100644
--- a/src/mint/afl-tests/id:000075,src:000000,op:flip1,pos:82,+cov
+++ b/src/exchange/afl-tests/id:000075,src:000000,op:flip1,pos:82,+cov
diff --git a/src/mint/afl-tests/id:000076,src:000000,op:flip1,pos:71 b/src/exchange/afl-tests/id:000076,src:000000,op:flip1,pos:71
index dba3e3724..dba3e3724 100644
--- a/src/mint/afl-tests/id:000076,src:000000,op:flip1,pos:71
+++ b/src/exchange/afl-tests/id:000076,src:000000,op:flip1,pos:71
diff --git a/src/mint/afl-tests/id:000076,src:000000,op:flip1,pos:83,+cov b/src/exchange/afl-tests/id:000076,src:000000,op:flip1,pos:83,+cov
index 0ca7b6520..0ca7b6520 100644
--- a/src/mint/afl-tests/id:000076,src:000000,op:flip1,pos:83,+cov
+++ b/src/exchange/afl-tests/id:000076,src:000000,op:flip1,pos:83,+cov
diff --git a/src/mint/afl-tests/id:000077,src:000000,op:flip1,pos:72,+cov b/src/exchange/afl-tests/id:000077,src:000000,op:flip1,pos:72,+cov
index 32f5f86e6..32f5f86e6 100644
--- a/src/mint/afl-tests/id:000077,src:000000,op:flip1,pos:72,+cov
+++ b/src/exchange/afl-tests/id:000077,src:000000,op:flip1,pos:72,+cov
diff --git a/src/mint/afl-tests/id:000077,src:000000,op:flip1,pos:85,+cov b/src/exchange/afl-tests/id:000077,src:000000,op:flip1,pos:85,+cov
index 499a159eb..499a159eb 100644
--- a/src/mint/afl-tests/id:000077,src:000000,op:flip1,pos:85,+cov
+++ b/src/exchange/afl-tests/id:000077,src:000000,op:flip1,pos:85,+cov
diff --git a/src/mint/afl-tests/id:000078,src:000000,op:flip1,pos:73,+cov b/src/exchange/afl-tests/id:000078,src:000000,op:flip1,pos:73,+cov
index 1eb904938..1eb904938 100644
--- a/src/mint/afl-tests/id:000078,src:000000,op:flip1,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000078,src:000000,op:flip1,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000078,src:000000,op:flip1,pos:87,+cov b/src/exchange/afl-tests/id:000078,src:000000,op:flip1,pos:87,+cov
index f9553ca12..f9553ca12 100644
--- a/src/mint/afl-tests/id:000078,src:000000,op:flip1,pos:87,+cov
+++ b/src/exchange/afl-tests/id:000078,src:000000,op:flip1,pos:87,+cov
diff --git a/src/mint/afl-tests/id:000079,src:000000,op:flip1,pos:74,+cov b/src/exchange/afl-tests/id:000079,src:000000,op:flip1,pos:74,+cov
index 83f03098e..83f03098e 100644
--- a/src/mint/afl-tests/id:000079,src:000000,op:flip1,pos:74,+cov
+++ b/src/exchange/afl-tests/id:000079,src:000000,op:flip1,pos:74,+cov
diff --git a/src/mint/afl-tests/id:000079,src:000000,op:flip1,pos:87,+cov b/src/exchange/afl-tests/id:000079,src:000000,op:flip1,pos:87,+cov
index f8c7d5710..f8c7d5710 100644
--- a/src/mint/afl-tests/id:000079,src:000000,op:flip1,pos:87,+cov
+++ b/src/exchange/afl-tests/id:000079,src:000000,op:flip1,pos:87,+cov
diff --git a/src/mint/afl-tests/id:000080,src:000000,op:flip1,pos:75,+cov b/src/exchange/afl-tests/id:000080,src:000000,op:flip1,pos:75,+cov
index 5e2b2b9b7..5e2b2b9b7 100644
--- a/src/mint/afl-tests/id:000080,src:000000,op:flip1,pos:75,+cov
+++ b/src/exchange/afl-tests/id:000080,src:000000,op:flip1,pos:75,+cov
diff --git a/src/mint/afl-tests/id:000080,src:000000,op:flip1,pos:87,+cov b/src/exchange/afl-tests/id:000080,src:000000,op:flip1,pos:87,+cov
index 32a24e382..32a24e382 100644
--- a/src/mint/afl-tests/id:000080,src:000000,op:flip1,pos:87,+cov
+++ b/src/exchange/afl-tests/id:000080,src:000000,op:flip1,pos:87,+cov
diff --git a/src/mint/afl-tests/id:000081,src:000000,op:flip1,pos:75,+cov b/src/exchange/afl-tests/id:000081,src:000000,op:flip1,pos:75,+cov
index 4502212cd..4502212cd 100644
--- a/src/mint/afl-tests/id:000081,src:000000,op:flip1,pos:75,+cov
+++ b/src/exchange/afl-tests/id:000081,src:000000,op:flip1,pos:75,+cov
diff --git a/src/mint/afl-tests/id:000081,src:000000,op:flip1,pos:90,+cov b/src/exchange/afl-tests/id:000081,src:000000,op:flip1,pos:90,+cov
index 3b63b93a1..3b63b93a1 100644
--- a/src/mint/afl-tests/id:000081,src:000000,op:flip1,pos:90,+cov
+++ b/src/exchange/afl-tests/id:000081,src:000000,op:flip1,pos:90,+cov
diff --git a/src/mint/afl-tests/id:000082,src:000000,op:flip1,pos:76,+cov b/src/exchange/afl-tests/id:000082,src:000000,op:flip1,pos:76,+cov
index 10625de92..10625de92 100644
--- a/src/mint/afl-tests/id:000082,src:000000,op:flip1,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000082,src:000000,op:flip1,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000082,src:000000,op:flip1,pos:92,+cov b/src/exchange/afl-tests/id:000082,src:000000,op:flip1,pos:92,+cov
index ce1c543de..ce1c543de 100644
--- a/src/mint/afl-tests/id:000082,src:000000,op:flip1,pos:92,+cov
+++ b/src/exchange/afl-tests/id:000082,src:000000,op:flip1,pos:92,+cov
diff --git a/src/mint/afl-tests/id:000083,src:000000,op:flip1,pos:78,+cov b/src/exchange/afl-tests/id:000083,src:000000,op:flip1,pos:78,+cov
index 2c98ec508..2c98ec508 100644
--- a/src/mint/afl-tests/id:000083,src:000000,op:flip1,pos:78,+cov
+++ b/src/exchange/afl-tests/id:000083,src:000000,op:flip1,pos:78,+cov
diff --git a/src/mint/afl-tests/id:000083,src:000000,op:flip1,pos:93,+cov b/src/exchange/afl-tests/id:000083,src:000000,op:flip1,pos:93,+cov
index d716cdbf1..d716cdbf1 100644
--- a/src/mint/afl-tests/id:000083,src:000000,op:flip1,pos:93,+cov
+++ b/src/exchange/afl-tests/id:000083,src:000000,op:flip1,pos:93,+cov
diff --git a/src/mint/afl-tests/id:000084,src:000000,op:flip1,pos:80,+cov b/src/exchange/afl-tests/id:000084,src:000000,op:flip1,pos:80,+cov
index daa253035..daa253035 100644
--- a/src/mint/afl-tests/id:000084,src:000000,op:flip1,pos:80,+cov
+++ b/src/exchange/afl-tests/id:000084,src:000000,op:flip1,pos:80,+cov
diff --git a/src/mint/afl-tests/id:000084,src:000000,op:flip1,pos:95,+cov b/src/exchange/afl-tests/id:000084,src:000000,op:flip1,pos:95,+cov
index aa123c67d..aa123c67d 100644
--- a/src/mint/afl-tests/id:000084,src:000000,op:flip1,pos:95,+cov
+++ b/src/exchange/afl-tests/id:000084,src:000000,op:flip1,pos:95,+cov
diff --git a/src/mint/afl-tests/id:000085,src:000000,op:flip1,pos:80,+cov b/src/exchange/afl-tests/id:000085,src:000000,op:flip1,pos:80,+cov
index 027d74b3e..027d74b3e 100644
--- a/src/mint/afl-tests/id:000085,src:000000,op:flip1,pos:80,+cov
+++ b/src/exchange/afl-tests/id:000085,src:000000,op:flip1,pos:80,+cov
diff --git a/src/mint/afl-tests/id:000085,src:000000,op:flip1,pos:95,+cov b/src/exchange/afl-tests/id:000085,src:000000,op:flip1,pos:95,+cov
index 3e2e8ef82..3e2e8ef82 100644
--- a/src/mint/afl-tests/id:000085,src:000000,op:flip1,pos:95,+cov
+++ b/src/exchange/afl-tests/id:000085,src:000000,op:flip1,pos:95,+cov
diff --git a/src/mint/afl-tests/id:000086,src:000000,op:flip1,pos:81,+cov b/src/exchange/afl-tests/id:000086,src:000000,op:flip1,pos:81,+cov
index 33755bbf0..33755bbf0 100644
--- a/src/mint/afl-tests/id:000086,src:000000,op:flip1,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000086,src:000000,op:flip1,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000086,src:000000,op:flip1,pos:96,+cov b/src/exchange/afl-tests/id:000086,src:000000,op:flip1,pos:96,+cov
index 66a826aa6..66a826aa6 100644
--- a/src/mint/afl-tests/id:000086,src:000000,op:flip1,pos:96,+cov
+++ b/src/exchange/afl-tests/id:000086,src:000000,op:flip1,pos:96,+cov
diff --git a/src/mint/afl-tests/id:000087,src:000000,op:flip1,pos:82,+cov b/src/exchange/afl-tests/id:000087,src:000000,op:flip1,pos:82,+cov
index ed126f923..ed126f923 100644
--- a/src/mint/afl-tests/id:000087,src:000000,op:flip1,pos:82,+cov
+++ b/src/exchange/afl-tests/id:000087,src:000000,op:flip1,pos:82,+cov
diff --git a/src/mint/afl-tests/id:000087,src:000000,op:flip1,pos:96,+cov b/src/exchange/afl-tests/id:000087,src:000000,op:flip1,pos:96,+cov
index fb1ee5046..fb1ee5046 100644
--- a/src/mint/afl-tests/id:000087,src:000000,op:flip1,pos:96,+cov
+++ b/src/exchange/afl-tests/id:000087,src:000000,op:flip1,pos:96,+cov
diff --git a/src/mint/afl-tests/id:000088,src:000000,op:flip1,pos:100,+cov b/src/exchange/afl-tests/id:000088,src:000000,op:flip1,pos:100,+cov
index f3f163262..f3f163262 100644
--- a/src/mint/afl-tests/id:000088,src:000000,op:flip1,pos:100,+cov
+++ b/src/exchange/afl-tests/id:000088,src:000000,op:flip1,pos:100,+cov
diff --git a/src/mint/afl-tests/id:000088,src:000000,op:flip1,pos:82,+cov b/src/exchange/afl-tests/id:000088,src:000000,op:flip1,pos:82,+cov
index 09ad95d46..09ad95d46 100644
--- a/src/mint/afl-tests/id:000088,src:000000,op:flip1,pos:82,+cov
+++ b/src/exchange/afl-tests/id:000088,src:000000,op:flip1,pos:82,+cov
diff --git a/src/mint/afl-tests/id:000089,src:000000,op:flip1,pos:105 b/src/exchange/afl-tests/id:000089,src:000000,op:flip1,pos:105
index c6f988227..c6f988227 100644
--- a/src/mint/afl-tests/id:000089,src:000000,op:flip1,pos:105
+++ b/src/exchange/afl-tests/id:000089,src:000000,op:flip1,pos:105
diff --git a/src/mint/afl-tests/id:000089,src:000000,op:flip1,pos:84,+cov b/src/exchange/afl-tests/id:000089,src:000000,op:flip1,pos:84,+cov
index ef0b4155b..ef0b4155b 100644
--- a/src/mint/afl-tests/id:000089,src:000000,op:flip1,pos:84,+cov
+++ b/src/exchange/afl-tests/id:000089,src:000000,op:flip1,pos:84,+cov
diff --git a/src/mint/afl-tests/id:000090,src:000000,op:flip1,pos:113,+cov b/src/exchange/afl-tests/id:000090,src:000000,op:flip1,pos:113,+cov
index b628943bc..b628943bc 100644
--- a/src/mint/afl-tests/id:000090,src:000000,op:flip1,pos:113,+cov
+++ b/src/exchange/afl-tests/id:000090,src:000000,op:flip1,pos:113,+cov
diff --git a/src/mint/afl-tests/id:000090,src:000000,op:flip1,pos:84,+cov b/src/exchange/afl-tests/id:000090,src:000000,op:flip1,pos:84,+cov
index 0c26f752d..0c26f752d 100644
--- a/src/mint/afl-tests/id:000090,src:000000,op:flip1,pos:84,+cov
+++ b/src/exchange/afl-tests/id:000090,src:000000,op:flip1,pos:84,+cov
diff --git a/src/mint/afl-tests/id:000091,src:000000,op:flip1,pos:114,+cov b/src/exchange/afl-tests/id:000091,src:000000,op:flip1,pos:114,+cov
index 4529026c6..4529026c6 100644
--- a/src/mint/afl-tests/id:000091,src:000000,op:flip1,pos:114,+cov
+++ b/src/exchange/afl-tests/id:000091,src:000000,op:flip1,pos:114,+cov
diff --git a/src/mint/afl-tests/id:000091,src:000000,op:flip1,pos:91,+cov b/src/exchange/afl-tests/id:000091,src:000000,op:flip1,pos:91,+cov
index ea6ec8e19..ea6ec8e19 100644
--- a/src/mint/afl-tests/id:000091,src:000000,op:flip1,pos:91,+cov
+++ b/src/exchange/afl-tests/id:000091,src:000000,op:flip1,pos:91,+cov
diff --git a/src/mint/afl-tests/id:000092,src:000000,op:flip1,pos:121,+cov b/src/exchange/afl-tests/id:000092,src:000000,op:flip1,pos:121,+cov
index 8f356caaf..8f356caaf 100644
--- a/src/mint/afl-tests/id:000092,src:000000,op:flip1,pos:121,+cov
+++ b/src/exchange/afl-tests/id:000092,src:000000,op:flip1,pos:121,+cov
diff --git a/src/mint/afl-tests/id:000092,src:000000,op:flip1,pos:92,+cov b/src/exchange/afl-tests/id:000092,src:000000,op:flip1,pos:92,+cov
index c612a5e8a..c612a5e8a 100644
--- a/src/mint/afl-tests/id:000092,src:000000,op:flip1,pos:92,+cov
+++ b/src/exchange/afl-tests/id:000092,src:000000,op:flip1,pos:92,+cov
diff --git a/src/mint/afl-tests/id:000093,src:000000,op:flip1,pos:123,+cov b/src/exchange/afl-tests/id:000093,src:000000,op:flip1,pos:123,+cov
index 7da2dd630..7da2dd630 100644
--- a/src/mint/afl-tests/id:000093,src:000000,op:flip1,pos:123,+cov
+++ b/src/exchange/afl-tests/id:000093,src:000000,op:flip1,pos:123,+cov
diff --git a/src/mint/afl-tests/id:000093,src:000000,op:flip1,pos:93,+cov b/src/exchange/afl-tests/id:000093,src:000000,op:flip1,pos:93,+cov
index 77e338910..77e338910 100644
--- a/src/mint/afl-tests/id:000093,src:000000,op:flip1,pos:93,+cov
+++ b/src/exchange/afl-tests/id:000093,src:000000,op:flip1,pos:93,+cov
diff --git a/src/mint/afl-tests/id:000094,src:000000,op:flip1,pos:126,+cov b/src/exchange/afl-tests/id:000094,src:000000,op:flip1,pos:126,+cov
index 60b4781da..60b4781da 100644
--- a/src/mint/afl-tests/id:000094,src:000000,op:flip1,pos:126,+cov
+++ b/src/exchange/afl-tests/id:000094,src:000000,op:flip1,pos:126,+cov
diff --git a/src/mint/afl-tests/id:000094,src:000000,op:flip1,pos:95,+cov b/src/exchange/afl-tests/id:000094,src:000000,op:flip1,pos:95,+cov
index 953a35925..953a35925 100644
--- a/src/mint/afl-tests/id:000094,src:000000,op:flip1,pos:95,+cov
+++ b/src/exchange/afl-tests/id:000094,src:000000,op:flip1,pos:95,+cov
diff --git a/src/mint/afl-tests/id:000095,src:000000,op:flip1,pos:135,+cov b/src/exchange/afl-tests/id:000095,src:000000,op:flip1,pos:135,+cov
index d93c02a69..d93c02a69 100644
--- a/src/mint/afl-tests/id:000095,src:000000,op:flip1,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000095,src:000000,op:flip1,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000095,src:000000,op:flip1,pos:96,+cov b/src/exchange/afl-tests/id:000095,src:000000,op:flip1,pos:96,+cov
index f7e319c82..f7e319c82 100644
--- a/src/mint/afl-tests/id:000095,src:000000,op:flip1,pos:96,+cov
+++ b/src/exchange/afl-tests/id:000095,src:000000,op:flip1,pos:96,+cov
diff --git a/src/mint/afl-tests/id:000096,src:000000,op:flip1,pos:135,+cov b/src/exchange/afl-tests/id:000096,src:000000,op:flip1,pos:135,+cov
index 58023e6c4..58023e6c4 100644
--- a/src/mint/afl-tests/id:000096,src:000000,op:flip1,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000096,src:000000,op:flip1,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000096,src:000000,op:flip1,pos:96,+cov b/src/exchange/afl-tests/id:000096,src:000000,op:flip1,pos:96,+cov
index 66a826aa6..66a826aa6 100644
--- a/src/mint/afl-tests/id:000096,src:000000,op:flip1,pos:96,+cov
+++ b/src/exchange/afl-tests/id:000096,src:000000,op:flip1,pos:96,+cov
diff --git a/src/mint/afl-tests/id:000097,src:000000,op:flip1,pos:135,+cov b/src/exchange/afl-tests/id:000097,src:000000,op:flip1,pos:135,+cov
index b334d40e2..b334d40e2 100644
--- a/src/mint/afl-tests/id:000097,src:000000,op:flip1,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000097,src:000000,op:flip1,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000097,src:000000,op:flip1,pos:97,+cov b/src/exchange/afl-tests/id:000097,src:000000,op:flip1,pos:97,+cov
index 804351fde..804351fde 100644
--- a/src/mint/afl-tests/id:000097,src:000000,op:flip1,pos:97,+cov
+++ b/src/exchange/afl-tests/id:000097,src:000000,op:flip1,pos:97,+cov
diff --git a/src/mint/afl-tests/id:000098,src:000000,op:flip1,pos:105 b/src/exchange/afl-tests/id:000098,src:000000,op:flip1,pos:105
index c6f988227..c6f988227 100644
--- a/src/mint/afl-tests/id:000098,src:000000,op:flip1,pos:105
+++ b/src/exchange/afl-tests/id:000098,src:000000,op:flip1,pos:105
diff --git a/src/mint/afl-tests/id:000098,src:000000,op:flip1,pos:136,+cov b/src/exchange/afl-tests/id:000098,src:000000,op:flip1,pos:136,+cov
index bbb9719f8..bbb9719f8 100644
--- a/src/mint/afl-tests/id:000098,src:000000,op:flip1,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000098,src:000000,op:flip1,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000099,src:000000,op:flip1,pos:106 b/src/exchange/afl-tests/id:000099,src:000000,op:flip1,pos:106
index 89c490d8a..89c490d8a 100644
--- a/src/mint/afl-tests/id:000099,src:000000,op:flip1,pos:106
+++ b/src/exchange/afl-tests/id:000099,src:000000,op:flip1,pos:106
diff --git a/src/mint/afl-tests/id:000099,src:000000,op:flip1,pos:136,+cov b/src/exchange/afl-tests/id:000099,src:000000,op:flip1,pos:136,+cov
index c2567eb9d..c2567eb9d 100644
--- a/src/mint/afl-tests/id:000099,src:000000,op:flip1,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000099,src:000000,op:flip1,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000100,src:000000,op:flip1,pos:113,+cov b/src/exchange/afl-tests/id:000100,src:000000,op:flip1,pos:113,+cov
index b628943bc..b628943bc 100644
--- a/src/mint/afl-tests/id:000100,src:000000,op:flip1,pos:113,+cov
+++ b/src/exchange/afl-tests/id:000100,src:000000,op:flip1,pos:113,+cov
diff --git a/src/mint/afl-tests/id:000100,src:000000,op:flip1,pos:136,+cov b/src/exchange/afl-tests/id:000100,src:000000,op:flip1,pos:136,+cov
index 1a6e5400f..1a6e5400f 100644
--- a/src/mint/afl-tests/id:000100,src:000000,op:flip1,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000100,src:000000,op:flip1,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000101,src:000000,op:flip1,pos:114,+cov b/src/exchange/afl-tests/id:000101,src:000000,op:flip1,pos:114,+cov
index 4529026c6..4529026c6 100644
--- a/src/mint/afl-tests/id:000101,src:000000,op:flip1,pos:114,+cov
+++ b/src/exchange/afl-tests/id:000101,src:000000,op:flip1,pos:114,+cov
diff --git a/src/mint/afl-tests/id:000101,src:000000,op:flip1,pos:136,+cov b/src/exchange/afl-tests/id:000101,src:000000,op:flip1,pos:136,+cov
index 34ab916be..34ab916be 100644
--- a/src/mint/afl-tests/id:000101,src:000000,op:flip1,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000101,src:000000,op:flip1,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000102,src:000000,op:flip1,pos:121,+cov b/src/exchange/afl-tests/id:000102,src:000000,op:flip1,pos:121,+cov
index 8f356caaf..8f356caaf 100644
--- a/src/mint/afl-tests/id:000102,src:000000,op:flip1,pos:121,+cov
+++ b/src/exchange/afl-tests/id:000102,src:000000,op:flip1,pos:121,+cov
diff --git a/src/mint/afl-tests/id:000102,src:000000,op:flip1,pos:137,+cov b/src/exchange/afl-tests/id:000102,src:000000,op:flip1,pos:137,+cov
index 344839c1b..344839c1b 100644
--- a/src/mint/afl-tests/id:000102,src:000000,op:flip1,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000102,src:000000,op:flip1,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000103,src:000000,op:flip1,pos:130,+cov b/src/exchange/afl-tests/id:000103,src:000000,op:flip1,pos:130,+cov
index 51d2182a9..51d2182a9 100644
--- a/src/mint/afl-tests/id:000103,src:000000,op:flip1,pos:130,+cov
+++ b/src/exchange/afl-tests/id:000103,src:000000,op:flip1,pos:130,+cov
diff --git a/src/mint/afl-tests/id:000103,src:000000,op:flip1,pos:138,+cov b/src/exchange/afl-tests/id:000103,src:000000,op:flip1,pos:138,+cov
index 9e06ca33c..9e06ca33c 100644
--- a/src/mint/afl-tests/id:000103,src:000000,op:flip1,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000103,src:000000,op:flip1,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000104,src:000000,op:flip1,pos:136,+cov b/src/exchange/afl-tests/id:000104,src:000000,op:flip1,pos:136,+cov
index bbb9719f8..bbb9719f8 100644
--- a/src/mint/afl-tests/id:000104,src:000000,op:flip1,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000104,src:000000,op:flip1,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000104,src:000000,op:flip1,pos:138,+cov b/src/exchange/afl-tests/id:000104,src:000000,op:flip1,pos:138,+cov
index 73831fca2..73831fca2 100644
--- a/src/mint/afl-tests/id:000104,src:000000,op:flip1,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000104,src:000000,op:flip1,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000105,src:000000,op:flip1,pos:137,+cov b/src/exchange/afl-tests/id:000105,src:000000,op:flip1,pos:137,+cov
index ffa4ecccc..ffa4ecccc 100644
--- a/src/mint/afl-tests/id:000105,src:000000,op:flip1,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000105,src:000000,op:flip1,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000105,src:000000,op:flip1,pos:139,+cov b/src/exchange/afl-tests/id:000105,src:000000,op:flip1,pos:139,+cov
index 55b879591..55b879591 100644
--- a/src/mint/afl-tests/id:000105,src:000000,op:flip1,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000105,src:000000,op:flip1,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000106,src:000000,op:flip1,pos:137,+cov b/src/exchange/afl-tests/id:000106,src:000000,op:flip1,pos:137,+cov
index 19daf0c22..19daf0c22 100644
--- a/src/mint/afl-tests/id:000106,src:000000,op:flip1,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000106,src:000000,op:flip1,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000106,src:000000,op:flip1,pos:139,+cov b/src/exchange/afl-tests/id:000106,src:000000,op:flip1,pos:139,+cov
index 28cb911f6..28cb911f6 100644
--- a/src/mint/afl-tests/id:000106,src:000000,op:flip1,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000106,src:000000,op:flip1,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000107,src:000000,op:flip1,pos:139,+cov b/src/exchange/afl-tests/id:000107,src:000000,op:flip1,pos:139,+cov
index 085dda8ee..085dda8ee 100644
--- a/src/mint/afl-tests/id:000107,src:000000,op:flip1,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000107,src:000000,op:flip1,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000107,src:000000,op:flip1,pos:140,+cov b/src/exchange/afl-tests/id:000107,src:000000,op:flip1,pos:140,+cov
index e488ec8c4..e488ec8c4 100644
--- a/src/mint/afl-tests/id:000107,src:000000,op:flip1,pos:140,+cov
+++ b/src/exchange/afl-tests/id:000107,src:000000,op:flip1,pos:140,+cov
diff --git a/src/mint/afl-tests/id:000108,src:000000,op:flip1,pos:140,+cov b/src/exchange/afl-tests/id:000108,src:000000,op:flip1,pos:140,+cov
index 5e435231c..5e435231c 100644
--- a/src/mint/afl-tests/id:000108,src:000000,op:flip1,pos:140,+cov
+++ b/src/exchange/afl-tests/id:000108,src:000000,op:flip1,pos:140,+cov
diff --git a/src/mint/afl-tests/id:000108,src:000000,op:flip1,pos:141,+cov b/src/exchange/afl-tests/id:000108,src:000000,op:flip1,pos:141,+cov
index 3ea1ff11e..3ea1ff11e 100644
--- a/src/mint/afl-tests/id:000108,src:000000,op:flip1,pos:141,+cov
+++ b/src/exchange/afl-tests/id:000108,src:000000,op:flip1,pos:141,+cov
diff --git a/src/mint/afl-tests/id:000109,src:000000,op:flip1,pos:140,+cov b/src/exchange/afl-tests/id:000109,src:000000,op:flip1,pos:140,+cov
index 08e96d8d6..08e96d8d6 100644
--- a/src/mint/afl-tests/id:000109,src:000000,op:flip1,pos:140,+cov
+++ b/src/exchange/afl-tests/id:000109,src:000000,op:flip1,pos:140,+cov
diff --git a/src/mint/afl-tests/id:000109,src:000000,op:flip1,pos:141,+cov b/src/exchange/afl-tests/id:000109,src:000000,op:flip1,pos:141,+cov
index 4ce12ecc7..4ce12ecc7 100644
--- a/src/mint/afl-tests/id:000109,src:000000,op:flip1,pos:141,+cov
+++ b/src/exchange/afl-tests/id:000109,src:000000,op:flip1,pos:141,+cov
diff --git a/src/mint/afl-tests/id:000110,src:000000,op:flip1,pos:141,+cov b/src/exchange/afl-tests/id:000110,src:000000,op:flip1,pos:141,+cov
index 2f146ad28..2f146ad28 100644
--- a/src/mint/afl-tests/id:000110,src:000000,op:flip1,pos:141,+cov
+++ b/src/exchange/afl-tests/id:000110,src:000000,op:flip1,pos:141,+cov
diff --git a/src/mint/afl-tests/id:000110,src:000000,op:flip1,pos:143,+cov b/src/exchange/afl-tests/id:000110,src:000000,op:flip1,pos:143,+cov
index 925c4586b..925c4586b 100644
--- a/src/mint/afl-tests/id:000110,src:000000,op:flip1,pos:143,+cov
+++ b/src/exchange/afl-tests/id:000110,src:000000,op:flip1,pos:143,+cov
diff --git a/src/mint/afl-tests/id:000111,src:000000,op:flip1,pos:141,+cov b/src/exchange/afl-tests/id:000111,src:000000,op:flip1,pos:141,+cov
index e2274d060..e2274d060 100644
--- a/src/mint/afl-tests/id:000111,src:000000,op:flip1,pos:141,+cov
+++ b/src/exchange/afl-tests/id:000111,src:000000,op:flip1,pos:141,+cov
diff --git a/src/mint/afl-tests/id:000111,src:000000,op:flip1,pos:145,+cov b/src/exchange/afl-tests/id:000111,src:000000,op:flip1,pos:145,+cov
index b1a501a81..b1a501a81 100644
--- a/src/mint/afl-tests/id:000111,src:000000,op:flip1,pos:145,+cov
+++ b/src/exchange/afl-tests/id:000111,src:000000,op:flip1,pos:145,+cov
diff --git a/src/mint/afl-tests/id:000112,src:000000,op:flip1,pos:142,+cov b/src/exchange/afl-tests/id:000112,src:000000,op:flip1,pos:142,+cov
index aee2d330d..aee2d330d 100644
--- a/src/mint/afl-tests/id:000112,src:000000,op:flip1,pos:142,+cov
+++ b/src/exchange/afl-tests/id:000112,src:000000,op:flip1,pos:142,+cov
diff --git a/src/mint/afl-tests/id:000112,src:000000,op:flip1,pos:147,+cov b/src/exchange/afl-tests/id:000112,src:000000,op:flip1,pos:147,+cov
index 3112e1f4c..3112e1f4c 100644
--- a/src/mint/afl-tests/id:000112,src:000000,op:flip1,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000112,src:000000,op:flip1,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000113,src:000000,op:flip1,pos:143,+cov b/src/exchange/afl-tests/id:000113,src:000000,op:flip1,pos:143,+cov
index 713d9c82a..713d9c82a 100644
--- a/src/mint/afl-tests/id:000113,src:000000,op:flip1,pos:143,+cov
+++ b/src/exchange/afl-tests/id:000113,src:000000,op:flip1,pos:143,+cov
diff --git a/src/mint/afl-tests/id:000113,src:000000,op:flip1,pos:147,+cov b/src/exchange/afl-tests/id:000113,src:000000,op:flip1,pos:147,+cov
index edc1ca6b0..edc1ca6b0 100644
--- a/src/mint/afl-tests/id:000113,src:000000,op:flip1,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000113,src:000000,op:flip1,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000114,src:000000,op:flip1,pos:144,+cov b/src/exchange/afl-tests/id:000114,src:000000,op:flip1,pos:144,+cov
index 75c3e9b4e..75c3e9b4e 100644
--- a/src/mint/afl-tests/id:000114,src:000000,op:flip1,pos:144,+cov
+++ b/src/exchange/afl-tests/id:000114,src:000000,op:flip1,pos:144,+cov
diff --git a/src/mint/afl-tests/id:000114,src:000000,op:flip1,pos:150,+cov b/src/exchange/afl-tests/id:000114,src:000000,op:flip1,pos:150,+cov
index a140ab564..a140ab564 100644
--- a/src/mint/afl-tests/id:000114,src:000000,op:flip1,pos:150,+cov
+++ b/src/exchange/afl-tests/id:000114,src:000000,op:flip1,pos:150,+cov
diff --git a/src/mint/afl-tests/id:000115,src:000000,op:flip1,pos:147,+cov b/src/exchange/afl-tests/id:000115,src:000000,op:flip1,pos:147,+cov
index 58004ecdb..58004ecdb 100644
--- a/src/mint/afl-tests/id:000115,src:000000,op:flip1,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000115,src:000000,op:flip1,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000115,src:000000,op:flip1,pos:153,+cov b/src/exchange/afl-tests/id:000115,src:000000,op:flip1,pos:153,+cov
index cf1bbf3a1..cf1bbf3a1 100644
--- a/src/mint/afl-tests/id:000115,src:000000,op:flip1,pos:153,+cov
+++ b/src/exchange/afl-tests/id:000115,src:000000,op:flip1,pos:153,+cov
diff --git a/src/mint/afl-tests/id:000116,src:000000,op:flip1,pos:150,+cov b/src/exchange/afl-tests/id:000116,src:000000,op:flip1,pos:150,+cov
index b09ae00c3..b09ae00c3 100644
--- a/src/mint/afl-tests/id:000116,src:000000,op:flip1,pos:150,+cov
+++ b/src/exchange/afl-tests/id:000116,src:000000,op:flip1,pos:150,+cov
diff --git a/src/mint/afl-tests/id:000116,src:000000,op:flip1,pos:154,+cov b/src/exchange/afl-tests/id:000116,src:000000,op:flip1,pos:154,+cov
index c83c4caa1..c83c4caa1 100644
--- a/src/mint/afl-tests/id:000116,src:000000,op:flip1,pos:154,+cov
+++ b/src/exchange/afl-tests/id:000116,src:000000,op:flip1,pos:154,+cov
diff --git a/src/mint/afl-tests/id:000117,src:000000,op:flip1,pos:151,+cov b/src/exchange/afl-tests/id:000117,src:000000,op:flip1,pos:151,+cov
index 0ed6ac3df..0ed6ac3df 100644
--- a/src/mint/afl-tests/id:000117,src:000000,op:flip1,pos:151,+cov
+++ b/src/exchange/afl-tests/id:000117,src:000000,op:flip1,pos:151,+cov
diff --git a/src/mint/afl-tests/id:000117,src:000000,op:flip1,pos:155,+cov b/src/exchange/afl-tests/id:000117,src:000000,op:flip1,pos:155,+cov
index 89799430e..89799430e 100644
--- a/src/mint/afl-tests/id:000117,src:000000,op:flip1,pos:155,+cov
+++ b/src/exchange/afl-tests/id:000117,src:000000,op:flip1,pos:155,+cov
diff --git a/src/mint/afl-tests/id:000118,src:000000,op:flip1,pos:151,+cov b/src/exchange/afl-tests/id:000118,src:000000,op:flip1,pos:151,+cov
index 1d1a985bd..1d1a985bd 100644
--- a/src/mint/afl-tests/id:000118,src:000000,op:flip1,pos:151,+cov
+++ b/src/exchange/afl-tests/id:000118,src:000000,op:flip1,pos:151,+cov
diff --git a/src/mint/afl-tests/id:000118,src:000000,op:flip1,pos:157,+cov b/src/exchange/afl-tests/id:000118,src:000000,op:flip1,pos:157,+cov
index 94e17ab78..94e17ab78 100644
--- a/src/mint/afl-tests/id:000118,src:000000,op:flip1,pos:157,+cov
+++ b/src/exchange/afl-tests/id:000118,src:000000,op:flip1,pos:157,+cov
diff --git a/src/mint/afl-tests/id:000119,src:000000,op:flip1,pos:154,+cov b/src/exchange/afl-tests/id:000119,src:000000,op:flip1,pos:154,+cov
index 17ed4d5fe..17ed4d5fe 100644
--- a/src/mint/afl-tests/id:000119,src:000000,op:flip1,pos:154,+cov
+++ b/src/exchange/afl-tests/id:000119,src:000000,op:flip1,pos:154,+cov
diff --git a/src/mint/afl-tests/id:000119,src:000000,op:flip1,pos:158,+cov b/src/exchange/afl-tests/id:000119,src:000000,op:flip1,pos:158,+cov
index 80d6e8c82..80d6e8c82 100644
--- a/src/mint/afl-tests/id:000119,src:000000,op:flip1,pos:158,+cov
+++ b/src/exchange/afl-tests/id:000119,src:000000,op:flip1,pos:158,+cov
diff --git a/src/mint/afl-tests/id:000120,src:000000,op:flip1,pos:155,+cov b/src/exchange/afl-tests/id:000120,src:000000,op:flip1,pos:155,+cov
index 89799430e..89799430e 100644
--- a/src/mint/afl-tests/id:000120,src:000000,op:flip1,pos:155,+cov
+++ b/src/exchange/afl-tests/id:000120,src:000000,op:flip1,pos:155,+cov
diff --git a/src/mint/afl-tests/id:000120,src:000000,op:flip1,pos:158,+cov b/src/exchange/afl-tests/id:000120,src:000000,op:flip1,pos:158,+cov
index 21435ffc1..21435ffc1 100644
--- a/src/mint/afl-tests/id:000120,src:000000,op:flip1,pos:158,+cov
+++ b/src/exchange/afl-tests/id:000120,src:000000,op:flip1,pos:158,+cov
diff --git a/src/mint/afl-tests/id:000121,src:000000,op:flip1,pos:156,+cov b/src/exchange/afl-tests/id:000121,src:000000,op:flip1,pos:156,+cov
index fd5d1d6dd..fd5d1d6dd 100644
--- a/src/mint/afl-tests/id:000121,src:000000,op:flip1,pos:156,+cov
+++ b/src/exchange/afl-tests/id:000121,src:000000,op:flip1,pos:156,+cov
diff --git a/src/mint/afl-tests/id:000121,src:000000,op:flip1,pos:159,+cov b/src/exchange/afl-tests/id:000121,src:000000,op:flip1,pos:159,+cov
index 20786b881..20786b881 100644
--- a/src/mint/afl-tests/id:000121,src:000000,op:flip1,pos:159,+cov
+++ b/src/exchange/afl-tests/id:000121,src:000000,op:flip1,pos:159,+cov
diff --git a/src/mint/afl-tests/id:000122,src:000000,op:flip1,pos:157,+cov b/src/exchange/afl-tests/id:000122,src:000000,op:flip1,pos:157,+cov
index 24183a7be..24183a7be 100644
--- a/src/mint/afl-tests/id:000122,src:000000,op:flip1,pos:157,+cov
+++ b/src/exchange/afl-tests/id:000122,src:000000,op:flip1,pos:157,+cov
diff --git a/src/mint/afl-tests/id:000122,src:000000,op:flip1,pos:159,+cov b/src/exchange/afl-tests/id:000122,src:000000,op:flip1,pos:159,+cov
index 886efcd3b..886efcd3b 100644
--- a/src/mint/afl-tests/id:000122,src:000000,op:flip1,pos:159,+cov
+++ b/src/exchange/afl-tests/id:000122,src:000000,op:flip1,pos:159,+cov
diff --git a/src/mint/afl-tests/id:000123,src:000000,op:flip1,pos:160,+cov b/src/exchange/afl-tests/id:000123,src:000000,op:flip1,pos:160,+cov
index 3febac853..3febac853 100644
--- a/src/mint/afl-tests/id:000123,src:000000,op:flip1,pos:160,+cov
+++ b/src/exchange/afl-tests/id:000123,src:000000,op:flip1,pos:160,+cov
diff --git a/src/mint/afl-tests/id:000123,src:000000,op:flip1,pos:161,+cov b/src/exchange/afl-tests/id:000123,src:000000,op:flip1,pos:161,+cov
index ce9a2ebc2..ce9a2ebc2 100644
--- a/src/mint/afl-tests/id:000123,src:000000,op:flip1,pos:161,+cov
+++ b/src/exchange/afl-tests/id:000123,src:000000,op:flip1,pos:161,+cov
diff --git a/src/mint/afl-tests/id:000124,src:000000,op:flip1,pos:161,+cov b/src/exchange/afl-tests/id:000124,src:000000,op:flip1,pos:161,+cov
index ce9a2ebc2..ce9a2ebc2 100644
--- a/src/mint/afl-tests/id:000124,src:000000,op:flip1,pos:161,+cov
+++ b/src/exchange/afl-tests/id:000124,src:000000,op:flip1,pos:161,+cov
diff --git a/src/mint/afl-tests/id:000124,src:000000,op:flip1,pos:164,+cov b/src/exchange/afl-tests/id:000124,src:000000,op:flip1,pos:164,+cov
index 5744b9975..5744b9975 100644
--- a/src/mint/afl-tests/id:000124,src:000000,op:flip1,pos:164,+cov
+++ b/src/exchange/afl-tests/id:000124,src:000000,op:flip1,pos:164,+cov
diff --git a/src/mint/afl-tests/id:000125,src:000000,op:flip1,pos:161,+cov b/src/exchange/afl-tests/id:000125,src:000000,op:flip1,pos:161,+cov
index f86f257a9..f86f257a9 100644
--- a/src/mint/afl-tests/id:000125,src:000000,op:flip1,pos:161,+cov
+++ b/src/exchange/afl-tests/id:000125,src:000000,op:flip1,pos:161,+cov
diff --git a/src/mint/afl-tests/id:000125,src:000000,op:flip1,pos:166,+cov b/src/exchange/afl-tests/id:000125,src:000000,op:flip1,pos:166,+cov
index 5beca5eea..5beca5eea 100644
--- a/src/mint/afl-tests/id:000125,src:000000,op:flip1,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000125,src:000000,op:flip1,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000126,src:000000,op:flip1,pos:163 b/src/exchange/afl-tests/id:000126,src:000000,op:flip1,pos:163
index 9425753e8..9425753e8 100644
--- a/src/mint/afl-tests/id:000126,src:000000,op:flip1,pos:163
+++ b/src/exchange/afl-tests/id:000126,src:000000,op:flip1,pos:163
diff --git a/src/mint/afl-tests/id:000126,src:000000,op:flip1,pos:166,+cov b/src/exchange/afl-tests/id:000126,src:000000,op:flip1,pos:166,+cov
index f002e4ec3..f002e4ec3 100644
--- a/src/mint/afl-tests/id:000126,src:000000,op:flip1,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000126,src:000000,op:flip1,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000127,src:000000,op:flip1,pos:166,+cov b/src/exchange/afl-tests/id:000127,src:000000,op:flip1,pos:166,+cov
index a3b1f320d..a3b1f320d 100644
--- a/src/mint/afl-tests/id:000127,src:000000,op:flip1,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000127,src:000000,op:flip1,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000127,src:000000,op:flip1,pos:167,+cov b/src/exchange/afl-tests/id:000127,src:000000,op:flip1,pos:167,+cov
index a60445b53..a60445b53 100644
--- a/src/mint/afl-tests/id:000127,src:000000,op:flip1,pos:167,+cov
+++ b/src/exchange/afl-tests/id:000127,src:000000,op:flip1,pos:167,+cov
diff --git a/src/mint/afl-tests/id:000128,src:000000,op:flip1,pos:167,+cov b/src/exchange/afl-tests/id:000128,src:000000,op:flip1,pos:167,+cov
index 4e352555f..4e352555f 100644
--- a/src/mint/afl-tests/id:000128,src:000000,op:flip1,pos:167,+cov
+++ b/src/exchange/afl-tests/id:000128,src:000000,op:flip1,pos:167,+cov
diff --git a/src/mint/afl-tests/id:000128,src:000000,op:flip1,pos:170,+cov b/src/exchange/afl-tests/id:000128,src:000000,op:flip1,pos:170,+cov
index cfa7c0d7b..cfa7c0d7b 100644
--- a/src/mint/afl-tests/id:000128,src:000000,op:flip1,pos:170,+cov
+++ b/src/exchange/afl-tests/id:000128,src:000000,op:flip1,pos:170,+cov
diff --git a/src/mint/afl-tests/id:000129,src:000000,op:flip1,pos:168,+cov b/src/exchange/afl-tests/id:000129,src:000000,op:flip1,pos:168,+cov
index 874140594..874140594 100644
--- a/src/mint/afl-tests/id:000129,src:000000,op:flip1,pos:168,+cov
+++ b/src/exchange/afl-tests/id:000129,src:000000,op:flip1,pos:168,+cov
diff --git a/src/mint/afl-tests/id:000129,src:000000,op:flip1,pos:173,+cov b/src/exchange/afl-tests/id:000129,src:000000,op:flip1,pos:173,+cov
index 1d8b5d505..1d8b5d505 100644
--- a/src/mint/afl-tests/id:000129,src:000000,op:flip1,pos:173,+cov
+++ b/src/exchange/afl-tests/id:000129,src:000000,op:flip1,pos:173,+cov
diff --git a/src/mint/afl-tests/id:000130,src:000000,op:flip1,pos:171,+cov b/src/exchange/afl-tests/id:000130,src:000000,op:flip1,pos:171,+cov
index 68e2ef202..68e2ef202 100644
--- a/src/mint/afl-tests/id:000130,src:000000,op:flip1,pos:171,+cov
+++ b/src/exchange/afl-tests/id:000130,src:000000,op:flip1,pos:171,+cov
diff --git a/src/mint/afl-tests/id:000130,src:000000,op:flip1,pos:173,+cov b/src/exchange/afl-tests/id:000130,src:000000,op:flip1,pos:173,+cov
index 4db18a5cc..4db18a5cc 100644
--- a/src/mint/afl-tests/id:000130,src:000000,op:flip1,pos:173,+cov
+++ b/src/exchange/afl-tests/id:000130,src:000000,op:flip1,pos:173,+cov
diff --git a/src/mint/afl-tests/id:000131,src:000000,op:flip1,pos:172,+cov b/src/exchange/afl-tests/id:000131,src:000000,op:flip1,pos:172,+cov
index 6ce6913a1..6ce6913a1 100644
--- a/src/mint/afl-tests/id:000131,src:000000,op:flip1,pos:172,+cov
+++ b/src/exchange/afl-tests/id:000131,src:000000,op:flip1,pos:172,+cov
diff --git a/src/mint/afl-tests/id:000131,src:000000,op:flip1,pos:174,+cov b/src/exchange/afl-tests/id:000131,src:000000,op:flip1,pos:174,+cov
index c3b3c2c97..c3b3c2c97 100644
--- a/src/mint/afl-tests/id:000131,src:000000,op:flip1,pos:174,+cov
+++ b/src/exchange/afl-tests/id:000131,src:000000,op:flip1,pos:174,+cov
diff --git a/src/mint/afl-tests/id:000132,src:000000,op:flip1,pos:173,+cov b/src/exchange/afl-tests/id:000132,src:000000,op:flip1,pos:173,+cov
index 92fa76678..92fa76678 100644
--- a/src/mint/afl-tests/id:000132,src:000000,op:flip1,pos:173,+cov
+++ b/src/exchange/afl-tests/id:000132,src:000000,op:flip1,pos:173,+cov
diff --git a/src/mint/afl-tests/id:000132,src:000000,op:flip1,pos:176,+cov b/src/exchange/afl-tests/id:000132,src:000000,op:flip1,pos:176,+cov
index 466b32724..466b32724 100644
--- a/src/mint/afl-tests/id:000132,src:000000,op:flip1,pos:176,+cov
+++ b/src/exchange/afl-tests/id:000132,src:000000,op:flip1,pos:176,+cov
diff --git a/src/mint/afl-tests/id:000133,src:000000,op:flip1,pos:173,+cov b/src/exchange/afl-tests/id:000133,src:000000,op:flip1,pos:173,+cov
index 4db18a5cc..4db18a5cc 100644
--- a/src/mint/afl-tests/id:000133,src:000000,op:flip1,pos:173,+cov
+++ b/src/exchange/afl-tests/id:000133,src:000000,op:flip1,pos:173,+cov
diff --git a/src/mint/afl-tests/id:000133,src:000000,op:flip1,pos:178,+cov b/src/exchange/afl-tests/id:000133,src:000000,op:flip1,pos:178,+cov
index a1962a789..a1962a789 100644
--- a/src/mint/afl-tests/id:000133,src:000000,op:flip1,pos:178,+cov
+++ b/src/exchange/afl-tests/id:000133,src:000000,op:flip1,pos:178,+cov
diff --git a/src/mint/afl-tests/id:000134,src:000000,op:flip1,pos:174,+cov b/src/exchange/afl-tests/id:000134,src:000000,op:flip1,pos:174,+cov
index c3b3c2c97..c3b3c2c97 100644
--- a/src/mint/afl-tests/id:000134,src:000000,op:flip1,pos:174,+cov
+++ b/src/exchange/afl-tests/id:000134,src:000000,op:flip1,pos:174,+cov
diff --git a/src/mint/afl-tests/id:000134,src:000000,op:flip1,pos:178,+cov b/src/exchange/afl-tests/id:000134,src:000000,op:flip1,pos:178,+cov
index 473caadeb..473caadeb 100644
--- a/src/mint/afl-tests/id:000134,src:000000,op:flip1,pos:178,+cov
+++ b/src/exchange/afl-tests/id:000134,src:000000,op:flip1,pos:178,+cov
diff --git a/src/mint/afl-tests/id:000135,src:000000,op:flip1,pos:179,+cov b/src/exchange/afl-tests/id:000135,src:000000,op:flip1,pos:179,+cov
index 54256b54e..54256b54e 100644
--- a/src/mint/afl-tests/id:000135,src:000000,op:flip1,pos:179,+cov
+++ b/src/exchange/afl-tests/id:000135,src:000000,op:flip1,pos:179,+cov
diff --git a/src/mint/afl-tests/id:000135,src:000000,op:flip1,pos:180 b/src/exchange/afl-tests/id:000135,src:000000,op:flip1,pos:180
index 986d184f8..986d184f8 100644
--- a/src/mint/afl-tests/id:000135,src:000000,op:flip1,pos:180
+++ b/src/exchange/afl-tests/id:000135,src:000000,op:flip1,pos:180
diff --git a/src/mint/afl-tests/id:000136,src:000000,op:flip1,pos:182,+cov b/src/exchange/afl-tests/id:000136,src:000000,op:flip1,pos:182,+cov
index a3aa1bf03..a3aa1bf03 100644
--- a/src/mint/afl-tests/id:000136,src:000000,op:flip1,pos:182,+cov
+++ b/src/exchange/afl-tests/id:000136,src:000000,op:flip1,pos:182,+cov
diff --git a/src/mint/afl-tests/id:000136,src:000000,op:flip1,pos:183,+cov b/src/exchange/afl-tests/id:000136,src:000000,op:flip1,pos:183,+cov
index 34e914ef2..34e914ef2 100644
--- a/src/mint/afl-tests/id:000136,src:000000,op:flip1,pos:183,+cov
+++ b/src/exchange/afl-tests/id:000136,src:000000,op:flip1,pos:183,+cov
diff --git a/src/mint/afl-tests/id:000137,src:000000,op:flip1,pos:182,+cov b/src/exchange/afl-tests/id:000137,src:000000,op:flip1,pos:182,+cov
index 2e6be2376..2e6be2376 100644
--- a/src/mint/afl-tests/id:000137,src:000000,op:flip1,pos:182,+cov
+++ b/src/exchange/afl-tests/id:000137,src:000000,op:flip1,pos:182,+cov
diff --git a/src/mint/afl-tests/id:000137,src:000000,op:flip1,pos:184,+cov b/src/exchange/afl-tests/id:000137,src:000000,op:flip1,pos:184,+cov
index bee5f4edd..bee5f4edd 100644
--- a/src/mint/afl-tests/id:000137,src:000000,op:flip1,pos:184,+cov
+++ b/src/exchange/afl-tests/id:000137,src:000000,op:flip1,pos:184,+cov
diff --git a/src/mint/afl-tests/id:000138,src:000000,op:flip1,pos:183 b/src/exchange/afl-tests/id:000138,src:000000,op:flip1,pos:183
index f38c4f23c..f38c4f23c 100644
--- a/src/mint/afl-tests/id:000138,src:000000,op:flip1,pos:183
+++ b/src/exchange/afl-tests/id:000138,src:000000,op:flip1,pos:183
diff --git a/src/mint/afl-tests/id:000138,src:000000,op:flip1,pos:185,+cov b/src/exchange/afl-tests/id:000138,src:000000,op:flip1,pos:185,+cov
index 2f2c920c5..2f2c920c5 100644
--- a/src/mint/afl-tests/id:000138,src:000000,op:flip1,pos:185,+cov
+++ b/src/exchange/afl-tests/id:000138,src:000000,op:flip1,pos:185,+cov
diff --git a/src/mint/afl-tests/id:000139,src:000000,op:flip1,pos:183,+cov b/src/exchange/afl-tests/id:000139,src:000000,op:flip1,pos:183,+cov
index 4b04164fc..4b04164fc 100644
--- a/src/mint/afl-tests/id:000139,src:000000,op:flip1,pos:183,+cov
+++ b/src/exchange/afl-tests/id:000139,src:000000,op:flip1,pos:183,+cov
diff --git a/src/mint/afl-tests/id:000139,src:000000,op:flip1,pos:190 b/src/exchange/afl-tests/id:000139,src:000000,op:flip1,pos:190
index d265410b3..d265410b3 100644
--- a/src/mint/afl-tests/id:000139,src:000000,op:flip1,pos:190
+++ b/src/exchange/afl-tests/id:000139,src:000000,op:flip1,pos:190
diff --git a/src/mint/afl-tests/id:000140,src:000000,op:flip1,pos:185,+cov b/src/exchange/afl-tests/id:000140,src:000000,op:flip1,pos:185,+cov
index 31bed44fe..31bed44fe 100644
--- a/src/mint/afl-tests/id:000140,src:000000,op:flip1,pos:185,+cov
+++ b/src/exchange/afl-tests/id:000140,src:000000,op:flip1,pos:185,+cov
diff --git a/src/mint/afl-tests/id:000140,src:000000,op:flip1,pos:200,+cov b/src/exchange/afl-tests/id:000140,src:000000,op:flip1,pos:200,+cov
index eb0718fb2..eb0718fb2 100644
--- a/src/mint/afl-tests/id:000140,src:000000,op:flip1,pos:200,+cov
+++ b/src/exchange/afl-tests/id:000140,src:000000,op:flip1,pos:200,+cov
diff --git a/src/mint/afl-tests/id:000141,src:000000,op:flip1,pos:185,+cov b/src/exchange/afl-tests/id:000141,src:000000,op:flip1,pos:185,+cov
index 5ab71dca9..5ab71dca9 100644
--- a/src/mint/afl-tests/id:000141,src:000000,op:flip1,pos:185,+cov
+++ b/src/exchange/afl-tests/id:000141,src:000000,op:flip1,pos:185,+cov
diff --git a/src/mint/afl-tests/id:000141,src:000000,op:flip1,pos:205,+cov b/src/exchange/afl-tests/id:000141,src:000000,op:flip1,pos:205,+cov
index 708264144..708264144 100644
--- a/src/mint/afl-tests/id:000141,src:000000,op:flip1,pos:205,+cov
+++ b/src/exchange/afl-tests/id:000141,src:000000,op:flip1,pos:205,+cov
diff --git a/src/mint/afl-tests/id:000142,src:000000,op:flip1,pos:190 b/src/exchange/afl-tests/id:000142,src:000000,op:flip1,pos:190
index d265410b3..d265410b3 100644
--- a/src/mint/afl-tests/id:000142,src:000000,op:flip1,pos:190
+++ b/src/exchange/afl-tests/id:000142,src:000000,op:flip1,pos:190
diff --git a/src/mint/afl-tests/id:000142,src:000000,op:flip1,pos:211,+cov b/src/exchange/afl-tests/id:000142,src:000000,op:flip1,pos:211,+cov
index 7ca49af05..7ca49af05 100644
--- a/src/mint/afl-tests/id:000142,src:000000,op:flip1,pos:211,+cov
+++ b/src/exchange/afl-tests/id:000142,src:000000,op:flip1,pos:211,+cov
diff --git a/src/mint/afl-tests/id:000143,src:000000,op:flip1,pos:193,+cov b/src/exchange/afl-tests/id:000143,src:000000,op:flip1,pos:193,+cov
index 1cbe18b03..1cbe18b03 100644
--- a/src/mint/afl-tests/id:000143,src:000000,op:flip1,pos:193,+cov
+++ b/src/exchange/afl-tests/id:000143,src:000000,op:flip1,pos:193,+cov
diff --git a/src/mint/afl-tests/id:000143,src:000000,op:flip1,pos:238,+cov b/src/exchange/afl-tests/id:000143,src:000000,op:flip1,pos:238,+cov
index 6f88553f4..6f88553f4 100644
--- a/src/mint/afl-tests/id:000143,src:000000,op:flip1,pos:238,+cov
+++ b/src/exchange/afl-tests/id:000143,src:000000,op:flip1,pos:238,+cov
diff --git a/src/mint/afl-tests/id:000144,src:000000,op:flip1,pos:200,+cov b/src/exchange/afl-tests/id:000144,src:000000,op:flip1,pos:200,+cov
index eb0718fb2..eb0718fb2 100644
--- a/src/mint/afl-tests/id:000144,src:000000,op:flip1,pos:200,+cov
+++ b/src/exchange/afl-tests/id:000144,src:000000,op:flip1,pos:200,+cov
diff --git a/src/mint/afl-tests/id:000144,src:000000,op:flip1,pos:238,+cov b/src/exchange/afl-tests/id:000144,src:000000,op:flip1,pos:238,+cov
index 0f84aff25..0f84aff25 100644
--- a/src/mint/afl-tests/id:000144,src:000000,op:flip1,pos:238,+cov
+++ b/src/exchange/afl-tests/id:000144,src:000000,op:flip1,pos:238,+cov
diff --git a/src/mint/afl-tests/id:000145,src:000000,op:flip1,pos:211,+cov b/src/exchange/afl-tests/id:000145,src:000000,op:flip1,pos:211,+cov
index 7ca49af05..7ca49af05 100644
--- a/src/mint/afl-tests/id:000145,src:000000,op:flip1,pos:211,+cov
+++ b/src/exchange/afl-tests/id:000145,src:000000,op:flip1,pos:211,+cov
diff --git a/src/mint/afl-tests/id:000145,src:000000,op:flip1,pos:241,+cov b/src/exchange/afl-tests/id:000145,src:000000,op:flip1,pos:241,+cov
index 501ddae33..501ddae33 100644
--- a/src/mint/afl-tests/id:000145,src:000000,op:flip1,pos:241,+cov
+++ b/src/exchange/afl-tests/id:000145,src:000000,op:flip1,pos:241,+cov
diff --git a/src/mint/afl-tests/id:000146,src:000000,op:flip1,pos:223,+cov b/src/exchange/afl-tests/id:000146,src:000000,op:flip1,pos:223,+cov
index c55c38248..c55c38248 100644
--- a/src/mint/afl-tests/id:000146,src:000000,op:flip1,pos:223,+cov
+++ b/src/exchange/afl-tests/id:000146,src:000000,op:flip1,pos:223,+cov
diff --git a/src/mint/afl-tests/id:000146,src:000000,op:flip1,pos:245 b/src/exchange/afl-tests/id:000146,src:000000,op:flip1,pos:245
index a15b71dd2..a15b71dd2 100644
--- a/src/mint/afl-tests/id:000146,src:000000,op:flip1,pos:245
+++ b/src/exchange/afl-tests/id:000146,src:000000,op:flip1,pos:245
diff --git a/src/mint/afl-tests/id:000147,src:000000,op:flip1,pos:245 b/src/exchange/afl-tests/id:000147,src:000000,op:flip1,pos:245
index a15b71dd2..a15b71dd2 100644
--- a/src/mint/afl-tests/id:000147,src:000000,op:flip1,pos:245
+++ b/src/exchange/afl-tests/id:000147,src:000000,op:flip1,pos:245
diff --git a/src/mint/afl-tests/id:000147,src:000000,op:flip1,pos:255,+cov b/src/exchange/afl-tests/id:000147,src:000000,op:flip1,pos:255,+cov
index e1f099496..e1f099496 100644
--- a/src/mint/afl-tests/id:000147,src:000000,op:flip1,pos:255,+cov
+++ b/src/exchange/afl-tests/id:000147,src:000000,op:flip1,pos:255,+cov
diff --git a/src/mint/afl-tests/id:000148,src:000000,op:flip1,pos:262,+cov b/src/exchange/afl-tests/id:000148,src:000000,op:flip1,pos:262,+cov
index f945518f1..f945518f1 100644
--- a/src/mint/afl-tests/id:000148,src:000000,op:flip1,pos:262,+cov
+++ b/src/exchange/afl-tests/id:000148,src:000000,op:flip1,pos:262,+cov
diff --git a/src/mint/afl-tests/id:000149,src:000000,op:flip1,pos:268,+cov b/src/exchange/afl-tests/id:000149,src:000000,op:flip1,pos:268,+cov
index 6c20c7496..6c20c7496 100644
--- a/src/mint/afl-tests/id:000149,src:000000,op:flip1,pos:268,+cov
+++ b/src/exchange/afl-tests/id:000149,src:000000,op:flip1,pos:268,+cov
diff --git a/src/mint/afl-tests/id:000149,src:000000,op:flip1,pos:270,+cov b/src/exchange/afl-tests/id:000149,src:000000,op:flip1,pos:270,+cov
index 689fe9458..689fe9458 100644
--- a/src/mint/afl-tests/id:000149,src:000000,op:flip1,pos:270,+cov
+++ b/src/exchange/afl-tests/id:000149,src:000000,op:flip1,pos:270,+cov
diff --git a/src/mint/afl-tests/id:000150,src:000000,op:flip1,pos:269,+cov b/src/exchange/afl-tests/id:000150,src:000000,op:flip1,pos:269,+cov
index 1f37e4510..1f37e4510 100644
--- a/src/mint/afl-tests/id:000150,src:000000,op:flip1,pos:269,+cov
+++ b/src/exchange/afl-tests/id:000150,src:000000,op:flip1,pos:269,+cov
diff --git a/src/mint/afl-tests/id:000150,src:000000,op:flip1,pos:279,+cov b/src/exchange/afl-tests/id:000150,src:000000,op:flip1,pos:279,+cov
index a6586b515..a6586b515 100644
--- a/src/mint/afl-tests/id:000150,src:000000,op:flip1,pos:279,+cov
+++ b/src/exchange/afl-tests/id:000150,src:000000,op:flip1,pos:279,+cov
diff --git a/src/mint/afl-tests/id:000151,src:000000,op:flip1,pos:270,+cov b/src/exchange/afl-tests/id:000151,src:000000,op:flip1,pos:270,+cov
index be7906884..be7906884 100644
--- a/src/mint/afl-tests/id:000151,src:000000,op:flip1,pos:270,+cov
+++ b/src/exchange/afl-tests/id:000151,src:000000,op:flip1,pos:270,+cov
diff --git a/src/mint/afl-tests/id:000151,src:000000,op:flip1,pos:279,+cov b/src/exchange/afl-tests/id:000151,src:000000,op:flip1,pos:279,+cov
index 230e7e807..230e7e807 100644
--- a/src/mint/afl-tests/id:000151,src:000000,op:flip1,pos:279,+cov
+++ b/src/exchange/afl-tests/id:000151,src:000000,op:flip1,pos:279,+cov
diff --git a/src/mint/afl-tests/id:000152,src:000000,op:flip1,pos:271,+cov b/src/exchange/afl-tests/id:000152,src:000000,op:flip1,pos:271,+cov
index 2ad3fd8ba..2ad3fd8ba 100644
--- a/src/mint/afl-tests/id:000152,src:000000,op:flip1,pos:271,+cov
+++ b/src/exchange/afl-tests/id:000152,src:000000,op:flip1,pos:271,+cov
diff --git a/src/mint/afl-tests/id:000152,src:000000,op:flip1,pos:283,+cov b/src/exchange/afl-tests/id:000152,src:000000,op:flip1,pos:283,+cov
index 672d4e494..672d4e494 100644
--- a/src/mint/afl-tests/id:000152,src:000000,op:flip1,pos:283,+cov
+++ b/src/exchange/afl-tests/id:000152,src:000000,op:flip1,pos:283,+cov
diff --git a/src/mint/afl-tests/id:000153,src:000000,op:flip1,pos:271,+cov b/src/exchange/afl-tests/id:000153,src:000000,op:flip1,pos:271,+cov
index 35890d911..35890d911 100644
--- a/src/mint/afl-tests/id:000153,src:000000,op:flip1,pos:271,+cov
+++ b/src/exchange/afl-tests/id:000153,src:000000,op:flip1,pos:271,+cov
diff --git a/src/mint/afl-tests/id:000153,src:000000,op:flip1,pos:291,+cov b/src/exchange/afl-tests/id:000153,src:000000,op:flip1,pos:291,+cov
index 0c04e72ec..0c04e72ec 100644
--- a/src/mint/afl-tests/id:000153,src:000000,op:flip1,pos:291,+cov
+++ b/src/exchange/afl-tests/id:000153,src:000000,op:flip1,pos:291,+cov
diff --git a/src/mint/afl-tests/id:000154,src:000000,op:flip1,pos:274,+cov b/src/exchange/afl-tests/id:000154,src:000000,op:flip1,pos:274,+cov
index a881299a1..a881299a1 100644
--- a/src/mint/afl-tests/id:000154,src:000000,op:flip1,pos:274,+cov
+++ b/src/exchange/afl-tests/id:000154,src:000000,op:flip1,pos:274,+cov
diff --git a/src/mint/afl-tests/id:000154,src:000000,op:flip1,pos:298,+cov b/src/exchange/afl-tests/id:000154,src:000000,op:flip1,pos:298,+cov
index 1f9995d71..1f9995d71 100644
--- a/src/mint/afl-tests/id:000154,src:000000,op:flip1,pos:298,+cov
+++ b/src/exchange/afl-tests/id:000154,src:000000,op:flip1,pos:298,+cov
diff --git a/src/mint/afl-tests/id:000155,src:000000,op:flip1,pos:279,+cov b/src/exchange/afl-tests/id:000155,src:000000,op:flip1,pos:279,+cov
index 88acf57fb..88acf57fb 100644
--- a/src/mint/afl-tests/id:000155,src:000000,op:flip1,pos:279,+cov
+++ b/src/exchange/afl-tests/id:000155,src:000000,op:flip1,pos:279,+cov
diff --git a/src/mint/afl-tests/id:000155,src:000000,op:flip1,pos:302,+cov b/src/exchange/afl-tests/id:000155,src:000000,op:flip1,pos:302,+cov
index 7996c1f8a..7996c1f8a 100644
--- a/src/mint/afl-tests/id:000155,src:000000,op:flip1,pos:302,+cov
+++ b/src/exchange/afl-tests/id:000155,src:000000,op:flip1,pos:302,+cov
diff --git a/src/mint/afl-tests/id:000156,src:000000,op:flip1,pos:281,+cov b/src/exchange/afl-tests/id:000156,src:000000,op:flip1,pos:281,+cov
index 0eb308738..0eb308738 100644
--- a/src/mint/afl-tests/id:000156,src:000000,op:flip1,pos:281,+cov
+++ b/src/exchange/afl-tests/id:000156,src:000000,op:flip1,pos:281,+cov
diff --git a/src/mint/afl-tests/id:000156,src:000000,op:flip1,pos:305,+cov b/src/exchange/afl-tests/id:000156,src:000000,op:flip1,pos:305,+cov
index f32354eac..f32354eac 100644
--- a/src/mint/afl-tests/id:000156,src:000000,op:flip1,pos:305,+cov
+++ b/src/exchange/afl-tests/id:000156,src:000000,op:flip1,pos:305,+cov
diff --git a/src/mint/afl-tests/id:000157,src:000000,op:flip1,pos:283,+cov b/src/exchange/afl-tests/id:000157,src:000000,op:flip1,pos:283,+cov
index 672d4e494..672d4e494 100644
--- a/src/mint/afl-tests/id:000157,src:000000,op:flip1,pos:283,+cov
+++ b/src/exchange/afl-tests/id:000157,src:000000,op:flip1,pos:283,+cov
diff --git a/src/mint/afl-tests/id:000157,src:000000,op:flip1,pos:307,+cov b/src/exchange/afl-tests/id:000157,src:000000,op:flip1,pos:307,+cov
index 34203b90f..34203b90f 100644
--- a/src/mint/afl-tests/id:000157,src:000000,op:flip1,pos:307,+cov
+++ b/src/exchange/afl-tests/id:000157,src:000000,op:flip1,pos:307,+cov
diff --git a/src/mint/afl-tests/id:000158,src:000000,op:flip1,pos:291,+cov b/src/exchange/afl-tests/id:000158,src:000000,op:flip1,pos:291,+cov
index 0c04e72ec..0c04e72ec 100644
--- a/src/mint/afl-tests/id:000158,src:000000,op:flip1,pos:291,+cov
+++ b/src/exchange/afl-tests/id:000158,src:000000,op:flip1,pos:291,+cov
diff --git a/src/mint/afl-tests/id:000158,src:000000,op:flip1,pos:313,+cov b/src/exchange/afl-tests/id:000158,src:000000,op:flip1,pos:313,+cov
index 374d46f3e..374d46f3e 100644
--- a/src/mint/afl-tests/id:000158,src:000000,op:flip1,pos:313,+cov
+++ b/src/exchange/afl-tests/id:000158,src:000000,op:flip1,pos:313,+cov
diff --git a/src/mint/afl-tests/id:000159,src:000000,op:flip1,pos:298,+cov b/src/exchange/afl-tests/id:000159,src:000000,op:flip1,pos:298,+cov
index 1f9995d71..1f9995d71 100644
--- a/src/mint/afl-tests/id:000159,src:000000,op:flip1,pos:298,+cov
+++ b/src/exchange/afl-tests/id:000159,src:000000,op:flip1,pos:298,+cov
diff --git a/src/mint/afl-tests/id:000159,src:000000,op:flip1,pos:313,+cov b/src/exchange/afl-tests/id:000159,src:000000,op:flip1,pos:313,+cov
index 0f5e14188..0f5e14188 100644
--- a/src/mint/afl-tests/id:000159,src:000000,op:flip1,pos:313,+cov
+++ b/src/exchange/afl-tests/id:000159,src:000000,op:flip1,pos:313,+cov
diff --git a/src/mint/afl-tests/id:000160,src:000000,op:flip1,pos:299,+cov b/src/exchange/afl-tests/id:000160,src:000000,op:flip1,pos:299,+cov
index da9ab67f7..da9ab67f7 100644
--- a/src/mint/afl-tests/id:000160,src:000000,op:flip1,pos:299,+cov
+++ b/src/exchange/afl-tests/id:000160,src:000000,op:flip1,pos:299,+cov
diff --git a/src/mint/afl-tests/id:000160,src:000000,op:flip1,pos:314,+cov b/src/exchange/afl-tests/id:000160,src:000000,op:flip1,pos:314,+cov
index da35d1b41..da35d1b41 100644
--- a/src/mint/afl-tests/id:000160,src:000000,op:flip1,pos:314,+cov
+++ b/src/exchange/afl-tests/id:000160,src:000000,op:flip1,pos:314,+cov
diff --git a/src/mint/afl-tests/id:000161,src:000000,op:flip1,pos:306,+cov b/src/exchange/afl-tests/id:000161,src:000000,op:flip1,pos:306,+cov
index a128da0a7..a128da0a7 100644
--- a/src/mint/afl-tests/id:000161,src:000000,op:flip1,pos:306,+cov
+++ b/src/exchange/afl-tests/id:000161,src:000000,op:flip1,pos:306,+cov
diff --git a/src/mint/afl-tests/id:000161,src:000000,op:flip1,pos:314,+cov b/src/exchange/afl-tests/id:000161,src:000000,op:flip1,pos:314,+cov
index 4d12e0f2b..4d12e0f2b 100644
--- a/src/mint/afl-tests/id:000161,src:000000,op:flip1,pos:314,+cov
+++ b/src/exchange/afl-tests/id:000161,src:000000,op:flip1,pos:314,+cov
diff --git a/src/mint/afl-tests/id:000162,src:000000,op:flip1,pos:308,+cov b/src/exchange/afl-tests/id:000162,src:000000,op:flip1,pos:308,+cov
index fe4b76672..fe4b76672 100644
--- a/src/mint/afl-tests/id:000162,src:000000,op:flip1,pos:308,+cov
+++ b/src/exchange/afl-tests/id:000162,src:000000,op:flip1,pos:308,+cov
diff --git a/src/mint/afl-tests/id:000162,src:000000,op:flip1,pos:315,+cov b/src/exchange/afl-tests/id:000162,src:000000,op:flip1,pos:315,+cov
index 274d55458..274d55458 100644
--- a/src/mint/afl-tests/id:000162,src:000000,op:flip1,pos:315,+cov
+++ b/src/exchange/afl-tests/id:000162,src:000000,op:flip1,pos:315,+cov
diff --git a/src/mint/afl-tests/id:000163,src:000000,op:flip1,pos:312,+cov b/src/exchange/afl-tests/id:000163,src:000000,op:flip1,pos:312,+cov
index 1e05fd6b2..1e05fd6b2 100644
--- a/src/mint/afl-tests/id:000163,src:000000,op:flip1,pos:312,+cov
+++ b/src/exchange/afl-tests/id:000163,src:000000,op:flip1,pos:312,+cov
diff --git a/src/mint/afl-tests/id:000163,src:000000,op:flip1,pos:316,+cov b/src/exchange/afl-tests/id:000163,src:000000,op:flip1,pos:316,+cov
index 12532705d..12532705d 100644
--- a/src/mint/afl-tests/id:000163,src:000000,op:flip1,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000163,src:000000,op:flip1,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000164,src:000000,op:flip1,pos:315,+cov b/src/exchange/afl-tests/id:000164,src:000000,op:flip1,pos:315,+cov
index bb0c664b9..bb0c664b9 100644
--- a/src/mint/afl-tests/id:000164,src:000000,op:flip1,pos:315,+cov
+++ b/src/exchange/afl-tests/id:000164,src:000000,op:flip1,pos:315,+cov
diff --git a/src/mint/afl-tests/id:000164,src:000000,op:flip1,pos:317 b/src/exchange/afl-tests/id:000164,src:000000,op:flip1,pos:317
index 3384c3d9d..3384c3d9d 100644
--- a/src/mint/afl-tests/id:000164,src:000000,op:flip1,pos:317
+++ b/src/exchange/afl-tests/id:000164,src:000000,op:flip1,pos:317
diff --git a/src/mint/afl-tests/id:000165,src:000000,op:flip1,pos:316,+cov b/src/exchange/afl-tests/id:000165,src:000000,op:flip1,pos:316,+cov
index efbdf7a65..efbdf7a65 100644
--- a/src/mint/afl-tests/id:000165,src:000000,op:flip1,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000165,src:000000,op:flip1,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000165,src:000000,op:flip1,pos:317,+cov b/src/exchange/afl-tests/id:000165,src:000000,op:flip1,pos:317,+cov
index d643b866f..d643b866f 100644
--- a/src/mint/afl-tests/id:000165,src:000000,op:flip1,pos:317,+cov
+++ b/src/exchange/afl-tests/id:000165,src:000000,op:flip1,pos:317,+cov
diff --git a/src/mint/afl-tests/id:000166,src:000000,op:flip1,pos:316,+cov b/src/exchange/afl-tests/id:000166,src:000000,op:flip1,pos:316,+cov
index cf277a865..cf277a865 100644
--- a/src/mint/afl-tests/id:000166,src:000000,op:flip1,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000166,src:000000,op:flip1,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000166,src:000000,op:flip1,pos:319,+cov b/src/exchange/afl-tests/id:000166,src:000000,op:flip1,pos:319,+cov
index 54c4ce79d..54c4ce79d 100644
--- a/src/mint/afl-tests/id:000166,src:000000,op:flip1,pos:319,+cov
+++ b/src/exchange/afl-tests/id:000166,src:000000,op:flip1,pos:319,+cov
diff --git a/src/mint/afl-tests/id:000167,src:000000,op:flip1,pos:317,+cov b/src/exchange/afl-tests/id:000167,src:000000,op:flip1,pos:317,+cov
index af8e0b86c..af8e0b86c 100644
--- a/src/mint/afl-tests/id:000167,src:000000,op:flip1,pos:317,+cov
+++ b/src/exchange/afl-tests/id:000167,src:000000,op:flip1,pos:317,+cov
diff --git a/src/mint/afl-tests/id:000167,src:000000,op:flip1,pos:320,+cov b/src/exchange/afl-tests/id:000167,src:000000,op:flip1,pos:320,+cov
index 1377c1e1a..1377c1e1a 100644
--- a/src/mint/afl-tests/id:000167,src:000000,op:flip1,pos:320,+cov
+++ b/src/exchange/afl-tests/id:000167,src:000000,op:flip1,pos:320,+cov
diff --git a/src/mint/afl-tests/id:000168,src:000000,op:flip1,pos:317,+cov b/src/exchange/afl-tests/id:000168,src:000000,op:flip1,pos:317,+cov
index 2cf0c4083..2cf0c4083 100644
--- a/src/mint/afl-tests/id:000168,src:000000,op:flip1,pos:317,+cov
+++ b/src/exchange/afl-tests/id:000168,src:000000,op:flip1,pos:317,+cov
diff --git a/src/mint/afl-tests/id:000168,src:000000,op:flip1,pos:322,+cov b/src/exchange/afl-tests/id:000168,src:000000,op:flip1,pos:322,+cov
index 9c98b9bee..9c98b9bee 100644
--- a/src/mint/afl-tests/id:000168,src:000000,op:flip1,pos:322,+cov
+++ b/src/exchange/afl-tests/id:000168,src:000000,op:flip1,pos:322,+cov
diff --git a/src/mint/afl-tests/id:000169,src:000000,op:flip1,pos:318,+cov b/src/exchange/afl-tests/id:000169,src:000000,op:flip1,pos:318,+cov
index a9e09aa17..a9e09aa17 100644
--- a/src/mint/afl-tests/id:000169,src:000000,op:flip1,pos:318,+cov
+++ b/src/exchange/afl-tests/id:000169,src:000000,op:flip1,pos:318,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000169,src:000000,op:flip1,pos:326,+cov b/src/exchange/afl-tests/id:000169,src:000000,op:flip1,pos:326,+cov
index 2cc738060..2cc738060 100644
--- a/src/mint/afl-tests/id:000169,src:000000,op:flip1,pos:326,+cov
+++ b/src/exchange/afl-tests/id:000169,src:000000,op:flip1,pos:326,+cov
diff --git a/src/mint/afl-tests/id:000170,src:000000,op:flip1,pos:319,+cov b/src/exchange/afl-tests/id:000170,src:000000,op:flip1,pos:319,+cov
index 7e894c436..7e894c436 100644
--- a/src/mint/afl-tests/id:000170,src:000000,op:flip1,pos:319,+cov
+++ b/src/exchange/afl-tests/id:000170,src:000000,op:flip1,pos:319,+cov
diff --git a/src/mint/afl-tests/id:000170,src:000000,op:flip1,pos:328,+cov b/src/exchange/afl-tests/id:000170,src:000000,op:flip1,pos:328,+cov
index 7e33b77a7..7e33b77a7 100644
--- a/src/mint/afl-tests/id:000170,src:000000,op:flip1,pos:328,+cov
+++ b/src/exchange/afl-tests/id:000170,src:000000,op:flip1,pos:328,+cov
diff --git a/src/mint/afl-tests/id:000171,src:000000,op:flip1,pos:326,+cov b/src/exchange/afl-tests/id:000171,src:000000,op:flip1,pos:326,+cov
index abb30eaa7..abb30eaa7 100644
--- a/src/mint/afl-tests/id:000171,src:000000,op:flip1,pos:326,+cov
+++ b/src/exchange/afl-tests/id:000171,src:000000,op:flip1,pos:326,+cov
diff --git a/src/mint/afl-tests/id:000171,src:000000,op:flip1,pos:329 b/src/exchange/afl-tests/id:000171,src:000000,op:flip1,pos:329
index 3ec05211c..3ec05211c 100644
--- a/src/mint/afl-tests/id:000171,src:000000,op:flip1,pos:329
+++ b/src/exchange/afl-tests/id:000171,src:000000,op:flip1,pos:329
diff --git a/src/mint/afl-tests/id:000172,src:000000,op:flip1,pos:327 b/src/exchange/afl-tests/id:000172,src:000000,op:flip1,pos:327
index 9298ec0fb..9298ec0fb 100644
--- a/src/mint/afl-tests/id:000172,src:000000,op:flip1,pos:327
+++ b/src/exchange/afl-tests/id:000172,src:000000,op:flip1,pos:327
diff --git a/src/mint/afl-tests/id:000172,src:000000,op:flip1,pos:332,+cov b/src/exchange/afl-tests/id:000172,src:000000,op:flip1,pos:332,+cov
index 87c92e792..87c92e792 100644
--- a/src/mint/afl-tests/id:000172,src:000000,op:flip1,pos:332,+cov
+++ b/src/exchange/afl-tests/id:000172,src:000000,op:flip1,pos:332,+cov
diff --git a/src/mint/afl-tests/id:000173,src:000000,op:flip1,pos:330,+cov b/src/exchange/afl-tests/id:000173,src:000000,op:flip1,pos:330,+cov
index b49ac79e6..b49ac79e6 100644
--- a/src/mint/afl-tests/id:000173,src:000000,op:flip1,pos:330,+cov
+++ b/src/exchange/afl-tests/id:000173,src:000000,op:flip1,pos:330,+cov
diff --git a/src/mint/afl-tests/id:000173,src:000000,op:flip2,pos:8,+cov b/src/exchange/afl-tests/id:000173,src:000000,op:flip2,pos:8,+cov
index 9ff09ec00..9ff09ec00 100644
--- a/src/mint/afl-tests/id:000173,src:000000,op:flip2,pos:8,+cov
+++ b/src/exchange/afl-tests/id:000173,src:000000,op:flip2,pos:8,+cov
diff --git a/src/mint/afl-tests/id:000174,src:000000,op:flip1,pos:331,+cov b/src/exchange/afl-tests/id:000174,src:000000,op:flip1,pos:331,+cov
index 2cd97546c..2cd97546c 100644
--- a/src/mint/afl-tests/id:000174,src:000000,op:flip1,pos:331,+cov
+++ b/src/exchange/afl-tests/id:000174,src:000000,op:flip1,pos:331,+cov
diff --git a/src/mint/afl-tests/id:000174,src:000000,op:flip2,pos:8,+cov b/src/exchange/afl-tests/id:000174,src:000000,op:flip2,pos:8,+cov
index 0a068cdcf..0a068cdcf 100644
--- a/src/mint/afl-tests/id:000174,src:000000,op:flip2,pos:8,+cov
+++ b/src/exchange/afl-tests/id:000174,src:000000,op:flip2,pos:8,+cov
diff --git a/src/mint/afl-tests/id:000175,src:000000,op:flip1,pos:338,+cov b/src/exchange/afl-tests/id:000175,src:000000,op:flip1,pos:338,+cov
index 34b27e1cb..34b27e1cb 100644
--- a/src/mint/afl-tests/id:000175,src:000000,op:flip1,pos:338,+cov
+++ b/src/exchange/afl-tests/id:000175,src:000000,op:flip1,pos:338,+cov
diff --git a/src/mint/afl-tests/id:000175,src:000000,op:flip2,pos:28,+cov b/src/exchange/afl-tests/id:000175,src:000000,op:flip2,pos:28,+cov
index 54e2bb6f1..54e2bb6f1 100644
--- a/src/mint/afl-tests/id:000175,src:000000,op:flip2,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000175,src:000000,op:flip2,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000176,src:000000,op:flip2,pos:30,+cov b/src/exchange/afl-tests/id:000176,src:000000,op:flip2,pos:30,+cov
index 1033ca7a7..1033ca7a7 100644
--- a/src/mint/afl-tests/id:000176,src:000000,op:flip2,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000176,src:000000,op:flip2,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000176,src:000000,op:flip2,pos:8,+cov b/src/exchange/afl-tests/id:000176,src:000000,op:flip2,pos:8,+cov
index 9ff09ec00..9ff09ec00 100644
--- a/src/mint/afl-tests/id:000176,src:000000,op:flip2,pos:8,+cov
+++ b/src/exchange/afl-tests/id:000176,src:000000,op:flip2,pos:8,+cov
diff --git a/src/mint/afl-tests/id:000177,src:000000,op:flip2,pos:25,+cov b/src/exchange/afl-tests/id:000177,src:000000,op:flip2,pos:25,+cov
index d95ac4ee1..d95ac4ee1 100644
--- a/src/mint/afl-tests/id:000177,src:000000,op:flip2,pos:25,+cov
+++ b/src/exchange/afl-tests/id:000177,src:000000,op:flip2,pos:25,+cov
diff --git a/src/mint/afl-tests/id:000177,src:000000,op:flip2,pos:30,+cov b/src/exchange/afl-tests/id:000177,src:000000,op:flip2,pos:30,+cov
index e3781370b..e3781370b 100644
--- a/src/mint/afl-tests/id:000177,src:000000,op:flip2,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000177,src:000000,op:flip2,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000178,src:000000,op:flip2,pos:26,+cov b/src/exchange/afl-tests/id:000178,src:000000,op:flip2,pos:26,+cov
index d66bb178b..d66bb178b 100644
--- a/src/mint/afl-tests/id:000178,src:000000,op:flip2,pos:26,+cov
+++ b/src/exchange/afl-tests/id:000178,src:000000,op:flip2,pos:26,+cov
diff --git a/src/mint/afl-tests/id:000178,src:000000,op:flip2,pos:31,+cov b/src/exchange/afl-tests/id:000178,src:000000,op:flip2,pos:31,+cov
index a971a77ad..a971a77ad 100644
--- a/src/mint/afl-tests/id:000178,src:000000,op:flip2,pos:31,+cov
+++ b/src/exchange/afl-tests/id:000178,src:000000,op:flip2,pos:31,+cov
diff --git a/src/mint/afl-tests/id:000179,src:000000,op:flip2,pos:29,+cov b/src/exchange/afl-tests/id:000179,src:000000,op:flip2,pos:29,+cov
index a84715234..a84715234 100644
--- a/src/mint/afl-tests/id:000179,src:000000,op:flip2,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000179,src:000000,op:flip2,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000179,src:000000,op:flip2,pos:31,+cov b/src/exchange/afl-tests/id:000179,src:000000,op:flip2,pos:31,+cov
index 01cb04198..01cb04198 100644
--- a/src/mint/afl-tests/id:000179,src:000000,op:flip2,pos:31,+cov
+++ b/src/exchange/afl-tests/id:000179,src:000000,op:flip2,pos:31,+cov
diff --git a/src/mint/afl-tests/id:000180,src:000000,op:flip2,pos:30,+cov b/src/exchange/afl-tests/id:000180,src:000000,op:flip2,pos:30,+cov
index 14304bd5b..14304bd5b 100644
--- a/src/mint/afl-tests/id:000180,src:000000,op:flip2,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000180,src:000000,op:flip2,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000180,src:000000,op:flip2,pos:32,+cov b/src/exchange/afl-tests/id:000180,src:000000,op:flip2,pos:32,+cov
index fa68f789c..fa68f789c 100644
--- a/src/mint/afl-tests/id:000180,src:000000,op:flip2,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000180,src:000000,op:flip2,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000181,src:000000,op:flip2,pos:33,+cov b/src/exchange/afl-tests/id:000181,src:000000,op:flip2,pos:33,+cov
index b01ef21d5..b01ef21d5 100644
--- a/src/mint/afl-tests/id:000181,src:000000,op:flip2,pos:33,+cov
+++ b/src/exchange/afl-tests/id:000181,src:000000,op:flip2,pos:33,+cov
diff --git a/src/mint/afl-tests/id:000181,src:000000,op:flip2,pos:36,+cov b/src/exchange/afl-tests/id:000181,src:000000,op:flip2,pos:36,+cov
index ae5dc006b..ae5dc006b 100644
--- a/src/mint/afl-tests/id:000181,src:000000,op:flip2,pos:36,+cov
+++ b/src/exchange/afl-tests/id:000181,src:000000,op:flip2,pos:36,+cov
diff --git a/src/mint/afl-tests/id:000182,src:000000,op:flip2,pos:38 b/src/exchange/afl-tests/id:000182,src:000000,op:flip2,pos:38
index 992a271cf..992a271cf 100644
--- a/src/mint/afl-tests/id:000182,src:000000,op:flip2,pos:38
+++ b/src/exchange/afl-tests/id:000182,src:000000,op:flip2,pos:38
diff --git a/src/mint/afl-tests/id:000183,src:000000,op:flip2,pos:39,+cov b/src/exchange/afl-tests/id:000183,src:000000,op:flip2,pos:39,+cov
index c9ba52ab8..c9ba52ab8 100644
--- a/src/mint/afl-tests/id:000183,src:000000,op:flip2,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000183,src:000000,op:flip2,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000184,src:000000,op:flip2,pos:40,+cov b/src/exchange/afl-tests/id:000184,src:000000,op:flip2,pos:40,+cov
index 51c7e9c45..51c7e9c45 100644
--- a/src/mint/afl-tests/id:000184,src:000000,op:flip2,pos:40,+cov
+++ b/src/exchange/afl-tests/id:000184,src:000000,op:flip2,pos:40,+cov
diff --git a/src/mint/afl-tests/id:000184,src:000000,op:flip2,pos:43,+cov b/src/exchange/afl-tests/id:000184,src:000000,op:flip2,pos:43,+cov
index 4dbf820b7..4dbf820b7 100644
--- a/src/mint/afl-tests/id:000184,src:000000,op:flip2,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000184,src:000000,op:flip2,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000185,src:000000,op:flip2,pos:40,+cov b/src/exchange/afl-tests/id:000185,src:000000,op:flip2,pos:40,+cov
index 8c8a01787..8c8a01787 100644
--- a/src/mint/afl-tests/id:000185,src:000000,op:flip2,pos:40,+cov
+++ b/src/exchange/afl-tests/id:000185,src:000000,op:flip2,pos:40,+cov
diff --git a/src/mint/afl-tests/id:000185,src:000000,op:flip2,pos:49,+cov b/src/exchange/afl-tests/id:000185,src:000000,op:flip2,pos:49,+cov
index 1e1b797a8..1e1b797a8 100644
--- a/src/mint/afl-tests/id:000185,src:000000,op:flip2,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000185,src:000000,op:flip2,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000186,src:000000,op:flip2,pos:40,+cov b/src/exchange/afl-tests/id:000186,src:000000,op:flip2,pos:40,+cov
index 4eaae78e7..4eaae78e7 100644
--- a/src/mint/afl-tests/id:000186,src:000000,op:flip2,pos:40,+cov
+++ b/src/exchange/afl-tests/id:000186,src:000000,op:flip2,pos:40,+cov
diff --git a/src/mint/afl-tests/id:000186,src:000000,op:flip2,pos:54,+cov b/src/exchange/afl-tests/id:000186,src:000000,op:flip2,pos:54,+cov
index e5aa0e1e9..e5aa0e1e9 100644
--- a/src/mint/afl-tests/id:000186,src:000000,op:flip2,pos:54,+cov
+++ b/src/exchange/afl-tests/id:000186,src:000000,op:flip2,pos:54,+cov
diff --git a/src/mint/afl-tests/id:000187,src:000000,op:flip2,pos:46,+cov b/src/exchange/afl-tests/id:000187,src:000000,op:flip2,pos:46,+cov
index 056435f02..056435f02 100644
--- a/src/mint/afl-tests/id:000187,src:000000,op:flip2,pos:46,+cov
+++ b/src/exchange/afl-tests/id:000187,src:000000,op:flip2,pos:46,+cov
diff --git a/src/mint/afl-tests/id:000187,src:000000,op:flip2,pos:60,+cov b/src/exchange/afl-tests/id:000187,src:000000,op:flip2,pos:60,+cov
index 893d717eb..893d717eb 100644
--- a/src/mint/afl-tests/id:000187,src:000000,op:flip2,pos:60,+cov
+++ b/src/exchange/afl-tests/id:000187,src:000000,op:flip2,pos:60,+cov
diff --git a/src/mint/afl-tests/id:000188,src:000000,op:flip2,pos:47,+cov b/src/exchange/afl-tests/id:000188,src:000000,op:flip2,pos:47,+cov
index 32b74c9d2..32b74c9d2 100644
--- a/src/mint/afl-tests/id:000188,src:000000,op:flip2,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000188,src:000000,op:flip2,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000188,src:000000,op:flip2,pos:64,+cov b/src/exchange/afl-tests/id:000188,src:000000,op:flip2,pos:64,+cov
index eaf966e60..eaf966e60 100644
--- a/src/mint/afl-tests/id:000188,src:000000,op:flip2,pos:64,+cov
+++ b/src/exchange/afl-tests/id:000188,src:000000,op:flip2,pos:64,+cov
diff --git a/src/mint/afl-tests/id:000189,src:000000,op:flip2,pos:48,+cov b/src/exchange/afl-tests/id:000189,src:000000,op:flip2,pos:48,+cov
index 1f24723d0..1f24723d0 100644
--- a/src/mint/afl-tests/id:000189,src:000000,op:flip2,pos:48,+cov
+++ b/src/exchange/afl-tests/id:000189,src:000000,op:flip2,pos:48,+cov
diff --git a/src/mint/afl-tests/id:000189,src:000000,op:flip2,pos:69,+cov b/src/exchange/afl-tests/id:000189,src:000000,op:flip2,pos:69,+cov
index 5497f76e1..5497f76e1 100644
--- a/src/mint/afl-tests/id:000189,src:000000,op:flip2,pos:69,+cov
+++ b/src/exchange/afl-tests/id:000189,src:000000,op:flip2,pos:69,+cov
diff --git a/src/mint/afl-tests/id:000190,src:000000,op:flip2,pos:49,+cov b/src/exchange/afl-tests/id:000190,src:000000,op:flip2,pos:49,+cov
index d89386901..d89386901 100644
--- a/src/mint/afl-tests/id:000190,src:000000,op:flip2,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000190,src:000000,op:flip2,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000190,src:000000,op:flip2,pos:71,+cov b/src/exchange/afl-tests/id:000190,src:000000,op:flip2,pos:71,+cov
index 061610e8a..061610e8a 100644
--- a/src/mint/afl-tests/id:000190,src:000000,op:flip2,pos:71,+cov
+++ b/src/exchange/afl-tests/id:000190,src:000000,op:flip2,pos:71,+cov
diff --git a/src/mint/afl-tests/id:000191,src:000000,op:flip2,pos:53,+cov b/src/exchange/afl-tests/id:000191,src:000000,op:flip2,pos:53,+cov
index ef622680e..ef622680e 100644
--- a/src/mint/afl-tests/id:000191,src:000000,op:flip2,pos:53,+cov
+++ b/src/exchange/afl-tests/id:000191,src:000000,op:flip2,pos:53,+cov
diff --git a/src/mint/afl-tests/id:000191,src:000000,op:flip2,pos:73,+cov b/src/exchange/afl-tests/id:000191,src:000000,op:flip2,pos:73,+cov
index 48a579fc9..48a579fc9 100644
--- a/src/mint/afl-tests/id:000191,src:000000,op:flip2,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000191,src:000000,op:flip2,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000192,src:000000,op:flip2,pos:53,+cov b/src/exchange/afl-tests/id:000192,src:000000,op:flip2,pos:53,+cov
index 5921e3b00..5921e3b00 100644
--- a/src/mint/afl-tests/id:000192,src:000000,op:flip2,pos:53,+cov
+++ b/src/exchange/afl-tests/id:000192,src:000000,op:flip2,pos:53,+cov
diff --git a/src/mint/afl-tests/id:000192,src:000000,op:flip2,pos:73,+cov b/src/exchange/afl-tests/id:000192,src:000000,op:flip2,pos:73,+cov
index 92a71100e..92a71100e 100644
--- a/src/mint/afl-tests/id:000192,src:000000,op:flip2,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000192,src:000000,op:flip2,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000193,src:000000,op:flip2,pos:62,+cov b/src/exchange/afl-tests/id:000193,src:000000,op:flip2,pos:62,+cov
index 49fd2ead1..49fd2ead1 100644
--- a/src/mint/afl-tests/id:000193,src:000000,op:flip2,pos:62,+cov
+++ b/src/exchange/afl-tests/id:000193,src:000000,op:flip2,pos:62,+cov
diff --git a/src/mint/afl-tests/id:000193,src:000000,op:flip2,pos:75 b/src/exchange/afl-tests/id:000193,src:000000,op:flip2,pos:75
index 7d1211bda..7d1211bda 100644
--- a/src/mint/afl-tests/id:000193,src:000000,op:flip2,pos:75
+++ b/src/exchange/afl-tests/id:000193,src:000000,op:flip2,pos:75
diff --git a/src/mint/afl-tests/id:000194,src:000000,op:flip2,pos:68,+cov b/src/exchange/afl-tests/id:000194,src:000000,op:flip2,pos:68,+cov
index c7bf5b290..c7bf5b290 100644
--- a/src/mint/afl-tests/id:000194,src:000000,op:flip2,pos:68,+cov
+++ b/src/exchange/afl-tests/id:000194,src:000000,op:flip2,pos:68,+cov
diff --git a/src/mint/afl-tests/id:000194,src:000000,op:flip2,pos:77,+cov b/src/exchange/afl-tests/id:000194,src:000000,op:flip2,pos:77,+cov
index 9366d52cf..9366d52cf 100644
--- a/src/mint/afl-tests/id:000194,src:000000,op:flip2,pos:77,+cov
+++ b/src/exchange/afl-tests/id:000194,src:000000,op:flip2,pos:77,+cov
diff --git a/src/mint/afl-tests/id:000195,src:000000,op:flip2,pos:70,+cov b/src/exchange/afl-tests/id:000195,src:000000,op:flip2,pos:70,+cov
index 293fa034f..293fa034f 100644
--- a/src/mint/afl-tests/id:000195,src:000000,op:flip2,pos:70,+cov
+++ b/src/exchange/afl-tests/id:000195,src:000000,op:flip2,pos:70,+cov
diff --git a/src/mint/afl-tests/id:000195,src:000000,op:flip2,pos:81,+cov b/src/exchange/afl-tests/id:000195,src:000000,op:flip2,pos:81,+cov
index 26524efd7..26524efd7 100644
--- a/src/mint/afl-tests/id:000195,src:000000,op:flip2,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000195,src:000000,op:flip2,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000196,src:000000,op:flip2,pos:73,+cov b/src/exchange/afl-tests/id:000196,src:000000,op:flip2,pos:73,+cov
index 28df18f79..28df18f79 100644
--- a/src/mint/afl-tests/id:000196,src:000000,op:flip2,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000196,src:000000,op:flip2,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000196,src:000000,op:flip2,pos:81,+cov b/src/exchange/afl-tests/id:000196,src:000000,op:flip2,pos:81,+cov
index a90cbb1fa..a90cbb1fa 100644
--- a/src/mint/afl-tests/id:000196,src:000000,op:flip2,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000196,src:000000,op:flip2,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000197,src:000000,op:flip2,pos:73,+cov b/src/exchange/afl-tests/id:000197,src:000000,op:flip2,pos:73,+cov
index 1da0cd778..1da0cd778 100644
--- a/src/mint/afl-tests/id:000197,src:000000,op:flip2,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000197,src:000000,op:flip2,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000197,src:000000,op:flip2,pos:83,+cov b/src/exchange/afl-tests/id:000197,src:000000,op:flip2,pos:83,+cov
index 5128e6a6d..5128e6a6d 100644
--- a/src/mint/afl-tests/id:000197,src:000000,op:flip2,pos:83,+cov
+++ b/src/exchange/afl-tests/id:000197,src:000000,op:flip2,pos:83,+cov
diff --git a/src/mint/afl-tests/id:000198,src:000000,op:flip2,pos:76,+cov b/src/exchange/afl-tests/id:000198,src:000000,op:flip2,pos:76,+cov
index dc134aaa6..dc134aaa6 100644
--- a/src/mint/afl-tests/id:000198,src:000000,op:flip2,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000198,src:000000,op:flip2,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000198,src:000000,op:flip2,pos:84,+cov b/src/exchange/afl-tests/id:000198,src:000000,op:flip2,pos:84,+cov
index 316809df4..316809df4 100644
--- a/src/mint/afl-tests/id:000198,src:000000,op:flip2,pos:84,+cov
+++ b/src/exchange/afl-tests/id:000198,src:000000,op:flip2,pos:84,+cov
diff --git a/src/mint/afl-tests/id:000199,src:000000,op:flip2,pos:76,+cov b/src/exchange/afl-tests/id:000199,src:000000,op:flip2,pos:76,+cov
index dfa6ef91f..dfa6ef91f 100644
--- a/src/mint/afl-tests/id:000199,src:000000,op:flip2,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000199,src:000000,op:flip2,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000199,src:000000,op:flip2,pos:85,+cov b/src/exchange/afl-tests/id:000199,src:000000,op:flip2,pos:85,+cov
index 0fe9dc00e..0fe9dc00e 100644
--- a/src/mint/afl-tests/id:000199,src:000000,op:flip2,pos:85,+cov
+++ b/src/exchange/afl-tests/id:000199,src:000000,op:flip2,pos:85,+cov
diff --git a/src/mint/afl-tests/id:000200,src:000000,op:flip2,pos:80,+cov b/src/exchange/afl-tests/id:000200,src:000000,op:flip2,pos:80,+cov
index 7c0365559..7c0365559 100644
--- a/src/mint/afl-tests/id:000200,src:000000,op:flip2,pos:80,+cov
+++ b/src/exchange/afl-tests/id:000200,src:000000,op:flip2,pos:80,+cov
diff --git a/src/mint/afl-tests/id:000200,src:000000,op:flip2,pos:86,+cov b/src/exchange/afl-tests/id:000200,src:000000,op:flip2,pos:86,+cov
index b4dc10232..b4dc10232 100644
--- a/src/mint/afl-tests/id:000200,src:000000,op:flip2,pos:86,+cov
+++ b/src/exchange/afl-tests/id:000200,src:000000,op:flip2,pos:86,+cov
diff --git a/src/mint/afl-tests/id:000201,src:000000,op:flip2,pos:86,+cov b/src/exchange/afl-tests/id:000201,src:000000,op:flip2,pos:86,+cov
index b4dc10232..b4dc10232 100644
--- a/src/mint/afl-tests/id:000201,src:000000,op:flip2,pos:86,+cov
+++ b/src/exchange/afl-tests/id:000201,src:000000,op:flip2,pos:86,+cov
diff --git a/src/mint/afl-tests/id:000201,src:000000,op:flip2,pos:89,+cov b/src/exchange/afl-tests/id:000201,src:000000,op:flip2,pos:89,+cov
index 93540b4e9..93540b4e9 100644
--- a/src/mint/afl-tests/id:000201,src:000000,op:flip2,pos:89,+cov
+++ b/src/exchange/afl-tests/id:000201,src:000000,op:flip2,pos:89,+cov
diff --git a/src/mint/afl-tests/id:000202,src:000000,op:flip2,pos:101,+cov b/src/exchange/afl-tests/id:000202,src:000000,op:flip2,pos:101,+cov
index 0bb944dac..0bb944dac 100644
--- a/src/mint/afl-tests/id:000202,src:000000,op:flip2,pos:101,+cov
+++ b/src/exchange/afl-tests/id:000202,src:000000,op:flip2,pos:101,+cov
diff --git a/src/mint/afl-tests/id:000202,src:000000,op:flip2,pos:90,+cov b/src/exchange/afl-tests/id:000202,src:000000,op:flip2,pos:90,+cov
index 3e2909dcb..3e2909dcb 100644
--- a/src/mint/afl-tests/id:000202,src:000000,op:flip2,pos:90,+cov
+++ b/src/exchange/afl-tests/id:000202,src:000000,op:flip2,pos:90,+cov
diff --git a/src/mint/afl-tests/id:000203,src:000000,op:flip2,pos:114 b/src/exchange/afl-tests/id:000203,src:000000,op:flip2,pos:114
index b2a169737..b2a169737 100644
--- a/src/mint/afl-tests/id:000203,src:000000,op:flip2,pos:114
+++ b/src/exchange/afl-tests/id:000203,src:000000,op:flip2,pos:114
diff --git a/src/mint/afl-tests/id:000203,src:000000,op:flip2,pos:93,+cov b/src/exchange/afl-tests/id:000203,src:000000,op:flip2,pos:93,+cov
index f797a1823..f797a1823 100644
--- a/src/mint/afl-tests/id:000203,src:000000,op:flip2,pos:93,+cov
+++ b/src/exchange/afl-tests/id:000203,src:000000,op:flip2,pos:93,+cov
diff --git a/src/mint/afl-tests/id:000204,src:000000,op:flip2,pos:100,+cov b/src/exchange/afl-tests/id:000204,src:000000,op:flip2,pos:100,+cov
index 76f5d0f22..76f5d0f22 100644
--- a/src/mint/afl-tests/id:000204,src:000000,op:flip2,pos:100,+cov
+++ b/src/exchange/afl-tests/id:000204,src:000000,op:flip2,pos:100,+cov
diff --git a/src/mint/afl-tests/id:000204,src:000000,op:flip2,pos:115,+cov b/src/exchange/afl-tests/id:000204,src:000000,op:flip2,pos:115,+cov
index ded00778e..ded00778e 100644
--- a/src/mint/afl-tests/id:000204,src:000000,op:flip2,pos:115,+cov
+++ b/src/exchange/afl-tests/id:000204,src:000000,op:flip2,pos:115,+cov
diff --git a/src/mint/afl-tests/id:000205,src:000000,op:flip2,pos:114 b/src/exchange/afl-tests/id:000205,src:000000,op:flip2,pos:114
index b2a169737..b2a169737 100644
--- a/src/mint/afl-tests/id:000205,src:000000,op:flip2,pos:114
+++ b/src/exchange/afl-tests/id:000205,src:000000,op:flip2,pos:114
diff --git a/src/mint/afl-tests/id:000205,src:000000,op:flip2,pos:116,+cov b/src/exchange/afl-tests/id:000205,src:000000,op:flip2,pos:116,+cov
index ad22cff45..ad22cff45 100644
--- a/src/mint/afl-tests/id:000205,src:000000,op:flip2,pos:116,+cov
+++ b/src/exchange/afl-tests/id:000205,src:000000,op:flip2,pos:116,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000206,src:000000,op:flip2,pos:115,+cov b/src/exchange/afl-tests/id:000206,src:000000,op:flip2,pos:115,+cov
index ded00778e..ded00778e 100644
--- a/src/mint/afl-tests/id:000206,src:000000,op:flip2,pos:115,+cov
+++ b/src/exchange/afl-tests/id:000206,src:000000,op:flip2,pos:115,+cov
diff --git a/src/mint/afl-tests/id:000206,src:000000,op:flip2,pos:140,+cov b/src/exchange/afl-tests/id:000206,src:000000,op:flip2,pos:140,+cov
index 329b0471d..329b0471d 100644
--- a/src/mint/afl-tests/id:000206,src:000000,op:flip2,pos:140,+cov
+++ b/src/exchange/afl-tests/id:000206,src:000000,op:flip2,pos:140,+cov
diff --git a/src/mint/afl-tests/id:000207,src:000000,op:flip2,pos:116,+cov b/src/exchange/afl-tests/id:000207,src:000000,op:flip2,pos:116,+cov
index ad22cff45..ad22cff45 100644
--- a/src/mint/afl-tests/id:000207,src:000000,op:flip2,pos:116,+cov
+++ b/src/exchange/afl-tests/id:000207,src:000000,op:flip2,pos:116,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000207,src:000000,op:flip2,pos:140,+cov b/src/exchange/afl-tests/id:000207,src:000000,op:flip2,pos:140,+cov
index 8619aa59e..8619aa59e 100644
--- a/src/mint/afl-tests/id:000207,src:000000,op:flip2,pos:140,+cov
+++ b/src/exchange/afl-tests/id:000207,src:000000,op:flip2,pos:140,+cov
diff --git a/src/mint/afl-tests/id:000208,src:000000,op:flip2,pos:124,+cov b/src/exchange/afl-tests/id:000208,src:000000,op:flip2,pos:124,+cov
index 0959d3c40..0959d3c40 100644
--- a/src/mint/afl-tests/id:000208,src:000000,op:flip2,pos:124,+cov
+++ b/src/exchange/afl-tests/id:000208,src:000000,op:flip2,pos:124,+cov
diff --git a/src/mint/afl-tests/id:000208,src:000000,op:flip2,pos:146,+cov b/src/exchange/afl-tests/id:000208,src:000000,op:flip2,pos:146,+cov
index 6f9d0856a..6f9d0856a 100644
--- a/src/mint/afl-tests/id:000208,src:000000,op:flip2,pos:146,+cov
+++ b/src/exchange/afl-tests/id:000208,src:000000,op:flip2,pos:146,+cov
diff --git a/src/mint/afl-tests/id:000209,src:000000,op:flip2,pos:135,+cov b/src/exchange/afl-tests/id:000209,src:000000,op:flip2,pos:135,+cov
index 25b4e53f1..25b4e53f1 100644
--- a/src/mint/afl-tests/id:000209,src:000000,op:flip2,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000209,src:000000,op:flip2,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000209,src:000000,op:flip2,pos:147,+cov b/src/exchange/afl-tests/id:000209,src:000000,op:flip2,pos:147,+cov
index 0ea0cd724..0ea0cd724 100644
--- a/src/mint/afl-tests/id:000209,src:000000,op:flip2,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000209,src:000000,op:flip2,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000210,src:000000,op:flip2,pos:137,+cov b/src/exchange/afl-tests/id:000210,src:000000,op:flip2,pos:137,+cov
index 74fbfe941..74fbfe941 100644
--- a/src/mint/afl-tests/id:000210,src:000000,op:flip2,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000210,src:000000,op:flip2,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000210,src:000000,op:flip2,pos:148,+cov b/src/exchange/afl-tests/id:000210,src:000000,op:flip2,pos:148,+cov
index af64a4be4..af64a4be4 100644
--- a/src/mint/afl-tests/id:000210,src:000000,op:flip2,pos:148,+cov
+++ b/src/exchange/afl-tests/id:000210,src:000000,op:flip2,pos:148,+cov
diff --git a/src/mint/afl-tests/id:000211,src:000000,op:flip2,pos:138,+cov b/src/exchange/afl-tests/id:000211,src:000000,op:flip2,pos:138,+cov
index 793d151f4..793d151f4 100644
--- a/src/mint/afl-tests/id:000211,src:000000,op:flip2,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000211,src:000000,op:flip2,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000211,src:000000,op:flip2,pos:148,+cov b/src/exchange/afl-tests/id:000211,src:000000,op:flip2,pos:148,+cov
index b4cc99427..b4cc99427 100644
--- a/src/mint/afl-tests/id:000211,src:000000,op:flip2,pos:148,+cov
+++ b/src/exchange/afl-tests/id:000211,src:000000,op:flip2,pos:148,+cov
diff --git a/src/mint/afl-tests/id:000212,src:000000,op:flip2,pos:138,+cov b/src/exchange/afl-tests/id:000212,src:000000,op:flip2,pos:138,+cov
index cf9fd94ed..cf9fd94ed 100644
--- a/src/mint/afl-tests/id:000212,src:000000,op:flip2,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000212,src:000000,op:flip2,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000212,src:000000,op:flip2,pos:159,+cov b/src/exchange/afl-tests/id:000212,src:000000,op:flip2,pos:159,+cov
index 5858dac25..5858dac25 100644
--- a/src/mint/afl-tests/id:000212,src:000000,op:flip2,pos:159,+cov
+++ b/src/exchange/afl-tests/id:000212,src:000000,op:flip2,pos:159,+cov
diff --git a/src/mint/afl-tests/id:000213,src:000000,op:flip2,pos:139,+cov b/src/exchange/afl-tests/id:000213,src:000000,op:flip2,pos:139,+cov
index de8783260..de8783260 100644
--- a/src/mint/afl-tests/id:000213,src:000000,op:flip2,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000213,src:000000,op:flip2,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000213,src:000000,op:flip2,pos:161,+cov b/src/exchange/afl-tests/id:000213,src:000000,op:flip2,pos:161,+cov
index 2893929d1..2893929d1 100644
--- a/src/mint/afl-tests/id:000213,src:000000,op:flip2,pos:161,+cov
+++ b/src/exchange/afl-tests/id:000213,src:000000,op:flip2,pos:161,+cov
diff --git a/src/mint/afl-tests/id:000214,src:000000,op:flip2,pos:143,+cov b/src/exchange/afl-tests/id:000214,src:000000,op:flip2,pos:143,+cov
index a9c5224fb..a9c5224fb 100644
--- a/src/mint/afl-tests/id:000214,src:000000,op:flip2,pos:143,+cov
+++ b/src/exchange/afl-tests/id:000214,src:000000,op:flip2,pos:143,+cov
diff --git a/src/mint/afl-tests/id:000214,src:000000,op:flip2,pos:164,+cov b/src/exchange/afl-tests/id:000214,src:000000,op:flip2,pos:164,+cov
index 49cb9c9b6..49cb9c9b6 100644
--- a/src/mint/afl-tests/id:000214,src:000000,op:flip2,pos:164,+cov
+++ b/src/exchange/afl-tests/id:000214,src:000000,op:flip2,pos:164,+cov
diff --git a/src/mint/afl-tests/id:000215,src:000000,op:flip2,pos:146,+cov b/src/exchange/afl-tests/id:000215,src:000000,op:flip2,pos:146,+cov
index 78ba2ab50..78ba2ab50 100644
--- a/src/mint/afl-tests/id:000215,src:000000,op:flip2,pos:146,+cov
+++ b/src/exchange/afl-tests/id:000215,src:000000,op:flip2,pos:146,+cov
diff --git a/src/mint/afl-tests/id:000215,src:000000,op:flip2,pos:164,+cov b/src/exchange/afl-tests/id:000215,src:000000,op:flip2,pos:164,+cov
index 3f08906bf..3f08906bf 100644
--- a/src/mint/afl-tests/id:000215,src:000000,op:flip2,pos:164,+cov
+++ b/src/exchange/afl-tests/id:000215,src:000000,op:flip2,pos:164,+cov
diff --git a/src/mint/afl-tests/id:000216,src:000000,op:flip2,pos:156,+cov b/src/exchange/afl-tests/id:000216,src:000000,op:flip2,pos:156,+cov
index 9a73dfa8c..9a73dfa8c 100644
--- a/src/mint/afl-tests/id:000216,src:000000,op:flip2,pos:156,+cov
+++ b/src/exchange/afl-tests/id:000216,src:000000,op:flip2,pos:156,+cov
diff --git a/src/mint/afl-tests/id:000216,src:000000,op:flip2,pos:166,+cov b/src/exchange/afl-tests/id:000216,src:000000,op:flip2,pos:166,+cov
index 6c9179075..6c9179075 100644
--- a/src/mint/afl-tests/id:000216,src:000000,op:flip2,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000216,src:000000,op:flip2,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000217,src:000000,op:flip2,pos:161,+cov b/src/exchange/afl-tests/id:000217,src:000000,op:flip2,pos:161,+cov
index 4fd4660d6..4fd4660d6 100644
--- a/src/mint/afl-tests/id:000217,src:000000,op:flip2,pos:161,+cov
+++ b/src/exchange/afl-tests/id:000217,src:000000,op:flip2,pos:161,+cov
diff --git a/src/mint/afl-tests/id:000217,src:000000,op:flip2,pos:170,+cov b/src/exchange/afl-tests/id:000217,src:000000,op:flip2,pos:170,+cov
index 39b8b5fd0..39b8b5fd0 100644
--- a/src/mint/afl-tests/id:000217,src:000000,op:flip2,pos:170,+cov
+++ b/src/exchange/afl-tests/id:000217,src:000000,op:flip2,pos:170,+cov
diff --git a/src/mint/afl-tests/id:000218,src:000000,op:flip2,pos:171,+cov b/src/exchange/afl-tests/id:000218,src:000000,op:flip2,pos:171,+cov
index 0de4d5016..0de4d5016 100644
--- a/src/mint/afl-tests/id:000218,src:000000,op:flip2,pos:171,+cov
+++ b/src/exchange/afl-tests/id:000218,src:000000,op:flip2,pos:171,+cov
diff --git a/src/mint/afl-tests/id:000218,src:000000,op:flip2,pos:176,+cov b/src/exchange/afl-tests/id:000218,src:000000,op:flip2,pos:176,+cov
index 5093d164a..5093d164a 100644
--- a/src/mint/afl-tests/id:000218,src:000000,op:flip2,pos:176,+cov
+++ b/src/exchange/afl-tests/id:000218,src:000000,op:flip2,pos:176,+cov
diff --git a/src/mint/afl-tests/id:000219,src:000000,op:flip2,pos:180 b/src/exchange/afl-tests/id:000219,src:000000,op:flip2,pos:180
index 79acdcf82..79acdcf82 100644
--- a/src/mint/afl-tests/id:000219,src:000000,op:flip2,pos:180
+++ b/src/exchange/afl-tests/id:000219,src:000000,op:flip2,pos:180
diff --git a/src/mint/afl-tests/id:000219,src:000000,op:flip2,pos:185,+cov b/src/exchange/afl-tests/id:000219,src:000000,op:flip2,pos:185,+cov
index db7216b13..db7216b13 100644
--- a/src/mint/afl-tests/id:000219,src:000000,op:flip2,pos:185,+cov
+++ b/src/exchange/afl-tests/id:000219,src:000000,op:flip2,pos:185,+cov
diff --git a/src/mint/afl-tests/id:000220,src:000000,op:flip2,pos:184,+cov b/src/exchange/afl-tests/id:000220,src:000000,op:flip2,pos:184,+cov
index 51e282862..51e282862 100644
--- a/src/mint/afl-tests/id:000220,src:000000,op:flip2,pos:184,+cov
+++ b/src/exchange/afl-tests/id:000220,src:000000,op:flip2,pos:184,+cov
diff --git a/src/mint/afl-tests/id:000220,src:000000,op:flip2,pos:193,+cov b/src/exchange/afl-tests/id:000220,src:000000,op:flip2,pos:193,+cov
index feb858ad0..feb858ad0 100644
--- a/src/mint/afl-tests/id:000220,src:000000,op:flip2,pos:193,+cov
+++ b/src/exchange/afl-tests/id:000220,src:000000,op:flip2,pos:193,+cov
diff --git a/src/mint/afl-tests/id:000221,src:000000,op:flip2,pos:211,+cov b/src/exchange/afl-tests/id:000221,src:000000,op:flip2,pos:211,+cov
index 82e190d20..82e190d20 100644
--- a/src/mint/afl-tests/id:000221,src:000000,op:flip2,pos:211,+cov
+++ b/src/exchange/afl-tests/id:000221,src:000000,op:flip2,pos:211,+cov
diff --git a/src/mint/afl-tests/id:000221,src:000000,op:flip2,pos:226,+cov b/src/exchange/afl-tests/id:000221,src:000000,op:flip2,pos:226,+cov
index 5ecc312d5..5ecc312d5 100644
--- a/src/mint/afl-tests/id:000221,src:000000,op:flip2,pos:226,+cov
+++ b/src/exchange/afl-tests/id:000221,src:000000,op:flip2,pos:226,+cov
diff --git a/src/mint/afl-tests/id:000222,src:000000,op:flip2,pos:218,+cov b/src/exchange/afl-tests/id:000222,src:000000,op:flip2,pos:218,+cov
index ca0c4b6ed..ca0c4b6ed 100644
--- a/src/mint/afl-tests/id:000222,src:000000,op:flip2,pos:218,+cov
+++ b/src/exchange/afl-tests/id:000222,src:000000,op:flip2,pos:218,+cov
diff --git a/src/mint/afl-tests/id:000222,src:000000,op:flip2,pos:232,+cov b/src/exchange/afl-tests/id:000222,src:000000,op:flip2,pos:232,+cov
index e0132c0dc..e0132c0dc 100644
--- a/src/mint/afl-tests/id:000222,src:000000,op:flip2,pos:232,+cov
+++ b/src/exchange/afl-tests/id:000222,src:000000,op:flip2,pos:232,+cov
diff --git a/src/mint/afl-tests/id:000223,src:000000,op:flip2,pos:239,+cov b/src/exchange/afl-tests/id:000223,src:000000,op:flip2,pos:239,+cov
index 8c26a19a4..8c26a19a4 100644
--- a/src/mint/afl-tests/id:000223,src:000000,op:flip2,pos:239,+cov
+++ b/src/exchange/afl-tests/id:000223,src:000000,op:flip2,pos:239,+cov
diff --git a/src/mint/afl-tests/id:000223,src:000000,op:flip2,pos:271,+cov b/src/exchange/afl-tests/id:000223,src:000000,op:flip2,pos:271,+cov
index 6e0e9f400..6e0e9f400 100644
--- a/src/mint/afl-tests/id:000223,src:000000,op:flip2,pos:271,+cov
+++ b/src/exchange/afl-tests/id:000223,src:000000,op:flip2,pos:271,+cov
diff --git a/src/mint/afl-tests/id:000224,src:000000,op:flip2,pos:241,+cov b/src/exchange/afl-tests/id:000224,src:000000,op:flip2,pos:241,+cov
index bf6eb8a80..bf6eb8a80 100644
--- a/src/mint/afl-tests/id:000224,src:000000,op:flip2,pos:241,+cov
+++ b/src/exchange/afl-tests/id:000224,src:000000,op:flip2,pos:241,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000224,src:000000,op:flip2,pos:279,+cov b/src/exchange/afl-tests/id:000224,src:000000,op:flip2,pos:279,+cov
index 0ce3373a5..0ce3373a5 100644
--- a/src/mint/afl-tests/id:000224,src:000000,op:flip2,pos:279,+cov
+++ b/src/exchange/afl-tests/id:000224,src:000000,op:flip2,pos:279,+cov
diff --git a/src/mint/afl-tests/id:000225,src:000000,op:flip2,pos:250,+cov b/src/exchange/afl-tests/id:000225,src:000000,op:flip2,pos:250,+cov
index 13301bc06..13301bc06 100644
--- a/src/mint/afl-tests/id:000225,src:000000,op:flip2,pos:250,+cov
+++ b/src/exchange/afl-tests/id:000225,src:000000,op:flip2,pos:250,+cov
diff --git a/src/mint/afl-tests/id:000225,src:000000,op:flip2,pos:308,+cov b/src/exchange/afl-tests/id:000225,src:000000,op:flip2,pos:308,+cov
index 811ade108..811ade108 100644
--- a/src/mint/afl-tests/id:000225,src:000000,op:flip2,pos:308,+cov
+++ b/src/exchange/afl-tests/id:000225,src:000000,op:flip2,pos:308,+cov
diff --git a/src/mint/afl-tests/id:000226,src:000000,op:flip2,pos:272,+cov b/src/exchange/afl-tests/id:000226,src:000000,op:flip2,pos:272,+cov
index 6185b798b..6185b798b 100644
--- a/src/mint/afl-tests/id:000226,src:000000,op:flip2,pos:272,+cov
+++ b/src/exchange/afl-tests/id:000226,src:000000,op:flip2,pos:272,+cov
diff --git a/src/mint/afl-tests/id:000226,src:000000,op:flip2,pos:315,+cov b/src/exchange/afl-tests/id:000226,src:000000,op:flip2,pos:315,+cov
index e13564fa3..e13564fa3 100644
--- a/src/mint/afl-tests/id:000226,src:000000,op:flip2,pos:315,+cov
+++ b/src/exchange/afl-tests/id:000226,src:000000,op:flip2,pos:315,+cov
diff --git a/src/mint/afl-tests/id:000227,src:000000,op:flip2,pos:277,+cov b/src/exchange/afl-tests/id:000227,src:000000,op:flip2,pos:277,+cov
index 0925b5182..0925b5182 100644
--- a/src/mint/afl-tests/id:000227,src:000000,op:flip2,pos:277,+cov
+++ b/src/exchange/afl-tests/id:000227,src:000000,op:flip2,pos:277,+cov
diff --git a/src/mint/afl-tests/id:000227,src:000000,op:flip2,pos:316,+cov b/src/exchange/afl-tests/id:000227,src:000000,op:flip2,pos:316,+cov
index f9b1c51be..f9b1c51be 100644
--- a/src/mint/afl-tests/id:000227,src:000000,op:flip2,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000227,src:000000,op:flip2,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000228,src:000000,op:flip2,pos:316,+cov b/src/exchange/afl-tests/id:000228,src:000000,op:flip2,pos:316,+cov
index e0c541cb4..e0c541cb4 100644
--- a/src/mint/afl-tests/id:000228,src:000000,op:flip2,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000228,src:000000,op:flip2,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000228,src:000000,op:flip2,pos:317,+cov b/src/exchange/afl-tests/id:000228,src:000000,op:flip2,pos:317,+cov
index 2f69f6e0d..2f69f6e0d 100644
--- a/src/mint/afl-tests/id:000228,src:000000,op:flip2,pos:317,+cov
+++ b/src/exchange/afl-tests/id:000228,src:000000,op:flip2,pos:317,+cov
diff --git a/src/mint/afl-tests/id:000229,src:000000,op:flip2,pos:316,+cov b/src/exchange/afl-tests/id:000229,src:000000,op:flip2,pos:316,+cov
index 02451d3ed..02451d3ed 100644
--- a/src/mint/afl-tests/id:000229,src:000000,op:flip2,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000229,src:000000,op:flip2,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000229,src:000000,op:flip2,pos:319,+cov b/src/exchange/afl-tests/id:000229,src:000000,op:flip2,pos:319,+cov
index 10acc6d6c..10acc6d6c 100644
--- a/src/mint/afl-tests/id:000229,src:000000,op:flip2,pos:319,+cov
+++ b/src/exchange/afl-tests/id:000229,src:000000,op:flip2,pos:319,+cov
diff --git a/src/mint/afl-tests/id:000230,src:000000,op:flip2,pos:316,+cov b/src/exchange/afl-tests/id:000230,src:000000,op:flip2,pos:316,+cov
index 57b65c8fa..57b65c8fa 100644
--- a/src/mint/afl-tests/id:000230,src:000000,op:flip2,pos:316,+cov
+++ b/src/exchange/afl-tests/id:000230,src:000000,op:flip2,pos:316,+cov
diff --git a/src/mint/afl-tests/id:000230,src:000000,op:flip2,pos:320,+cov b/src/exchange/afl-tests/id:000230,src:000000,op:flip2,pos:320,+cov
index f2e7ab291..f2e7ab291 100644
--- a/src/mint/afl-tests/id:000230,src:000000,op:flip2,pos:320,+cov
+++ b/src/exchange/afl-tests/id:000230,src:000000,op:flip2,pos:320,+cov
diff --git a/src/mint/afl-tests/id:000231,src:000000,op:flip2,pos:317,+cov b/src/exchange/afl-tests/id:000231,src:000000,op:flip2,pos:317,+cov
index 2f69f6e0d..2f69f6e0d 100644
--- a/src/mint/afl-tests/id:000231,src:000000,op:flip2,pos:317,+cov
+++ b/src/exchange/afl-tests/id:000231,src:000000,op:flip2,pos:317,+cov
diff --git a/src/mint/afl-tests/id:000231,src:000000,op:flip2,pos:326,+cov b/src/exchange/afl-tests/id:000231,src:000000,op:flip2,pos:326,+cov
index b3f072ba3..b3f072ba3 100644
--- a/src/mint/afl-tests/id:000231,src:000000,op:flip2,pos:326,+cov
+++ b/src/exchange/afl-tests/id:000231,src:000000,op:flip2,pos:326,+cov
diff --git a/src/mint/afl-tests/id:000232,src:000000,op:flip2,pos:320,+cov b/src/exchange/afl-tests/id:000232,src:000000,op:flip2,pos:320,+cov
index b7f8ac374..b7f8ac374 100644
--- a/src/mint/afl-tests/id:000232,src:000000,op:flip2,pos:320,+cov
+++ b/src/exchange/afl-tests/id:000232,src:000000,op:flip2,pos:320,+cov
diff --git a/src/mint/afl-tests/id:000232,src:000000,op:flip2,pos:327,+cov b/src/exchange/afl-tests/id:000232,src:000000,op:flip2,pos:327,+cov
index 1a3a957ff..1a3a957ff 100644
--- a/src/mint/afl-tests/id:000232,src:000000,op:flip2,pos:327,+cov
+++ b/src/exchange/afl-tests/id:000232,src:000000,op:flip2,pos:327,+cov
diff --git a/src/mint/afl-tests/id:000233,src:000000,op:flip2,pos:321,+cov b/src/exchange/afl-tests/id:000233,src:000000,op:flip2,pos:321,+cov
index 94532445d..94532445d 100644
--- a/src/mint/afl-tests/id:000233,src:000000,op:flip2,pos:321,+cov
+++ b/src/exchange/afl-tests/id:000233,src:000000,op:flip2,pos:321,+cov
diff --git a/src/mint/afl-tests/id:000233,src:000000,op:flip2,pos:331,+cov b/src/exchange/afl-tests/id:000233,src:000000,op:flip2,pos:331,+cov
index 86cf97463..86cf97463 100644
--- a/src/mint/afl-tests/id:000233,src:000000,op:flip2,pos:331,+cov
+++ b/src/exchange/afl-tests/id:000233,src:000000,op:flip2,pos:331,+cov
diff --git a/src/mint/afl-tests/id:000234,src:000000,op:flip2,pos:327,+cov b/src/exchange/afl-tests/id:000234,src:000000,op:flip2,pos:327,+cov
index f065598bd..f065598bd 100644
--- a/src/mint/afl-tests/id:000234,src:000000,op:flip2,pos:327,+cov
+++ b/src/exchange/afl-tests/id:000234,src:000000,op:flip2,pos:327,+cov
diff --git a/src/mint/afl-tests/id:000234,src:000000,op:flip4,pos:5,+cov b/src/exchange/afl-tests/id:000234,src:000000,op:flip4,pos:5,+cov
index 7d907ad6c..7d907ad6c 100644
--- a/src/mint/afl-tests/id:000234,src:000000,op:flip4,pos:5,+cov
+++ b/src/exchange/afl-tests/id:000234,src:000000,op:flip4,pos:5,+cov
diff --git a/src/mint/afl-tests/id:000235,src:000000,op:flip2,pos:328,+cov b/src/exchange/afl-tests/id:000235,src:000000,op:flip2,pos:328,+cov
index f1a1bbef5..f1a1bbef5 100644
--- a/src/mint/afl-tests/id:000235,src:000000,op:flip2,pos:328,+cov
+++ b/src/exchange/afl-tests/id:000235,src:000000,op:flip2,pos:328,+cov
diff --git a/src/mint/afl-tests/id:000235,src:000000,op:flip4,pos:20,+cov b/src/exchange/afl-tests/id:000235,src:000000,op:flip4,pos:20,+cov
index 0c6ca440a..0c6ca440a 100644
--- a/src/mint/afl-tests/id:000235,src:000000,op:flip4,pos:20,+cov
+++ b/src/exchange/afl-tests/id:000235,src:000000,op:flip4,pos:20,+cov
diff --git a/src/mint/afl-tests/id:000236,src:000000,op:flip2,pos:330,+cov b/src/exchange/afl-tests/id:000236,src:000000,op:flip2,pos:330,+cov
index cb260a2ff..cb260a2ff 100644
--- a/src/mint/afl-tests/id:000236,src:000000,op:flip2,pos:330,+cov
+++ b/src/exchange/afl-tests/id:000236,src:000000,op:flip2,pos:330,+cov
diff --git a/src/mint/afl-tests/id:000236,src:000000,op:flip4,pos:27,+cov b/src/exchange/afl-tests/id:000236,src:000000,op:flip4,pos:27,+cov
index 44406dc9a..44406dc9a 100644
--- a/src/mint/afl-tests/id:000236,src:000000,op:flip4,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000236,src:000000,op:flip4,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000237,src:000000,op:flip2,pos:331,+cov b/src/exchange/afl-tests/id:000237,src:000000,op:flip2,pos:331,+cov
index 78ee62ec0..78ee62ec0 100644
--- a/src/mint/afl-tests/id:000237,src:000000,op:flip2,pos:331,+cov
+++ b/src/exchange/afl-tests/id:000237,src:000000,op:flip2,pos:331,+cov
diff --git a/src/mint/afl-tests/id:000237,src:000000,op:flip4,pos:30 b/src/exchange/afl-tests/id:000237,src:000000,op:flip4,pos:30
index 2c7116baf..2c7116baf 100644
--- a/src/mint/afl-tests/id:000237,src:000000,op:flip4,pos:30
+++ b/src/exchange/afl-tests/id:000237,src:000000,op:flip4,pos:30
diff --git a/src/mint/afl-tests/id:000238,src:000000,op:flip4,pos:32 b/src/exchange/afl-tests/id:000238,src:000000,op:flip4,pos:32
index 8f85c2958..8f85c2958 100644
--- a/src/mint/afl-tests/id:000238,src:000000,op:flip4,pos:32
+++ b/src/exchange/afl-tests/id:000238,src:000000,op:flip4,pos:32
diff --git a/src/mint/afl-tests/id:000238,src:000000,op:flip4,pos:5,+cov b/src/exchange/afl-tests/id:000238,src:000000,op:flip4,pos:5,+cov
index 7d907ad6c..7d907ad6c 100644
--- a/src/mint/afl-tests/id:000238,src:000000,op:flip4,pos:5,+cov
+++ b/src/exchange/afl-tests/id:000238,src:000000,op:flip4,pos:5,+cov
diff --git a/src/mint/afl-tests/id:000239,src:000000,op:flip4,pos:25,+cov b/src/exchange/afl-tests/id:000239,src:000000,op:flip4,pos:25,+cov
index 86210d53c..86210d53c 100644
--- a/src/mint/afl-tests/id:000239,src:000000,op:flip4,pos:25,+cov
+++ b/src/exchange/afl-tests/id:000239,src:000000,op:flip4,pos:25,+cov
diff --git a/src/mint/afl-tests/id:000239,src:000000,op:flip4,pos:34,+cov b/src/exchange/afl-tests/id:000239,src:000000,op:flip4,pos:34,+cov
index e2049b06a..e2049b06a 100644
--- a/src/mint/afl-tests/id:000239,src:000000,op:flip4,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000239,src:000000,op:flip4,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000240,src:000000,op:flip4,pos:29,+cov b/src/exchange/afl-tests/id:000240,src:000000,op:flip4,pos:29,+cov
index 58c1859ed..58c1859ed 100644
--- a/src/mint/afl-tests/id:000240,src:000000,op:flip4,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000240,src:000000,op:flip4,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000240,src:000000,op:flip4,pos:35 b/src/exchange/afl-tests/id:000240,src:000000,op:flip4,pos:35
index 4dde38854..4dde38854 100644
--- a/src/mint/afl-tests/id:000240,src:000000,op:flip4,pos:35
+++ b/src/exchange/afl-tests/id:000240,src:000000,op:flip4,pos:35
diff --git a/src/mint/afl-tests/id:000241,src:000000,op:flip4,pos:30 b/src/exchange/afl-tests/id:000241,src:000000,op:flip4,pos:30
index 2c7116baf..2c7116baf 100644
--- a/src/mint/afl-tests/id:000241,src:000000,op:flip4,pos:30
+++ b/src/exchange/afl-tests/id:000241,src:000000,op:flip4,pos:30
diff --git a/src/mint/afl-tests/id:000241,src:000000,op:flip4,pos:36 b/src/exchange/afl-tests/id:000241,src:000000,op:flip4,pos:36
index c9b483417..c9b483417 100644
--- a/src/mint/afl-tests/id:000241,src:000000,op:flip4,pos:36
+++ b/src/exchange/afl-tests/id:000241,src:000000,op:flip4,pos:36
diff --git a/src/mint/afl-tests/id:000242,src:000000,op:flip4,pos:32 b/src/exchange/afl-tests/id:000242,src:000000,op:flip4,pos:32
index 8f85c2958..8f85c2958 100644
--- a/src/mint/afl-tests/id:000242,src:000000,op:flip4,pos:32
+++ b/src/exchange/afl-tests/id:000242,src:000000,op:flip4,pos:32
diff --git a/src/mint/afl-tests/id:000242,src:000000,op:flip4,pos:39,+cov b/src/exchange/afl-tests/id:000242,src:000000,op:flip4,pos:39,+cov
index d00310226..d00310226 100644
--- a/src/mint/afl-tests/id:000242,src:000000,op:flip4,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000242,src:000000,op:flip4,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000243,src:000000,op:flip4,pos:37,+cov b/src/exchange/afl-tests/id:000243,src:000000,op:flip4,pos:37,+cov
index 962ffca03..962ffca03 100644
--- a/src/mint/afl-tests/id:000243,src:000000,op:flip4,pos:37,+cov
+++ b/src/exchange/afl-tests/id:000243,src:000000,op:flip4,pos:37,+cov
diff --git a/src/mint/afl-tests/id:000243,src:000000,op:flip4,pos:44,+cov b/src/exchange/afl-tests/id:000243,src:000000,op:flip4,pos:44,+cov
index a22a184f5..a22a184f5 100644
--- a/src/mint/afl-tests/id:000243,src:000000,op:flip4,pos:44,+cov
+++ b/src/exchange/afl-tests/id:000243,src:000000,op:flip4,pos:44,+cov
diff --git a/src/mint/afl-tests/id:000244,src:000000,op:flip4,pos:39,+cov b/src/exchange/afl-tests/id:000244,src:000000,op:flip4,pos:39,+cov
index bd0135a70..bd0135a70 100644
--- a/src/mint/afl-tests/id:000244,src:000000,op:flip4,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000244,src:000000,op:flip4,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000244,src:000000,op:flip4,pos:48,+cov b/src/exchange/afl-tests/id:000244,src:000000,op:flip4,pos:48,+cov
index adce19002..adce19002 100644
--- a/src/mint/afl-tests/id:000244,src:000000,op:flip4,pos:48,+cov
+++ b/src/exchange/afl-tests/id:000244,src:000000,op:flip4,pos:48,+cov
diff --git a/src/mint/afl-tests/id:000245,src:000000,op:flip4,pos:45,+cov b/src/exchange/afl-tests/id:000245,src:000000,op:flip4,pos:45,+cov
index 10ccaf900..10ccaf900 100644
--- a/src/mint/afl-tests/id:000245,src:000000,op:flip4,pos:45,+cov
+++ b/src/exchange/afl-tests/id:000245,src:000000,op:flip4,pos:45,+cov
diff --git a/src/mint/afl-tests/id:000245,src:000000,op:flip4,pos:56,+cov b/src/exchange/afl-tests/id:000245,src:000000,op:flip4,pos:56,+cov
index 1c11de4c7..1c11de4c7 100644
--- a/src/mint/afl-tests/id:000245,src:000000,op:flip4,pos:56,+cov
+++ b/src/exchange/afl-tests/id:000245,src:000000,op:flip4,pos:56,+cov
diff --git a/src/mint/afl-tests/id:000246,src:000000,op:flip4,pos:47,+cov b/src/exchange/afl-tests/id:000246,src:000000,op:flip4,pos:47,+cov
index c2f41f0fa..c2f41f0fa 100644
--- a/src/mint/afl-tests/id:000246,src:000000,op:flip4,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000246,src:000000,op:flip4,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000246,src:000000,op:flip4,pos:59,+cov b/src/exchange/afl-tests/id:000246,src:000000,op:flip4,pos:59,+cov
index e4eb0cd34..e4eb0cd34 100644
--- a/src/mint/afl-tests/id:000246,src:000000,op:flip4,pos:59,+cov
+++ b/src/exchange/afl-tests/id:000246,src:000000,op:flip4,pos:59,+cov
diff --git a/src/mint/afl-tests/id:000247,src:000000,op:flip4,pos:50,+cov b/src/exchange/afl-tests/id:000247,src:000000,op:flip4,pos:50,+cov
index a0e2f3beb..a0e2f3beb 100644
--- a/src/mint/afl-tests/id:000247,src:000000,op:flip4,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000247,src:000000,op:flip4,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000247,src:000000,op:flip4,pos:65,+cov b/src/exchange/afl-tests/id:000247,src:000000,op:flip4,pos:65,+cov
index ed8b19072..ed8b19072 100644
--- a/src/mint/afl-tests/id:000247,src:000000,op:flip4,pos:65,+cov
+++ b/src/exchange/afl-tests/id:000247,src:000000,op:flip4,pos:65,+cov
diff --git a/src/mint/afl-tests/id:000248,src:000000,op:flip4,pos:60,+cov b/src/exchange/afl-tests/id:000248,src:000000,op:flip4,pos:60,+cov
index 584c2a9ae..584c2a9ae 100644
--- a/src/mint/afl-tests/id:000248,src:000000,op:flip4,pos:60,+cov
+++ b/src/exchange/afl-tests/id:000248,src:000000,op:flip4,pos:60,+cov
diff --git a/src/mint/afl-tests/id:000248,src:000000,op:flip4,pos:68,+cov b/src/exchange/afl-tests/id:000248,src:000000,op:flip4,pos:68,+cov
index cf3d9d4a4..cf3d9d4a4 100644
--- a/src/mint/afl-tests/id:000248,src:000000,op:flip4,pos:68,+cov
+++ b/src/exchange/afl-tests/id:000248,src:000000,op:flip4,pos:68,+cov
diff --git a/src/mint/afl-tests/id:000249,src:000000,op:flip4,pos:68,+cov b/src/exchange/afl-tests/id:000249,src:000000,op:flip4,pos:68,+cov
index 677f6128b..677f6128b 100644
--- a/src/mint/afl-tests/id:000249,src:000000,op:flip4,pos:68,+cov
+++ b/src/exchange/afl-tests/id:000249,src:000000,op:flip4,pos:68,+cov
diff --git a/src/mint/afl-tests/id:000250,src:000000,op:flip4,pos:68,+cov b/src/exchange/afl-tests/id:000250,src:000000,op:flip4,pos:68,+cov
index a5c06c65b..a5c06c65b 100644
--- a/src/mint/afl-tests/id:000250,src:000000,op:flip4,pos:68,+cov
+++ b/src/exchange/afl-tests/id:000250,src:000000,op:flip4,pos:68,+cov
diff --git a/src/mint/afl-tests/id:000250,src:000000,op:flip4,pos:73,+cov b/src/exchange/afl-tests/id:000250,src:000000,op:flip4,pos:73,+cov
index 92725c8c5..92725c8c5 100644
--- a/src/mint/afl-tests/id:000250,src:000000,op:flip4,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000250,src:000000,op:flip4,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000251,src:000000,op:flip4,pos:74,+cov b/src/exchange/afl-tests/id:000251,src:000000,op:flip4,pos:74,+cov
index 7b5839f18..7b5839f18 100644
--- a/src/mint/afl-tests/id:000251,src:000000,op:flip4,pos:74,+cov
+++ b/src/exchange/afl-tests/id:000251,src:000000,op:flip4,pos:74,+cov
diff --git a/src/mint/afl-tests/id:000251,src:000000,op:flip4,pos:81,+cov b/src/exchange/afl-tests/id:000251,src:000000,op:flip4,pos:81,+cov
index 58601be35..58601be35 100644
--- a/src/mint/afl-tests/id:000251,src:000000,op:flip4,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000251,src:000000,op:flip4,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000252,src:000000,op:flip4,pos:75,+cov b/src/exchange/afl-tests/id:000252,src:000000,op:flip4,pos:75,+cov
index 4f38b9a57..4f38b9a57 100644
--- a/src/mint/afl-tests/id:000252,src:000000,op:flip4,pos:75,+cov
+++ b/src/exchange/afl-tests/id:000252,src:000000,op:flip4,pos:75,+cov
diff --git a/src/mint/afl-tests/id:000252,src:000000,op:flip4,pos:82,+cov b/src/exchange/afl-tests/id:000252,src:000000,op:flip4,pos:82,+cov
index 8d7afa996..8d7afa996 100644
--- a/src/mint/afl-tests/id:000252,src:000000,op:flip4,pos:82,+cov
+++ b/src/exchange/afl-tests/id:000252,src:000000,op:flip4,pos:82,+cov
diff --git a/src/mint/afl-tests/id:000253,src:000000,op:flip4,pos:75,+cov b/src/exchange/afl-tests/id:000253,src:000000,op:flip4,pos:75,+cov
index f3564e76b..f3564e76b 100644
--- a/src/mint/afl-tests/id:000253,src:000000,op:flip4,pos:75,+cov
+++ b/src/exchange/afl-tests/id:000253,src:000000,op:flip4,pos:75,+cov
diff --git a/src/mint/afl-tests/id:000253,src:000000,op:flip4,pos:85,+cov b/src/exchange/afl-tests/id:000253,src:000000,op:flip4,pos:85,+cov
index 31b6418f5..31b6418f5 100644
--- a/src/mint/afl-tests/id:000253,src:000000,op:flip4,pos:85,+cov
+++ b/src/exchange/afl-tests/id:000253,src:000000,op:flip4,pos:85,+cov
diff --git a/src/mint/afl-tests/id:000254,src:000000,op:flip4,pos:76,+cov b/src/exchange/afl-tests/id:000254,src:000000,op:flip4,pos:76,+cov
index 5707cd53a..5707cd53a 100644
--- a/src/mint/afl-tests/id:000254,src:000000,op:flip4,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000254,src:000000,op:flip4,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000254,src:000000,op:flip4,pos:88,+cov b/src/exchange/afl-tests/id:000254,src:000000,op:flip4,pos:88,+cov
index 6d0eef981..6d0eef981 100644
--- a/src/mint/afl-tests/id:000254,src:000000,op:flip4,pos:88,+cov
+++ b/src/exchange/afl-tests/id:000254,src:000000,op:flip4,pos:88,+cov
diff --git a/src/mint/afl-tests/id:000255,src:000000,op:flip4,pos:81,+cov b/src/exchange/afl-tests/id:000255,src:000000,op:flip4,pos:81,+cov
index b9308a5b0..b9308a5b0 100644
--- a/src/mint/afl-tests/id:000255,src:000000,op:flip4,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000255,src:000000,op:flip4,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000255,src:000000,op:flip4,pos:91,+cov b/src/exchange/afl-tests/id:000255,src:000000,op:flip4,pos:91,+cov
index d9ae11ace..d9ae11ace 100644
--- a/src/mint/afl-tests/id:000255,src:000000,op:flip4,pos:91,+cov
+++ b/src/exchange/afl-tests/id:000255,src:000000,op:flip4,pos:91,+cov
diff --git a/src/mint/afl-tests/id:000256,src:000000,op:flip4,pos:83,+cov b/src/exchange/afl-tests/id:000256,src:000000,op:flip4,pos:83,+cov
index 805fa7976..805fa7976 100644
--- a/src/mint/afl-tests/id:000256,src:000000,op:flip4,pos:83,+cov
+++ b/src/exchange/afl-tests/id:000256,src:000000,op:flip4,pos:83,+cov
diff --git a/src/mint/afl-tests/id:000256,src:000000,op:flip4,pos:94,+cov b/src/exchange/afl-tests/id:000256,src:000000,op:flip4,pos:94,+cov
index e8a54a9b5..e8a54a9b5 100644
--- a/src/mint/afl-tests/id:000256,src:000000,op:flip4,pos:94,+cov
+++ b/src/exchange/afl-tests/id:000256,src:000000,op:flip4,pos:94,+cov
diff --git a/src/mint/afl-tests/id:000257,src:000000,op:flip4,pos:86,+cov b/src/exchange/afl-tests/id:000257,src:000000,op:flip4,pos:86,+cov
index b710069f5..b710069f5 100644
--- a/src/mint/afl-tests/id:000257,src:000000,op:flip4,pos:86,+cov
+++ b/src/exchange/afl-tests/id:000257,src:000000,op:flip4,pos:86,+cov
diff --git a/src/mint/afl-tests/id:000257,src:000000,op:flip4,pos:95,+cov b/src/exchange/afl-tests/id:000257,src:000000,op:flip4,pos:95,+cov
index 2f52b89a2..2f52b89a2 100644
--- a/src/mint/afl-tests/id:000257,src:000000,op:flip4,pos:95,+cov
+++ b/src/exchange/afl-tests/id:000257,src:000000,op:flip4,pos:95,+cov
diff --git a/src/mint/afl-tests/id:000258,src:000000,op:flip4,pos:88,+cov b/src/exchange/afl-tests/id:000258,src:000000,op:flip4,pos:88,+cov
index bc30ba7e5..bc30ba7e5 100644
--- a/src/mint/afl-tests/id:000258,src:000000,op:flip4,pos:88,+cov
+++ b/src/exchange/afl-tests/id:000258,src:000000,op:flip4,pos:88,+cov
diff --git a/src/mint/afl-tests/id:000258,src:000000,op:flip4,pos:95,+cov b/src/exchange/afl-tests/id:000258,src:000000,op:flip4,pos:95,+cov
index 89f3f1fa8..89f3f1fa8 100644
--- a/src/mint/afl-tests/id:000258,src:000000,op:flip4,pos:95,+cov
+++ b/src/exchange/afl-tests/id:000258,src:000000,op:flip4,pos:95,+cov
diff --git a/src/mint/afl-tests/id:000259,src:000000,op:flip4,pos:114 b/src/exchange/afl-tests/id:000259,src:000000,op:flip4,pos:114
index d33f6c0c5..d33f6c0c5 100644
--- a/src/mint/afl-tests/id:000259,src:000000,op:flip4,pos:114
+++ b/src/exchange/afl-tests/id:000259,src:000000,op:flip4,pos:114
diff --git a/src/mint/afl-tests/id:000259,src:000000,op:flip4,pos:91,+cov b/src/exchange/afl-tests/id:000259,src:000000,op:flip4,pos:91,+cov
index ba5159f5e..ba5159f5e 100644
--- a/src/mint/afl-tests/id:000259,src:000000,op:flip4,pos:91,+cov
+++ b/src/exchange/afl-tests/id:000259,src:000000,op:flip4,pos:91,+cov
diff --git a/src/mint/afl-tests/id:000260,src:000000,op:flip4,pos:112,+cov b/src/exchange/afl-tests/id:000260,src:000000,op:flip4,pos:112,+cov
index a877da04e..a877da04e 100644
--- a/src/mint/afl-tests/id:000260,src:000000,op:flip4,pos:112,+cov
+++ b/src/exchange/afl-tests/id:000260,src:000000,op:flip4,pos:112,+cov
diff --git a/src/mint/afl-tests/id:000260,src:000000,op:flip4,pos:137,+cov b/src/exchange/afl-tests/id:000260,src:000000,op:flip4,pos:137,+cov
index ca9b8e8f8..ca9b8e8f8 100644
--- a/src/mint/afl-tests/id:000260,src:000000,op:flip4,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000260,src:000000,op:flip4,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000261,src:000000,op:flip4,pos:139,+cov b/src/exchange/afl-tests/id:000261,src:000000,op:flip4,pos:139,+cov
index 73f929277..73f929277 100644
--- a/src/mint/afl-tests/id:000261,src:000000,op:flip4,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000261,src:000000,op:flip4,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000261,src:000000,op:flip4,pos:147,+cov b/src/exchange/afl-tests/id:000261,src:000000,op:flip4,pos:147,+cov
index 88fb9b186..88fb9b186 100644
--- a/src/mint/afl-tests/id:000261,src:000000,op:flip4,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000261,src:000000,op:flip4,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000262,src:000000,op:flip4,pos:142,+cov b/src/exchange/afl-tests/id:000262,src:000000,op:flip4,pos:142,+cov
index d186af9f9..d186af9f9 100644
--- a/src/mint/afl-tests/id:000262,src:000000,op:flip4,pos:142,+cov
+++ b/src/exchange/afl-tests/id:000262,src:000000,op:flip4,pos:142,+cov
diff --git a/src/mint/afl-tests/id:000262,src:000000,op:flip4,pos:164,+cov b/src/exchange/afl-tests/id:000262,src:000000,op:flip4,pos:164,+cov
index 41838fab5..41838fab5 100644
--- a/src/mint/afl-tests/id:000262,src:000000,op:flip4,pos:164,+cov
+++ b/src/exchange/afl-tests/id:000262,src:000000,op:flip4,pos:164,+cov
diff --git a/src/mint/afl-tests/id:000263,src:000000,op:flip4,pos:147,+cov b/src/exchange/afl-tests/id:000263,src:000000,op:flip4,pos:147,+cov
index 64c7ecc5a..64c7ecc5a 100644
--- a/src/mint/afl-tests/id:000263,src:000000,op:flip4,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000263,src:000000,op:flip4,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000263,src:000000,op:flip4,pos:169,+cov b/src/exchange/afl-tests/id:000263,src:000000,op:flip4,pos:169,+cov
index 27ec78964..27ec78964 100644
--- a/src/mint/afl-tests/id:000263,src:000000,op:flip4,pos:169,+cov
+++ b/src/exchange/afl-tests/id:000263,src:000000,op:flip4,pos:169,+cov
diff --git a/src/mint/afl-tests/id:000264,src:000000,op:flip4,pos:157,+cov b/src/exchange/afl-tests/id:000264,src:000000,op:flip4,pos:157,+cov
index f86e70fe3..f86e70fe3 100644
--- a/src/mint/afl-tests/id:000264,src:000000,op:flip4,pos:157,+cov
+++ b/src/exchange/afl-tests/id:000264,src:000000,op:flip4,pos:157,+cov
diff --git a/src/mint/afl-tests/id:000264,src:000000,op:flip4,pos:172,+cov b/src/exchange/afl-tests/id:000264,src:000000,op:flip4,pos:172,+cov
index e0685daa8..e0685daa8 100644
--- a/src/mint/afl-tests/id:000264,src:000000,op:flip4,pos:172,+cov
+++ b/src/exchange/afl-tests/id:000264,src:000000,op:flip4,pos:172,+cov
diff --git a/src/mint/afl-tests/id:000265,src:000000,op:flip4,pos:157,+cov b/src/exchange/afl-tests/id:000265,src:000000,op:flip4,pos:157,+cov
index 131458df0..131458df0 100644
--- a/src/mint/afl-tests/id:000265,src:000000,op:flip4,pos:157,+cov
+++ b/src/exchange/afl-tests/id:000265,src:000000,op:flip4,pos:157,+cov
diff --git a/src/mint/afl-tests/id:000265,src:000000,op:flip4,pos:175,+cov b/src/exchange/afl-tests/id:000265,src:000000,op:flip4,pos:175,+cov
index 27910870d..27910870d 100644
--- a/src/mint/afl-tests/id:000265,src:000000,op:flip4,pos:175,+cov
+++ b/src/exchange/afl-tests/id:000265,src:000000,op:flip4,pos:175,+cov
diff --git a/src/mint/afl-tests/id:000266,src:000000,op:flip4,pos:176,+cov b/src/exchange/afl-tests/id:000266,src:000000,op:flip4,pos:176,+cov
index 82ec22dc6..82ec22dc6 100644
--- a/src/mint/afl-tests/id:000266,src:000000,op:flip4,pos:176,+cov
+++ b/src/exchange/afl-tests/id:000266,src:000000,op:flip4,pos:176,+cov
diff --git a/src/mint/afl-tests/id:000266,src:000000,op:flip4,pos:177,+cov b/src/exchange/afl-tests/id:000266,src:000000,op:flip4,pos:177,+cov
index 24b643fe5..24b643fe5 100644
--- a/src/mint/afl-tests/id:000266,src:000000,op:flip4,pos:177,+cov
+++ b/src/exchange/afl-tests/id:000266,src:000000,op:flip4,pos:177,+cov
diff --git a/src/mint/afl-tests/id:000267,src:000000,op:flip4,pos:179,+cov b/src/exchange/afl-tests/id:000267,src:000000,op:flip4,pos:179,+cov
index 360154992..360154992 100644
--- a/src/mint/afl-tests/id:000267,src:000000,op:flip4,pos:179,+cov
+++ b/src/exchange/afl-tests/id:000267,src:000000,op:flip4,pos:179,+cov
diff --git a/src/mint/afl-tests/id:000267,src:000000,op:flip4,pos:225,+cov b/src/exchange/afl-tests/id:000267,src:000000,op:flip4,pos:225,+cov
index f7151ae26..f7151ae26 100644
--- a/src/mint/afl-tests/id:000267,src:000000,op:flip4,pos:225,+cov
+++ b/src/exchange/afl-tests/id:000267,src:000000,op:flip4,pos:225,+cov
diff --git a/src/mint/afl-tests/id:000268,src:000000,op:flip4,pos:183,+cov b/src/exchange/afl-tests/id:000268,src:000000,op:flip4,pos:183,+cov
index 6d1bc2588..6d1bc2588 100644
--- a/src/mint/afl-tests/id:000268,src:000000,op:flip4,pos:183,+cov
+++ b/src/exchange/afl-tests/id:000268,src:000000,op:flip4,pos:183,+cov
diff --git a/src/mint/afl-tests/id:000268,src:000000,op:flip4,pos:258,+cov b/src/exchange/afl-tests/id:000268,src:000000,op:flip4,pos:258,+cov
index 87d7b817a..87d7b817a 100644
--- a/src/mint/afl-tests/id:000268,src:000000,op:flip4,pos:258,+cov
+++ b/src/exchange/afl-tests/id:000268,src:000000,op:flip4,pos:258,+cov
diff --git a/src/mint/afl-tests/id:000269,src:000000,op:flip4,pos:262,+cov b/src/exchange/afl-tests/id:000269,src:000000,op:flip4,pos:262,+cov
index 5cb2cb0a6..5cb2cb0a6 100644
--- a/src/mint/afl-tests/id:000269,src:000000,op:flip4,pos:262,+cov
+++ b/src/exchange/afl-tests/id:000269,src:000000,op:flip4,pos:262,+cov
diff --git a/src/mint/afl-tests/id:000269,src:000000,op:flip4,pos:270,+cov b/src/exchange/afl-tests/id:000269,src:000000,op:flip4,pos:270,+cov
index a08c275a9..a08c275a9 100644
--- a/src/mint/afl-tests/id:000269,src:000000,op:flip4,pos:270,+cov
+++ b/src/exchange/afl-tests/id:000269,src:000000,op:flip4,pos:270,+cov
diff --git a/src/mint/afl-tests/id:000270,src:000000,op:flip4,pos:276,+cov b/src/exchange/afl-tests/id:000270,src:000000,op:flip4,pos:276,+cov
index b0fb2cef9..b0fb2cef9 100644
--- a/src/mint/afl-tests/id:000270,src:000000,op:flip4,pos:276,+cov
+++ b/src/exchange/afl-tests/id:000270,src:000000,op:flip4,pos:276,+cov
diff --git a/src/mint/afl-tests/id:000270,src:000000,op:flip4,pos:280,+cov b/src/exchange/afl-tests/id:000270,src:000000,op:flip4,pos:280,+cov
index 9273332cd..9273332cd 100644
--- a/src/mint/afl-tests/id:000270,src:000000,op:flip4,pos:280,+cov
+++ b/src/exchange/afl-tests/id:000270,src:000000,op:flip4,pos:280,+cov
diff --git a/src/mint/afl-tests/id:000271,src:000000,op:flip4,pos:284,+cov b/src/exchange/afl-tests/id:000271,src:000000,op:flip4,pos:284,+cov
index 66d79eb73..66d79eb73 100644
--- a/src/mint/afl-tests/id:000271,src:000000,op:flip4,pos:284,+cov
+++ b/src/exchange/afl-tests/id:000271,src:000000,op:flip4,pos:284,+cov
diff --git a/src/mint/afl-tests/id:000271,src:000000,op:flip4,pos:307,+cov b/src/exchange/afl-tests/id:000271,src:000000,op:flip4,pos:307,+cov
index c275db95d..c275db95d 100644
--- a/src/mint/afl-tests/id:000271,src:000000,op:flip4,pos:307,+cov
+++ b/src/exchange/afl-tests/id:000271,src:000000,op:flip4,pos:307,+cov
diff --git a/src/mint/afl-tests/id:000272,src:000000,op:flip4,pos:314,+cov b/src/exchange/afl-tests/id:000272,src:000000,op:flip4,pos:314,+cov
index 473c0d79e..473c0d79e 100644
--- a/src/mint/afl-tests/id:000272,src:000000,op:flip4,pos:314,+cov
+++ b/src/exchange/afl-tests/id:000272,src:000000,op:flip4,pos:314,+cov
diff --git a/src/mint/afl-tests/id:000272,src:000000,op:flip4,pos:317,+cov b/src/exchange/afl-tests/id:000272,src:000000,op:flip4,pos:317,+cov
index cd1ff487c..cd1ff487c 100644
--- a/src/mint/afl-tests/id:000272,src:000000,op:flip4,pos:317,+cov
+++ b/src/exchange/afl-tests/id:000272,src:000000,op:flip4,pos:317,+cov
diff --git a/src/mint/afl-tests/id:000273,src:000000,op:flip4,pos:318,+cov b/src/exchange/afl-tests/id:000273,src:000000,op:flip4,pos:318,+cov
index 4d1ec655a..4d1ec655a 100644
--- a/src/mint/afl-tests/id:000273,src:000000,op:flip4,pos:318,+cov
+++ b/src/exchange/afl-tests/id:000273,src:000000,op:flip4,pos:318,+cov
diff --git a/src/mint/afl-tests/id:000273,src:000000,op:flip4,pos:328,+cov b/src/exchange/afl-tests/id:000273,src:000000,op:flip4,pos:328,+cov
index 18ab5851c..18ab5851c 100644
--- a/src/mint/afl-tests/id:000273,src:000000,op:flip4,pos:328,+cov
+++ b/src/exchange/afl-tests/id:000273,src:000000,op:flip4,pos:328,+cov
diff --git a/src/mint/afl-tests/id:000274,src:000000,op:flip4,pos:330,+cov b/src/exchange/afl-tests/id:000274,src:000000,op:flip4,pos:330,+cov
index 3471f5668..3471f5668 100644
--- a/src/mint/afl-tests/id:000274,src:000000,op:flip4,pos:330,+cov
+++ b/src/exchange/afl-tests/id:000274,src:000000,op:flip4,pos:330,+cov
diff --git a/src/mint/afl-tests/id:000275,src:000000,op:flip4,pos:331,+cov b/src/exchange/afl-tests/id:000275,src:000000,op:flip4,pos:331,+cov
index a633b436d..a633b436d 100644
--- a/src/mint/afl-tests/id:000275,src:000000,op:flip4,pos:331,+cov
+++ b/src/exchange/afl-tests/id:000275,src:000000,op:flip4,pos:331,+cov
diff --git a/src/mint/afl-tests/id:000275,src:000000,op:flip8,pos:32,+cov b/src/exchange/afl-tests/id:000275,src:000000,op:flip8,pos:32,+cov
index 9380f3bad..9380f3bad 100644
--- a/src/mint/afl-tests/id:000275,src:000000,op:flip8,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000275,src:000000,op:flip8,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000276,src:000000,op:flip8,pos:43,+cov b/src/exchange/afl-tests/id:000276,src:000000,op:flip8,pos:43,+cov
index 807c60f27..807c60f27 100644
--- a/src/mint/afl-tests/id:000276,src:000000,op:flip8,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000276,src:000000,op:flip8,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000276,src:000000,op:flip8,pos:47,+cov b/src/exchange/afl-tests/id:000276,src:000000,op:flip8,pos:47,+cov
index d4ae83d7d..d4ae83d7d 100644
--- a/src/mint/afl-tests/id:000276,src:000000,op:flip8,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000276,src:000000,op:flip8,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000277,src:000000,op:flip8,pos:190,+cov b/src/exchange/afl-tests/id:000277,src:000000,op:flip8,pos:190,+cov
index e34d6b3a8..e34d6b3a8 100644
--- a/src/mint/afl-tests/id:000277,src:000000,op:flip8,pos:190,+cov
+++ b/src/exchange/afl-tests/id:000277,src:000000,op:flip8,pos:190,+cov
diff --git a/src/mint/afl-tests/id:000277,src:000000,op:flip8,pos:52,+cov b/src/exchange/afl-tests/id:000277,src:000000,op:flip8,pos:52,+cov
index ecff769d5..ecff769d5 100644
--- a/src/mint/afl-tests/id:000277,src:000000,op:flip8,pos:52,+cov
+++ b/src/exchange/afl-tests/id:000277,src:000000,op:flip8,pos:52,+cov
diff --git a/src/mint/afl-tests/id:000278,src:000000,op:flip16,pos:51,+cov b/src/exchange/afl-tests/id:000278,src:000000,op:flip16,pos:51,+cov
index cd088519b..cd088519b 100644
--- a/src/mint/afl-tests/id:000278,src:000000,op:flip16,pos:51,+cov
+++ b/src/exchange/afl-tests/id:000278,src:000000,op:flip16,pos:51,+cov
diff --git a/src/mint/afl-tests/id:000278,src:000000,op:flip8,pos:62,+cov b/src/exchange/afl-tests/id:000278,src:000000,op:flip8,pos:62,+cov
index c357e97c3..c357e97c3 100644
--- a/src/mint/afl-tests/id:000278,src:000000,op:flip8,pos:62,+cov
+++ b/src/exchange/afl-tests/id:000278,src:000000,op:flip8,pos:62,+cov
diff --git a/src/mint/afl-tests/id:000279,src:000000,op:flip16,pos:219,+cov b/src/exchange/afl-tests/id:000279,src:000000,op:flip16,pos:219,+cov
index 4d506ae4d..4d506ae4d 100644
--- a/src/mint/afl-tests/id:000279,src:000000,op:flip16,pos:219,+cov
+++ b/src/exchange/afl-tests/id:000279,src:000000,op:flip16,pos:219,+cov
diff --git a/src/mint/afl-tests/id:000279,src:000000,op:flip8,pos:87,+cov b/src/exchange/afl-tests/id:000279,src:000000,op:flip8,pos:87,+cov
index 2ac89cdd3..2ac89cdd3 100644
--- a/src/mint/afl-tests/id:000279,src:000000,op:flip8,pos:87,+cov
+++ b/src/exchange/afl-tests/id:000279,src:000000,op:flip8,pos:87,+cov
diff --git a/src/mint/afl-tests/id:000280,src:000000,op:flip32,pos:55,+cov b/src/exchange/afl-tests/id:000280,src:000000,op:flip32,pos:55,+cov
index b760bf503..b760bf503 100644
--- a/src/mint/afl-tests/id:000280,src:000000,op:flip32,pos:55,+cov
+++ b/src/exchange/afl-tests/id:000280,src:000000,op:flip32,pos:55,+cov
diff --git a/src/mint/afl-tests/id:000280,src:000000,op:flip8,pos:88,+cov b/src/exchange/afl-tests/id:000280,src:000000,op:flip8,pos:88,+cov
index decf04feb..decf04feb 100644
--- a/src/mint/afl-tests/id:000280,src:000000,op:flip8,pos:88,+cov
+++ b/src/exchange/afl-tests/id:000280,src:000000,op:flip8,pos:88,+cov
diff --git a/src/mint/afl-tests/id:000281,src:000000,op:flip32,pos:68,+cov b/src/exchange/afl-tests/id:000281,src:000000,op:flip32,pos:68,+cov
index 3747666ea..3747666ea 100644
--- a/src/mint/afl-tests/id:000281,src:000000,op:flip32,pos:68,+cov
+++ b/src/exchange/afl-tests/id:000281,src:000000,op:flip32,pos:68,+cov
diff --git a/src/mint/afl-tests/id:000281,src:000000,op:flip8,pos:331,+cov b/src/exchange/afl-tests/id:000281,src:000000,op:flip8,pos:331,+cov
index 55cd8836d..55cd8836d 100644
--- a/src/mint/afl-tests/id:000281,src:000000,op:flip8,pos:331,+cov
+++ b/src/exchange/afl-tests/id:000281,src:000000,op:flip8,pos:331,+cov
diff --git a/src/mint/afl-tests/id:000282,src:000000,op:arith8,pos:4,val:-19 b/src/exchange/afl-tests/id:000282,src:000000,op:arith8,pos:4,val:-19
index 12e0ae2a8..12e0ae2a8 100644
--- a/src/mint/afl-tests/id:000282,src:000000,op:arith8,pos:4,val:-19
+++ b/src/exchange/afl-tests/id:000282,src:000000,op:arith8,pos:4,val:-19
diff --git a/src/mint/afl-tests/id:000282,src:000000,op:flip16,pos:39,+cov b/src/exchange/afl-tests/id:000282,src:000000,op:flip16,pos:39,+cov
index 6d70030f3..6d70030f3 100644
--- a/src/mint/afl-tests/id:000282,src:000000,op:flip16,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000282,src:000000,op:flip16,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000283,src:000000,op:arith8,pos:4,val:-22 b/src/exchange/afl-tests/id:000283,src:000000,op:arith8,pos:4,val:-22
index bbeeb110a..bbeeb110a 100644
--- a/src/mint/afl-tests/id:000283,src:000000,op:arith8,pos:4,val:-22
+++ b/src/exchange/afl-tests/id:000283,src:000000,op:arith8,pos:4,val:-22
diff --git a/src/mint/afl-tests/id:000283,src:000000,op:flip16,pos:85,+cov b/src/exchange/afl-tests/id:000283,src:000000,op:flip16,pos:85,+cov
index b707ff1a3..b707ff1a3 100644
--- a/src/mint/afl-tests/id:000283,src:000000,op:flip16,pos:85,+cov
+++ b/src/exchange/afl-tests/id:000283,src:000000,op:flip16,pos:85,+cov
diff --git a/src/mint/afl-tests/id:000284,src:000000,op:arith8,pos:5,val:-10,+cov b/src/exchange/afl-tests/id:000284,src:000000,op:arith8,pos:5,val:-10,+cov
index 2e1ce6848..2e1ce6848 100644
--- a/src/mint/afl-tests/id:000284,src:000000,op:arith8,pos:5,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000284,src:000000,op:arith8,pos:5,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000284,src:000000,op:flip32,pos:49,+cov b/src/exchange/afl-tests/id:000284,src:000000,op:flip32,pos:49,+cov
index 586994698..586994698 100644
--- a/src/mint/afl-tests/id:000284,src:000000,op:flip32,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000284,src:000000,op:flip32,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000285,src:000000,op:arith8,pos:5,val:-34 b/src/exchange/afl-tests/id:000285,src:000000,op:arith8,pos:5,val:-34
index b4194fc37..b4194fc37 100644
--- a/src/mint/afl-tests/id:000285,src:000000,op:arith8,pos:5,val:-34
+++ b/src/exchange/afl-tests/id:000285,src:000000,op:arith8,pos:5,val:-34
diff --git a/src/mint/afl-tests/id:000285,src:000000,op:flip32,pos:62 b/src/exchange/afl-tests/id:000285,src:000000,op:flip32,pos:62
index c42ccc4d7..c42ccc4d7 100644
--- a/src/mint/afl-tests/id:000285,src:000000,op:flip32,pos:62
+++ b/src/exchange/afl-tests/id:000285,src:000000,op:flip32,pos:62
diff --git a/src/mint/afl-tests/id:000286,src:000000,op:arith8,pos:6,val:-34,+cov b/src/exchange/afl-tests/id:000286,src:000000,op:arith8,pos:6,val:-34,+cov
index 7c6c9e9a4..7c6c9e9a4 100644
--- a/src/mint/afl-tests/id:000286,src:000000,op:arith8,pos:6,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000286,src:000000,op:arith8,pos:6,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000286,src:000000,op:flip32,pos:86,+cov b/src/exchange/afl-tests/id:000286,src:000000,op:flip32,pos:86,+cov
index f6b0961c1..f6b0961c1 100644
--- a/src/mint/afl-tests/id:000286,src:000000,op:flip32,pos:86,+cov
+++ b/src/exchange/afl-tests/id:000286,src:000000,op:flip32,pos:86,+cov
diff --git a/src/mint/afl-tests/id:000287,src:000000,op:arith8,pos:11,val:-34 b/src/exchange/afl-tests/id:000287,src:000000,op:arith8,pos:11,val:-34
index 800f11d77..800f11d77 100644
--- a/src/mint/afl-tests/id:000287,src:000000,op:arith8,pos:11,val:-34
+++ b/src/exchange/afl-tests/id:000287,src:000000,op:arith8,pos:11,val:-34
diff --git a/src/mint/afl-tests/id:000287,src:000000,op:flip32,pos:92,+cov b/src/exchange/afl-tests/id:000287,src:000000,op:flip32,pos:92,+cov
index db12f8d50..db12f8d50 100644
--- a/src/mint/afl-tests/id:000287,src:000000,op:flip32,pos:92,+cov
+++ b/src/exchange/afl-tests/id:000287,src:000000,op:flip32,pos:92,+cov
diff --git a/src/mint/afl-tests/id:000288,src:000000,op:arith8,pos:15,val:-10,+cov b/src/exchange/afl-tests/id:000288,src:000000,op:arith8,pos:15,val:-10,+cov
index eb694617c..eb694617c 100644
--- a/src/mint/afl-tests/id:000288,src:000000,op:arith8,pos:15,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000288,src:000000,op:arith8,pos:15,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000288,src:000000,op:arith8,pos:4,val:-19 b/src/exchange/afl-tests/id:000288,src:000000,op:arith8,pos:4,val:-19
index 12e0ae2a8..12e0ae2a8 100644
--- a/src/mint/afl-tests/id:000288,src:000000,op:arith8,pos:4,val:-19
+++ b/src/exchange/afl-tests/id:000288,src:000000,op:arith8,pos:4,val:-19
diff --git a/src/mint/afl-tests/id:000289,src:000000,op:arith8,pos:22,val:+5,+cov b/src/exchange/afl-tests/id:000289,src:000000,op:arith8,pos:22,val:+5,+cov
index 4b360a211..4b360a211 100644
--- a/src/mint/afl-tests/id:000289,src:000000,op:arith8,pos:22,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000289,src:000000,op:arith8,pos:22,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000289,src:000000,op:arith8,pos:4,val:-22 b/src/exchange/afl-tests/id:000289,src:000000,op:arith8,pos:4,val:-22
index bbeeb110a..bbeeb110a 100644
--- a/src/mint/afl-tests/id:000289,src:000000,op:arith8,pos:4,val:-22
+++ b/src/exchange/afl-tests/id:000289,src:000000,op:arith8,pos:4,val:-22
diff --git a/src/mint/afl-tests/id:000290,src:000000,op:arith8,pos:24,val:+10,+cov b/src/exchange/afl-tests/id:000290,src:000000,op:arith8,pos:24,val:+10,+cov
index 6b727d2dd..6b727d2dd 100644
--- a/src/mint/afl-tests/id:000290,src:000000,op:arith8,pos:24,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000290,src:000000,op:arith8,pos:24,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000290,src:000000,op:arith8,pos:5,val:-10,+cov b/src/exchange/afl-tests/id:000290,src:000000,op:arith8,pos:5,val:-10,+cov
index 2e1ce6848..2e1ce6848 100644
--- a/src/mint/afl-tests/id:000290,src:000000,op:arith8,pos:5,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000290,src:000000,op:arith8,pos:5,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000291,src:000000,op:arith8,pos:25,val:-6,+cov b/src/exchange/afl-tests/id:000291,src:000000,op:arith8,pos:25,val:-6,+cov
index 266c585e9..266c585e9 100644
--- a/src/mint/afl-tests/id:000291,src:000000,op:arith8,pos:25,val:-6,+cov
+++ b/src/exchange/afl-tests/id:000291,src:000000,op:arith8,pos:25,val:-6,+cov
diff --git a/src/mint/afl-tests/id:000291,src:000000,op:arith8,pos:5,val:-34 b/src/exchange/afl-tests/id:000291,src:000000,op:arith8,pos:5,val:-34
index b4194fc37..b4194fc37 100644
--- a/src/mint/afl-tests/id:000291,src:000000,op:arith8,pos:5,val:-34
+++ b/src/exchange/afl-tests/id:000291,src:000000,op:arith8,pos:5,val:-34
diff --git a/src/mint/afl-tests/id:000292,src:000000,op:arith8,pos:25,val:-25,+cov b/src/exchange/afl-tests/id:000292,src:000000,op:arith8,pos:25,val:-25,+cov
index d3cf6bd8c..d3cf6bd8c 100644
--- a/src/mint/afl-tests/id:000292,src:000000,op:arith8,pos:25,val:-25,+cov
+++ b/src/exchange/afl-tests/id:000292,src:000000,op:arith8,pos:25,val:-25,+cov
diff --git a/src/mint/afl-tests/id:000292,src:000000,op:arith8,pos:6,val:-34,+cov b/src/exchange/afl-tests/id:000292,src:000000,op:arith8,pos:6,val:-34,+cov
index 7c6c9e9a4..7c6c9e9a4 100644
--- a/src/mint/afl-tests/id:000292,src:000000,op:arith8,pos:6,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000292,src:000000,op:arith8,pos:6,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000293,src:000000,op:arith8,pos:25,val:-29,+cov b/src/exchange/afl-tests/id:000293,src:000000,op:arith8,pos:25,val:-29,+cov
index 7001abfc8..7001abfc8 100644
--- a/src/mint/afl-tests/id:000293,src:000000,op:arith8,pos:25,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000293,src:000000,op:arith8,pos:25,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000293,src:000000,op:arith8,pos:7,val:-34,+cov b/src/exchange/afl-tests/id:000293,src:000000,op:arith8,pos:7,val:-34,+cov
index f94f08c7e..f94f08c7e 100644
--- a/src/mint/afl-tests/id:000293,src:000000,op:arith8,pos:7,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000293,src:000000,op:arith8,pos:7,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000294,src:000000,op:arith8,pos:11,val:-34 b/src/exchange/afl-tests/id:000294,src:000000,op:arith8,pos:11,val:-34
index 800f11d77..800f11d77 100644
--- a/src/mint/afl-tests/id:000294,src:000000,op:arith8,pos:11,val:-34
+++ b/src/exchange/afl-tests/id:000294,src:000000,op:arith8,pos:11,val:-34
diff --git a/src/mint/afl-tests/id:000294,src:000000,op:arith8,pos:26,val:+12,+cov b/src/exchange/afl-tests/id:000294,src:000000,op:arith8,pos:26,val:+12,+cov
index 898b7b54e..898b7b54e 100644
--- a/src/mint/afl-tests/id:000294,src:000000,op:arith8,pos:26,val:+12,+cov
+++ b/src/exchange/afl-tests/id:000294,src:000000,op:arith8,pos:26,val:+12,+cov
diff --git a/src/mint/afl-tests/id:000295,src:000000,op:arith8,pos:15,val:-10,+cov b/src/exchange/afl-tests/id:000295,src:000000,op:arith8,pos:15,val:-10,+cov
index eb694617c..eb694617c 100644
--- a/src/mint/afl-tests/id:000295,src:000000,op:arith8,pos:15,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000295,src:000000,op:arith8,pos:15,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000295,src:000000,op:arith8,pos:26,val:+17,+cov b/src/exchange/afl-tests/id:000295,src:000000,op:arith8,pos:26,val:+17,+cov
index 3b82a7a45..3b82a7a45 100644
--- a/src/mint/afl-tests/id:000295,src:000000,op:arith8,pos:26,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000295,src:000000,op:arith8,pos:26,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000296,src:000000,op:arith8,pos:25,val:+24,+cov b/src/exchange/afl-tests/id:000296,src:000000,op:arith8,pos:25,val:+24,+cov
index e27e05c18..e27e05c18 100644
--- a/src/mint/afl-tests/id:000296,src:000000,op:arith8,pos:25,val:+24,+cov
+++ b/src/exchange/afl-tests/id:000296,src:000000,op:arith8,pos:25,val:+24,+cov
diff --git a/src/mint/afl-tests/id:000296,src:000000,op:arith8,pos:27,val:-29,+cov b/src/exchange/afl-tests/id:000296,src:000000,op:arith8,pos:27,val:-29,+cov
index 7033fc108..7033fc108 100644
--- a/src/mint/afl-tests/id:000296,src:000000,op:arith8,pos:27,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000296,src:000000,op:arith8,pos:27,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+26,+cov b/src/exchange/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+26,+cov
index e3e645d56..e3e645d56 100644
--- a/src/mint/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+33,+cov b/src/exchange/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+33,+cov
index 2354f9ec9..2354f9ec9 100644
--- a/src/mint/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000297,src:000000,op:arith8,pos:27,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+13,+cov b/src/exchange/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+13,+cov
index 042d4e2eb..042d4e2eb 100644
--- a/src/mint/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+9,+cov b/src/exchange/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+9,+cov
index 828e367ad..828e367ad 100644
--- a/src/mint/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000298,src:000000,op:arith8,pos:28,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-15,+cov b/src/exchange/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-15,+cov
index a8f4f133d..a8f4f133d 100644
--- a/src/mint/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-17 b/src/exchange/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-17
index e10776344..e10776344 100644
--- a/src/mint/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-17
+++ b/src/exchange/afl-tests/id:000299,src:000000,op:arith8,pos:28,val:-17
diff --git a/src/mint/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:+27,+cov b/src/exchange/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:+27,+cov
index f39331171..f39331171 100644
--- a/src/mint/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:-33,+cov b/src/exchange/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:-33,+cov
index 9583e2475..9583e2475 100644
--- a/src/mint/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000300,src:000000,op:arith8,pos:28,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000301,src:000000,op:arith8,pos:28,val:-31,+cov b/src/exchange/afl-tests/id:000301,src:000000,op:arith8,pos:28,val:-31,+cov
index 6c9b2146b..6c9b2146b 100644
--- a/src/mint/afl-tests/id:000301,src:000000,op:arith8,pos:28,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000301,src:000000,op:arith8,pos:28,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000301,src:000000,op:arith8,pos:29,val:+14,+cov b/src/exchange/afl-tests/id:000301,src:000000,op:arith8,pos:29,val:+14,+cov
index aacd0de6e..aacd0de6e 100644
--- a/src/mint/afl-tests/id:000301,src:000000,op:arith8,pos:29,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000301,src:000000,op:arith8,pos:29,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000302,src:000000,op:arith8,pos:29,val:-29,+cov b/src/exchange/afl-tests/id:000302,src:000000,op:arith8,pos:29,val:-29,+cov
index 8e2ad654a..8e2ad654a 100644
--- a/src/mint/afl-tests/id:000302,src:000000,op:arith8,pos:29,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000302,src:000000,op:arith8,pos:29,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000302,src:000000,op:arith8,pos:30,val:+3,+cov b/src/exchange/afl-tests/id:000302,src:000000,op:arith8,pos:30,val:+3,+cov
index a88e5b104..a88e5b104 100644
--- a/src/mint/afl-tests/id:000302,src:000000,op:arith8,pos:30,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000302,src:000000,op:arith8,pos:30,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+18,+cov b/src/exchange/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+18,+cov
index 869a1de15..869a1de15 100644
--- a/src/mint/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+31,+cov b/src/exchange/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+31,+cov
index 8551cf990..8551cf990 100644
--- a/src/mint/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000303,src:000000,op:arith8,pos:30,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:+19,+cov b/src/exchange/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:+19,+cov
index 51a9ffc4e..51a9ffc4e 100644
--- a/src/mint/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:-33,+cov b/src/exchange/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:-33,+cov
index 7b6803aec..7b6803aec 100644
--- a/src/mint/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000304,src:000000,op:arith8,pos:31,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000305,src:000000,op:arith8,pos:31,val:-29,+cov b/src/exchange/afl-tests/id:000305,src:000000,op:arith8,pos:31,val:-29,+cov
index caa9eaa75..caa9eaa75 100644
--- a/src/mint/afl-tests/id:000305,src:000000,op:arith8,pos:31,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000305,src:000000,op:arith8,pos:31,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000305,src:000000,op:arith8,pos:32,val:+19,+cov b/src/exchange/afl-tests/id:000305,src:000000,op:arith8,pos:32,val:+19,+cov
index 0d5448ad2..0d5448ad2 100644
--- a/src/mint/afl-tests/id:000305,src:000000,op:arith8,pos:32,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000305,src:000000,op:arith8,pos:32,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000306,src:000000,op:arith8,pos:31,val:-33,+cov b/src/exchange/afl-tests/id:000306,src:000000,op:arith8,pos:31,val:-33,+cov
index 7b6803aec..7b6803aec 100644
--- a/src/mint/afl-tests/id:000306,src:000000,op:arith8,pos:31,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000306,src:000000,op:arith8,pos:31,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000306,src:000000,op:arith8,pos:33,val:+15,+cov b/src/exchange/afl-tests/id:000306,src:000000,op:arith8,pos:33,val:+15,+cov
index 4be075df1..4be075df1 100644
--- a/src/mint/afl-tests/id:000306,src:000000,op:arith8,pos:33,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000306,src:000000,op:arith8,pos:33,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000307,src:000000,op:arith8,pos:31,val:+34,+cov b/src/exchange/afl-tests/id:000307,src:000000,op:arith8,pos:31,val:+34,+cov
index 867da0989..867da0989 100644
--- a/src/mint/afl-tests/id:000307,src:000000,op:arith8,pos:31,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000307,src:000000,op:arith8,pos:31,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000307,src:000000,op:arith8,pos:33,val:-15,+cov b/src/exchange/afl-tests/id:000307,src:000000,op:arith8,pos:33,val:-15,+cov
index 5a265f063..5a265f063 100644
--- a/src/mint/afl-tests/id:000307,src:000000,op:arith8,pos:33,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000307,src:000000,op:arith8,pos:33,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000308,src:000000,op:arith8,pos:32,val:+10,+cov b/src/exchange/afl-tests/id:000308,src:000000,op:arith8,pos:32,val:+10,+cov
index 96afd8789..96afd8789 100644
--- a/src/mint/afl-tests/id:000308,src:000000,op:arith8,pos:32,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000308,src:000000,op:arith8,pos:32,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000308,src:000000,op:arith8,pos:34,val:-27,+cov b/src/exchange/afl-tests/id:000308,src:000000,op:arith8,pos:34,val:-27,+cov
index 5f4c01bfb..5f4c01bfb 100644
--- a/src/mint/afl-tests/id:000308,src:000000,op:arith8,pos:34,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000308,src:000000,op:arith8,pos:34,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000309,src:000000,op:arith8,pos:32,val:-20,+cov b/src/exchange/afl-tests/id:000309,src:000000,op:arith8,pos:32,val:-20,+cov
index cf060fe14..cf060fe14 100644
--- a/src/mint/afl-tests/id:000309,src:000000,op:arith8,pos:32,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000309,src:000000,op:arith8,pos:32,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000309,src:000000,op:arith8,pos:34,val:+34,+cov b/src/exchange/afl-tests/id:000309,src:000000,op:arith8,pos:34,val:+34,+cov
index 8cd22904a..8cd22904a 100644
--- a/src/mint/afl-tests/id:000309,src:000000,op:arith8,pos:34,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000309,src:000000,op:arith8,pos:34,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000310,src:000000,op:arith8,pos:33,val:+20,+cov b/src/exchange/afl-tests/id:000310,src:000000,op:arith8,pos:33,val:+20,+cov
index eef35d6e9..eef35d6e9 100644
--- a/src/mint/afl-tests/id:000310,src:000000,op:arith8,pos:33,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000310,src:000000,op:arith8,pos:33,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000310,src:000000,op:arith8,pos:35,val:+18,+cov b/src/exchange/afl-tests/id:000310,src:000000,op:arith8,pos:35,val:+18,+cov
index 39ff8930c..39ff8930c 100644
--- a/src/mint/afl-tests/id:000310,src:000000,op:arith8,pos:35,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000310,src:000000,op:arith8,pos:35,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000311,src:000000,op:arith8,pos:33,val:+24,+cov b/src/exchange/afl-tests/id:000311,src:000000,op:arith8,pos:33,val:+24,+cov
index 54136c35e..54136c35e 100644
--- a/src/mint/afl-tests/id:000311,src:000000,op:arith8,pos:33,val:+24,+cov
+++ b/src/exchange/afl-tests/id:000311,src:000000,op:arith8,pos:33,val:+24,+cov
diff --git a/src/mint/afl-tests/id:000311,src:000000,op:arith8,pos:35,val:-27,+cov b/src/exchange/afl-tests/id:000311,src:000000,op:arith8,pos:35,val:-27,+cov
index 1e8c67e55..1e8c67e55 100644
--- a/src/mint/afl-tests/id:000311,src:000000,op:arith8,pos:35,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000311,src:000000,op:arith8,pos:35,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000312,src:000000,op:arith8,pos:34,val:-3,+cov b/src/exchange/afl-tests/id:000312,src:000000,op:arith8,pos:34,val:-3,+cov
index 784a8b8ee..784a8b8ee 100644
--- a/src/mint/afl-tests/id:000312,src:000000,op:arith8,pos:34,val:-3,+cov
+++ b/src/exchange/afl-tests/id:000312,src:000000,op:arith8,pos:34,val:-3,+cov
diff --git a/src/mint/afl-tests/id:000312,src:000000,op:arith8,pos:35,val:+35,+cov b/src/exchange/afl-tests/id:000312,src:000000,op:arith8,pos:35,val:+35,+cov
index 79e7968a1..79e7968a1 100644
--- a/src/mint/afl-tests/id:000312,src:000000,op:arith8,pos:35,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000312,src:000000,op:arith8,pos:35,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000313,src:000000,op:arith8,pos:34,val:+18,+cov b/src/exchange/afl-tests/id:000313,src:000000,op:arith8,pos:34,val:+18,+cov
index 1c066c9b0..1c066c9b0 100644
--- a/src/mint/afl-tests/id:000313,src:000000,op:arith8,pos:34,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000313,src:000000,op:arith8,pos:34,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000313,src:000000,op:arith8,pos:36,val:+13,+cov b/src/exchange/afl-tests/id:000313,src:000000,op:arith8,pos:36,val:+13,+cov
index 0c03053cc..0c03053cc 100644
--- a/src/mint/afl-tests/id:000313,src:000000,op:arith8,pos:36,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000313,src:000000,op:arith8,pos:36,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000314,src:000000,op:arith8,pos:34,val:-30,+cov b/src/exchange/afl-tests/id:000314,src:000000,op:arith8,pos:34,val:-30,+cov
index c1cb683ed..c1cb683ed 100644
--- a/src/mint/afl-tests/id:000314,src:000000,op:arith8,pos:34,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000314,src:000000,op:arith8,pos:34,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000314,src:000000,op:arith8,pos:36,val:+32,+cov b/src/exchange/afl-tests/id:000314,src:000000,op:arith8,pos:36,val:+32,+cov
index de112273f..de112273f 100644
--- a/src/mint/afl-tests/id:000314,src:000000,op:arith8,pos:36,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000314,src:000000,op:arith8,pos:36,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000315,src:000000,op:arith8,pos:35,val:+17,+cov b/src/exchange/afl-tests/id:000315,src:000000,op:arith8,pos:35,val:+17,+cov
index 2ebedf6dc..2ebedf6dc 100644
--- a/src/mint/afl-tests/id:000315,src:000000,op:arith8,pos:35,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000315,src:000000,op:arith8,pos:35,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000315,src:000000,op:arith8,pos:37,val:+24,+cov b/src/exchange/afl-tests/id:000315,src:000000,op:arith8,pos:37,val:+24,+cov
index 5aec0d42d..5aec0d42d 100644
--- a/src/mint/afl-tests/id:000315,src:000000,op:arith8,pos:37,val:+24,+cov
+++ b/src/exchange/afl-tests/id:000315,src:000000,op:arith8,pos:37,val:+24,+cov
diff --git a/src/mint/afl-tests/id:000316,src:000000,op:arith8,pos:35,val:-19,+cov b/src/exchange/afl-tests/id:000316,src:000000,op:arith8,pos:35,val:-19,+cov
index cd15cde9d..cd15cde9d 100644
--- a/src/mint/afl-tests/id:000316,src:000000,op:arith8,pos:35,val:-19,+cov
+++ b/src/exchange/afl-tests/id:000316,src:000000,op:arith8,pos:35,val:-19,+cov
diff --git a/src/mint/afl-tests/id:000316,src:000000,op:arith8,pos:37,val:+32,+cov b/src/exchange/afl-tests/id:000316,src:000000,op:arith8,pos:37,val:+32,+cov
index dcc0db138..dcc0db138 100644
--- a/src/mint/afl-tests/id:000316,src:000000,op:arith8,pos:37,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000316,src:000000,op:arith8,pos:37,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000317,src:000000,op:arith8,pos:36,val:-26,+cov b/src/exchange/afl-tests/id:000317,src:000000,op:arith8,pos:36,val:-26,+cov
index 2f7d8883f..2f7d8883f 100644
--- a/src/mint/afl-tests/id:000317,src:000000,op:arith8,pos:36,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000317,src:000000,op:arith8,pos:36,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000317,src:000000,op:arith8,pos:38,val:-35,+cov b/src/exchange/afl-tests/id:000317,src:000000,op:arith8,pos:38,val:-35,+cov
index 01ef24ba5..01ef24ba5 100644
--- a/src/mint/afl-tests/id:000317,src:000000,op:arith8,pos:38,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000317,src:000000,op:arith8,pos:38,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000318,src:000000,op:arith8,pos:36,val:+27,+cov b/src/exchange/afl-tests/id:000318,src:000000,op:arith8,pos:36,val:+27,+cov
index d8d0b5a1e..d8d0b5a1e 100644
--- a/src/mint/afl-tests/id:000318,src:000000,op:arith8,pos:36,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000318,src:000000,op:arith8,pos:36,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000318,src:000000,op:arith8,pos:39,val:+18,+cov b/src/exchange/afl-tests/id:000318,src:000000,op:arith8,pos:39,val:+18,+cov
index 3182b8002..3182b8002 100644
--- a/src/mint/afl-tests/id:000318,src:000000,op:arith8,pos:39,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000318,src:000000,op:arith8,pos:39,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000319,src:000000,op:arith8,pos:36,val:+32,+cov b/src/exchange/afl-tests/id:000319,src:000000,op:arith8,pos:36,val:+32,+cov
index de112273f..de112273f 100644
--- a/src/mint/afl-tests/id:000319,src:000000,op:arith8,pos:36,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000319,src:000000,op:arith8,pos:36,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000319,src:000000,op:arith8,pos:39,val:-23,+cov b/src/exchange/afl-tests/id:000319,src:000000,op:arith8,pos:39,val:-23,+cov
index 04deb0197..04deb0197 100644
--- a/src/mint/afl-tests/id:000319,src:000000,op:arith8,pos:39,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000319,src:000000,op:arith8,pos:39,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000320,src:000000,op:arith8,pos:37,val:-9,+cov b/src/exchange/afl-tests/id:000320,src:000000,op:arith8,pos:37,val:-9,+cov
index 37328bc13..37328bc13 100644
--- a/src/mint/afl-tests/id:000320,src:000000,op:arith8,pos:37,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000320,src:000000,op:arith8,pos:37,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000320,src:000000,op:arith8,pos:39,val:-24,+cov b/src/exchange/afl-tests/id:000320,src:000000,op:arith8,pos:39,val:-24,+cov
index e2a4f6109..e2a4f6109 100644
--- a/src/mint/afl-tests/id:000320,src:000000,op:arith8,pos:39,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000320,src:000000,op:arith8,pos:39,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000321,src:000000,op:arith8,pos:37,val:+21 b/src/exchange/afl-tests/id:000321,src:000000,op:arith8,pos:37,val:+21
index 434e64b8a..434e64b8a 100644
--- a/src/mint/afl-tests/id:000321,src:000000,op:arith8,pos:37,val:+21
+++ b/src/exchange/afl-tests/id:000321,src:000000,op:arith8,pos:37,val:+21
diff --git a/src/mint/afl-tests/id:000321,src:000000,op:arith8,pos:39,val:+25,+cov b/src/exchange/afl-tests/id:000321,src:000000,op:arith8,pos:39,val:+25,+cov
index fadf00ff8..fadf00ff8 100644
--- a/src/mint/afl-tests/id:000321,src:000000,op:arith8,pos:39,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000321,src:000000,op:arith8,pos:39,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000322,src:000000,op:arith8,pos:37,val:+24,+cov b/src/exchange/afl-tests/id:000322,src:000000,op:arith8,pos:37,val:+24,+cov
index 5aec0d42d..5aec0d42d 100644
--- a/src/mint/afl-tests/id:000322,src:000000,op:arith8,pos:37,val:+24,+cov
+++ b/src/exchange/afl-tests/id:000322,src:000000,op:arith8,pos:37,val:+24,+cov
diff --git a/src/mint/afl-tests/id:000322,src:000000,op:arith8,pos:40,val:-21,+cov b/src/exchange/afl-tests/id:000322,src:000000,op:arith8,pos:40,val:-21,+cov
index 84863ad69..84863ad69 100644
--- a/src/mint/afl-tests/id:000322,src:000000,op:arith8,pos:40,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000322,src:000000,op:arith8,pos:40,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000323,src:000000,op:arith8,pos:39,val:+13,+cov b/src/exchange/afl-tests/id:000323,src:000000,op:arith8,pos:39,val:+13,+cov
index 77572467c..77572467c 100644
--- a/src/mint/afl-tests/id:000323,src:000000,op:arith8,pos:39,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000323,src:000000,op:arith8,pos:39,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000323,src:000000,op:arith8,pos:41,val:-5,+cov b/src/exchange/afl-tests/id:000323,src:000000,op:arith8,pos:41,val:-5,+cov
index 05370d441..05370d441 100644
--- a/src/mint/afl-tests/id:000323,src:000000,op:arith8,pos:41,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000323,src:000000,op:arith8,pos:41,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000324,src:000000,op:arith8,pos:39,val:-23,+cov b/src/exchange/afl-tests/id:000324,src:000000,op:arith8,pos:39,val:-23,+cov
index 04deb0197..04deb0197 100644
--- a/src/mint/afl-tests/id:000324,src:000000,op:arith8,pos:39,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000324,src:000000,op:arith8,pos:39,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000324,src:000000,op:arith8,pos:41,val:+13,+cov b/src/exchange/afl-tests/id:000324,src:000000,op:arith8,pos:41,val:+13,+cov
index ade405849..ade405849 100644
--- a/src/mint/afl-tests/id:000324,src:000000,op:arith8,pos:41,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000324,src:000000,op:arith8,pos:41,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000325,src:000000,op:arith8,pos:40,val:+20,+cov b/src/exchange/afl-tests/id:000325,src:000000,op:arith8,pos:40,val:+20,+cov
index 201588bd2..201588bd2 100644
--- a/src/mint/afl-tests/id:000325,src:000000,op:arith8,pos:40,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000325,src:000000,op:arith8,pos:40,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000325,src:000000,op:arith8,pos:41,val:+26,+cov b/src/exchange/afl-tests/id:000325,src:000000,op:arith8,pos:41,val:+26,+cov
index 6f6d851cd..6f6d851cd 100644
--- a/src/mint/afl-tests/id:000325,src:000000,op:arith8,pos:41,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000325,src:000000,op:arith8,pos:41,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000326,src:000000,op:arith8,pos:40,val:+27,+cov b/src/exchange/afl-tests/id:000326,src:000000,op:arith8,pos:40,val:+27,+cov
index 45220e0ac..45220e0ac 100644
--- a/src/mint/afl-tests/id:000326,src:000000,op:arith8,pos:40,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000326,src:000000,op:arith8,pos:40,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000326,src:000000,op:arith8,pos:41,val:+27,+cov b/src/exchange/afl-tests/id:000326,src:000000,op:arith8,pos:41,val:+27,+cov
index f4fc79ece..f4fc79ece 100644
--- a/src/mint/afl-tests/id:000326,src:000000,op:arith8,pos:41,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000326,src:000000,op:arith8,pos:41,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000327,src:000000,op:arith8,pos:41,val:-33,+cov b/src/exchange/afl-tests/id:000327,src:000000,op:arith8,pos:41,val:-33,+cov
index 1214430bd..1214430bd 100644
--- a/src/mint/afl-tests/id:000327,src:000000,op:arith8,pos:41,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000327,src:000000,op:arith8,pos:41,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000327,src:000000,op:arith8,pos:42,val:+29,+cov b/src/exchange/afl-tests/id:000327,src:000000,op:arith8,pos:42,val:+29,+cov
index fbeb7bd6e..fbeb7bd6e 100644
--- a/src/mint/afl-tests/id:000327,src:000000,op:arith8,pos:42,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000327,src:000000,op:arith8,pos:42,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000328,src:000000,op:arith8,pos:41,val:+35,+cov b/src/exchange/afl-tests/id:000328,src:000000,op:arith8,pos:41,val:+35,+cov
index f1effb60a..f1effb60a 100644
--- a/src/mint/afl-tests/id:000328,src:000000,op:arith8,pos:41,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000328,src:000000,op:arith8,pos:41,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000328,src:000000,op:arith8,pos:43,val:-33,+cov b/src/exchange/afl-tests/id:000328,src:000000,op:arith8,pos:43,val:-33,+cov
index 6f2b6fc48..6f2b6fc48 100644
--- a/src/mint/afl-tests/id:000328,src:000000,op:arith8,pos:43,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000328,src:000000,op:arith8,pos:43,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000329,src:000000,op:arith8,pos:42,val:-6,+cov b/src/exchange/afl-tests/id:000329,src:000000,op:arith8,pos:42,val:-6,+cov
index 9a521a0e5..9a521a0e5 100644
--- a/src/mint/afl-tests/id:000329,src:000000,op:arith8,pos:42,val:-6,+cov
+++ b/src/exchange/afl-tests/id:000329,src:000000,op:arith8,pos:42,val:-6,+cov
diff --git a/src/mint/afl-tests/id:000329,src:000000,op:arith8,pos:44,val:+17,+cov b/src/exchange/afl-tests/id:000329,src:000000,op:arith8,pos:44,val:+17,+cov
index aa9ed97ab..aa9ed97ab 100644
--- a/src/mint/afl-tests/id:000329,src:000000,op:arith8,pos:44,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000329,src:000000,op:arith8,pos:44,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000330,src:000000,op:arith8,pos:42,val:+13,+cov b/src/exchange/afl-tests/id:000330,src:000000,op:arith8,pos:42,val:+13,+cov
index 265f9c882..265f9c882 100644
--- a/src/mint/afl-tests/id:000330,src:000000,op:arith8,pos:42,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000330,src:000000,op:arith8,pos:42,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000330,src:000000,op:arith8,pos:45,val:-5,+cov b/src/exchange/afl-tests/id:000330,src:000000,op:arith8,pos:45,val:-5,+cov
index be5fd9601..be5fd9601 100644
--- a/src/mint/afl-tests/id:000330,src:000000,op:arith8,pos:45,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000330,src:000000,op:arith8,pos:45,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000331,src:000000,op:arith8,pos:42,val:+18,+cov b/src/exchange/afl-tests/id:000331,src:000000,op:arith8,pos:42,val:+18,+cov
index ed24295ca..ed24295ca 100644
--- a/src/mint/afl-tests/id:000331,src:000000,op:arith8,pos:42,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000331,src:000000,op:arith8,pos:42,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000331,src:000000,op:arith8,pos:45,val:-11,+cov b/src/exchange/afl-tests/id:000331,src:000000,op:arith8,pos:45,val:-11,+cov
index e104a0ff9..e104a0ff9 100644
--- a/src/mint/afl-tests/id:000331,src:000000,op:arith8,pos:45,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000331,src:000000,op:arith8,pos:45,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000332,src:000000,op:arith8,pos:43,val:-23,+cov b/src/exchange/afl-tests/id:000332,src:000000,op:arith8,pos:43,val:-23,+cov
index a76187ff3..a76187ff3 100644
--- a/src/mint/afl-tests/id:000332,src:000000,op:arith8,pos:43,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000332,src:000000,op:arith8,pos:43,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000332,src:000000,op:arith8,pos:45,val:+19,+cov b/src/exchange/afl-tests/id:000332,src:000000,op:arith8,pos:45,val:+19,+cov
index 890ecd562..890ecd562 100644
--- a/src/mint/afl-tests/id:000332,src:000000,op:arith8,pos:45,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000332,src:000000,op:arith8,pos:45,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000333,src:000000,op:arith8,pos:43,val:+33,+cov b/src/exchange/afl-tests/id:000333,src:000000,op:arith8,pos:43,val:+33,+cov
index a93066c16..a93066c16 100644
--- a/src/mint/afl-tests/id:000333,src:000000,op:arith8,pos:43,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000333,src:000000,op:arith8,pos:43,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000333,src:000000,op:arith8,pos:51,val:-12,+cov b/src/exchange/afl-tests/id:000333,src:000000,op:arith8,pos:51,val:-12,+cov
index 48b4263e2..48b4263e2 100644
--- a/src/mint/afl-tests/id:000333,src:000000,op:arith8,pos:51,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000333,src:000000,op:arith8,pos:51,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000334,src:000000,op:arith8,pos:44,val:+11,+cov b/src/exchange/afl-tests/id:000334,src:000000,op:arith8,pos:44,val:+11,+cov
index 22c401b0e..22c401b0e 100644
--- a/src/mint/afl-tests/id:000334,src:000000,op:arith8,pos:44,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000334,src:000000,op:arith8,pos:44,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000334,src:000000,op:arith8,pos:51,val:+14,+cov b/src/exchange/afl-tests/id:000334,src:000000,op:arith8,pos:51,val:+14,+cov
index 197abf747..197abf747 100644
--- a/src/mint/afl-tests/id:000334,src:000000,op:arith8,pos:51,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000334,src:000000,op:arith8,pos:51,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000335,src:000000,op:arith8,pos:45,val:-24,+cov b/src/exchange/afl-tests/id:000335,src:000000,op:arith8,pos:45,val:-24,+cov
index 75f8c8168..75f8c8168 100644
--- a/src/mint/afl-tests/id:000335,src:000000,op:arith8,pos:45,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000335,src:000000,op:arith8,pos:45,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000335,src:000000,op:arith8,pos:51,val:-22,+cov b/src/exchange/afl-tests/id:000335,src:000000,op:arith8,pos:51,val:-22,+cov
index c6c8c7e77..c6c8c7e77 100644
--- a/src/mint/afl-tests/id:000335,src:000000,op:arith8,pos:51,val:-22,+cov
+++ b/src/exchange/afl-tests/id:000335,src:000000,op:arith8,pos:51,val:-22,+cov
diff --git a/src/mint/afl-tests/id:000336,src:000000,op:arith8,pos:45,val:-27,+cov b/src/exchange/afl-tests/id:000336,src:000000,op:arith8,pos:45,val:-27,+cov
index a1d9ecf23..a1d9ecf23 100644
--- a/src/mint/afl-tests/id:000336,src:000000,op:arith8,pos:45,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000336,src:000000,op:arith8,pos:45,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000336,src:000000,op:arith8,pos:51,val:-23,+cov b/src/exchange/afl-tests/id:000336,src:000000,op:arith8,pos:51,val:-23,+cov
index 9af2a6024..9af2a6024 100644
--- a/src/mint/afl-tests/id:000336,src:000000,op:arith8,pos:51,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000336,src:000000,op:arith8,pos:51,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000337,src:000000,op:arith8,pos:46,val:+7,+cov b/src/exchange/afl-tests/id:000337,src:000000,op:arith8,pos:46,val:+7,+cov
index 4385a7c57..4385a7c57 100644
--- a/src/mint/afl-tests/id:000337,src:000000,op:arith8,pos:46,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000337,src:000000,op:arith8,pos:46,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000337,src:000000,op:arith8,pos:52,val:-14,+cov b/src/exchange/afl-tests/id:000337,src:000000,op:arith8,pos:52,val:-14,+cov
index d25613950..d25613950 100644
--- a/src/mint/afl-tests/id:000337,src:000000,op:arith8,pos:52,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000337,src:000000,op:arith8,pos:52,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000338,src:000000,op:arith8,pos:46,val:-21,+cov b/src/exchange/afl-tests/id:000338,src:000000,op:arith8,pos:46,val:-21,+cov
index 95e84f3f7..95e84f3f7 100644
--- a/src/mint/afl-tests/id:000338,src:000000,op:arith8,pos:46,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000338,src:000000,op:arith8,pos:46,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000338,src:000000,op:arith8,pos:52,val:+28,+cov b/src/exchange/afl-tests/id:000338,src:000000,op:arith8,pos:52,val:+28,+cov
index 7b3de684c..7b3de684c 100644
--- a/src/mint/afl-tests/id:000338,src:000000,op:arith8,pos:52,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000338,src:000000,op:arith8,pos:52,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000339,src:000000,op:arith8,pos:46,val:+31,+cov b/src/exchange/afl-tests/id:000339,src:000000,op:arith8,pos:46,val:+31,+cov
index 478dfb61b..478dfb61b 100644
--- a/src/mint/afl-tests/id:000339,src:000000,op:arith8,pos:46,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000339,src:000000,op:arith8,pos:46,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000339,src:000000,op:arith8,pos:53,val:+9,+cov b/src/exchange/afl-tests/id:000339,src:000000,op:arith8,pos:53,val:+9,+cov
index ee250cea6..ee250cea6 100644
--- a/src/mint/afl-tests/id:000339,src:000000,op:arith8,pos:53,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000339,src:000000,op:arith8,pos:53,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000340,src:000000,op:arith8,pos:49,val:+16,+cov b/src/exchange/afl-tests/id:000340,src:000000,op:arith8,pos:49,val:+16,+cov
index b6021dc00..b6021dc00 100644
--- a/src/mint/afl-tests/id:000340,src:000000,op:arith8,pos:49,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000340,src:000000,op:arith8,pos:49,val:+16,+cov
diff --git a/src/mint/afl-tests/id:000340,src:000000,op:arith8,pos:53,val:-11,+cov b/src/exchange/afl-tests/id:000340,src:000000,op:arith8,pos:53,val:-11,+cov
index 08ce9745c..08ce9745c 100644
--- a/src/mint/afl-tests/id:000340,src:000000,op:arith8,pos:53,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000340,src:000000,op:arith8,pos:53,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000341,src:000000,op:arith8,pos:49,val:-26,+cov b/src/exchange/afl-tests/id:000341,src:000000,op:arith8,pos:49,val:-26,+cov
index 5c62397e1..5c62397e1 100644
--- a/src/mint/afl-tests/id:000341,src:000000,op:arith8,pos:49,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000341,src:000000,op:arith8,pos:49,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000341,src:000000,op:arith8,pos:53,val:-17,+cov b/src/exchange/afl-tests/id:000341,src:000000,op:arith8,pos:53,val:-17,+cov
index b8cb610c3..b8cb610c3 100644
--- a/src/mint/afl-tests/id:000341,src:000000,op:arith8,pos:53,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000341,src:000000,op:arith8,pos:53,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000342,src:000000,op:arith8,pos:49,val:+34,+cov b/src/exchange/afl-tests/id:000342,src:000000,op:arith8,pos:49,val:+34,+cov
index 01649ac14..01649ac14 100644
--- a/src/mint/afl-tests/id:000342,src:000000,op:arith8,pos:49,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000342,src:000000,op:arith8,pos:49,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000342,src:000000,op:arith8,pos:53,val:-18,+cov b/src/exchange/afl-tests/id:000342,src:000000,op:arith8,pos:53,val:-18,+cov
index 476d139fa..476d139fa 100644
--- a/src/mint/afl-tests/id:000342,src:000000,op:arith8,pos:53,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000342,src:000000,op:arith8,pos:53,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000343,src:000000,op:arith8,pos:50,val:-7,+cov b/src/exchange/afl-tests/id:000343,src:000000,op:arith8,pos:50,val:-7,+cov
index 6b387c042..6b387c042 100644
--- a/src/mint/afl-tests/id:000343,src:000000,op:arith8,pos:50,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000343,src:000000,op:arith8,pos:50,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000343,src:000000,op:arith8,pos:53,val:-35,+cov b/src/exchange/afl-tests/id:000343,src:000000,op:arith8,pos:53,val:-35,+cov
index 55575e0de..55575e0de 100644
--- a/src/mint/afl-tests/id:000343,src:000000,op:arith8,pos:53,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000343,src:000000,op:arith8,pos:53,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000344,src:000000,op:arith8,pos:50,val:+22,+cov b/src/exchange/afl-tests/id:000344,src:000000,op:arith8,pos:50,val:+22,+cov
index 4f30622ad..4f30622ad 100644
--- a/src/mint/afl-tests/id:000344,src:000000,op:arith8,pos:50,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000344,src:000000,op:arith8,pos:50,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000344,src:000000,op:arith8,pos:54,val:-15,+cov b/src/exchange/afl-tests/id:000344,src:000000,op:arith8,pos:54,val:-15,+cov
index 384c20aea..384c20aea 100644
--- a/src/mint/afl-tests/id:000344,src:000000,op:arith8,pos:54,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000344,src:000000,op:arith8,pos:54,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000345,src:000000,op:arith8,pos:50,val:+24,+cov b/src/exchange/afl-tests/id:000345,src:000000,op:arith8,pos:50,val:+24,+cov
index dde5226a5..dde5226a5 100644
--- a/src/mint/afl-tests/id:000345,src:000000,op:arith8,pos:50,val:+24,+cov
+++ b/src/exchange/afl-tests/id:000345,src:000000,op:arith8,pos:50,val:+24,+cov
diff --git a/src/mint/afl-tests/id:000345,src:000000,op:arith8,pos:54,val:-22,+cov b/src/exchange/afl-tests/id:000345,src:000000,op:arith8,pos:54,val:-22,+cov
index 8dc2cc2b6..8dc2cc2b6 100644
--- a/src/mint/afl-tests/id:000345,src:000000,op:arith8,pos:54,val:-22,+cov
+++ b/src/exchange/afl-tests/id:000345,src:000000,op:arith8,pos:54,val:-22,+cov
diff --git a/src/mint/afl-tests/id:000346,src:000000,op:arith8,pos:50,val:-31,+cov b/src/exchange/afl-tests/id:000346,src:000000,op:arith8,pos:50,val:-31,+cov
index b427c527c..b427c527c 100644
--- a/src/mint/afl-tests/id:000346,src:000000,op:arith8,pos:50,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000346,src:000000,op:arith8,pos:50,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000346,src:000000,op:arith8,pos:55,val:-7 b/src/exchange/afl-tests/id:000346,src:000000,op:arith8,pos:55,val:-7
index 83853ac8b..83853ac8b 100644
--- a/src/mint/afl-tests/id:000346,src:000000,op:arith8,pos:55,val:-7
+++ b/src/exchange/afl-tests/id:000346,src:000000,op:arith8,pos:55,val:-7
diff --git a/src/mint/afl-tests/id:000347,src:000000,op:arith8,pos:51,val:-1,+cov b/src/exchange/afl-tests/id:000347,src:000000,op:arith8,pos:51,val:-1,+cov
index e77d55e74..e77d55e74 100644
--- a/src/mint/afl-tests/id:000347,src:000000,op:arith8,pos:51,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000347,src:000000,op:arith8,pos:51,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000347,src:000000,op:arith8,pos:55,val:-33,+cov b/src/exchange/afl-tests/id:000347,src:000000,op:arith8,pos:55,val:-33,+cov
index 79bb709e0..79bb709e0 100644
--- a/src/mint/afl-tests/id:000347,src:000000,op:arith8,pos:55,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000347,src:000000,op:arith8,pos:55,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000348,src:000000,op:arith8,pos:51,val:+18,+cov b/src/exchange/afl-tests/id:000348,src:000000,op:arith8,pos:51,val:+18,+cov
index 756e21abc..756e21abc 100644
--- a/src/mint/afl-tests/id:000348,src:000000,op:arith8,pos:51,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000348,src:000000,op:arith8,pos:51,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000348,src:000000,op:arith8,pos:55,val:-35,+cov b/src/exchange/afl-tests/id:000348,src:000000,op:arith8,pos:55,val:-35,+cov
index cc275f3a4..cc275f3a4 100644
--- a/src/mint/afl-tests/id:000348,src:000000,op:arith8,pos:55,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000348,src:000000,op:arith8,pos:55,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000349,src:000000,op:arith8,pos:52,val:-6,+cov b/src/exchange/afl-tests/id:000349,src:000000,op:arith8,pos:52,val:-6,+cov
index 51043edca..51043edca 100644
--- a/src/mint/afl-tests/id:000349,src:000000,op:arith8,pos:52,val:-6,+cov
+++ b/src/exchange/afl-tests/id:000349,src:000000,op:arith8,pos:52,val:-6,+cov
diff --git a/src/mint/afl-tests/id:000349,src:000000,op:arith8,pos:57,val:-14,+cov b/src/exchange/afl-tests/id:000349,src:000000,op:arith8,pos:57,val:-14,+cov
index 287ad5180..287ad5180 100644
--- a/src/mint/afl-tests/id:000349,src:000000,op:arith8,pos:57,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000349,src:000000,op:arith8,pos:57,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000350,src:000000,op:arith8,pos:52,val:+22,+cov b/src/exchange/afl-tests/id:000350,src:000000,op:arith8,pos:52,val:+22,+cov
index 58bfbf06f..58bfbf06f 100644
--- a/src/mint/afl-tests/id:000350,src:000000,op:arith8,pos:52,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000350,src:000000,op:arith8,pos:52,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000350,src:000000,op:arith8,pos:57,val:+28,+cov b/src/exchange/afl-tests/id:000350,src:000000,op:arith8,pos:57,val:+28,+cov
index 84c5ada46..84c5ada46 100644
--- a/src/mint/afl-tests/id:000350,src:000000,op:arith8,pos:57,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000350,src:000000,op:arith8,pos:57,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000351,src:000000,op:arith8,pos:52,val:-31,+cov b/src/exchange/afl-tests/id:000351,src:000000,op:arith8,pos:52,val:-31,+cov
index 1218a5644..1218a5644 100644
--- a/src/mint/afl-tests/id:000351,src:000000,op:arith8,pos:52,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000351,src:000000,op:arith8,pos:52,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000351,src:000000,op:arith8,pos:57,val:-29,+cov b/src/exchange/afl-tests/id:000351,src:000000,op:arith8,pos:57,val:-29,+cov
index 4c42e3349..4c42e3349 100644
--- a/src/mint/afl-tests/id:000351,src:000000,op:arith8,pos:57,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000351,src:000000,op:arith8,pos:57,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000352,src:000000,op:arith8,pos:53,val:-18,+cov b/src/exchange/afl-tests/id:000352,src:000000,op:arith8,pos:53,val:-18,+cov
index 476d139fa..476d139fa 100644
--- a/src/mint/afl-tests/id:000352,src:000000,op:arith8,pos:53,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000352,src:000000,op:arith8,pos:53,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000352,src:000000,op:arith8,pos:58,val:-29,+cov b/src/exchange/afl-tests/id:000352,src:000000,op:arith8,pos:58,val:-29,+cov
index ea61327a8..ea61327a8 100644
--- a/src/mint/afl-tests/id:000352,src:000000,op:arith8,pos:58,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000352,src:000000,op:arith8,pos:58,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000353,src:000000,op:arith8,pos:53,val:+27,+cov b/src/exchange/afl-tests/id:000353,src:000000,op:arith8,pos:53,val:+27,+cov
index 600a225c7..600a225c7 100644
--- a/src/mint/afl-tests/id:000353,src:000000,op:arith8,pos:53,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000353,src:000000,op:arith8,pos:53,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000353,src:000000,op:arith8,pos:59,val:+10,+cov b/src/exchange/afl-tests/id:000353,src:000000,op:arith8,pos:59,val:+10,+cov
index 511d2abaf..511d2abaf 100644
--- a/src/mint/afl-tests/id:000353,src:000000,op:arith8,pos:59,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000353,src:000000,op:arith8,pos:59,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000354,src:000000,op:arith8,pos:53,val:-27,+cov b/src/exchange/afl-tests/id:000354,src:000000,op:arith8,pos:53,val:-27,+cov
index 4416ec448..4416ec448 100644
--- a/src/mint/afl-tests/id:000354,src:000000,op:arith8,pos:53,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000354,src:000000,op:arith8,pos:53,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000354,src:000000,op:arith8,pos:59,val:+23,+cov b/src/exchange/afl-tests/id:000354,src:000000,op:arith8,pos:59,val:+23,+cov
index 7d8d86141..7d8d86141 100644
--- a/src/mint/afl-tests/id:000354,src:000000,op:arith8,pos:59,val:+23,+cov
+++ b/src/exchange/afl-tests/id:000354,src:000000,op:arith8,pos:59,val:+23,+cov
diff --git a/src/mint/afl-tests/id:000355,src:000000,op:arith8,pos:53,val:-28,+cov b/src/exchange/afl-tests/id:000355,src:000000,op:arith8,pos:53,val:-28,+cov
index 9242a73f3..9242a73f3 100644
--- a/src/mint/afl-tests/id:000355,src:000000,op:arith8,pos:53,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000355,src:000000,op:arith8,pos:53,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000355,src:000000,op:arith8,pos:62,val:+9,+cov b/src/exchange/afl-tests/id:000355,src:000000,op:arith8,pos:62,val:+9,+cov
index 73cde5c1f..73cde5c1f 100644
--- a/src/mint/afl-tests/id:000355,src:000000,op:arith8,pos:62,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000355,src:000000,op:arith8,pos:62,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000356,src:000000,op:arith8,pos:55,val:-2,+cov b/src/exchange/afl-tests/id:000356,src:000000,op:arith8,pos:55,val:-2,+cov
index 15b64e89f..15b64e89f 100644
--- a/src/mint/afl-tests/id:000356,src:000000,op:arith8,pos:55,val:-2,+cov
+++ b/src/exchange/afl-tests/id:000356,src:000000,op:arith8,pos:55,val:-2,+cov
diff --git a/src/mint/afl-tests/id:000356,src:000000,op:arith8,pos:62,val:-21,+cov b/src/exchange/afl-tests/id:000356,src:000000,op:arith8,pos:62,val:-21,+cov
index 9d31eb13c..9d31eb13c 100644
--- a/src/mint/afl-tests/id:000356,src:000000,op:arith8,pos:62,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000356,src:000000,op:arith8,pos:62,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000357,src:000000,op:arith8,pos:55,val:-7 b/src/exchange/afl-tests/id:000357,src:000000,op:arith8,pos:55,val:-7
index 83853ac8b..83853ac8b 100644
--- a/src/mint/afl-tests/id:000357,src:000000,op:arith8,pos:55,val:-7
+++ b/src/exchange/afl-tests/id:000357,src:000000,op:arith8,pos:55,val:-7
diff --git a/src/mint/afl-tests/id:000357,src:000000,op:arith8,pos:62,val:-23,+cov b/src/exchange/afl-tests/id:000357,src:000000,op:arith8,pos:62,val:-23,+cov
index 8aae00c08..8aae00c08 100644
--- a/src/mint/afl-tests/id:000357,src:000000,op:arith8,pos:62,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000357,src:000000,op:arith8,pos:62,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000358,src:000000,op:arith8,pos:55,val:-33,+cov b/src/exchange/afl-tests/id:000358,src:000000,op:arith8,pos:55,val:-33,+cov
index 79bb709e0..79bb709e0 100644
--- a/src/mint/afl-tests/id:000358,src:000000,op:arith8,pos:55,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000358,src:000000,op:arith8,pos:55,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000358,src:000000,op:arith8,pos:62,val:-35,+cov b/src/exchange/afl-tests/id:000358,src:000000,op:arith8,pos:62,val:-35,+cov
index 4f0f25f14..4f0f25f14 100644
--- a/src/mint/afl-tests/id:000358,src:000000,op:arith8,pos:62,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000358,src:000000,op:arith8,pos:62,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000359,src:000000,op:arith8,pos:56,val:-17,+cov b/src/exchange/afl-tests/id:000359,src:000000,op:arith8,pos:56,val:-17,+cov
index 96cb6e711..96cb6e711 100644
--- a/src/mint/afl-tests/id:000359,src:000000,op:arith8,pos:56,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000359,src:000000,op:arith8,pos:56,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000359,src:000000,op:arith8,pos:63,val:+3,+cov b/src/exchange/afl-tests/id:000359,src:000000,op:arith8,pos:63,val:+3,+cov
index 4c76060a5..4c76060a5 100644
--- a/src/mint/afl-tests/id:000359,src:000000,op:arith8,pos:63,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000359,src:000000,op:arith8,pos:63,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000360,src:000000,op:arith8,pos:56,val:+34,+cov b/src/exchange/afl-tests/id:000360,src:000000,op:arith8,pos:56,val:+34,+cov
index b2c0945dc..b2c0945dc 100644
--- a/src/mint/afl-tests/id:000360,src:000000,op:arith8,pos:56,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000360,src:000000,op:arith8,pos:56,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000360,src:000000,op:arith8,pos:64,val:-5,+cov b/src/exchange/afl-tests/id:000360,src:000000,op:arith8,pos:64,val:-5,+cov
index 36f40fe69..36f40fe69 100644
--- a/src/mint/afl-tests/id:000360,src:000000,op:arith8,pos:64,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000360,src:000000,op:arith8,pos:64,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000361,src:000000,op:arith8,pos:57,val:-23,+cov b/src/exchange/afl-tests/id:000361,src:000000,op:arith8,pos:57,val:-23,+cov
index 733f19152..733f19152 100644
--- a/src/mint/afl-tests/id:000361,src:000000,op:arith8,pos:57,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000361,src:000000,op:arith8,pos:57,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000361,src:000000,op:arith8,pos:64,val:-26,+cov b/src/exchange/afl-tests/id:000361,src:000000,op:arith8,pos:64,val:-26,+cov
index 4013f836c..4013f836c 100644
--- a/src/mint/afl-tests/id:000361,src:000000,op:arith8,pos:64,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000361,src:000000,op:arith8,pos:64,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000362,src:000000,op:arith8,pos:58,val:+34,+cov b/src/exchange/afl-tests/id:000362,src:000000,op:arith8,pos:58,val:+34,+cov
index 003f5f4bc..003f5f4bc 100644
--- a/src/mint/afl-tests/id:000362,src:000000,op:arith8,pos:58,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000362,src:000000,op:arith8,pos:58,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000362,src:000000,op:arith8,pos:65,val:-10,+cov b/src/exchange/afl-tests/id:000362,src:000000,op:arith8,pos:65,val:-10,+cov
index db763f9a8..db763f9a8 100644
--- a/src/mint/afl-tests/id:000362,src:000000,op:arith8,pos:65,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000362,src:000000,op:arith8,pos:65,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000363,src:000000,op:arith8,pos:60,val:-14,+cov b/src/exchange/afl-tests/id:000363,src:000000,op:arith8,pos:60,val:-14,+cov
index 1c86d6b65..1c86d6b65 100644
--- a/src/mint/afl-tests/id:000363,src:000000,op:arith8,pos:60,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000363,src:000000,op:arith8,pos:60,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000363,src:000000,op:arith8,pos:65,val:-27,+cov b/src/exchange/afl-tests/id:000363,src:000000,op:arith8,pos:65,val:-27,+cov
index 58a2799bd..58a2799bd 100644
--- a/src/mint/afl-tests/id:000363,src:000000,op:arith8,pos:65,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000363,src:000000,op:arith8,pos:65,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000364,src:000000,op:arith8,pos:60,val:-15,+cov b/src/exchange/afl-tests/id:000364,src:000000,op:arith8,pos:60,val:-15,+cov
index 8fb47065b..8fb47065b 100644
--- a/src/mint/afl-tests/id:000364,src:000000,op:arith8,pos:60,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000364,src:000000,op:arith8,pos:60,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000364,src:000000,op:arith8,pos:65,val:-30,+cov b/src/exchange/afl-tests/id:000364,src:000000,op:arith8,pos:65,val:-30,+cov
index 14a29e995..14a29e995 100644
--- a/src/mint/afl-tests/id:000364,src:000000,op:arith8,pos:65,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000364,src:000000,op:arith8,pos:65,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000365,src:000000,op:arith8,pos:60,val:-27,+cov b/src/exchange/afl-tests/id:000365,src:000000,op:arith8,pos:60,val:-27,+cov
index 6d8cf1eba..6d8cf1eba 100644
--- a/src/mint/afl-tests/id:000365,src:000000,op:arith8,pos:60,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000365,src:000000,op:arith8,pos:60,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000365,src:000000,op:arith8,pos:66,val:+13,+cov b/src/exchange/afl-tests/id:000365,src:000000,op:arith8,pos:66,val:+13,+cov
index 16cee21dd..16cee21dd 100644
--- a/src/mint/afl-tests/id:000365,src:000000,op:arith8,pos:66,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000365,src:000000,op:arith8,pos:66,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000366,src:000000,op:arith8,pos:62,val:+13,+cov b/src/exchange/afl-tests/id:000366,src:000000,op:arith8,pos:62,val:+13,+cov
index b3b6f749c..b3b6f749c 100644
--- a/src/mint/afl-tests/id:000366,src:000000,op:arith8,pos:62,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000366,src:000000,op:arith8,pos:62,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000366,src:000000,op:arith8,pos:67,val:-9 b/src/exchange/afl-tests/id:000366,src:000000,op:arith8,pos:67,val:-9
index 342b2c758..342b2c758 100644
--- a/src/mint/afl-tests/id:000366,src:000000,op:arith8,pos:67,val:-9
+++ b/src/exchange/afl-tests/id:000366,src:000000,op:arith8,pos:67,val:-9
diff --git a/src/mint/afl-tests/id:000367,src:000000,op:arith8,pos:62,val:-21,+cov b/src/exchange/afl-tests/id:000367,src:000000,op:arith8,pos:62,val:-21,+cov
index 9d31eb13c..9d31eb13c 100644
--- a/src/mint/afl-tests/id:000367,src:000000,op:arith8,pos:62,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000367,src:000000,op:arith8,pos:62,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000367,src:000000,op:arith8,pos:67,val:+15,+cov b/src/exchange/afl-tests/id:000367,src:000000,op:arith8,pos:67,val:+15,+cov
index ac73aaeba..ac73aaeba 100644
--- a/src/mint/afl-tests/id:000367,src:000000,op:arith8,pos:67,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000367,src:000000,op:arith8,pos:67,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000368,src:000000,op:arith8,pos:62,val:-23,+cov b/src/exchange/afl-tests/id:000368,src:000000,op:arith8,pos:62,val:-23,+cov
index 8aae00c08..8aae00c08 100644
--- a/src/mint/afl-tests/id:000368,src:000000,op:arith8,pos:62,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000368,src:000000,op:arith8,pos:62,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000368,src:000000,op:arith8,pos:67,val:-35 b/src/exchange/afl-tests/id:000368,src:000000,op:arith8,pos:67,val:-35
index d212fb451..d212fb451 100644
--- a/src/mint/afl-tests/id:000368,src:000000,op:arith8,pos:67,val:-35
+++ b/src/exchange/afl-tests/id:000368,src:000000,op:arith8,pos:67,val:-35
diff --git a/src/mint/afl-tests/id:000369,src:000000,op:arith8,pos:63,val:+6,+cov b/src/exchange/afl-tests/id:000369,src:000000,op:arith8,pos:63,val:+6,+cov
index 45b407399..45b407399 100644
--- a/src/mint/afl-tests/id:000369,src:000000,op:arith8,pos:63,val:+6,+cov
+++ b/src/exchange/afl-tests/id:000369,src:000000,op:arith8,pos:63,val:+6,+cov
diff --git a/src/mint/afl-tests/id:000369,src:000000,op:arith8,pos:72,val:+30,+cov b/src/exchange/afl-tests/id:000369,src:000000,op:arith8,pos:72,val:+30,+cov
index 1c8dcf9a3..1c8dcf9a3 100644
--- a/src/mint/afl-tests/id:000369,src:000000,op:arith8,pos:72,val:+30,+cov
+++ b/src/exchange/afl-tests/id:000369,src:000000,op:arith8,pos:72,val:+30,+cov
diff --git a/src/mint/afl-tests/id:000370,src:000000,op:arith8,pos:63,val:-18,+cov b/src/exchange/afl-tests/id:000370,src:000000,op:arith8,pos:63,val:-18,+cov
index 3af96a221..3af96a221 100644
--- a/src/mint/afl-tests/id:000370,src:000000,op:arith8,pos:63,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000370,src:000000,op:arith8,pos:63,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000370,src:000000,op:arith8,pos:72,val:-35,+cov b/src/exchange/afl-tests/id:000370,src:000000,op:arith8,pos:72,val:-35,+cov
index 4fbe66ead..4fbe66ead 100644
--- a/src/mint/afl-tests/id:000370,src:000000,op:arith8,pos:72,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000370,src:000000,op:arith8,pos:72,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000371,src:000000,op:arith8,pos:63,val:-28,+cov b/src/exchange/afl-tests/id:000371,src:000000,op:arith8,pos:63,val:-28,+cov
index 24439695b..24439695b 100644
--- a/src/mint/afl-tests/id:000371,src:000000,op:arith8,pos:63,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000371,src:000000,op:arith8,pos:63,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000371,src:000000,op:arith8,pos:74,val:+5,+cov b/src/exchange/afl-tests/id:000371,src:000000,op:arith8,pos:74,val:+5,+cov
index 121077e6d..121077e6d 100644
--- a/src/mint/afl-tests/id:000371,src:000000,op:arith8,pos:74,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000371,src:000000,op:arith8,pos:74,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000372,src:000000,op:arith8,pos:64,val:-5,+cov b/src/exchange/afl-tests/id:000372,src:000000,op:arith8,pos:64,val:-5,+cov
index 36f40fe69..36f40fe69 100644
--- a/src/mint/afl-tests/id:000372,src:000000,op:arith8,pos:64,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000372,src:000000,op:arith8,pos:64,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000372,src:000000,op:arith8,pos:75,val:-23,+cov b/src/exchange/afl-tests/id:000372,src:000000,op:arith8,pos:75,val:-23,+cov
index c9c888cf1..c9c888cf1 100644
--- a/src/mint/afl-tests/id:000372,src:000000,op:arith8,pos:75,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000372,src:000000,op:arith8,pos:75,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000373,src:000000,op:arith8,pos:64,val:-13,+cov b/src/exchange/afl-tests/id:000373,src:000000,op:arith8,pos:64,val:-13,+cov
index c079cc3f2..c079cc3f2 100644
--- a/src/mint/afl-tests/id:000373,src:000000,op:arith8,pos:64,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000373,src:000000,op:arith8,pos:64,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000373,src:000000,op:arith8,pos:75,val:+28,+cov b/src/exchange/afl-tests/id:000373,src:000000,op:arith8,pos:75,val:+28,+cov
index caaa0d4e2..caaa0d4e2 100644
--- a/src/mint/afl-tests/id:000373,src:000000,op:arith8,pos:75,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000373,src:000000,op:arith8,pos:75,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000374,src:000000,op:arith8,pos:64,val:-18,+cov b/src/exchange/afl-tests/id:000374,src:000000,op:arith8,pos:64,val:-18,+cov
index 40fd0b4fc..40fd0b4fc 100644
--- a/src/mint/afl-tests/id:000374,src:000000,op:arith8,pos:64,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000374,src:000000,op:arith8,pos:64,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000374,src:000000,op:arith8,pos:76,val:-5,+cov b/src/exchange/afl-tests/id:000374,src:000000,op:arith8,pos:76,val:-5,+cov
index 574206184..574206184 100644
--- a/src/mint/afl-tests/id:000374,src:000000,op:arith8,pos:76,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000374,src:000000,op:arith8,pos:76,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000375,src:000000,op:arith8,pos:64,val:-35,+cov b/src/exchange/afl-tests/id:000375,src:000000,op:arith8,pos:64,val:-35,+cov
index d1b6f7973..d1b6f7973 100644
--- a/src/mint/afl-tests/id:000375,src:000000,op:arith8,pos:64,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000375,src:000000,op:arith8,pos:64,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000375,src:000000,op:arith8,pos:76,val:-20,+cov b/src/exchange/afl-tests/id:000375,src:000000,op:arith8,pos:76,val:-20,+cov
index 7869112f2..7869112f2 100644
--- a/src/mint/afl-tests/id:000375,src:000000,op:arith8,pos:76,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000375,src:000000,op:arith8,pos:76,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000376,src:000000,op:arith8,pos:65,val:-27,+cov b/src/exchange/afl-tests/id:000376,src:000000,op:arith8,pos:65,val:-27,+cov
index 58a2799bd..58a2799bd 100644
--- a/src/mint/afl-tests/id:000376,src:000000,op:arith8,pos:65,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000376,src:000000,op:arith8,pos:65,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000376,src:000000,op:arith8,pos:77,val:-5,+cov b/src/exchange/afl-tests/id:000376,src:000000,op:arith8,pos:77,val:-5,+cov
index 280458e91..280458e91 100644
--- a/src/mint/afl-tests/id:000376,src:000000,op:arith8,pos:77,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000376,src:000000,op:arith8,pos:77,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000377,src:000000,op:arith8,pos:65,val:+29,+cov b/src/exchange/afl-tests/id:000377,src:000000,op:arith8,pos:65,val:+29,+cov
index 9ac6164de..9ac6164de 100644
--- a/src/mint/afl-tests/id:000377,src:000000,op:arith8,pos:65,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000377,src:000000,op:arith8,pos:65,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000377,src:000000,op:arith8,pos:77,val:+25,+cov b/src/exchange/afl-tests/id:000377,src:000000,op:arith8,pos:77,val:+25,+cov
index d10217b1a..d10217b1a 100644
--- a/src/mint/afl-tests/id:000377,src:000000,op:arith8,pos:77,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000377,src:000000,op:arith8,pos:77,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000378,src:000000,op:arith8,pos:66,val:-20,+cov b/src/exchange/afl-tests/id:000378,src:000000,op:arith8,pos:66,val:-20,+cov
index e661db8f9..e661db8f9 100644
--- a/src/mint/afl-tests/id:000378,src:000000,op:arith8,pos:66,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000378,src:000000,op:arith8,pos:66,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000378,src:000000,op:arith8,pos:80,val:+20,+cov b/src/exchange/afl-tests/id:000378,src:000000,op:arith8,pos:80,val:+20,+cov
index e4d53d47d..e4d53d47d 100644
--- a/src/mint/afl-tests/id:000378,src:000000,op:arith8,pos:80,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000378,src:000000,op:arith8,pos:80,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000379,src:000000,op:arith8,pos:66,val:+28,+cov b/src/exchange/afl-tests/id:000379,src:000000,op:arith8,pos:66,val:+28,+cov
index 5705e3539..5705e3539 100644
--- a/src/mint/afl-tests/id:000379,src:000000,op:arith8,pos:66,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000379,src:000000,op:arith8,pos:66,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000379,src:000000,op:arith8,pos:81,val:+20,+cov b/src/exchange/afl-tests/id:000379,src:000000,op:arith8,pos:81,val:+20,+cov
index 4d38460f0..4d38460f0 100644
--- a/src/mint/afl-tests/id:000379,src:000000,op:arith8,pos:81,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000379,src:000000,op:arith8,pos:81,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000380,src:000000,op:arith8,pos:66,val:-31,+cov b/src/exchange/afl-tests/id:000380,src:000000,op:arith8,pos:66,val:-31,+cov
index eb15fcf58..eb15fcf58 100644
--- a/src/mint/afl-tests/id:000380,src:000000,op:arith8,pos:66,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000380,src:000000,op:arith8,pos:66,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000380,src:000000,op:arith8,pos:82,val:-5,+cov b/src/exchange/afl-tests/id:000380,src:000000,op:arith8,pos:82,val:-5,+cov
index bc3c6f6f8..bc3c6f6f8 100644
--- a/src/mint/afl-tests/id:000380,src:000000,op:arith8,pos:82,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000380,src:000000,op:arith8,pos:82,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000381,src:000000,op:arith8,pos:67,val:-9 b/src/exchange/afl-tests/id:000381,src:000000,op:arith8,pos:67,val:-9
index 342b2c758..342b2c758 100644
--- a/src/mint/afl-tests/id:000381,src:000000,op:arith8,pos:67,val:-9
+++ b/src/exchange/afl-tests/id:000381,src:000000,op:arith8,pos:67,val:-9
diff --git a/src/mint/afl-tests/id:000381,src:000000,op:arith8,pos:83,val:-18,+cov b/src/exchange/afl-tests/id:000381,src:000000,op:arith8,pos:83,val:-18,+cov
index a51a07c12..a51a07c12 100644
--- a/src/mint/afl-tests/id:000381,src:000000,op:arith8,pos:83,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000381,src:000000,op:arith8,pos:83,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000382,src:000000,op:arith8,pos:67,val:+10,+cov b/src/exchange/afl-tests/id:000382,src:000000,op:arith8,pos:67,val:+10,+cov
index 5fb3a2c6e..5fb3a2c6e 100644
--- a/src/mint/afl-tests/id:000382,src:000000,op:arith8,pos:67,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000382,src:000000,op:arith8,pos:67,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000382,src:000000,op:arith8,pos:84,val:+10,+cov b/src/exchange/afl-tests/id:000382,src:000000,op:arith8,pos:84,val:+10,+cov
index 78f2e3e14..78f2e3e14 100644
--- a/src/mint/afl-tests/id:000382,src:000000,op:arith8,pos:84,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000382,src:000000,op:arith8,pos:84,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000383,src:000000,op:arith8,pos:67,val:-15,+cov b/src/exchange/afl-tests/id:000383,src:000000,op:arith8,pos:67,val:-15,+cov
index e5c3f5e39..e5c3f5e39 100644
--- a/src/mint/afl-tests/id:000383,src:000000,op:arith8,pos:67,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000383,src:000000,op:arith8,pos:67,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000383,src:000000,op:arith8,pos:84,val:-30,+cov b/src/exchange/afl-tests/id:000383,src:000000,op:arith8,pos:84,val:-30,+cov
index db1d90cc1..db1d90cc1 100644
--- a/src/mint/afl-tests/id:000383,src:000000,op:arith8,pos:84,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000383,src:000000,op:arith8,pos:84,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000384,src:000000,op:arith8,pos:67,val:-35 b/src/exchange/afl-tests/id:000384,src:000000,op:arith8,pos:67,val:-35
index d212fb451..d212fb451 100644
--- a/src/mint/afl-tests/id:000384,src:000000,op:arith8,pos:67,val:-35
+++ b/src/exchange/afl-tests/id:000384,src:000000,op:arith8,pos:67,val:-35
diff --git a/src/mint/afl-tests/id:000384,src:000000,op:arith8,pos:84,val:+34,+cov b/src/exchange/afl-tests/id:000384,src:000000,op:arith8,pos:84,val:+34,+cov
index 1d7e43e71..1d7e43e71 100644
--- a/src/mint/afl-tests/id:000384,src:000000,op:arith8,pos:84,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000384,src:000000,op:arith8,pos:84,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000385,src:000000,op:arith8,pos:68,val:+32,+cov b/src/exchange/afl-tests/id:000385,src:000000,op:arith8,pos:68,val:+32,+cov
index a931c55d4..a931c55d4 100644
--- a/src/mint/afl-tests/id:000385,src:000000,op:arith8,pos:68,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000385,src:000000,op:arith8,pos:68,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000385,src:000000,op:arith8,pos:86,val:-9,+cov b/src/exchange/afl-tests/id:000385,src:000000,op:arith8,pos:86,val:-9,+cov
index bc5b8fe4d..bc5b8fe4d 100644
--- a/src/mint/afl-tests/id:000385,src:000000,op:arith8,pos:86,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000385,src:000000,op:arith8,pos:86,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000386,src:000000,op:arith8,pos:69,val:+14,+cov b/src/exchange/afl-tests/id:000386,src:000000,op:arith8,pos:69,val:+14,+cov
index 55a2fc126..55a2fc126 100644
--- a/src/mint/afl-tests/id:000386,src:000000,op:arith8,pos:69,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000386,src:000000,op:arith8,pos:69,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000386,src:000000,op:arith8,pos:86,val:-19,+cov b/src/exchange/afl-tests/id:000386,src:000000,op:arith8,pos:86,val:-19,+cov
index 96292d482..96292d482 100644
--- a/src/mint/afl-tests/id:000386,src:000000,op:arith8,pos:86,val:-19,+cov
+++ b/src/exchange/afl-tests/id:000386,src:000000,op:arith8,pos:86,val:-19,+cov
diff --git a/src/mint/afl-tests/id:000387,src:000000,op:arith8,pos:70,val:-21,+cov b/src/exchange/afl-tests/id:000387,src:000000,op:arith8,pos:70,val:-21,+cov
index 7632c9a41..7632c9a41 100644
--- a/src/mint/afl-tests/id:000387,src:000000,op:arith8,pos:70,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000387,src:000000,op:arith8,pos:70,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000387,src:000000,op:arith8,pos:87,val:+10,+cov b/src/exchange/afl-tests/id:000387,src:000000,op:arith8,pos:87,val:+10,+cov
index b421ad8b3..b421ad8b3 100644
--- a/src/mint/afl-tests/id:000387,src:000000,op:arith8,pos:87,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000387,src:000000,op:arith8,pos:87,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000388,src:000000,op:arith8,pos:71,val:+3 b/src/exchange/afl-tests/id:000388,src:000000,op:arith8,pos:71,val:+3
index 5d81f8098..5d81f8098 100644
--- a/src/mint/afl-tests/id:000388,src:000000,op:arith8,pos:71,val:+3
+++ b/src/exchange/afl-tests/id:000388,src:000000,op:arith8,pos:71,val:+3
diff --git a/src/mint/afl-tests/id:000388,src:000000,op:arith8,pos:87,val:+15,+cov b/src/exchange/afl-tests/id:000388,src:000000,op:arith8,pos:87,val:+15,+cov
index 2ada1fd95..2ada1fd95 100644
--- a/src/mint/afl-tests/id:000388,src:000000,op:arith8,pos:87,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000388,src:000000,op:arith8,pos:87,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000389,src:000000,op:arith8,pos:72,val:-7,+cov b/src/exchange/afl-tests/id:000389,src:000000,op:arith8,pos:72,val:-7,+cov
index fb8e5878e..fb8e5878e 100644
--- a/src/mint/afl-tests/id:000389,src:000000,op:arith8,pos:72,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000389,src:000000,op:arith8,pos:72,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000389,src:000000,op:arith8,pos:87,val:-26,+cov b/src/exchange/afl-tests/id:000389,src:000000,op:arith8,pos:87,val:-26,+cov
index d0f444dfe..d0f444dfe 100644
--- a/src/mint/afl-tests/id:000389,src:000000,op:arith8,pos:87,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000389,src:000000,op:arith8,pos:87,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000390,src:000000,op:arith8,pos:72,val:+30,+cov b/src/exchange/afl-tests/id:000390,src:000000,op:arith8,pos:72,val:+30,+cov
index 1c8dcf9a3..1c8dcf9a3 100644
--- a/src/mint/afl-tests/id:000390,src:000000,op:arith8,pos:72,val:+30,+cov
+++ b/src/exchange/afl-tests/id:000390,src:000000,op:arith8,pos:72,val:+30,+cov
diff --git a/src/mint/afl-tests/id:000390,src:000000,op:arith8,pos:88,val:+9,+cov b/src/exchange/afl-tests/id:000390,src:000000,op:arith8,pos:88,val:+9,+cov
index 44d664f2f..44d664f2f 100644
--- a/src/mint/afl-tests/id:000390,src:000000,op:arith8,pos:88,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000390,src:000000,op:arith8,pos:88,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000391,src:000000,op:arith8,pos:73,val:-13,+cov b/src/exchange/afl-tests/id:000391,src:000000,op:arith8,pos:73,val:-13,+cov
index 592e62300..592e62300 100644
--- a/src/mint/afl-tests/id:000391,src:000000,op:arith8,pos:73,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000391,src:000000,op:arith8,pos:73,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000391,src:000000,op:arith8,pos:88,val:+25 b/src/exchange/afl-tests/id:000391,src:000000,op:arith8,pos:88,val:+25
index 1e434b113..1e434b113 100644
--- a/src/mint/afl-tests/id:000391,src:000000,op:arith8,pos:88,val:+25
+++ b/src/exchange/afl-tests/id:000391,src:000000,op:arith8,pos:88,val:+25
diff --git a/src/mint/afl-tests/id:000392,src:000000,op:arith8,pos:73,val:-29,+cov b/src/exchange/afl-tests/id:000392,src:000000,op:arith8,pos:73,val:-29,+cov
index ea51aae54..ea51aae54 100644
--- a/src/mint/afl-tests/id:000392,src:000000,op:arith8,pos:73,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000392,src:000000,op:arith8,pos:73,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000392,src:000000,op:arith8,pos:88,val:+26,+cov b/src/exchange/afl-tests/id:000392,src:000000,op:arith8,pos:88,val:+26,+cov
index f6ae2f90b..f6ae2f90b 100644
--- a/src/mint/afl-tests/id:000392,src:000000,op:arith8,pos:88,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000392,src:000000,op:arith8,pos:88,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000393,src:000000,op:arith8,pos:73,val:-35,+cov b/src/exchange/afl-tests/id:000393,src:000000,op:arith8,pos:73,val:-35,+cov
index d0cdc32e8..d0cdc32e8 100644
--- a/src/mint/afl-tests/id:000393,src:000000,op:arith8,pos:73,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000393,src:000000,op:arith8,pos:73,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000393,src:000000,op:arith8,pos:90,val:-33,+cov b/src/exchange/afl-tests/id:000393,src:000000,op:arith8,pos:90,val:-33,+cov
index 770ac9f7f..770ac9f7f 100644
--- a/src/mint/afl-tests/id:000393,src:000000,op:arith8,pos:90,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000393,src:000000,op:arith8,pos:90,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000394,src:000000,op:arith8,pos:75,val:-20,+cov b/src/exchange/afl-tests/id:000394,src:000000,op:arith8,pos:75,val:-20,+cov
index 3547dc013..3547dc013 100644
--- a/src/mint/afl-tests/id:000394,src:000000,op:arith8,pos:75,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000394,src:000000,op:arith8,pos:75,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000394,src:000000,op:arith8,pos:91,val:-14,+cov b/src/exchange/afl-tests/id:000394,src:000000,op:arith8,pos:91,val:-14,+cov
index 906eb83cc..906eb83cc 100644
--- a/src/mint/afl-tests/id:000394,src:000000,op:arith8,pos:91,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000394,src:000000,op:arith8,pos:91,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000395,src:000000,op:arith8,pos:76,val:+21,+cov b/src/exchange/afl-tests/id:000395,src:000000,op:arith8,pos:76,val:+21,+cov
index 39774c970..39774c970 100644
--- a/src/mint/afl-tests/id:000395,src:000000,op:arith8,pos:76,val:+21,+cov
+++ b/src/exchange/afl-tests/id:000395,src:000000,op:arith8,pos:76,val:+21,+cov
diff --git a/src/mint/afl-tests/id:000395,src:000000,op:arith8,pos:91,val:+24 b/src/exchange/afl-tests/id:000395,src:000000,op:arith8,pos:91,val:+24
index bdf7967b5..bdf7967b5 100644
--- a/src/mint/afl-tests/id:000395,src:000000,op:arith8,pos:91,val:+24
+++ b/src/exchange/afl-tests/id:000395,src:000000,op:arith8,pos:91,val:+24
diff --git a/src/mint/afl-tests/id:000396,src:000000,op:arith8,pos:77,val:+24,+cov b/src/exchange/afl-tests/id:000396,src:000000,op:arith8,pos:77,val:+24,+cov
index e6f484add..e6f484add 100644
--- a/src/mint/afl-tests/id:000396,src:000000,op:arith8,pos:77,val:+24,+cov
+++ b/src/exchange/afl-tests/id:000396,src:000000,op:arith8,pos:77,val:+24,+cov
diff --git a/src/mint/afl-tests/id:000396,src:000000,op:arith8,pos:92,val:+11,+cov b/src/exchange/afl-tests/id:000396,src:000000,op:arith8,pos:92,val:+11,+cov
index 86b1ac8a0..86b1ac8a0 100644
--- a/src/mint/afl-tests/id:000396,src:000000,op:arith8,pos:92,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000396,src:000000,op:arith8,pos:92,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000397,src:000000,op:arith8,pos:80,val:-11,+cov b/src/exchange/afl-tests/id:000397,src:000000,op:arith8,pos:80,val:-11,+cov
index edc039186..edc039186 100644
--- a/src/mint/afl-tests/id:000397,src:000000,op:arith8,pos:80,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000397,src:000000,op:arith8,pos:80,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000397,src:000000,op:arith8,pos:92,val:-23,+cov b/src/exchange/afl-tests/id:000397,src:000000,op:arith8,pos:92,val:-23,+cov
index 58e65acc0..58e65acc0 100644
--- a/src/mint/afl-tests/id:000397,src:000000,op:arith8,pos:92,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000397,src:000000,op:arith8,pos:92,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000398,src:000000,op:arith8,pos:80,val:+18,+cov b/src/exchange/afl-tests/id:000398,src:000000,op:arith8,pos:80,val:+18,+cov
index 39a16ed4c..39a16ed4c 100644
--- a/src/mint/afl-tests/id:000398,src:000000,op:arith8,pos:80,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000398,src:000000,op:arith8,pos:80,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000398,src:000000,op:arith8,pos:93,val:+19,+cov b/src/exchange/afl-tests/id:000398,src:000000,op:arith8,pos:93,val:+19,+cov
index 82af6cc6d..82af6cc6d 100644
--- a/src/mint/afl-tests/id:000398,src:000000,op:arith8,pos:93,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000398,src:000000,op:arith8,pos:93,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000399,src:000000,op:arith8,pos:81,val:+22,+cov b/src/exchange/afl-tests/id:000399,src:000000,op:arith8,pos:81,val:+22,+cov
index f2ab9f29e..f2ab9f29e 100644
--- a/src/mint/afl-tests/id:000399,src:000000,op:arith8,pos:81,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000399,src:000000,op:arith8,pos:81,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000399,src:000000,op:arith8,pos:93,val:-25,+cov b/src/exchange/afl-tests/id:000399,src:000000,op:arith8,pos:93,val:-25,+cov
index 0dd4c3aac..0dd4c3aac 100644
--- a/src/mint/afl-tests/id:000399,src:000000,op:arith8,pos:93,val:-25,+cov
+++ b/src/exchange/afl-tests/id:000399,src:000000,op:arith8,pos:93,val:-25,+cov
diff --git a/src/mint/afl-tests/id:000400,src:000000,op:arith8,pos:81,val:-30,+cov b/src/exchange/afl-tests/id:000400,src:000000,op:arith8,pos:81,val:-30,+cov
index 6d1fdc6c9..6d1fdc6c9 100644
--- a/src/mint/afl-tests/id:000400,src:000000,op:arith8,pos:81,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000400,src:000000,op:arith8,pos:81,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000400,src:000000,op:arith8,pos:93,val:+35,+cov b/src/exchange/afl-tests/id:000400,src:000000,op:arith8,pos:93,val:+35,+cov
index e854f6e80..e854f6e80 100644
--- a/src/mint/afl-tests/id:000400,src:000000,op:arith8,pos:93,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000400,src:000000,op:arith8,pos:93,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000401,src:000000,op:arith8,pos:83,val:-1 b/src/exchange/afl-tests/id:000401,src:000000,op:arith8,pos:83,val:-1
index 6d0f8547d..6d0f8547d 100644
--- a/src/mint/afl-tests/id:000401,src:000000,op:arith8,pos:83,val:-1
+++ b/src/exchange/afl-tests/id:000401,src:000000,op:arith8,pos:83,val:-1
diff --git a/src/mint/afl-tests/id:000401,src:000000,op:arith8,pos:96,val:-5,+cov b/src/exchange/afl-tests/id:000401,src:000000,op:arith8,pos:96,val:-5,+cov
index 9ae7f0c3e..9ae7f0c3e 100644
--- a/src/mint/afl-tests/id:000401,src:000000,op:arith8,pos:96,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000401,src:000000,op:arith8,pos:96,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000402,src:000000,op:arith8,pos:83,val:-22,+cov b/src/exchange/afl-tests/id:000402,src:000000,op:arith8,pos:83,val:-22,+cov
index cbfebffe4..cbfebffe4 100644
--- a/src/mint/afl-tests/id:000402,src:000000,op:arith8,pos:83,val:-22,+cov
+++ b/src/exchange/afl-tests/id:000402,src:000000,op:arith8,pos:83,val:-22,+cov
diff --git a/src/mint/afl-tests/id:000402,src:000000,op:arith8,pos:96,val:+32,+cov b/src/exchange/afl-tests/id:000402,src:000000,op:arith8,pos:96,val:+32,+cov
index de122f609..de122f609 100644
--- a/src/mint/afl-tests/id:000402,src:000000,op:arith8,pos:96,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000402,src:000000,op:arith8,pos:96,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000403,src:000000,op:arith8,pos:83,val:+35,+cov b/src/exchange/afl-tests/id:000403,src:000000,op:arith8,pos:83,val:+35,+cov
index 6cbad71ae..6cbad71ae 100644
--- a/src/mint/afl-tests/id:000403,src:000000,op:arith8,pos:83,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000403,src:000000,op:arith8,pos:83,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000403,src:000000,op:arith8,pos:96,val:-34,+cov b/src/exchange/afl-tests/id:000403,src:000000,op:arith8,pos:96,val:-34,+cov
index 682321985..682321985 100644
--- a/src/mint/afl-tests/id:000403,src:000000,op:arith8,pos:96,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000403,src:000000,op:arith8,pos:96,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000404,src:000000,op:arith8,pos:84,val:+7,+cov b/src/exchange/afl-tests/id:000404,src:000000,op:arith8,pos:84,val:+7,+cov
index 9eec2bca0..9eec2bca0 100644
--- a/src/mint/afl-tests/id:000404,src:000000,op:arith8,pos:84,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000404,src:000000,op:arith8,pos:84,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000404,src:000000,op:arith8,pos:98,val:-34,+cov b/src/exchange/afl-tests/id:000404,src:000000,op:arith8,pos:98,val:-34,+cov
index 426033a42..426033a42 100644
--- a/src/mint/afl-tests/id:000404,src:000000,op:arith8,pos:98,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000404,src:000000,op:arith8,pos:98,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000405,src:000000,op:arith8,pos:84,val:+31,+cov b/src/exchange/afl-tests/id:000405,src:000000,op:arith8,pos:84,val:+31,+cov
index 6c4fe17dd..6c4fe17dd 100644
--- a/src/mint/afl-tests/id:000405,src:000000,op:arith8,pos:84,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000405,src:000000,op:arith8,pos:84,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000405,src:000000,op:arith8,pos:98,val:-35 b/src/exchange/afl-tests/id:000405,src:000000,op:arith8,pos:98,val:-35
index 94bdaa4d0..94bdaa4d0 100644
--- a/src/mint/afl-tests/id:000405,src:000000,op:arith8,pos:98,val:-35
+++ b/src/exchange/afl-tests/id:000405,src:000000,op:arith8,pos:98,val:-35
diff --git a/src/mint/afl-tests/id:000406,src:000000,op:arith8,pos:113,val:-19 b/src/exchange/afl-tests/id:000406,src:000000,op:arith8,pos:113,val:-19
index cc3fad352..cc3fad352 100644
--- a/src/mint/afl-tests/id:000406,src:000000,op:arith8,pos:113,val:-19
+++ b/src/exchange/afl-tests/id:000406,src:000000,op:arith8,pos:113,val:-19
diff --git a/src/mint/afl-tests/id:000406,src:000000,op:arith8,pos:86,val:-11,+cov b/src/exchange/afl-tests/id:000406,src:000000,op:arith8,pos:86,val:-11,+cov
index a65305252..a65305252 100644
--- a/src/mint/afl-tests/id:000406,src:000000,op:arith8,pos:86,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000406,src:000000,op:arith8,pos:86,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000407,src:000000,op:arith8,pos:113,val:-22 b/src/exchange/afl-tests/id:000407,src:000000,op:arith8,pos:113,val:-22
index d5822f356..d5822f356 100644
--- a/src/mint/afl-tests/id:000407,src:000000,op:arith8,pos:113,val:-22
+++ b/src/exchange/afl-tests/id:000407,src:000000,op:arith8,pos:113,val:-22
diff --git a/src/mint/afl-tests/id:000407,src:000000,op:arith8,pos:86,val:+22,+cov b/src/exchange/afl-tests/id:000407,src:000000,op:arith8,pos:86,val:+22,+cov
index 0019d1140..0019d1140 100644
--- a/src/mint/afl-tests/id:000407,src:000000,op:arith8,pos:86,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000407,src:000000,op:arith8,pos:86,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000408,src:000000,op:arith8,pos:121,val:-13,+cov b/src/exchange/afl-tests/id:000408,src:000000,op:arith8,pos:121,val:-13,+cov
index 4eb7d6082..4eb7d6082 100644
--- a/src/mint/afl-tests/id:000408,src:000000,op:arith8,pos:121,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000408,src:000000,op:arith8,pos:121,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000408,src:000000,op:arith8,pos:86,val:-24 b/src/exchange/afl-tests/id:000408,src:000000,op:arith8,pos:86,val:-24
index 072983d1d..072983d1d 100644
--- a/src/mint/afl-tests/id:000408,src:000000,op:arith8,pos:86,val:-24
+++ b/src/exchange/afl-tests/id:000408,src:000000,op:arith8,pos:86,val:-24
diff --git a/src/mint/afl-tests/id:000409,src:000000,op:arith8,pos:135,val:+23,+cov b/src/exchange/afl-tests/id:000409,src:000000,op:arith8,pos:135,val:+23,+cov
index 151cc0aa2..151cc0aa2 100644
--- a/src/mint/afl-tests/id:000409,src:000000,op:arith8,pos:135,val:+23,+cov
+++ b/src/exchange/afl-tests/id:000409,src:000000,op:arith8,pos:135,val:+23,+cov
diff --git a/src/mint/afl-tests/id:000409,src:000000,op:arith8,pos:87,val:-2,+cov b/src/exchange/afl-tests/id:000409,src:000000,op:arith8,pos:87,val:-2,+cov
index 03614562b..03614562b 100644
--- a/src/mint/afl-tests/id:000409,src:000000,op:arith8,pos:87,val:-2,+cov
+++ b/src/exchange/afl-tests/id:000409,src:000000,op:arith8,pos:87,val:-2,+cov
diff --git a/src/mint/afl-tests/id:000410,src:000000,op:arith8,pos:136,val:-9,+cov b/src/exchange/afl-tests/id:000410,src:000000,op:arith8,pos:136,val:-9,+cov
index b5629267f..b5629267f 100644
--- a/src/mint/afl-tests/id:000410,src:000000,op:arith8,pos:136,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000410,src:000000,op:arith8,pos:136,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000410,src:000000,op:arith8,pos:87,val:+9,+cov b/src/exchange/afl-tests/id:000410,src:000000,op:arith8,pos:87,val:+9,+cov
index 0d50ae025..0d50ae025 100644
--- a/src/mint/afl-tests/id:000410,src:000000,op:arith8,pos:87,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000410,src:000000,op:arith8,pos:87,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000411,src:000000,op:arith8,pos:136,val:-21,+cov b/src/exchange/afl-tests/id:000411,src:000000,op:arith8,pos:136,val:-21,+cov
index c139840b0..c139840b0 100644
--- a/src/mint/afl-tests/id:000411,src:000000,op:arith8,pos:136,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000411,src:000000,op:arith8,pos:136,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000411,src:000000,op:arith8,pos:87,val:-15,+cov b/src/exchange/afl-tests/id:000411,src:000000,op:arith8,pos:87,val:-15,+cov
index aa4d902e2..aa4d902e2 100644
--- a/src/mint/afl-tests/id:000411,src:000000,op:arith8,pos:87,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000411,src:000000,op:arith8,pos:87,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000412,src:000000,op:arith8,pos:137,val:+8,+cov b/src/exchange/afl-tests/id:000412,src:000000,op:arith8,pos:137,val:+8,+cov
index 165c83f72..165c83f72 100644
--- a/src/mint/afl-tests/id:000412,src:000000,op:arith8,pos:137,val:+8,+cov
+++ b/src/exchange/afl-tests/id:000412,src:000000,op:arith8,pos:137,val:+8,+cov
diff --git a/src/mint/afl-tests/id:000412,src:000000,op:arith8,pos:87,val:-24,+cov b/src/exchange/afl-tests/id:000412,src:000000,op:arith8,pos:87,val:-24,+cov
index 7a4e13ce5..7a4e13ce5 100644
--- a/src/mint/afl-tests/id:000412,src:000000,op:arith8,pos:87,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000412,src:000000,op:arith8,pos:87,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000413,src:000000,op:arith8,pos:137,val:-11 b/src/exchange/afl-tests/id:000413,src:000000,op:arith8,pos:137,val:-11
index 35bf7ebc0..35bf7ebc0 100644
--- a/src/mint/afl-tests/id:000413,src:000000,op:arith8,pos:137,val:-11
+++ b/src/exchange/afl-tests/id:000413,src:000000,op:arith8,pos:137,val:-11
diff --git a/src/mint/afl-tests/id:000413,src:000000,op:arith8,pos:88,val:+30,+cov b/src/exchange/afl-tests/id:000413,src:000000,op:arith8,pos:88,val:+30,+cov
index 3864a91ce..3864a91ce 100644
--- a/src/mint/afl-tests/id:000413,src:000000,op:arith8,pos:88,val:+30,+cov
+++ b/src/exchange/afl-tests/id:000413,src:000000,op:arith8,pos:88,val:+30,+cov
diff --git a/src/mint/afl-tests/id:000414,src:000000,op:arith8,pos:137,val:-19,+cov b/src/exchange/afl-tests/id:000414,src:000000,op:arith8,pos:137,val:-19,+cov
index 43f1f126d..43f1f126d 100644
--- a/src/mint/afl-tests/id:000414,src:000000,op:arith8,pos:137,val:-19,+cov
+++ b/src/exchange/afl-tests/id:000414,src:000000,op:arith8,pos:137,val:-19,+cov
diff --git a/src/mint/afl-tests/id:000414,src:000000,op:arith8,pos:89,val:+29,+cov b/src/exchange/afl-tests/id:000414,src:000000,op:arith8,pos:89,val:+29,+cov
index e9b9b392c..e9b9b392c 100644
--- a/src/mint/afl-tests/id:000414,src:000000,op:arith8,pos:89,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000414,src:000000,op:arith8,pos:89,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000415,src:000000,op:arith8,pos:138,val:+3,+cov b/src/exchange/afl-tests/id:000415,src:000000,op:arith8,pos:138,val:+3,+cov
index c47b34658..c47b34658 100644
--- a/src/mint/afl-tests/id:000415,src:000000,op:arith8,pos:138,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000415,src:000000,op:arith8,pos:138,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000415,src:000000,op:arith8,pos:90,val:-21,+cov b/src/exchange/afl-tests/id:000415,src:000000,op:arith8,pos:90,val:-21,+cov
index cef95dabf..cef95dabf 100644
--- a/src/mint/afl-tests/id:000415,src:000000,op:arith8,pos:90,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000415,src:000000,op:arith8,pos:90,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000416,src:000000,op:arith8,pos:138,val:-12,+cov b/src/exchange/afl-tests/id:000416,src:000000,op:arith8,pos:138,val:-12,+cov
index 88d2411e9..88d2411e9 100644
--- a/src/mint/afl-tests/id:000416,src:000000,op:arith8,pos:138,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000416,src:000000,op:arith8,pos:138,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000416,src:000000,op:arith8,pos:91,val:+28,+cov b/src/exchange/afl-tests/id:000416,src:000000,op:arith8,pos:91,val:+28,+cov
index 20b530e66..20b530e66 100644
--- a/src/mint/afl-tests/id:000416,src:000000,op:arith8,pos:91,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000416,src:000000,op:arith8,pos:91,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000417,src:000000,op:arith8,pos:139,val:-10,+cov b/src/exchange/afl-tests/id:000417,src:000000,op:arith8,pos:139,val:-10,+cov
index cb7f6c812..cb7f6c812 100644
--- a/src/mint/afl-tests/id:000417,src:000000,op:arith8,pos:139,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000417,src:000000,op:arith8,pos:139,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000417,src:000000,op:arith8,pos:91,val:+34,+cov b/src/exchange/afl-tests/id:000417,src:000000,op:arith8,pos:91,val:+34,+cov
index 2714cce39..2714cce39 100644
--- a/src/mint/afl-tests/id:000417,src:000000,op:arith8,pos:91,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000417,src:000000,op:arith8,pos:91,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000418,src:000000,op:arith8,pos:139,val:-26,+cov b/src/exchange/afl-tests/id:000418,src:000000,op:arith8,pos:139,val:-26,+cov
index 8500eb30f..8500eb30f 100644
--- a/src/mint/afl-tests/id:000418,src:000000,op:arith8,pos:139,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000418,src:000000,op:arith8,pos:139,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000418,src:000000,op:arith8,pos:94,val:-23,+cov b/src/exchange/afl-tests/id:000418,src:000000,op:arith8,pos:94,val:-23,+cov
index e77f3268f..e77f3268f 100644
--- a/src/mint/afl-tests/id:000418,src:000000,op:arith8,pos:94,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000418,src:000000,op:arith8,pos:94,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000419,src:000000,op:arith8,pos:143,val:+21,+cov b/src/exchange/afl-tests/id:000419,src:000000,op:arith8,pos:143,val:+21,+cov
index 627b50a98..627b50a98 100644
--- a/src/mint/afl-tests/id:000419,src:000000,op:arith8,pos:143,val:+21,+cov
+++ b/src/exchange/afl-tests/id:000419,src:000000,op:arith8,pos:143,val:+21,+cov
diff --git a/src/mint/afl-tests/id:000419,src:000000,op:arith8,pos:95,val:+3,+cov b/src/exchange/afl-tests/id:000419,src:000000,op:arith8,pos:95,val:+3,+cov
index 718934f56..718934f56 100644
--- a/src/mint/afl-tests/id:000419,src:000000,op:arith8,pos:95,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000419,src:000000,op:arith8,pos:95,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000420,src:000000,op:arith8,pos:145,val:+15,+cov b/src/exchange/afl-tests/id:000420,src:000000,op:arith8,pos:145,val:+15,+cov
index 8fcfc0cd5..8fcfc0cd5 100644
--- a/src/mint/afl-tests/id:000420,src:000000,op:arith8,pos:145,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000420,src:000000,op:arith8,pos:145,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000420,src:000000,op:arith8,pos:95,val:-23,+cov b/src/exchange/afl-tests/id:000420,src:000000,op:arith8,pos:95,val:-23,+cov
index f7ca0f47c..f7ca0f47c 100644
--- a/src/mint/afl-tests/id:000420,src:000000,op:arith8,pos:95,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000420,src:000000,op:arith8,pos:95,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000421,src:000000,op:arith8,pos:146,val:-14,+cov b/src/exchange/afl-tests/id:000421,src:000000,op:arith8,pos:146,val:-14,+cov
index b84436fb6..b84436fb6 100644
--- a/src/mint/afl-tests/id:000421,src:000000,op:arith8,pos:146,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000421,src:000000,op:arith8,pos:146,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000421,src:000000,op:arith8,pos:95,val:+31,+cov b/src/exchange/afl-tests/id:000421,src:000000,op:arith8,pos:95,val:+31,+cov
index e1f56f79c..e1f56f79c 100644
--- a/src/mint/afl-tests/id:000421,src:000000,op:arith8,pos:95,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000421,src:000000,op:arith8,pos:95,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000422,src:000000,op:arith8,pos:148,val:+28,+cov b/src/exchange/afl-tests/id:000422,src:000000,op:arith8,pos:148,val:+28,+cov
index 9ca2a6194..9ca2a6194 100644
--- a/src/mint/afl-tests/id:000422,src:000000,op:arith8,pos:148,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000422,src:000000,op:arith8,pos:148,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000422,src:000000,op:arith8,pos:98,val:-35 b/src/exchange/afl-tests/id:000422,src:000000,op:arith8,pos:98,val:-35
index 94bdaa4d0..94bdaa4d0 100644
--- a/src/mint/afl-tests/id:000422,src:000000,op:arith8,pos:98,val:-35
+++ b/src/exchange/afl-tests/id:000422,src:000000,op:arith8,pos:98,val:-35
diff --git a/src/mint/afl-tests/id:000423,src:000000,op:arith8,pos:100,val:-33,+cov b/src/exchange/afl-tests/id:000423,src:000000,op:arith8,pos:100,val:-33,+cov
index db7378d99..db7378d99 100644
--- a/src/mint/afl-tests/id:000423,src:000000,op:arith8,pos:100,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000423,src:000000,op:arith8,pos:100,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000423,src:000000,op:arith8,pos:151,val:-35,+cov b/src/exchange/afl-tests/id:000423,src:000000,op:arith8,pos:151,val:-35,+cov
index 6306c04cb..6306c04cb 100644
--- a/src/mint/afl-tests/id:000423,src:000000,op:arith8,pos:151,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000423,src:000000,op:arith8,pos:151,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000424,src:000000,op:arith8,pos:113,val:-19 b/src/exchange/afl-tests/id:000424,src:000000,op:arith8,pos:113,val:-19
index cc3fad352..cc3fad352 100644
--- a/src/mint/afl-tests/id:000424,src:000000,op:arith8,pos:113,val:-19
+++ b/src/exchange/afl-tests/id:000424,src:000000,op:arith8,pos:113,val:-19
diff --git a/src/mint/afl-tests/id:000424,src:000000,op:arith8,pos:152,val:-12,+cov b/src/exchange/afl-tests/id:000424,src:000000,op:arith8,pos:152,val:-12,+cov
index 67774fb72..67774fb72 100644
--- a/src/mint/afl-tests/id:000424,src:000000,op:arith8,pos:152,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000424,src:000000,op:arith8,pos:152,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000425,src:000000,op:arith8,pos:113,val:-22 b/src/exchange/afl-tests/id:000425,src:000000,op:arith8,pos:113,val:-22
index d5822f356..d5822f356 100644
--- a/src/mint/afl-tests/id:000425,src:000000,op:arith8,pos:113,val:-22
+++ b/src/exchange/afl-tests/id:000425,src:000000,op:arith8,pos:113,val:-22
diff --git a/src/mint/afl-tests/id:000425,src:000000,op:arith8,pos:152,val:+27,+cov b/src/exchange/afl-tests/id:000425,src:000000,op:arith8,pos:152,val:+27,+cov
index 76d693963..76d693963 100644
--- a/src/mint/afl-tests/id:000425,src:000000,op:arith8,pos:152,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000425,src:000000,op:arith8,pos:152,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000426,src:000000,op:arith8,pos:127,val:-20,+cov b/src/exchange/afl-tests/id:000426,src:000000,op:arith8,pos:127,val:-20,+cov
index 4e7375db7..4e7375db7 100644
--- a/src/mint/afl-tests/id:000426,src:000000,op:arith8,pos:127,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000426,src:000000,op:arith8,pos:127,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000426,src:000000,op:arith8,pos:152,val:+31,+cov b/src/exchange/afl-tests/id:000426,src:000000,op:arith8,pos:152,val:+31,+cov
index fff730b94..fff730b94 100644
--- a/src/mint/afl-tests/id:000426,src:000000,op:arith8,pos:152,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000426,src:000000,op:arith8,pos:152,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000427,src:000000,op:arith8,pos:131,val:-20,+cov b/src/exchange/afl-tests/id:000427,src:000000,op:arith8,pos:131,val:-20,+cov
index c4e16be49..c4e16be49 100644
--- a/src/mint/afl-tests/id:000427,src:000000,op:arith8,pos:131,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000427,src:000000,op:arith8,pos:131,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000427,src:000000,op:arith8,pos:153,val:+20,+cov b/src/exchange/afl-tests/id:000427,src:000000,op:arith8,pos:153,val:+20,+cov
index 0b6d26013..0b6d26013 100644
--- a/src/mint/afl-tests/id:000427,src:000000,op:arith8,pos:153,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000427,src:000000,op:arith8,pos:153,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000428,src:000000,op:arith8,pos:132,val:+6,+cov b/src/exchange/afl-tests/id:000428,src:000000,op:arith8,pos:132,val:+6,+cov
index 493e8dc0a..493e8dc0a 100644
--- a/src/mint/afl-tests/id:000428,src:000000,op:arith8,pos:132,val:+6,+cov
+++ b/src/exchange/afl-tests/id:000428,src:000000,op:arith8,pos:132,val:+6,+cov
diff --git a/src/mint/afl-tests/id:000428,src:000000,op:arith8,pos:154,val:+7,+cov b/src/exchange/afl-tests/id:000428,src:000000,op:arith8,pos:154,val:+7,+cov
index 7ecf8fcaf..7ecf8fcaf 100644
--- a/src/mint/afl-tests/id:000428,src:000000,op:arith8,pos:154,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000428,src:000000,op:arith8,pos:154,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000429,src:000000,op:arith8,pos:135,val:-28,+cov b/src/exchange/afl-tests/id:000429,src:000000,op:arith8,pos:135,val:-28,+cov
index f88d76318..f88d76318 100644
--- a/src/mint/afl-tests/id:000429,src:000000,op:arith8,pos:135,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000429,src:000000,op:arith8,pos:135,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000429,src:000000,op:arith8,pos:156,val:+18,+cov b/src/exchange/afl-tests/id:000429,src:000000,op:arith8,pos:156,val:+18,+cov
index 9c41a8c09..9c41a8c09 100644
--- a/src/mint/afl-tests/id:000429,src:000000,op:arith8,pos:156,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000429,src:000000,op:arith8,pos:156,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000430,src:000000,op:arith8,pos:135,val:-35,+cov b/src/exchange/afl-tests/id:000430,src:000000,op:arith8,pos:135,val:-35,+cov
index 410faaf1d..410faaf1d 100644
--- a/src/mint/afl-tests/id:000430,src:000000,op:arith8,pos:135,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000430,src:000000,op:arith8,pos:135,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000430,src:000000,op:arith8,pos:156,val:+28,+cov b/src/exchange/afl-tests/id:000430,src:000000,op:arith8,pos:156,val:+28,+cov
index 3694a205c..3694a205c 100644
--- a/src/mint/afl-tests/id:000430,src:000000,op:arith8,pos:156,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000430,src:000000,op:arith8,pos:156,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000431,src:000000,op:arith8,pos:136,val:+3,+cov b/src/exchange/afl-tests/id:000431,src:000000,op:arith8,pos:136,val:+3,+cov
index 4e155e64a..4e155e64a 100644
--- a/src/mint/afl-tests/id:000431,src:000000,op:arith8,pos:136,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000431,src:000000,op:arith8,pos:136,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000431,src:000000,op:arith8,pos:159,val:-30,+cov b/src/exchange/afl-tests/id:000431,src:000000,op:arith8,pos:159,val:-30,+cov
index 63b86d2b0..63b86d2b0 100644
--- a/src/mint/afl-tests/id:000431,src:000000,op:arith8,pos:159,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000431,src:000000,op:arith8,pos:159,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000432,src:000000,op:arith8,pos:136,val:-5,+cov b/src/exchange/afl-tests/id:000432,src:000000,op:arith8,pos:136,val:-5,+cov
index 8f88c0498..8f88c0498 100644
--- a/src/mint/afl-tests/id:000432,src:000000,op:arith8,pos:136,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000432,src:000000,op:arith8,pos:136,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000432,src:000000,op:arith8,pos:160,val:-31,+cov b/src/exchange/afl-tests/id:000432,src:000000,op:arith8,pos:160,val:-31,+cov
index ee9357cdc..ee9357cdc 100644
--- a/src/mint/afl-tests/id:000432,src:000000,op:arith8,pos:160,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000432,src:000000,op:arith8,pos:160,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000433,src:000000,op:arith8,pos:136,val:-9,+cov b/src/exchange/afl-tests/id:000433,src:000000,op:arith8,pos:136,val:-9,+cov
index b5629267f..b5629267f 100644
--- a/src/mint/afl-tests/id:000433,src:000000,op:arith8,pos:136,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000433,src:000000,op:arith8,pos:136,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000433,src:000000,op:arith8,pos:161,val:+5,+cov b/src/exchange/afl-tests/id:000433,src:000000,op:arith8,pos:161,val:+5,+cov
index c9829f145..c9829f145 100644
--- a/src/mint/afl-tests/id:000433,src:000000,op:arith8,pos:161,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000433,src:000000,op:arith8,pos:161,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000434,src:000000,op:arith8,pos:136,val:+20,+cov b/src/exchange/afl-tests/id:000434,src:000000,op:arith8,pos:136,val:+20,+cov
index 4b138b218..4b138b218 100644
--- a/src/mint/afl-tests/id:000434,src:000000,op:arith8,pos:136,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000434,src:000000,op:arith8,pos:136,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000434,src:000000,op:arith8,pos:161,val:-11,+cov b/src/exchange/afl-tests/id:000434,src:000000,op:arith8,pos:161,val:-11,+cov
index bf0362966..bf0362966 100644
--- a/src/mint/afl-tests/id:000434,src:000000,op:arith8,pos:161,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000434,src:000000,op:arith8,pos:161,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000435,src:000000,op:arith8,pos:136,val:-29,+cov b/src/exchange/afl-tests/id:000435,src:000000,op:arith8,pos:136,val:-29,+cov
index d6c3b3c2d..d6c3b3c2d 100644
--- a/src/mint/afl-tests/id:000435,src:000000,op:arith8,pos:136,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000435,src:000000,op:arith8,pos:136,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000435,src:000000,op:arith8,pos:162,val:+22 b/src/exchange/afl-tests/id:000435,src:000000,op:arith8,pos:162,val:+22
index a50b8a578..a50b8a578 100644
--- a/src/mint/afl-tests/id:000435,src:000000,op:arith8,pos:162,val:+22
+++ b/src/exchange/afl-tests/id:000435,src:000000,op:arith8,pos:162,val:+22
diff --git a/src/mint/afl-tests/id:000436,src:000000,op:arith8,pos:137,val:+7,+cov b/src/exchange/afl-tests/id:000436,src:000000,op:arith8,pos:137,val:+7,+cov
index 192928abd..192928abd 100644
--- a/src/mint/afl-tests/id:000436,src:000000,op:arith8,pos:137,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000436,src:000000,op:arith8,pos:137,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000436,src:000000,op:arith8,pos:163,val:+19,+cov b/src/exchange/afl-tests/id:000436,src:000000,op:arith8,pos:163,val:+19,+cov
index c1dedadd1..c1dedadd1 100644
--- a/src/mint/afl-tests/id:000436,src:000000,op:arith8,pos:163,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000436,src:000000,op:arith8,pos:163,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000437,src:000000,op:arith8,pos:137,val:+10,+cov b/src/exchange/afl-tests/id:000437,src:000000,op:arith8,pos:137,val:+10,+cov
index 2dac2ca15..2dac2ca15 100644
--- a/src/mint/afl-tests/id:000437,src:000000,op:arith8,pos:137,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000437,src:000000,op:arith8,pos:137,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000437,src:000000,op:arith8,pos:164,val:+27,+cov b/src/exchange/afl-tests/id:000437,src:000000,op:arith8,pos:164,val:+27,+cov
index 768fe303c..768fe303c 100644
--- a/src/mint/afl-tests/id:000437,src:000000,op:arith8,pos:164,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000437,src:000000,op:arith8,pos:164,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000438,src:000000,op:arith8,pos:138,val:+19,+cov b/src/exchange/afl-tests/id:000438,src:000000,op:arith8,pos:138,val:+19,+cov
index f9a48f6c7..f9a48f6c7 100644
--- a/src/mint/afl-tests/id:000438,src:000000,op:arith8,pos:138,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000438,src:000000,op:arith8,pos:138,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000438,src:000000,op:arith8,pos:166,val:+13,+cov b/src/exchange/afl-tests/id:000438,src:000000,op:arith8,pos:166,val:+13,+cov
index effa2c9a2..effa2c9a2 100644
--- a/src/mint/afl-tests/id:000438,src:000000,op:arith8,pos:166,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000438,src:000000,op:arith8,pos:166,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000439,src:000000,op:arith8,pos:139,val:+25,+cov b/src/exchange/afl-tests/id:000439,src:000000,op:arith8,pos:139,val:+25,+cov
index d9201b105..d9201b105 100644
--- a/src/mint/afl-tests/id:000439,src:000000,op:arith8,pos:139,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000439,src:000000,op:arith8,pos:139,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000439,src:000000,op:arith8,pos:167,val:+33,+cov b/src/exchange/afl-tests/id:000439,src:000000,op:arith8,pos:167,val:+33,+cov
index 30d33e17d..30d33e17d 100644
--- a/src/mint/afl-tests/id:000439,src:000000,op:arith8,pos:167,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000439,src:000000,op:arith8,pos:167,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000440,src:000000,op:arith8,pos:139,val:-26,+cov b/src/exchange/afl-tests/id:000440,src:000000,op:arith8,pos:139,val:-26,+cov
index 8500eb30f..8500eb30f 100644
--- a/src/mint/afl-tests/id:000440,src:000000,op:arith8,pos:139,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000440,src:000000,op:arith8,pos:139,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000440,src:000000,op:arith8,pos:168,val:-17,+cov b/src/exchange/afl-tests/id:000440,src:000000,op:arith8,pos:168,val:-17,+cov
index f5480d81f..f5480d81f 100644
--- a/src/mint/afl-tests/id:000440,src:000000,op:arith8,pos:168,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000440,src:000000,op:arith8,pos:168,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000441,src:000000,op:arith8,pos:140,val:+20,+cov b/src/exchange/afl-tests/id:000441,src:000000,op:arith8,pos:140,val:+20,+cov
index 820448777..820448777 100644
--- a/src/mint/afl-tests/id:000441,src:000000,op:arith8,pos:140,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000441,src:000000,op:arith8,pos:140,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000441,src:000000,op:arith8,pos:168,val:+29,+cov b/src/exchange/afl-tests/id:000441,src:000000,op:arith8,pos:168,val:+29,+cov
index 1f4bda2c4..1f4bda2c4 100644
--- a/src/mint/afl-tests/id:000441,src:000000,op:arith8,pos:168,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000441,src:000000,op:arith8,pos:168,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000442,src:000000,op:arith8,pos:141,val:+6,+cov b/src/exchange/afl-tests/id:000442,src:000000,op:arith8,pos:141,val:+6,+cov
index 61ea67ae3..61ea67ae3 100644
--- a/src/mint/afl-tests/id:000442,src:000000,op:arith8,pos:141,val:+6,+cov
+++ b/src/exchange/afl-tests/id:000442,src:000000,op:arith8,pos:141,val:+6,+cov
diff --git a/src/mint/afl-tests/id:000442,src:000000,op:arith8,pos:168,val:+30,+cov b/src/exchange/afl-tests/id:000442,src:000000,op:arith8,pos:168,val:+30,+cov
index b49f9857d..b49f9857d 100644
--- a/src/mint/afl-tests/id:000442,src:000000,op:arith8,pos:168,val:+30,+cov
+++ b/src/exchange/afl-tests/id:000442,src:000000,op:arith8,pos:168,val:+30,+cov
diff --git a/src/mint/afl-tests/id:000443,src:000000,op:arith8,pos:141,val:+10,+cov b/src/exchange/afl-tests/id:000443,src:000000,op:arith8,pos:141,val:+10,+cov
index 9c8c7b374..9c8c7b374 100644
--- a/src/mint/afl-tests/id:000443,src:000000,op:arith8,pos:141,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000443,src:000000,op:arith8,pos:141,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000443,src:000000,op:arith8,pos:171,val:+22,+cov b/src/exchange/afl-tests/id:000443,src:000000,op:arith8,pos:171,val:+22,+cov
index 8e63b0dae..8e63b0dae 100644
--- a/src/mint/afl-tests/id:000443,src:000000,op:arith8,pos:171,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000443,src:000000,op:arith8,pos:171,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000444,src:000000,op:arith8,pos:141,val:+13,+cov b/src/exchange/afl-tests/id:000444,src:000000,op:arith8,pos:141,val:+13,+cov
index 35f21e74f..35f21e74f 100644
--- a/src/mint/afl-tests/id:000444,src:000000,op:arith8,pos:141,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000444,src:000000,op:arith8,pos:141,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000444,src:000000,op:arith8,pos:171,val:+25,+cov b/src/exchange/afl-tests/id:000444,src:000000,op:arith8,pos:171,val:+25,+cov
index 506a1510c..506a1510c 100644
--- a/src/mint/afl-tests/id:000444,src:000000,op:arith8,pos:171,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000444,src:000000,op:arith8,pos:171,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000445,src:000000,op:arith8,pos:141,val:+20,+cov b/src/exchange/afl-tests/id:000445,src:000000,op:arith8,pos:141,val:+20,+cov
index 63db44e2b..63db44e2b 100644
--- a/src/mint/afl-tests/id:000445,src:000000,op:arith8,pos:141,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000445,src:000000,op:arith8,pos:141,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000445,src:000000,op:arith8,pos:172,val:-13,+cov b/src/exchange/afl-tests/id:000445,src:000000,op:arith8,pos:172,val:-13,+cov
index 2fe1562e8..2fe1562e8 100644
--- a/src/mint/afl-tests/id:000445,src:000000,op:arith8,pos:172,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000445,src:000000,op:arith8,pos:172,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000446,src:000000,op:arith8,pos:142,val:+6,+cov b/src/exchange/afl-tests/id:000446,src:000000,op:arith8,pos:142,val:+6,+cov
index 297b2993e..297b2993e 100644
--- a/src/mint/afl-tests/id:000446,src:000000,op:arith8,pos:142,val:+6,+cov
+++ b/src/exchange/afl-tests/id:000446,src:000000,op:arith8,pos:142,val:+6,+cov
diff --git a/src/mint/afl-tests/id:000446,src:000000,op:arith8,pos:172,val:+19,+cov b/src/exchange/afl-tests/id:000446,src:000000,op:arith8,pos:172,val:+19,+cov
index ed3d1c7d4..ed3d1c7d4 100644
--- a/src/mint/afl-tests/id:000446,src:000000,op:arith8,pos:172,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000446,src:000000,op:arith8,pos:172,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000447,src:000000,op:arith8,pos:142,val:-20,+cov b/src/exchange/afl-tests/id:000447,src:000000,op:arith8,pos:142,val:-20,+cov
index 07fa3dc9b..07fa3dc9b 100644
--- a/src/mint/afl-tests/id:000447,src:000000,op:arith8,pos:142,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000447,src:000000,op:arith8,pos:142,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000447,src:000000,op:arith8,pos:173,val:-15,+cov b/src/exchange/afl-tests/id:000447,src:000000,op:arith8,pos:173,val:-15,+cov
index adcf02bdf..adcf02bdf 100644
--- a/src/mint/afl-tests/id:000447,src:000000,op:arith8,pos:173,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000447,src:000000,op:arith8,pos:173,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000448,src:000000,op:arith8,pos:143,val:+17,+cov b/src/exchange/afl-tests/id:000448,src:000000,op:arith8,pos:143,val:+17,+cov
index 548552a04..548552a04 100644
--- a/src/mint/afl-tests/id:000448,src:000000,op:arith8,pos:143,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000448,src:000000,op:arith8,pos:143,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000448,src:000000,op:arith8,pos:174,val:+23,+cov b/src/exchange/afl-tests/id:000448,src:000000,op:arith8,pos:174,val:+23,+cov
index 307771d87..307771d87 100644
--- a/src/mint/afl-tests/id:000448,src:000000,op:arith8,pos:174,val:+23,+cov
+++ b/src/exchange/afl-tests/id:000448,src:000000,op:arith8,pos:174,val:+23,+cov
diff --git a/src/mint/afl-tests/id:000449,src:000000,op:arith8,pos:144,val:+28,+cov b/src/exchange/afl-tests/id:000449,src:000000,op:arith8,pos:144,val:+28,+cov
index 931806502..931806502 100644
--- a/src/mint/afl-tests/id:000449,src:000000,op:arith8,pos:144,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000449,src:000000,op:arith8,pos:144,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000449,src:000000,op:arith8,pos:174,val:+33,+cov b/src/exchange/afl-tests/id:000449,src:000000,op:arith8,pos:174,val:+33,+cov
index 14de52665..14de52665 100644
--- a/src/mint/afl-tests/id:000449,src:000000,op:arith8,pos:174,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000449,src:000000,op:arith8,pos:174,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000450,src:000000,op:arith8,pos:145,val:+27,+cov b/src/exchange/afl-tests/id:000450,src:000000,op:arith8,pos:145,val:+27,+cov
index 4ece763df..4ece763df 100644
--- a/src/mint/afl-tests/id:000450,src:000000,op:arith8,pos:145,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000450,src:000000,op:arith8,pos:145,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000450,src:000000,op:arith8,pos:176,val:+20,+cov b/src/exchange/afl-tests/id:000450,src:000000,op:arith8,pos:176,val:+20,+cov
index 72a01931e..72a01931e 100644
--- a/src/mint/afl-tests/id:000450,src:000000,op:arith8,pos:176,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000450,src:000000,op:arith8,pos:176,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000451,src:000000,op:arith8,pos:146,val:-11,+cov b/src/exchange/afl-tests/id:000451,src:000000,op:arith8,pos:146,val:-11,+cov
index 1bd939b73..1bd939b73 100644
--- a/src/mint/afl-tests/id:000451,src:000000,op:arith8,pos:146,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000451,src:000000,op:arith8,pos:146,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000451,src:000000,op:arith8,pos:177,val:+33,+cov b/src/exchange/afl-tests/id:000451,src:000000,op:arith8,pos:177,val:+33,+cov
index 33a81bae4..33a81bae4 100644
--- a/src/mint/afl-tests/id:000451,src:000000,op:arith8,pos:177,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000451,src:000000,op:arith8,pos:177,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000452,src:000000,op:arith8,pos:146,val:-13,+cov b/src/exchange/afl-tests/id:000452,src:000000,op:arith8,pos:146,val:-13,+cov
index 0aad43f11..0aad43f11 100644
--- a/src/mint/afl-tests/id:000452,src:000000,op:arith8,pos:146,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000452,src:000000,op:arith8,pos:146,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000452,src:000000,op:arith8,pos:181,val:+12,+cov b/src/exchange/afl-tests/id:000452,src:000000,op:arith8,pos:181,val:+12,+cov
index da7b5cee6..da7b5cee6 100644
--- a/src/mint/afl-tests/id:000452,src:000000,op:arith8,pos:181,val:+12,+cov
+++ b/src/exchange/afl-tests/id:000452,src:000000,op:arith8,pos:181,val:+12,+cov
diff --git a/src/mint/afl-tests/id:000453,src:000000,op:arith8,pos:146,val:-21,+cov b/src/exchange/afl-tests/id:000453,src:000000,op:arith8,pos:146,val:-21,+cov
index 1ae69b17a..1ae69b17a 100644
--- a/src/mint/afl-tests/id:000453,src:000000,op:arith8,pos:146,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000453,src:000000,op:arith8,pos:146,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000453,src:000000,op:arith8,pos:181,val:+21 b/src/exchange/afl-tests/id:000453,src:000000,op:arith8,pos:181,val:+21
index 09fcb96fa..09fcb96fa 100644
--- a/src/mint/afl-tests/id:000453,src:000000,op:arith8,pos:181,val:+21
+++ b/src/exchange/afl-tests/id:000453,src:000000,op:arith8,pos:181,val:+21
diff --git a/src/mint/afl-tests/id:000454,src:000000,op:arith8,pos:147,val:-3,+cov b/src/exchange/afl-tests/id:000454,src:000000,op:arith8,pos:147,val:-3,+cov
index 9ff533460..9ff533460 100644
--- a/src/mint/afl-tests/id:000454,src:000000,op:arith8,pos:147,val:-3,+cov
+++ b/src/exchange/afl-tests/id:000454,src:000000,op:arith8,pos:147,val:-3,+cov
diff --git a/src/mint/afl-tests/id:000454,src:000000,op:arith8,pos:181,val:+25,+cov b/src/exchange/afl-tests/id:000454,src:000000,op:arith8,pos:181,val:+25,+cov
index 8e290456a..8e290456a 100644
--- a/src/mint/afl-tests/id:000454,src:000000,op:arith8,pos:181,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000454,src:000000,op:arith8,pos:181,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000455,src:000000,op:arith8,pos:147,val:-9,+cov b/src/exchange/afl-tests/id:000455,src:000000,op:arith8,pos:147,val:-9,+cov
index a94d76b99..a94d76b99 100644
--- a/src/mint/afl-tests/id:000455,src:000000,op:arith8,pos:147,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000455,src:000000,op:arith8,pos:147,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000455,src:000000,op:arith8,pos:183,val:-3 b/src/exchange/afl-tests/id:000455,src:000000,op:arith8,pos:183,val:-3
index e41f1c87d..e41f1c87d 100644
--- a/src/mint/afl-tests/id:000455,src:000000,op:arith8,pos:183,val:-3
+++ b/src/exchange/afl-tests/id:000455,src:000000,op:arith8,pos:183,val:-3
diff --git a/src/mint/afl-tests/id:000456,src:000000,op:arith8,pos:147,val:-13,+cov b/src/exchange/afl-tests/id:000456,src:000000,op:arith8,pos:147,val:-13,+cov
index b53294317..b53294317 100644
--- a/src/mint/afl-tests/id:000456,src:000000,op:arith8,pos:147,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000456,src:000000,op:arith8,pos:147,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000456,src:000000,op:arith8,pos:184,val:-13 b/src/exchange/afl-tests/id:000456,src:000000,op:arith8,pos:184,val:-13
index 02714457a..02714457a 100644
--- a/src/mint/afl-tests/id:000456,src:000000,op:arith8,pos:184,val:-13
+++ b/src/exchange/afl-tests/id:000456,src:000000,op:arith8,pos:184,val:-13
diff --git a/src/mint/afl-tests/id:000457,src:000000,op:arith8,pos:148,val:+12,+cov b/src/exchange/afl-tests/id:000457,src:000000,op:arith8,pos:148,val:+12,+cov
index 297a3677c..297a3677c 100644
--- a/src/mint/afl-tests/id:000457,src:000000,op:arith8,pos:148,val:+12,+cov
+++ b/src/exchange/afl-tests/id:000457,src:000000,op:arith8,pos:148,val:+12,+cov
diff --git a/src/mint/afl-tests/id:000457,src:000000,op:arith8,pos:184,val:-34,+cov b/src/exchange/afl-tests/id:000457,src:000000,op:arith8,pos:184,val:-34,+cov
index 65c13f3e8..65c13f3e8 100644
--- a/src/mint/afl-tests/id:000457,src:000000,op:arith8,pos:184,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000457,src:000000,op:arith8,pos:184,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000458,src:000000,op:arith8,pos:151,val:-7,+cov b/src/exchange/afl-tests/id:000458,src:000000,op:arith8,pos:151,val:-7,+cov
index 7a4a55286..7a4a55286 100644
--- a/src/mint/afl-tests/id:000458,src:000000,op:arith8,pos:151,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000458,src:000000,op:arith8,pos:151,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000458,src:000000,op:arith8,pos:185,val:-6,+cov b/src/exchange/afl-tests/id:000458,src:000000,op:arith8,pos:185,val:-6,+cov
index 41f82367a..41f82367a 100644
--- a/src/mint/afl-tests/id:000458,src:000000,op:arith8,pos:185,val:-6,+cov
+++ b/src/exchange/afl-tests/id:000458,src:000000,op:arith8,pos:185,val:-6,+cov
diff --git a/src/mint/afl-tests/id:000459,src:000000,op:arith8,pos:151,val:+15,+cov b/src/exchange/afl-tests/id:000459,src:000000,op:arith8,pos:151,val:+15,+cov
index 9dab0d5d9..9dab0d5d9 100644
--- a/src/mint/afl-tests/id:000459,src:000000,op:arith8,pos:151,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000459,src:000000,op:arith8,pos:151,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000459,src:000000,op:arith8,pos:185,val:+14,+cov b/src/exchange/afl-tests/id:000459,src:000000,op:arith8,pos:185,val:+14,+cov
index a2d874949..a2d874949 100644
--- a/src/mint/afl-tests/id:000459,src:000000,op:arith8,pos:185,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000459,src:000000,op:arith8,pos:185,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000460,src:000000,op:arith8,pos:152,val:-7,+cov b/src/exchange/afl-tests/id:000460,src:000000,op:arith8,pos:152,val:-7,+cov
index af849ade9..af849ade9 100644
--- a/src/mint/afl-tests/id:000460,src:000000,op:arith8,pos:152,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000460,src:000000,op:arith8,pos:152,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000460,src:000000,op:arith8,pos:185,val:+29,+cov b/src/exchange/afl-tests/id:000460,src:000000,op:arith8,pos:185,val:+29,+cov
index 3e720e184..3e720e184 100644
--- a/src/mint/afl-tests/id:000460,src:000000,op:arith8,pos:185,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000460,src:000000,op:arith8,pos:185,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000461,src:000000,op:arith8,pos:152,val:+25,+cov b/src/exchange/afl-tests/id:000461,src:000000,op:arith8,pos:152,val:+25,+cov
index ec79f0f25..ec79f0f25 100644
--- a/src/mint/afl-tests/id:000461,src:000000,op:arith8,pos:152,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000461,src:000000,op:arith8,pos:152,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000461,src:000000,op:arith8,pos:186,val:+23,+cov b/src/exchange/afl-tests/id:000461,src:000000,op:arith8,pos:186,val:+23,+cov
index fd6016541..fd6016541 100644
--- a/src/mint/afl-tests/id:000461,src:000000,op:arith8,pos:186,val:+23,+cov
+++ b/src/exchange/afl-tests/id:000461,src:000000,op:arith8,pos:186,val:+23,+cov
diff --git a/src/mint/afl-tests/id:000462,src:000000,op:arith8,pos:152,val:-30 b/src/exchange/afl-tests/id:000462,src:000000,op:arith8,pos:152,val:-30
index b17543cf4..b17543cf4 100644
--- a/src/mint/afl-tests/id:000462,src:000000,op:arith8,pos:152,val:-30
+++ b/src/exchange/afl-tests/id:000462,src:000000,op:arith8,pos:152,val:-30
diff --git a/src/mint/afl-tests/id:000462,src:000000,op:arith8,pos:191,val:-26,+cov b/src/exchange/afl-tests/id:000462,src:000000,op:arith8,pos:191,val:-26,+cov
index f9f03502c..f9f03502c 100644
--- a/src/mint/afl-tests/id:000462,src:000000,op:arith8,pos:191,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000462,src:000000,op:arith8,pos:191,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000463,src:000000,op:arith8,pos:153,val:+28,+cov b/src/exchange/afl-tests/id:000463,src:000000,op:arith8,pos:153,val:+28,+cov
index de4bba6fe..de4bba6fe 100644
--- a/src/mint/afl-tests/id:000463,src:000000,op:arith8,pos:153,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000463,src:000000,op:arith8,pos:153,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000463,src:000000,op:arith8,pos:196,val:-18,+cov b/src/exchange/afl-tests/id:000463,src:000000,op:arith8,pos:196,val:-18,+cov
index ba7cce630..ba7cce630 100644
--- a/src/mint/afl-tests/id:000463,src:000000,op:arith8,pos:196,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000463,src:000000,op:arith8,pos:196,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000464,src:000000,op:arith8,pos:157,val:+8,+cov b/src/exchange/afl-tests/id:000464,src:000000,op:arith8,pos:157,val:+8,+cov
index 56dec1da7..56dec1da7 100644
--- a/src/mint/afl-tests/id:000464,src:000000,op:arith8,pos:157,val:+8,+cov
+++ b/src/exchange/afl-tests/id:000464,src:000000,op:arith8,pos:157,val:+8,+cov
diff --git a/src/mint/afl-tests/id:000464,src:000000,op:arith8,pos:203,val:+22,+cov b/src/exchange/afl-tests/id:000464,src:000000,op:arith8,pos:203,val:+22,+cov
index 950bac3e8..950bac3e8 100644
--- a/src/mint/afl-tests/id:000464,src:000000,op:arith8,pos:203,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000464,src:000000,op:arith8,pos:203,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000465,src:000000,op:arith8,pos:157,val:-9,+cov b/src/exchange/afl-tests/id:000465,src:000000,op:arith8,pos:157,val:-9,+cov
index cee6141df..cee6141df 100644
--- a/src/mint/afl-tests/id:000465,src:000000,op:arith8,pos:157,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000465,src:000000,op:arith8,pos:157,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000465,src:000000,op:arith8,pos:225,val:-6,+cov b/src/exchange/afl-tests/id:000465,src:000000,op:arith8,pos:225,val:-6,+cov
index 9626a14a8..9626a14a8 100644
--- a/src/mint/afl-tests/id:000465,src:000000,op:arith8,pos:225,val:-6,+cov
+++ b/src/exchange/afl-tests/id:000465,src:000000,op:arith8,pos:225,val:-6,+cov
diff --git a/src/mint/afl-tests/id:000466,src:000000,op:arith8,pos:157,val:-12,+cov b/src/exchange/afl-tests/id:000466,src:000000,op:arith8,pos:157,val:-12,+cov
index 2f07f5900..2f07f5900 100644
--- a/src/mint/afl-tests/id:000466,src:000000,op:arith8,pos:157,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000466,src:000000,op:arith8,pos:157,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000466,src:000000,op:arith8,pos:241,val:-26,+cov b/src/exchange/afl-tests/id:000466,src:000000,op:arith8,pos:241,val:-26,+cov
index b0c893c5e..b0c893c5e 100644
--- a/src/mint/afl-tests/id:000466,src:000000,op:arith8,pos:241,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000466,src:000000,op:arith8,pos:241,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000467,src:000000,op:arith8,pos:157,val:-21,+cov b/src/exchange/afl-tests/id:000467,src:000000,op:arith8,pos:157,val:-21,+cov
index 66560a702..66560a702 100644
--- a/src/mint/afl-tests/id:000467,src:000000,op:arith8,pos:157,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000467,src:000000,op:arith8,pos:157,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000467,src:000000,op:arith8,pos:268,val:-4,+cov b/src/exchange/afl-tests/id:000467,src:000000,op:arith8,pos:268,val:-4,+cov
index cd62df7e1..cd62df7e1 100644
--- a/src/mint/afl-tests/id:000467,src:000000,op:arith8,pos:268,val:-4,+cov
+++ b/src/exchange/afl-tests/id:000467,src:000000,op:arith8,pos:268,val:-4,+cov
diff --git a/src/mint/afl-tests/id:000468,src:000000,op:arith8,pos:158,val:-9,+cov b/src/exchange/afl-tests/id:000468,src:000000,op:arith8,pos:158,val:-9,+cov
index 2a10abb37..2a10abb37 100644
--- a/src/mint/afl-tests/id:000468,src:000000,op:arith8,pos:158,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000468,src:000000,op:arith8,pos:158,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000468,src:000000,op:arith8,pos:268,val:+7,+cov b/src/exchange/afl-tests/id:000468,src:000000,op:arith8,pos:268,val:+7,+cov
index d88da41ab..d88da41ab 100644
--- a/src/mint/afl-tests/id:000468,src:000000,op:arith8,pos:268,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000468,src:000000,op:arith8,pos:268,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000469,src:000000,op:arith8,pos:158,val:+25,+cov b/src/exchange/afl-tests/id:000469,src:000000,op:arith8,pos:158,val:+25,+cov
index 16a083e5c..16a083e5c 100644
--- a/src/mint/afl-tests/id:000469,src:000000,op:arith8,pos:158,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000469,src:000000,op:arith8,pos:158,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000469,src:000000,op:arith8,pos:269,val:+11,+cov b/src/exchange/afl-tests/id:000469,src:000000,op:arith8,pos:269,val:+11,+cov
index 7793c098b..7793c098b 100644
--- a/src/mint/afl-tests/id:000469,src:000000,op:arith8,pos:269,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000469,src:000000,op:arith8,pos:269,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000470,src:000000,op:arith8,pos:159,val:-7,+cov b/src/exchange/afl-tests/id:000470,src:000000,op:arith8,pos:159,val:-7,+cov
index 831cba553..831cba553 100644
--- a/src/mint/afl-tests/id:000470,src:000000,op:arith8,pos:159,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000470,src:000000,op:arith8,pos:159,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000470,src:000000,op:arith8,pos:272,val:+29,+cov b/src/exchange/afl-tests/id:000470,src:000000,op:arith8,pos:272,val:+29,+cov
index 7a0565d3b..7a0565d3b 100644
--- a/src/mint/afl-tests/id:000470,src:000000,op:arith8,pos:272,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000470,src:000000,op:arith8,pos:272,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000471,src:000000,op:arith8,pos:159,val:+10,+cov b/src/exchange/afl-tests/id:000471,src:000000,op:arith8,pos:159,val:+10,+cov
index 56a9de5cd..56a9de5cd 100644
--- a/src/mint/afl-tests/id:000471,src:000000,op:arith8,pos:159,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000471,src:000000,op:arith8,pos:159,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000471,src:000000,op:arith8,pos:273,val:+29,+cov b/src/exchange/afl-tests/id:000471,src:000000,op:arith8,pos:273,val:+29,+cov
index 4676ad82c..4676ad82c 100644
--- a/src/mint/afl-tests/id:000471,src:000000,op:arith8,pos:273,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000471,src:000000,op:arith8,pos:273,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000472,src:000000,op:arith8,pos:159,val:-11,+cov b/src/exchange/afl-tests/id:000472,src:000000,op:arith8,pos:159,val:-11,+cov
index befe62436..befe62436 100644
--- a/src/mint/afl-tests/id:000472,src:000000,op:arith8,pos:159,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000472,src:000000,op:arith8,pos:159,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000472,src:000000,op:arith8,pos:274,val:+11,+cov b/src/exchange/afl-tests/id:000472,src:000000,op:arith8,pos:274,val:+11,+cov
index 63916d85a..63916d85a 100644
--- a/src/mint/afl-tests/id:000472,src:000000,op:arith8,pos:274,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000472,src:000000,op:arith8,pos:274,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000473,src:000000,op:arith8,pos:160,val:+19,+cov b/src/exchange/afl-tests/id:000473,src:000000,op:arith8,pos:160,val:+19,+cov
index 5463016e5..5463016e5 100644
--- a/src/mint/afl-tests/id:000473,src:000000,op:arith8,pos:160,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000473,src:000000,op:arith8,pos:160,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000473,src:000000,op:arith8,pos:276,val:+9,+cov b/src/exchange/afl-tests/id:000473,src:000000,op:arith8,pos:276,val:+9,+cov
index 9646bcbfe..9646bcbfe 100644
--- a/src/mint/afl-tests/id:000473,src:000000,op:arith8,pos:276,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000473,src:000000,op:arith8,pos:276,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000474,src:000000,op:arith8,pos:161,val:+14,+cov b/src/exchange/afl-tests/id:000474,src:000000,op:arith8,pos:161,val:+14,+cov
index 09756f9a8..09756f9a8 100644
--- a/src/mint/afl-tests/id:000474,src:000000,op:arith8,pos:161,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000474,src:000000,op:arith8,pos:161,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000474,src:000000,op:arith8,pos:276,val:+19,+cov b/src/exchange/afl-tests/id:000474,src:000000,op:arith8,pos:276,val:+19,+cov
index 70fd22e89..70fd22e89 100644
--- a/src/mint/afl-tests/id:000474,src:000000,op:arith8,pos:276,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000474,src:000000,op:arith8,pos:276,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000475,src:000000,op:arith8,pos:162,val:+7,+cov b/src/exchange/afl-tests/id:000475,src:000000,op:arith8,pos:162,val:+7,+cov
index e0c167c5f..e0c167c5f 100644
--- a/src/mint/afl-tests/id:000475,src:000000,op:arith8,pos:162,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000475,src:000000,op:arith8,pos:162,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000475,src:000000,op:arith8,pos:277,val:+35,+cov b/src/exchange/afl-tests/id:000475,src:000000,op:arith8,pos:277,val:+35,+cov
index 5ba54d7fd..5ba54d7fd 100644
--- a/src/mint/afl-tests/id:000475,src:000000,op:arith8,pos:277,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000475,src:000000,op:arith8,pos:277,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000476,src:000000,op:arith8,pos:163,val:+26,+cov b/src/exchange/afl-tests/id:000476,src:000000,op:arith8,pos:163,val:+26,+cov
index 8a6320384..8a6320384 100644
--- a/src/mint/afl-tests/id:000476,src:000000,op:arith8,pos:163,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000476,src:000000,op:arith8,pos:163,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000476,src:000000,op:arith8,pos:278,val:+5,+cov b/src/exchange/afl-tests/id:000476,src:000000,op:arith8,pos:278,val:+5,+cov
index 2fbf6ce63..2fbf6ce63 100644
--- a/src/mint/afl-tests/id:000476,src:000000,op:arith8,pos:278,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000476,src:000000,op:arith8,pos:278,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000477,src:000000,op:arith8,pos:163,val:+31,+cov b/src/exchange/afl-tests/id:000477,src:000000,op:arith8,pos:163,val:+31,+cov
index f12180d05..f12180d05 100644
--- a/src/mint/afl-tests/id:000477,src:000000,op:arith8,pos:163,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000477,src:000000,op:arith8,pos:163,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000477,src:000000,op:arith8,pos:305,val:+14,+cov b/src/exchange/afl-tests/id:000477,src:000000,op:arith8,pos:305,val:+14,+cov
index d5a1e9f8b..d5a1e9f8b 100644
--- a/src/mint/afl-tests/id:000477,src:000000,op:arith8,pos:305,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000477,src:000000,op:arith8,pos:305,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000478,src:000000,op:arith8,pos:164,val:+2,+cov b/src/exchange/afl-tests/id:000478,src:000000,op:arith8,pos:164,val:+2,+cov
index 371cbf60a..371cbf60a 100644
--- a/src/mint/afl-tests/id:000478,src:000000,op:arith8,pos:164,val:+2,+cov
+++ b/src/exchange/afl-tests/id:000478,src:000000,op:arith8,pos:164,val:+2,+cov
diff --git a/src/mint/afl-tests/id:000478,src:000000,op:arith8,pos:306,val:-20,+cov b/src/exchange/afl-tests/id:000478,src:000000,op:arith8,pos:306,val:-20,+cov
index dc245dfaa..dc245dfaa 100644
--- a/src/mint/afl-tests/id:000478,src:000000,op:arith8,pos:306,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000478,src:000000,op:arith8,pos:306,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000479,src:000000,op:arith8,pos:169,val:+7,+cov b/src/exchange/afl-tests/id:000479,src:000000,op:arith8,pos:169,val:+7,+cov
index 979c6d178..979c6d178 100644
--- a/src/mint/afl-tests/id:000479,src:000000,op:arith8,pos:169,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000479,src:000000,op:arith8,pos:169,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000479,src:000000,op:arith8,pos:314,val:-17,+cov b/src/exchange/afl-tests/id:000479,src:000000,op:arith8,pos:314,val:-17,+cov
index df6b70815..df6b70815 100644
--- a/src/mint/afl-tests/id:000479,src:000000,op:arith8,pos:314,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000479,src:000000,op:arith8,pos:314,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000480,src:000000,op:arith8,pos:169,val:-9,+cov b/src/exchange/afl-tests/id:000480,src:000000,op:arith8,pos:169,val:-9,+cov
index cff131ce3..cff131ce3 100644
--- a/src/mint/afl-tests/id:000480,src:000000,op:arith8,pos:169,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000480,src:000000,op:arith8,pos:169,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000480,src:000000,op:arith8,pos:315,val:-17,+cov b/src/exchange/afl-tests/id:000480,src:000000,op:arith8,pos:315,val:-17,+cov
index b14c57e7c..b14c57e7c 100644
--- a/src/mint/afl-tests/id:000480,src:000000,op:arith8,pos:315,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000480,src:000000,op:arith8,pos:315,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000481,src:000000,op:arith8,pos:169,val:+19,+cov b/src/exchange/afl-tests/id:000481,src:000000,op:arith8,pos:169,val:+19,+cov
index 5850b5927..5850b5927 100644
--- a/src/mint/afl-tests/id:000481,src:000000,op:arith8,pos:169,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000481,src:000000,op:arith8,pos:169,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000481,src:000000,op:arith8,pos:315,val:-19,+cov b/src/exchange/afl-tests/id:000481,src:000000,op:arith8,pos:315,val:-19,+cov
index a91fce20d..a91fce20d 100644
--- a/src/mint/afl-tests/id:000481,src:000000,op:arith8,pos:315,val:-19,+cov
+++ b/src/exchange/afl-tests/id:000481,src:000000,op:arith8,pos:315,val:-19,+cov
diff --git a/src/mint/afl-tests/id:000482,src:000000,op:arith8,pos:172,val:-3,+cov b/src/exchange/afl-tests/id:000482,src:000000,op:arith8,pos:172,val:-3,+cov
index 20a536e0f..20a536e0f 100644
--- a/src/mint/afl-tests/id:000482,src:000000,op:arith8,pos:172,val:-3,+cov
+++ b/src/exchange/afl-tests/id:000482,src:000000,op:arith8,pos:172,val:-3,+cov
diff --git a/src/mint/afl-tests/id:000482,src:000000,op:arith8,pos:315,val:-29,+cov b/src/exchange/afl-tests/id:000482,src:000000,op:arith8,pos:315,val:-29,+cov
index 4c75418da..4c75418da 100644
--- a/src/mint/afl-tests/id:000482,src:000000,op:arith8,pos:315,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000482,src:000000,op:arith8,pos:315,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000483,src:000000,op:arith8,pos:172,val:-33,+cov b/src/exchange/afl-tests/id:000483,src:000000,op:arith8,pos:172,val:-33,+cov
index 69ae6a5bb..69ae6a5bb 100644
--- a/src/mint/afl-tests/id:000483,src:000000,op:arith8,pos:172,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000483,src:000000,op:arith8,pos:172,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000483,src:000000,op:arith8,pos:316,val:+14,+cov b/src/exchange/afl-tests/id:000483,src:000000,op:arith8,pos:316,val:+14,+cov
index 435df94f5..435df94f5 100644
--- a/src/mint/afl-tests/id:000483,src:000000,op:arith8,pos:316,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000483,src:000000,op:arith8,pos:316,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000484,src:000000,op:arith8,pos:175,val:+20,+cov b/src/exchange/afl-tests/id:000484,src:000000,op:arith8,pos:175,val:+20,+cov
index a8bc9137c..a8bc9137c 100644
--- a/src/mint/afl-tests/id:000484,src:000000,op:arith8,pos:175,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000484,src:000000,op:arith8,pos:175,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000484,src:000000,op:arith8,pos:316,val:+17,+cov b/src/exchange/afl-tests/id:000484,src:000000,op:arith8,pos:316,val:+17,+cov
index 1982395ae..1982395ae 100644
--- a/src/mint/afl-tests/id:000484,src:000000,op:arith8,pos:316,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000484,src:000000,op:arith8,pos:316,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000485,src:000000,op:arith8,pos:176,val:+7,+cov b/src/exchange/afl-tests/id:000485,src:000000,op:arith8,pos:176,val:+7,+cov
index 223007cc6..223007cc6 100644
--- a/src/mint/afl-tests/id:000485,src:000000,op:arith8,pos:176,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000485,src:000000,op:arith8,pos:176,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000485,src:000000,op:arith8,pos:316,val:-23,+cov b/src/exchange/afl-tests/id:000485,src:000000,op:arith8,pos:316,val:-23,+cov
index 4c8cda9c1..4c8cda9c1 100644
--- a/src/mint/afl-tests/id:000485,src:000000,op:arith8,pos:316,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000485,src:000000,op:arith8,pos:316,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000486,src:000000,op:arith8,pos:176,val:-28,+cov b/src/exchange/afl-tests/id:000486,src:000000,op:arith8,pos:176,val:-28,+cov
index 7fbb8ba3a..7fbb8ba3a 100644
--- a/src/mint/afl-tests/id:000486,src:000000,op:arith8,pos:176,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000486,src:000000,op:arith8,pos:176,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000486,src:000000,op:arith8,pos:317,val:-30,+cov b/src/exchange/afl-tests/id:000486,src:000000,op:arith8,pos:317,val:-30,+cov
index 7f749ef56..7f749ef56 100644
--- a/src/mint/afl-tests/id:000486,src:000000,op:arith8,pos:317,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000486,src:000000,op:arith8,pos:317,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000487,src:000000,op:arith8,pos:177,val:+11,+cov b/src/exchange/afl-tests/id:000487,src:000000,op:arith8,pos:177,val:+11,+cov
index a7255c135..a7255c135 100644
--- a/src/mint/afl-tests/id:000487,src:000000,op:arith8,pos:177,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000487,src:000000,op:arith8,pos:177,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000487,src:000000,op:arith8,pos:319,val:-7,+cov b/src/exchange/afl-tests/id:000487,src:000000,op:arith8,pos:319,val:-7,+cov
index 09cc326d0..09cc326d0 100644
--- a/src/mint/afl-tests/id:000487,src:000000,op:arith8,pos:319,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000487,src:000000,op:arith8,pos:319,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000488,src:000000,op:arith8,pos:177,val:+17,+cov b/src/exchange/afl-tests/id:000488,src:000000,op:arith8,pos:177,val:+17,+cov
index 11f42ae9e..11f42ae9e 100644
--- a/src/mint/afl-tests/id:000488,src:000000,op:arith8,pos:177,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000488,src:000000,op:arith8,pos:177,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000488,src:000000,op:arith8,pos:319,val:+9,+cov b/src/exchange/afl-tests/id:000488,src:000000,op:arith8,pos:319,val:+9,+cov
index e4c0caf88..e4c0caf88 100644
--- a/src/mint/afl-tests/id:000488,src:000000,op:arith8,pos:319,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000488,src:000000,op:arith8,pos:319,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000489,src:000000,op:arith8,pos:177,val:+22,+cov b/src/exchange/afl-tests/id:000489,src:000000,op:arith8,pos:177,val:+22,+cov
index f59556be3..f59556be3 100644
--- a/src/mint/afl-tests/id:000489,src:000000,op:arith8,pos:177,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000489,src:000000,op:arith8,pos:177,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000489,src:000000,op:arith8,pos:320,val:-7,+cov b/src/exchange/afl-tests/id:000489,src:000000,op:arith8,pos:320,val:-7,+cov
index ee9ea63c0..ee9ea63c0 100644
--- a/src/mint/afl-tests/id:000489,src:000000,op:arith8,pos:320,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000489,src:000000,op:arith8,pos:320,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000490,src:000000,op:arith8,pos:178,val:-5,+cov b/src/exchange/afl-tests/id:000490,src:000000,op:arith8,pos:178,val:-5,+cov
index 767c0c043..767c0c043 100644
--- a/src/mint/afl-tests/id:000490,src:000000,op:arith8,pos:178,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000490,src:000000,op:arith8,pos:178,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000490,src:000000,op:arith8,pos:320,val:-25,+cov b/src/exchange/afl-tests/id:000490,src:000000,op:arith8,pos:320,val:-25,+cov
index 12f1566f3..12f1566f3 100644
--- a/src/mint/afl-tests/id:000490,src:000000,op:arith8,pos:320,val:-25,+cov
+++ b/src/exchange/afl-tests/id:000490,src:000000,op:arith8,pos:320,val:-25,+cov
diff --git a/src/mint/afl-tests/id:000491,src:000000,op:arith8,pos:178,val:+23,+cov b/src/exchange/afl-tests/id:000491,src:000000,op:arith8,pos:178,val:+23,+cov
index 699f2d607..699f2d607 100644
--- a/src/mint/afl-tests/id:000491,src:000000,op:arith8,pos:178,val:+23,+cov
+++ b/src/exchange/afl-tests/id:000491,src:000000,op:arith8,pos:178,val:+23,+cov
diff --git a/src/mint/afl-tests/id:000491,src:000000,op:arith8,pos:321,val:+11,+cov b/src/exchange/afl-tests/id:000491,src:000000,op:arith8,pos:321,val:+11,+cov
index b9ed1db61..b9ed1db61 100644
--- a/src/mint/afl-tests/id:000491,src:000000,op:arith8,pos:321,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000491,src:000000,op:arith8,pos:321,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000492,src:000000,op:arith8,pos:181,val:-12,+cov b/src/exchange/afl-tests/id:000492,src:000000,op:arith8,pos:181,val:-12,+cov
index 5ad7d66e7..5ad7d66e7 100644
--- a/src/mint/afl-tests/id:000492,src:000000,op:arith8,pos:181,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000492,src:000000,op:arith8,pos:181,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000492,src:000000,op:arith8,pos:321,val:-24,+cov b/src/exchange/afl-tests/id:000492,src:000000,op:arith8,pos:321,val:-24,+cov
index 5aed71dcb..5aed71dcb 100644
--- a/src/mint/afl-tests/id:000492,src:000000,op:arith8,pos:321,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000492,src:000000,op:arith8,pos:321,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000493,src:000000,op:arith8,pos:182,val:-15,+cov b/src/exchange/afl-tests/id:000493,src:000000,op:arith8,pos:182,val:-15,+cov
index 06dee424f..06dee424f 100644
--- a/src/mint/afl-tests/id:000493,src:000000,op:arith8,pos:182,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000493,src:000000,op:arith8,pos:182,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000493,src:000000,op:arith8,pos:322,val:-21,+cov b/src/exchange/afl-tests/id:000493,src:000000,op:arith8,pos:322,val:-21,+cov
index 555f46ae8..555f46ae8 100644
--- a/src/mint/afl-tests/id:000493,src:000000,op:arith8,pos:322,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000493,src:000000,op:arith8,pos:322,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000494,src:000000,op:arith8,pos:182,val:+22,+cov b/src/exchange/afl-tests/id:000494,src:000000,op:arith8,pos:182,val:+22,+cov
index 2089dffdd..2089dffdd 100644
--- a/src/mint/afl-tests/id:000494,src:000000,op:arith8,pos:182,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000494,src:000000,op:arith8,pos:182,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000494,src:000000,op:arith8,pos:326,val:-20,+cov b/src/exchange/afl-tests/id:000494,src:000000,op:arith8,pos:326,val:-20,+cov
index cc6db3b4b..cc6db3b4b 100644
--- a/src/mint/afl-tests/id:000494,src:000000,op:arith8,pos:326,val:-20,+cov
+++ b/src/exchange/afl-tests/id:000494,src:000000,op:arith8,pos:326,val:-20,+cov
diff --git a/src/mint/afl-tests/id:000495,src:000000,op:arith8,pos:183,val:-11 b/src/exchange/afl-tests/id:000495,src:000000,op:arith8,pos:183,val:-11
index 25d10dc00..25d10dc00 100644
--- a/src/mint/afl-tests/id:000495,src:000000,op:arith8,pos:183,val:-11
+++ b/src/exchange/afl-tests/id:000495,src:000000,op:arith8,pos:183,val:-11
diff --git a/src/mint/afl-tests/id:000495,src:000000,op:arith8,pos:328,val:+27,+cov b/src/exchange/afl-tests/id:000495,src:000000,op:arith8,pos:328,val:+27,+cov
index ecb03d5da..ecb03d5da 100644
--- a/src/mint/afl-tests/id:000495,src:000000,op:arith8,pos:328,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000495,src:000000,op:arith8,pos:328,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000496,src:000000,op:arith8,pos:183,val:+15,+cov b/src/exchange/afl-tests/id:000496,src:000000,op:arith8,pos:183,val:+15,+cov
index 6f40bcc02..6f40bcc02 100644
--- a/src/mint/afl-tests/id:000496,src:000000,op:arith8,pos:183,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000496,src:000000,op:arith8,pos:183,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000496,src:000000,op:arith8,pos:328,val:-27,+cov b/src/exchange/afl-tests/id:000496,src:000000,op:arith8,pos:328,val:-27,+cov
index 7afc12382..7afc12382 100644
--- a/src/mint/afl-tests/id:000496,src:000000,op:arith8,pos:328,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000496,src:000000,op:arith8,pos:328,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000497,src:000000,op:arith8,pos:184,val:-14,+cov b/src/exchange/afl-tests/id:000497,src:000000,op:arith8,pos:184,val:-14,+cov
index 3524e63c0..3524e63c0 100644
--- a/src/mint/afl-tests/id:000497,src:000000,op:arith8,pos:184,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000497,src:000000,op:arith8,pos:184,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000497,src:000000,op:arith8,pos:329,val:+5,+cov b/src/exchange/afl-tests/id:000497,src:000000,op:arith8,pos:329,val:+5,+cov
index c3283926f..c3283926f 100644
--- a/src/mint/afl-tests/id:000497,src:000000,op:arith8,pos:329,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000497,src:000000,op:arith8,pos:329,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000498,src:000000,op:arith8,pos:184,val:+33,+cov b/src/exchange/afl-tests/id:000498,src:000000,op:arith8,pos:184,val:+33,+cov
index 837a3a2b0..837a3a2b0 100644
--- a/src/mint/afl-tests/id:000498,src:000000,op:arith8,pos:184,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000498,src:000000,op:arith8,pos:184,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000498,src:000000,op:arith8,pos:329,val:-24,+cov b/src/exchange/afl-tests/id:000498,src:000000,op:arith8,pos:329,val:-24,+cov
index cc69a5981..cc69a5981 100644
--- a/src/mint/afl-tests/id:000498,src:000000,op:arith8,pos:329,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000498,src:000000,op:arith8,pos:329,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000499,src:000000,op:arith8,pos:184,val:-35,+cov b/src/exchange/afl-tests/id:000499,src:000000,op:arith8,pos:184,val:-35,+cov
index c5469e461..c5469e461 100644
--- a/src/mint/afl-tests/id:000499,src:000000,op:arith8,pos:184,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000499,src:000000,op:arith8,pos:184,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000499,src:000000,op:arith8,pos:330,val:-3,+cov b/src/exchange/afl-tests/id:000499,src:000000,op:arith8,pos:330,val:-3,+cov
index 2a7d42a57..2a7d42a57 100644
--- a/src/mint/afl-tests/id:000499,src:000000,op:arith8,pos:330,val:-3,+cov
+++ b/src/exchange/afl-tests/id:000499,src:000000,op:arith8,pos:330,val:-3,+cov
diff --git a/src/mint/afl-tests/id:000500,src:000000,op:arith8,pos:185,val:+3,+cov b/src/exchange/afl-tests/id:000500,src:000000,op:arith8,pos:185,val:+3,+cov
index 0d75e538d..0d75e538d 100644
--- a/src/mint/afl-tests/id:000500,src:000000,op:arith8,pos:185,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000500,src:000000,op:arith8,pos:185,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000500,src:000000,op:arith8,pos:331,val:-14,+cov b/src/exchange/afl-tests/id:000500,src:000000,op:arith8,pos:331,val:-14,+cov
index 05d9c2e61..05d9c2e61 100644
--- a/src/mint/afl-tests/id:000500,src:000000,op:arith8,pos:331,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000500,src:000000,op:arith8,pos:331,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000501,src:000000,op:arith8,pos:185,val:+7,+cov b/src/exchange/afl-tests/id:000501,src:000000,op:arith8,pos:185,val:+7,+cov
index bfd66f575..bfd66f575 100644
--- a/src/mint/afl-tests/id:000501,src:000000,op:arith8,pos:185,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000501,src:000000,op:arith8,pos:185,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000501,src:000000,op:arith8,pos:332,val:-15,+cov b/src/exchange/afl-tests/id:000501,src:000000,op:arith8,pos:332,val:-15,+cov
index e25945929..e25945929 100644
--- a/src/mint/afl-tests/id:000501,src:000000,op:arith8,pos:332,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000501,src:000000,op:arith8,pos:332,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000502,src:000000,op:arith16,pos:33,val:-12,+cov b/src/exchange/afl-tests/id:000502,src:000000,op:arith16,pos:33,val:-12,+cov
index 4cc8f8d31..4cc8f8d31 100644
--- a/src/mint/afl-tests/id:000502,src:000000,op:arith16,pos:33,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000502,src:000000,op:arith16,pos:33,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000502,src:000000,op:arith8,pos:192,val:+9,+cov b/src/exchange/afl-tests/id:000502,src:000000,op:arith8,pos:192,val:+9,+cov
index e06cf9443..e06cf9443 100644
--- a/src/mint/afl-tests/id:000502,src:000000,op:arith8,pos:192,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000502,src:000000,op:arith8,pos:192,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000503,src:000000,op:arith16,pos:65,val:be:-27,+cov b/src/exchange/afl-tests/id:000503,src:000000,op:arith16,pos:65,val:be:-27,+cov
index 5a3f0f67c..5a3f0f67c 100644
--- a/src/mint/afl-tests/id:000503,src:000000,op:arith16,pos:65,val:be:-27,+cov
+++ b/src/exchange/afl-tests/id:000503,src:000000,op:arith16,pos:65,val:be:-27,+cov
diff --git a/src/mint/afl-tests/id:000503,src:000000,op:arith8,pos:237,val:-26,+cov b/src/exchange/afl-tests/id:000503,src:000000,op:arith8,pos:237,val:-26,+cov
index 44551d5f3..44551d5f3 100644
--- a/src/mint/afl-tests/id:000503,src:000000,op:arith8,pos:237,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000503,src:000000,op:arith8,pos:237,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000504,src:000000,op:arith8,pos:238,val:+5,+cov b/src/exchange/afl-tests/id:000504,src:000000,op:arith8,pos:238,val:+5,+cov
index adc521b02..adc521b02 100644
--- a/src/mint/afl-tests/id:000504,src:000000,op:arith8,pos:238,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000504,src:000000,op:arith8,pos:238,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000504,src:000000,op:int8,pos:6,val:+0 b/src/exchange/afl-tests/id:000504,src:000000,op:int8,pos:6,val:+0
index 1617639fa..1617639fa 100644
--- a/src/mint/afl-tests/id:000504,src:000000,op:int8,pos:6,val:+0
+++ b/src/exchange/afl-tests/id:000504,src:000000,op:int8,pos:6,val:+0
Binary files differ
diff --git a/src/mint/afl-tests/id:000505,src:000000,op:arith8,pos:241,val:+7,+cov b/src/exchange/afl-tests/id:000505,src:000000,op:arith8,pos:241,val:+7,+cov
index d8d8f1c3a..d8d8f1c3a 100644
--- a/src/mint/afl-tests/id:000505,src:000000,op:arith8,pos:241,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000505,src:000000,op:arith8,pos:241,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000505,src:000000,op:int8,pos:7,val:+0 b/src/exchange/afl-tests/id:000505,src:000000,op:int8,pos:7,val:+0
index bf79da717..bf79da717 100644
--- a/src/mint/afl-tests/id:000505,src:000000,op:int8,pos:7,val:+0
+++ b/src/exchange/afl-tests/id:000505,src:000000,op:int8,pos:7,val:+0
Binary files differ
diff --git a/src/mint/afl-tests/id:000506,src:000000,op:arith8,pos:268,val:-4,+cov b/src/exchange/afl-tests/id:000506,src:000000,op:arith8,pos:268,val:-4,+cov
index cd62df7e1..cd62df7e1 100644
--- a/src/mint/afl-tests/id:000506,src:000000,op:arith8,pos:268,val:-4,+cov
+++ b/src/exchange/afl-tests/id:000506,src:000000,op:arith8,pos:268,val:-4,+cov
diff --git a/src/mint/afl-tests/id:000506,src:000000,op:int8,pos:9,val:+0 b/src/exchange/afl-tests/id:000506,src:000000,op:int8,pos:9,val:+0
index 3bd6a1d9b..3bd6a1d9b 100644
--- a/src/mint/afl-tests/id:000506,src:000000,op:int8,pos:9,val:+0
+++ b/src/exchange/afl-tests/id:000506,src:000000,op:int8,pos:9,val:+0
Binary files differ
diff --git a/src/mint/afl-tests/id:000507,src:000000,op:arith8,pos:269,val:+19,+cov b/src/exchange/afl-tests/id:000507,src:000000,op:arith8,pos:269,val:+19,+cov
index 3af908cef..3af908cef 100644
--- a/src/mint/afl-tests/id:000507,src:000000,op:arith8,pos:269,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000507,src:000000,op:arith8,pos:269,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000507,src:000000,op:int8,pos:26,val:+32,+cov b/src/exchange/afl-tests/id:000507,src:000000,op:int8,pos:26,val:+32,+cov
index 2bd400350..2bd400350 100644
--- a/src/mint/afl-tests/id:000507,src:000000,op:int8,pos:26,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000507,src:000000,op:int8,pos:26,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000508,src:000000,op:arith8,pos:271,val:-12,+cov b/src/exchange/afl-tests/id:000508,src:000000,op:arith8,pos:271,val:-12,+cov
index 984918f2b..984918f2b 100644
--- a/src/mint/afl-tests/id:000508,src:000000,op:arith8,pos:271,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000508,src:000000,op:arith8,pos:271,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000508,src:000000,op:int8,pos:27,val:+127,+cov b/src/exchange/afl-tests/id:000508,src:000000,op:int8,pos:27,val:+127,+cov
index 1b108c548..1b108c548 100644
--- a/src/mint/afl-tests/id:000508,src:000000,op:int8,pos:27,val:+127,+cov
+++ b/src/exchange/afl-tests/id:000508,src:000000,op:int8,pos:27,val:+127,+cov
diff --git a/src/mint/afl-tests/id:000509,src:000000,op:arith8,pos:272,val:+7,+cov b/src/exchange/afl-tests/id:000509,src:000000,op:arith8,pos:272,val:+7,+cov
index 84afe05df..84afe05df 100644
--- a/src/mint/afl-tests/id:000509,src:000000,op:arith8,pos:272,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000509,src:000000,op:arith8,pos:272,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000509,src:000000,op:int8,pos:34,val:+0,+cov b/src/exchange/afl-tests/id:000509,src:000000,op:int8,pos:34,val:+0,+cov
index b44840248..b44840248 100644
--- a/src/mint/afl-tests/id:000509,src:000000,op:int8,pos:34,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000509,src:000000,op:int8,pos:34,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000510,src:000000,op:arith8,pos:274,val:+11,+cov b/src/exchange/afl-tests/id:000510,src:000000,op:arith8,pos:274,val:+11,+cov
index 63916d85a..63916d85a 100644
--- a/src/mint/afl-tests/id:000510,src:000000,op:arith8,pos:274,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000510,src:000000,op:arith8,pos:274,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000510,src:000000,op:int8,pos:40,val:+0,+cov b/src/exchange/afl-tests/id:000510,src:000000,op:int8,pos:40,val:+0,+cov
index 1753c57a2..1753c57a2 100644
--- a/src/mint/afl-tests/id:000510,src:000000,op:int8,pos:40,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000510,src:000000,op:int8,pos:40,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000511,src:000000,op:arith8,pos:274,val:+25,+cov b/src/exchange/afl-tests/id:000511,src:000000,op:arith8,pos:274,val:+25,+cov
index f2d727b45..f2d727b45 100644
--- a/src/mint/afl-tests/id:000511,src:000000,op:arith8,pos:274,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000511,src:000000,op:arith8,pos:274,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000511,src:000000,op:int8,pos:40,val:+32 b/src/exchange/afl-tests/id:000511,src:000000,op:int8,pos:40,val:+32
index 478612835..478612835 100644
--- a/src/mint/afl-tests/id:000511,src:000000,op:int8,pos:40,val:+32
+++ b/src/exchange/afl-tests/id:000511,src:000000,op:int8,pos:40,val:+32
diff --git a/src/mint/afl-tests/id:000512,src:000000,op:arith8,pos:275,val:-11,+cov b/src/exchange/afl-tests/id:000512,src:000000,op:arith8,pos:275,val:-11,+cov
index ffb3010f1..ffb3010f1 100644
--- a/src/mint/afl-tests/id:000512,src:000000,op:arith8,pos:275,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000512,src:000000,op:arith8,pos:275,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000512,src:000000,op:int8,pos:46,val:+1,+cov b/src/exchange/afl-tests/id:000512,src:000000,op:int8,pos:46,val:+1,+cov
index ba5eeaa7d..ba5eeaa7d 100644
--- a/src/mint/afl-tests/id:000512,src:000000,op:int8,pos:46,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000512,src:000000,op:int8,pos:46,val:+1,+cov
diff --git a/src/mint/afl-tests/id:000513,src:000000,op:arith8,pos:275,val:-12,+cov b/src/exchange/afl-tests/id:000513,src:000000,op:arith8,pos:275,val:-12,+cov
index b23a69c22..b23a69c22 100644
--- a/src/mint/afl-tests/id:000513,src:000000,op:arith8,pos:275,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000513,src:000000,op:arith8,pos:275,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000513,src:000000,op:int8,pos:51,val:+1 b/src/exchange/afl-tests/id:000513,src:000000,op:int8,pos:51,val:+1
index d5b552421..d5b552421 100644
--- a/src/mint/afl-tests/id:000513,src:000000,op:int8,pos:51,val:+1
+++ b/src/exchange/afl-tests/id:000513,src:000000,op:int8,pos:51,val:+1
diff --git a/src/mint/afl-tests/id:000514,src:000000,op:arith8,pos:275,val:+27,+cov b/src/exchange/afl-tests/id:000514,src:000000,op:arith8,pos:275,val:+27,+cov
index f85ed882e..f85ed882e 100644
--- a/src/mint/afl-tests/id:000514,src:000000,op:arith8,pos:275,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000514,src:000000,op:arith8,pos:275,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000514,src:000000,op:int8,pos:52,val:-128,+cov b/src/exchange/afl-tests/id:000514,src:000000,op:int8,pos:52,val:-128,+cov
index 93902d9a7..93902d9a7 100644
--- a/src/mint/afl-tests/id:000514,src:000000,op:int8,pos:52,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000514,src:000000,op:int8,pos:52,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000515,src:000000,op:arith8,pos:277,val:-10,+cov b/src/exchange/afl-tests/id:000515,src:000000,op:arith8,pos:277,val:-10,+cov
index 52881ecd8..52881ecd8 100644
--- a/src/mint/afl-tests/id:000515,src:000000,op:arith8,pos:277,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000515,src:000000,op:arith8,pos:277,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000515,src:000000,op:int8,pos:53,val:-1,+cov b/src/exchange/afl-tests/id:000515,src:000000,op:int8,pos:53,val:-1,+cov
index dd38e8b23..dd38e8b23 100644
--- a/src/mint/afl-tests/id:000515,src:000000,op:int8,pos:53,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000515,src:000000,op:int8,pos:53,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000516,src:000000,op:arith8,pos:277,val:+35,+cov b/src/exchange/afl-tests/id:000516,src:000000,op:arith8,pos:277,val:+35,+cov
index 5ba54d7fd..5ba54d7fd 100644
--- a/src/mint/afl-tests/id:000516,src:000000,op:arith8,pos:277,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000516,src:000000,op:arith8,pos:277,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000516,src:000000,op:int8,pos:69,val:+32,+cov b/src/exchange/afl-tests/id:000516,src:000000,op:int8,pos:69,val:+32,+cov
index b37e6ccf8..b37e6ccf8 100644
--- a/src/mint/afl-tests/id:000516,src:000000,op:int8,pos:69,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000516,src:000000,op:int8,pos:69,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000517,src:000000,op:arith8,pos:279,val:+28,+cov b/src/exchange/afl-tests/id:000517,src:000000,op:arith8,pos:279,val:+28,+cov
index 22434630a..22434630a 100644
--- a/src/mint/afl-tests/id:000517,src:000000,op:arith8,pos:279,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000517,src:000000,op:arith8,pos:279,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000517,src:000000,op:int8,pos:70,val:+32,+cov b/src/exchange/afl-tests/id:000517,src:000000,op:int8,pos:70,val:+32,+cov
index fb2181584..fb2181584 100644
--- a/src/mint/afl-tests/id:000517,src:000000,op:int8,pos:70,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000517,src:000000,op:int8,pos:70,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000518,src:000000,op:arith8,pos:290,val:-28,+cov b/src/exchange/afl-tests/id:000518,src:000000,op:arith8,pos:290,val:-28,+cov
index 5d9d1b1f0..5d9d1b1f0 100644
--- a/src/mint/afl-tests/id:000518,src:000000,op:arith8,pos:290,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000518,src:000000,op:arith8,pos:290,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000518,src:000000,op:int8,pos:71,val:+64,+cov b/src/exchange/afl-tests/id:000518,src:000000,op:int8,pos:71,val:+64,+cov
index 9973a3a51..9973a3a51 100644
--- a/src/mint/afl-tests/id:000518,src:000000,op:int8,pos:71,val:+64,+cov
+++ b/src/exchange/afl-tests/id:000518,src:000000,op:int8,pos:71,val:+64,+cov
diff --git a/src/mint/afl-tests/id:000519,src:000000,op:arith8,pos:305,val:-3,+cov b/src/exchange/afl-tests/id:000519,src:000000,op:arith8,pos:305,val:-3,+cov
index 95d8c6cbd..95d8c6cbd 100644
--- a/src/mint/afl-tests/id:000519,src:000000,op:arith8,pos:305,val:-3,+cov
+++ b/src/exchange/afl-tests/id:000519,src:000000,op:arith8,pos:305,val:-3,+cov
diff --git a/src/mint/afl-tests/id:000519,src:000000,op:int8,pos:74,val:-1,+cov b/src/exchange/afl-tests/id:000519,src:000000,op:int8,pos:74,val:-1,+cov
index eaeb46aa7..eaeb46aa7 100644
--- a/src/mint/afl-tests/id:000519,src:000000,op:int8,pos:74,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000519,src:000000,op:int8,pos:74,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000520,src:000000,op:arith8,pos:306,val:+7,+cov b/src/exchange/afl-tests/id:000520,src:000000,op:arith8,pos:306,val:+7,+cov
index 33de1560e..33de1560e 100644
--- a/src/mint/afl-tests/id:000520,src:000000,op:arith8,pos:306,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000520,src:000000,op:arith8,pos:306,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000520,src:000000,op:int8,pos:115,val:+0,+cov b/src/exchange/afl-tests/id:000520,src:000000,op:int8,pos:115,val:+0,+cov
index fdb09920c..fdb09920c 100644
--- a/src/mint/afl-tests/id:000520,src:000000,op:int8,pos:115,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000520,src:000000,op:int8,pos:115,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000521,src:000000,op:arith8,pos:306,val:-12,+cov b/src/exchange/afl-tests/id:000521,src:000000,op:arith8,pos:306,val:-12,+cov
index 11cbf677b..11cbf677b 100644
--- a/src/mint/afl-tests/id:000521,src:000000,op:arith8,pos:306,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000521,src:000000,op:arith8,pos:306,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000521,src:000000,op:int8,pos:188,val:+1,+cov b/src/exchange/afl-tests/id:000521,src:000000,op:int8,pos:188,val:+1,+cov
index 215d414bf..215d414bf 100644
--- a/src/mint/afl-tests/id:000521,src:000000,op:int8,pos:188,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000521,src:000000,op:int8,pos:188,val:+1,+cov
diff --git a/src/mint/afl-tests/id:000522,src:000000,op:arith8,pos:306,val:+20,+cov b/src/exchange/afl-tests/id:000522,src:000000,op:arith8,pos:306,val:+20,+cov
index 31fc87302..31fc87302 100644
--- a/src/mint/afl-tests/id:000522,src:000000,op:arith8,pos:306,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000522,src:000000,op:arith8,pos:306,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000522,src:000000,op:int8,pos:276,val:+100,+cov b/src/exchange/afl-tests/id:000522,src:000000,op:int8,pos:276,val:+100,+cov
index 1d58eb298..1d58eb298 100644
--- a/src/mint/afl-tests/id:000522,src:000000,op:int8,pos:276,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000522,src:000000,op:int8,pos:276,val:+100,+cov
diff --git a/src/mint/afl-tests/id:000523,src:000000,op:arith8,pos:307,val:+13,+cov b/src/exchange/afl-tests/id:000523,src:000000,op:arith8,pos:307,val:+13,+cov
index f2156516a..f2156516a 100644
--- a/src/mint/afl-tests/id:000523,src:000000,op:arith8,pos:307,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000523,src:000000,op:arith8,pos:307,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000523,src:000000,op:int8,pos:307,val:+32,+cov b/src/exchange/afl-tests/id:000523,src:000000,op:int8,pos:307,val:+32,+cov
index a5eb0a938..a5eb0a938 100644
--- a/src/mint/afl-tests/id:000523,src:000000,op:int8,pos:307,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000523,src:000000,op:int8,pos:307,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000524,src:000000,op:arith8,pos:308,val:+19,+cov b/src/exchange/afl-tests/id:000524,src:000000,op:arith8,pos:308,val:+19,+cov
index 5b763e04c..5b763e04c 100644
--- a/src/mint/afl-tests/id:000524,src:000000,op:arith8,pos:308,val:+19,+cov
+++ b/src/exchange/afl-tests/id:000524,src:000000,op:arith8,pos:308,val:+19,+cov
diff --git a/src/mint/afl-tests/id:000524,src:000000,op:int8,pos:313,val:+64,+cov b/src/exchange/afl-tests/id:000524,src:000000,op:int8,pos:313,val:+64,+cov
index 6448809a0..6448809a0 100644
--- a/src/mint/afl-tests/id:000524,src:000000,op:int8,pos:313,val:+64,+cov
+++ b/src/exchange/afl-tests/id:000524,src:000000,op:int8,pos:313,val:+64,+cov
diff --git a/src/mint/afl-tests/id:000525,src:000000,op:arith8,pos:308,val:-27,+cov b/src/exchange/afl-tests/id:000525,src:000000,op:arith8,pos:308,val:-27,+cov
index 7ab902fb3..7ab902fb3 100644
--- a/src/mint/afl-tests/id:000525,src:000000,op:arith8,pos:308,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000525,src:000000,op:arith8,pos:308,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000525,src:000000,op:int8,pos:314,val:-1,+cov b/src/exchange/afl-tests/id:000525,src:000000,op:int8,pos:314,val:-1,+cov
index 33ac0ef2b..33ac0ef2b 100644
--- a/src/mint/afl-tests/id:000525,src:000000,op:int8,pos:314,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000525,src:000000,op:int8,pos:314,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000526,src:000000,op:arith8,pos:312,val:+3,+cov b/src/exchange/afl-tests/id:000526,src:000000,op:arith8,pos:312,val:+3,+cov
index 419f8d5e6..419f8d5e6 100644
--- a/src/mint/afl-tests/id:000526,src:000000,op:arith8,pos:312,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000526,src:000000,op:arith8,pos:312,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000526,src:000000,op:int8,pos:322,val:+32,+cov b/src/exchange/afl-tests/id:000526,src:000000,op:int8,pos:322,val:+32,+cov
index ec280ab06..ec280ab06 100644
--- a/src/mint/afl-tests/id:000526,src:000000,op:int8,pos:322,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000526,src:000000,op:int8,pos:322,val:+32,+cov
diff --git a/src/mint/afl-tests/id:000527,src:000000,op:arith8,pos:312,val:+5,+cov b/src/exchange/afl-tests/id:000527,src:000000,op:arith8,pos:312,val:+5,+cov
index f9e66d758..f9e66d758 100644
--- a/src/mint/afl-tests/id:000527,src:000000,op:arith8,pos:312,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000527,src:000000,op:arith8,pos:312,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000527,src:000000,op:int16,pos:25,val:be:+100,+cov b/src/exchange/afl-tests/id:000527,src:000000,op:int16,pos:25,val:be:+100,+cov
index 384fad6ab..384fad6ab 100644
--- a/src/mint/afl-tests/id:000527,src:000000,op:int16,pos:25,val:be:+100,+cov
+++ b/src/exchange/afl-tests/id:000527,src:000000,op:int16,pos:25,val:be:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000528,src:000000,op:arith8,pos:312,val:-11,+cov b/src/exchange/afl-tests/id:000528,src:000000,op:arith8,pos:312,val:-11,+cov
index c42a0a94f..c42a0a94f 100644
--- a/src/mint/afl-tests/id:000528,src:000000,op:arith8,pos:312,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000528,src:000000,op:arith8,pos:312,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000528,src:000000,op:int16,pos:29,val:-1,+cov b/src/exchange/afl-tests/id:000528,src:000000,op:int16,pos:29,val:-1,+cov
index 82b6ef639..82b6ef639 100644
--- a/src/mint/afl-tests/id:000528,src:000000,op:int16,pos:29,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000528,src:000000,op:int16,pos:29,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000529,src:000000,op:arith8,pos:313,val:-33,+cov b/src/exchange/afl-tests/id:000529,src:000000,op:arith8,pos:313,val:-33,+cov
index 054577779..054577779 100644
--- a/src/mint/afl-tests/id:000529,src:000000,op:arith8,pos:313,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000529,src:000000,op:arith8,pos:313,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000529,src:000000,op:int16,pos:32,val:+32767,+cov b/src/exchange/afl-tests/id:000529,src:000000,op:int16,pos:32,val:+32767,+cov
index a8e3abbe8..a8e3abbe8 100644
--- a/src/mint/afl-tests/id:000529,src:000000,op:int16,pos:32,val:+32767,+cov
+++ b/src/exchange/afl-tests/id:000529,src:000000,op:int16,pos:32,val:+32767,+cov
diff --git a/src/mint/afl-tests/id:000530,src:000000,op:arith8,pos:314,val:-3,+cov b/src/exchange/afl-tests/id:000530,src:000000,op:arith8,pos:314,val:-3,+cov
index db962f187..db962f187 100644
--- a/src/mint/afl-tests/id:000530,src:000000,op:arith8,pos:314,val:-3,+cov
+++ b/src/exchange/afl-tests/id:000530,src:000000,op:arith8,pos:314,val:-3,+cov
diff --git a/src/mint/afl-tests/id:000530,src:000000,op:int16,pos:41,val:-128,+cov b/src/exchange/afl-tests/id:000530,src:000000,op:int16,pos:41,val:-128,+cov
index e5c56d098..e5c56d098 100644
--- a/src/mint/afl-tests/id:000530,src:000000,op:int16,pos:41,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000530,src:000000,op:int16,pos:41,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000531,src:000000,op:arith8,pos:314,val:-25,+cov b/src/exchange/afl-tests/id:000531,src:000000,op:arith8,pos:314,val:-25,+cov
index 2160ca427..2160ca427 100644
--- a/src/mint/afl-tests/id:000531,src:000000,op:arith8,pos:314,val:-25,+cov
+++ b/src/exchange/afl-tests/id:000531,src:000000,op:arith8,pos:314,val:-25,+cov
diff --git a/src/mint/afl-tests/id:000531,src:000000,op:int16,pos:41,val:+32,+cov b/src/exchange/afl-tests/id:000531,src:000000,op:int16,pos:41,val:+32,+cov
index e645b00c9..e645b00c9 100644
--- a/src/mint/afl-tests/id:000531,src:000000,op:int16,pos:41,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000531,src:000000,op:int16,pos:41,val:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000532,src:000000,op:arith8,pos:316,val:+20,+cov b/src/exchange/afl-tests/id:000532,src:000000,op:arith8,pos:316,val:+20,+cov
index d451a7b00..d451a7b00 100644
--- a/src/mint/afl-tests/id:000532,src:000000,op:arith8,pos:316,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000532,src:000000,op:arith8,pos:316,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000532,src:000000,op:int16,pos:42,val:+64,+cov b/src/exchange/afl-tests/id:000532,src:000000,op:int16,pos:42,val:+64,+cov
index 3d44f62bc..3d44f62bc 100644
--- a/src/mint/afl-tests/id:000532,src:000000,op:int16,pos:42,val:+64,+cov
+++ b/src/exchange/afl-tests/id:000532,src:000000,op:int16,pos:42,val:+64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000533,src:000000,op:arith8,pos:316,val:-23,+cov b/src/exchange/afl-tests/id:000533,src:000000,op:arith8,pos:316,val:-23,+cov
index 4c8cda9c1..4c8cda9c1 100644
--- a/src/mint/afl-tests/id:000533,src:000000,op:arith8,pos:316,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000533,src:000000,op:arith8,pos:316,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000533,src:000000,op:int16,pos:47,val:+128,+cov b/src/exchange/afl-tests/id:000533,src:000000,op:int16,pos:47,val:+128,+cov
index 6706ee7fa..6706ee7fa 100644
--- a/src/mint/afl-tests/id:000533,src:000000,op:int16,pos:47,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000533,src:000000,op:int16,pos:47,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000534,src:000000,op:arith8,pos:316,val:-28,+cov b/src/exchange/afl-tests/id:000534,src:000000,op:arith8,pos:316,val:-28,+cov
index 13473031a..13473031a 100644
--- a/src/mint/afl-tests/id:000534,src:000000,op:arith8,pos:316,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000534,src:000000,op:arith8,pos:316,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000534,src:000000,op:int16,pos:48,val:be:+1000,+cov b/src/exchange/afl-tests/id:000534,src:000000,op:int16,pos:48,val:be:+1000,+cov
index 9fe141673..9fe141673 100644
--- a/src/mint/afl-tests/id:000534,src:000000,op:int16,pos:48,val:be:+1000,+cov
+++ b/src/exchange/afl-tests/id:000534,src:000000,op:int16,pos:48,val:be:+1000,+cov
diff --git a/src/mint/afl-tests/id:000535,src:000000,op:arith8,pos:317,val:-31,+cov b/src/exchange/afl-tests/id:000535,src:000000,op:arith8,pos:317,val:-31,+cov
index c0e1ac204..c0e1ac204 100644
--- a/src/mint/afl-tests/id:000535,src:000000,op:arith8,pos:317,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000535,src:000000,op:arith8,pos:317,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000535,src:000000,op:int16,pos:50,val:+16,+cov b/src/exchange/afl-tests/id:000535,src:000000,op:int16,pos:50,val:+16,+cov
index 96e2a8f09..96e2a8f09 100644
--- a/src/mint/afl-tests/id:000535,src:000000,op:int16,pos:50,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000535,src:000000,op:int16,pos:50,val:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000536,src:000000,op:arith8,pos:318,val:+23,+cov b/src/exchange/afl-tests/id:000536,src:000000,op:arith8,pos:318,val:+23,+cov
index 05c5c4a56..05c5c4a56 100644
--- a/src/mint/afl-tests/id:000536,src:000000,op:arith8,pos:318,val:+23,+cov
+++ b/src/exchange/afl-tests/id:000536,src:000000,op:arith8,pos:318,val:+23,+cov
diff --git a/src/mint/afl-tests/id:000536,src:000000,op:int16,pos:50,val:be:+1024,+cov b/src/exchange/afl-tests/id:000536,src:000000,op:int16,pos:50,val:be:+1024,+cov
index 21b0ca0a4..21b0ca0a4 100644
--- a/src/mint/afl-tests/id:000536,src:000000,op:int16,pos:50,val:be:+1024,+cov
+++ b/src/exchange/afl-tests/id:000536,src:000000,op:int16,pos:50,val:be:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000537,src:000000,op:arith8,pos:319,val:-12,+cov b/src/exchange/afl-tests/id:000537,src:000000,op:arith8,pos:319,val:-12,+cov
index 8f779e896..8f779e896 100644
--- a/src/mint/afl-tests/id:000537,src:000000,op:arith8,pos:319,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000537,src:000000,op:arith8,pos:319,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000537,src:000000,op:int16,pos:52,val:-129,+cov b/src/exchange/afl-tests/id:000537,src:000000,op:int16,pos:52,val:-129,+cov
index 3a2388b2e..3a2388b2e 100644
--- a/src/mint/afl-tests/id:000537,src:000000,op:int16,pos:52,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000537,src:000000,op:int16,pos:52,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000538,src:000000,op:arith8,pos:320,val:+17,+cov b/src/exchange/afl-tests/id:000538,src:000000,op:arith8,pos:320,val:+17,+cov
index 6d98cc067..6d98cc067 100644
--- a/src/mint/afl-tests/id:000538,src:000000,op:arith8,pos:320,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000538,src:000000,op:arith8,pos:320,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000538,src:000000,op:int16,pos:52,val:+128,+cov b/src/exchange/afl-tests/id:000538,src:000000,op:int16,pos:52,val:+128,+cov
index 61400e2da..61400e2da 100644
--- a/src/mint/afl-tests/id:000538,src:000000,op:int16,pos:52,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000538,src:000000,op:int16,pos:52,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000539,src:000000,op:arith8,pos:320,val:-31,+cov b/src/exchange/afl-tests/id:000539,src:000000,op:arith8,pos:320,val:-31,+cov
index 1a8d6bb70..1a8d6bb70 100644
--- a/src/mint/afl-tests/id:000539,src:000000,op:arith8,pos:320,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000539,src:000000,op:arith8,pos:320,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000539,src:000000,op:int16,pos:52,val:be:+255,+cov b/src/exchange/afl-tests/id:000539,src:000000,op:int16,pos:52,val:be:+255,+cov
index 022b499b1..022b499b1 100644
--- a/src/mint/afl-tests/id:000539,src:000000,op:int16,pos:52,val:be:+255,+cov
+++ b/src/exchange/afl-tests/id:000539,src:000000,op:int16,pos:52,val:be:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000540,src:000000,op:arith8,pos:321,val:-34,+cov b/src/exchange/afl-tests/id:000540,src:000000,op:arith8,pos:321,val:-34,+cov
index 49a3d1a94..49a3d1a94 100644
--- a/src/mint/afl-tests/id:000540,src:000000,op:arith8,pos:321,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000540,src:000000,op:arith8,pos:321,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000540,src:000000,op:int16,pos:53,val:+0,+cov b/src/exchange/afl-tests/id:000540,src:000000,op:int16,pos:53,val:+0,+cov
index 9e4846de1..9e4846de1 100644
--- a/src/mint/afl-tests/id:000540,src:000000,op:int16,pos:53,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000540,src:000000,op:int16,pos:53,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000541,src:000000,op:arith8,pos:322,val:+3,+cov b/src/exchange/afl-tests/id:000541,src:000000,op:arith8,pos:322,val:+3,+cov
index 088824785..088824785 100644
--- a/src/mint/afl-tests/id:000541,src:000000,op:arith8,pos:322,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000541,src:000000,op:arith8,pos:322,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000541,src:000000,op:int16,pos:54,val:+1,+cov b/src/exchange/afl-tests/id:000541,src:000000,op:int16,pos:54,val:+1,+cov
index d95a3bd2e..d95a3bd2e 100644
--- a/src/mint/afl-tests/id:000541,src:000000,op:int16,pos:54,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000541,src:000000,op:int16,pos:54,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000542,src:000000,op:arith8,pos:322,val:+7,+cov b/src/exchange/afl-tests/id:000542,src:000000,op:arith8,pos:322,val:+7,+cov
index dd78df26f..dd78df26f 100644
--- a/src/mint/afl-tests/id:000542,src:000000,op:arith8,pos:322,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000542,src:000000,op:arith8,pos:322,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000542,src:000000,op:int16,pos:69,val:-129,+cov b/src/exchange/afl-tests/id:000542,src:000000,op:int16,pos:69,val:-129,+cov
index 6a42bbe18..6a42bbe18 100644
--- a/src/mint/afl-tests/id:000542,src:000000,op:int16,pos:69,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000542,src:000000,op:int16,pos:69,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000543,src:000000,op:arith8,pos:326,val:-9,+cov b/src/exchange/afl-tests/id:000543,src:000000,op:arith8,pos:326,val:-9,+cov
index d6b49c729..d6b49c729 100644
--- a/src/mint/afl-tests/id:000543,src:000000,op:arith8,pos:326,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000543,src:000000,op:arith8,pos:326,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000543,src:000000,op:int16,pos:74,val:be:-128,+cov b/src/exchange/afl-tests/id:000543,src:000000,op:int16,pos:74,val:be:-128,+cov
index d1176bdf5..d1176bdf5 100644
--- a/src/mint/afl-tests/id:000543,src:000000,op:int16,pos:74,val:be:-128,+cov
+++ b/src/exchange/afl-tests/id:000543,src:000000,op:int16,pos:74,val:be:-128,+cov
diff --git a/src/mint/afl-tests/id:000544,src:000000,op:arith8,pos:326,val:-31,+cov b/src/exchange/afl-tests/id:000544,src:000000,op:arith8,pos:326,val:-31,+cov
index be070dcd3..be070dcd3 100644
--- a/src/mint/afl-tests/id:000544,src:000000,op:arith8,pos:326,val:-31,+cov
+++ b/src/exchange/afl-tests/id:000544,src:000000,op:arith8,pos:326,val:-31,+cov
diff --git a/src/mint/afl-tests/id:000544,src:000000,op:int16,pos:78,val:be:+127,+cov b/src/exchange/afl-tests/id:000544,src:000000,op:int16,pos:78,val:be:+127,+cov
index e0e32e3f8..e0e32e3f8 100644
--- a/src/mint/afl-tests/id:000544,src:000000,op:int16,pos:78,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000544,src:000000,op:int16,pos:78,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000545,src:000000,op:arith8,pos:326,val:-35,+cov b/src/exchange/afl-tests/id:000545,src:000000,op:arith8,pos:326,val:-35,+cov
index 56c9b289a..56c9b289a 100644
--- a/src/mint/afl-tests/id:000545,src:000000,op:arith8,pos:326,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000545,src:000000,op:arith8,pos:326,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000545,src:000000,op:int16,pos:81,val:+32767,+cov b/src/exchange/afl-tests/id:000545,src:000000,op:int16,pos:81,val:+32767,+cov
index 8cebabded..8cebabded 100644
--- a/src/mint/afl-tests/id:000545,src:000000,op:int16,pos:81,val:+32767,+cov
+++ b/src/exchange/afl-tests/id:000545,src:000000,op:int16,pos:81,val:+32767,+cov
diff --git a/src/mint/afl-tests/id:000546,src:000000,op:arith8,pos:327,val:+5 b/src/exchange/afl-tests/id:000546,src:000000,op:arith8,pos:327,val:+5
index 59aa85414..59aa85414 100644
--- a/src/mint/afl-tests/id:000546,src:000000,op:arith8,pos:327,val:+5
+++ b/src/exchange/afl-tests/id:000546,src:000000,op:arith8,pos:327,val:+5
diff --git a/src/mint/afl-tests/id:000546,src:000000,op:int16,pos:83,val:+127,+cov b/src/exchange/afl-tests/id:000546,src:000000,op:int16,pos:83,val:+127,+cov
index 55a511c14..55a511c14 100644
--- a/src/mint/afl-tests/id:000546,src:000000,op:int16,pos:83,val:+127,+cov
+++ b/src/exchange/afl-tests/id:000546,src:000000,op:int16,pos:83,val:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000547,src:000000,op:arith8,pos:327,val:+7,+cov b/src/exchange/afl-tests/id:000547,src:000000,op:arith8,pos:327,val:+7,+cov
index 96d86ac77..96d86ac77 100644
--- a/src/mint/afl-tests/id:000547,src:000000,op:arith8,pos:327,val:+7,+cov
+++ b/src/exchange/afl-tests/id:000547,src:000000,op:arith8,pos:327,val:+7,+cov
diff --git a/src/mint/afl-tests/id:000547,src:000000,op:int16,pos:86,val:+4096,+cov b/src/exchange/afl-tests/id:000547,src:000000,op:int16,pos:86,val:+4096,+cov
index 1ad848ad0..1ad848ad0 100644
--- a/src/mint/afl-tests/id:000547,src:000000,op:int16,pos:86,val:+4096,+cov
+++ b/src/exchange/afl-tests/id:000547,src:000000,op:int16,pos:86,val:+4096,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000548,src:000000,op:arith8,pos:327,val:+11,+cov b/src/exchange/afl-tests/id:000548,src:000000,op:arith8,pos:327,val:+11,+cov
index bb9534e22..bb9534e22 100644
--- a/src/mint/afl-tests/id:000548,src:000000,op:arith8,pos:327,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000548,src:000000,op:arith8,pos:327,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000548,src:000000,op:int16,pos:87,val:+16,+cov b/src/exchange/afl-tests/id:000548,src:000000,op:int16,pos:87,val:+16,+cov
index 342d6ec3d..342d6ec3d 100644
--- a/src/mint/afl-tests/id:000548,src:000000,op:int16,pos:87,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000548,src:000000,op:int16,pos:87,val:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000549,src:000000,op:arith8,pos:327,val:-24,+cov b/src/exchange/afl-tests/id:000549,src:000000,op:arith8,pos:327,val:-24,+cov
index bf2457f29..bf2457f29 100644
--- a/src/mint/afl-tests/id:000549,src:000000,op:arith8,pos:327,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000549,src:000000,op:arith8,pos:327,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000549,src:000000,op:int16,pos:87,val:-32768,+cov b/src/exchange/afl-tests/id:000549,src:000000,op:int16,pos:87,val:-32768,+cov
index 55e87c367..55e87c367 100644
--- a/src/mint/afl-tests/id:000549,src:000000,op:int16,pos:87,val:-32768,+cov
+++ b/src/exchange/afl-tests/id:000549,src:000000,op:int16,pos:87,val:-32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000550,src:000000,op:arith8,pos:328,val:+14,+cov b/src/exchange/afl-tests/id:000550,src:000000,op:arith8,pos:328,val:+14,+cov
index c7a962042..c7a962042 100644
--- a/src/mint/afl-tests/id:000550,src:000000,op:arith8,pos:328,val:+14,+cov
+++ b/src/exchange/afl-tests/id:000550,src:000000,op:arith8,pos:328,val:+14,+cov
diff --git a/src/mint/afl-tests/id:000550,src:000000,op:int16,pos:90,val:+256,+cov b/src/exchange/afl-tests/id:000550,src:000000,op:int16,pos:90,val:+256,+cov
index a0ca91e90..a0ca91e90 100644
--- a/src/mint/afl-tests/id:000550,src:000000,op:int16,pos:90,val:+256,+cov
+++ b/src/exchange/afl-tests/id:000550,src:000000,op:int16,pos:90,val:+256,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000551,src:000000,op:arith8,pos:329,val:+1,+cov b/src/exchange/afl-tests/id:000551,src:000000,op:arith8,pos:329,val:+1,+cov
index 90b8dc4cb..90b8dc4cb 100644
--- a/src/mint/afl-tests/id:000551,src:000000,op:arith8,pos:329,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000551,src:000000,op:arith8,pos:329,val:+1,+cov
diff --git a/src/mint/afl-tests/id:000551,src:000000,op:int16,pos:91,val:+32,+cov b/src/exchange/afl-tests/id:000551,src:000000,op:int16,pos:91,val:+32,+cov
index 9555e4734..9555e4734 100644
--- a/src/mint/afl-tests/id:000551,src:000000,op:int16,pos:91,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000551,src:000000,op:int16,pos:91,val:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000552,src:000000,op:arith8,pos:330,val:+9,+cov b/src/exchange/afl-tests/id:000552,src:000000,op:arith8,pos:330,val:+9,+cov
index abe39d19d..abe39d19d 100644
--- a/src/mint/afl-tests/id:000552,src:000000,op:arith8,pos:330,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000552,src:000000,op:arith8,pos:330,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000552,src:000000,op:int16,pos:91,val:-129,+cov b/src/exchange/afl-tests/id:000552,src:000000,op:int16,pos:91,val:-129,+cov
index 1c85703bf..1c85703bf 100644
--- a/src/mint/afl-tests/id:000552,src:000000,op:int16,pos:91,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000552,src:000000,op:int16,pos:91,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000553,src:000000,op:arith8,pos:330,val:-24,+cov b/src/exchange/afl-tests/id:000553,src:000000,op:arith8,pos:330,val:-24,+cov
index 00bd938a9..00bd938a9 100644
--- a/src/mint/afl-tests/id:000553,src:000000,op:arith8,pos:330,val:-24,+cov
+++ b/src/exchange/afl-tests/id:000553,src:000000,op:arith8,pos:330,val:-24,+cov
diff --git a/src/mint/afl-tests/id:000553,src:000000,op:int16,pos:93,val:+0,+cov b/src/exchange/afl-tests/id:000553,src:000000,op:int16,pos:93,val:+0,+cov
index d4ac1e214..d4ac1e214 100644
--- a/src/mint/afl-tests/id:000553,src:000000,op:int16,pos:93,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000553,src:000000,op:int16,pos:93,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000554,src:000000,op:int16,pos:94,val:be:+64,+cov b/src/exchange/afl-tests/id:000554,src:000000,op:int16,pos:94,val:be:+64,+cov
index f92553794..f92553794 100644
--- a/src/mint/afl-tests/id:000554,src:000000,op:int16,pos:94,val:be:+64,+cov
+++ b/src/exchange/afl-tests/id:000554,src:000000,op:int16,pos:94,val:be:+64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000554,src:000000,op:int8,pos:6,val:+0 b/src/exchange/afl-tests/id:000554,src:000000,op:int8,pos:6,val:+0
index 1617639fa..1617639fa 100644
--- a/src/mint/afl-tests/id:000554,src:000000,op:int8,pos:6,val:+0
+++ b/src/exchange/afl-tests/id:000554,src:000000,op:int8,pos:6,val:+0
Binary files differ
diff --git a/src/mint/afl-tests/id:000555,src:000000,op:int16,pos:94,val:be:+100,+cov b/src/exchange/afl-tests/id:000555,src:000000,op:int16,pos:94,val:be:+100,+cov
index 14c00a0e5..14c00a0e5 100644
--- a/src/mint/afl-tests/id:000555,src:000000,op:int16,pos:94,val:be:+100,+cov
+++ b/src/exchange/afl-tests/id:000555,src:000000,op:int16,pos:94,val:be:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000555,src:000000,op:int8,pos:7,val:+0 b/src/exchange/afl-tests/id:000555,src:000000,op:int8,pos:7,val:+0
index bf79da717..bf79da717 100644
--- a/src/mint/afl-tests/id:000555,src:000000,op:int8,pos:7,val:+0
+++ b/src/exchange/afl-tests/id:000555,src:000000,op:int8,pos:7,val:+0
Binary files differ
diff --git a/src/mint/afl-tests/id:000556,src:000000,op:int16,pos:232,val:+1,+cov b/src/exchange/afl-tests/id:000556,src:000000,op:int16,pos:232,val:+1,+cov
index 28ac725fa..28ac725fa 100644
--- a/src/mint/afl-tests/id:000556,src:000000,op:int16,pos:232,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000556,src:000000,op:int16,pos:232,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000556,src:000000,op:int8,pos:9,val:+0 b/src/exchange/afl-tests/id:000556,src:000000,op:int8,pos:9,val:+0
index 3bd6a1d9b..3bd6a1d9b 100644
--- a/src/mint/afl-tests/id:000556,src:000000,op:int8,pos:9,val:+0
+++ b/src/exchange/afl-tests/id:000556,src:000000,op:int8,pos:9,val:+0
Binary files differ
diff --git a/src/mint/afl-tests/id:000557,src:000000,op:int16,pos:254,val:+256,+cov b/src/exchange/afl-tests/id:000557,src:000000,op:int16,pos:254,val:+256,+cov
index 20a869e0d..20a869e0d 100644
--- a/src/mint/afl-tests/id:000557,src:000000,op:int16,pos:254,val:+256,+cov
+++ b/src/exchange/afl-tests/id:000557,src:000000,op:int16,pos:254,val:+256,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000557,src:000000,op:int8,pos:34,val:+0,+cov b/src/exchange/afl-tests/id:000557,src:000000,op:int8,pos:34,val:+0,+cov
index b44840248..b44840248 100644
--- a/src/mint/afl-tests/id:000557,src:000000,op:int8,pos:34,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000557,src:000000,op:int8,pos:34,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000558,src:000000,op:int16,pos:262,val:+1000,+cov b/src/exchange/afl-tests/id:000558,src:000000,op:int16,pos:262,val:+1000,+cov
index 3e20e1735..3e20e1735 100644
--- a/src/mint/afl-tests/id:000558,src:000000,op:int16,pos:262,val:+1000,+cov
+++ b/src/exchange/afl-tests/id:000558,src:000000,op:int16,pos:262,val:+1000,+cov
diff --git a/src/mint/afl-tests/id:000558,src:000000,op:int8,pos:40,val:+0,+cov b/src/exchange/afl-tests/id:000558,src:000000,op:int8,pos:40,val:+0,+cov
index 1753c57a2..1753c57a2 100644
--- a/src/mint/afl-tests/id:000558,src:000000,op:int8,pos:40,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000558,src:000000,op:int8,pos:40,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000559,src:000000,op:int16,pos:303,val:+128,+cov b/src/exchange/afl-tests/id:000559,src:000000,op:int16,pos:303,val:+128,+cov
index 531d5555b..531d5555b 100644
--- a/src/mint/afl-tests/id:000559,src:000000,op:int16,pos:303,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000559,src:000000,op:int16,pos:303,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000559,src:000000,op:int8,pos:40,val:+32 b/src/exchange/afl-tests/id:000559,src:000000,op:int8,pos:40,val:+32
index 478612835..478612835 100644
--- a/src/mint/afl-tests/id:000559,src:000000,op:int8,pos:40,val:+32
+++ b/src/exchange/afl-tests/id:000559,src:000000,op:int8,pos:40,val:+32
diff --git a/src/mint/afl-tests/id:000560,src:000000,op:int32,pos:3,val:be:+1000 b/src/exchange/afl-tests/id:000560,src:000000,op:int32,pos:3,val:be:+1000
index 8082e7b4f..8082e7b4f 100644
--- a/src/mint/afl-tests/id:000560,src:000000,op:int32,pos:3,val:be:+1000
+++ b/src/exchange/afl-tests/id:000560,src:000000,op:int32,pos:3,val:be:+1000
Binary files differ
diff --git a/src/mint/afl-tests/id:000560,src:000000,op:int8,pos:44,val:-1,+cov b/src/exchange/afl-tests/id:000560,src:000000,op:int8,pos:44,val:-1,+cov
index 1993f7098..1993f7098 100644
--- a/src/mint/afl-tests/id:000560,src:000000,op:int8,pos:44,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000560,src:000000,op:int8,pos:44,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000561,src:000000,op:int32,pos:28,val:+32768,+cov b/src/exchange/afl-tests/id:000561,src:000000,op:int32,pos:28,val:+32768,+cov
index a73cd86bc..a73cd86bc 100644
--- a/src/mint/afl-tests/id:000561,src:000000,op:int32,pos:28,val:+32768,+cov
+++ b/src/exchange/afl-tests/id:000561,src:000000,op:int32,pos:28,val:+32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000561,src:000000,op:int8,pos:51,val:-1,+cov b/src/exchange/afl-tests/id:000561,src:000000,op:int8,pos:51,val:-1,+cov
index 6270e9412..6270e9412 100644
--- a/src/mint/afl-tests/id:000561,src:000000,op:int8,pos:51,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000561,src:000000,op:int8,pos:51,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000562,src:000000,op:int32,pos:29,val:-128,+cov b/src/exchange/afl-tests/id:000562,src:000000,op:int32,pos:29,val:-128,+cov
index 6a7ac1b1f..6a7ac1b1f 100644
--- a/src/mint/afl-tests/id:000562,src:000000,op:int32,pos:29,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000562,src:000000,op:int32,pos:29,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000562,src:000000,op:int8,pos:62,val:-128,+cov b/src/exchange/afl-tests/id:000562,src:000000,op:int8,pos:62,val:-128,+cov
index 420f20062..420f20062 100644
--- a/src/mint/afl-tests/id:000562,src:000000,op:int8,pos:62,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000562,src:000000,op:int8,pos:62,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000563,src:000000,op:int32,pos:33,val:-128,+cov b/src/exchange/afl-tests/id:000563,src:000000,op:int32,pos:33,val:-128,+cov
index 0c72e988b..0c72e988b 100644
--- a/src/mint/afl-tests/id:000563,src:000000,op:int32,pos:33,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000563,src:000000,op:int32,pos:33,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000563,src:000000,op:int8,pos:135,val:+127,+cov b/src/exchange/afl-tests/id:000563,src:000000,op:int8,pos:135,val:+127,+cov
index 3a784fe63..3a784fe63 100644
--- a/src/mint/afl-tests/id:000563,src:000000,op:int8,pos:135,val:+127,+cov
+++ b/src/exchange/afl-tests/id:000563,src:000000,op:int8,pos:135,val:+127,+cov
diff --git a/src/mint/afl-tests/id:000564,src:000000,op:int32,pos:33,val:+1024,+cov b/src/exchange/afl-tests/id:000564,src:000000,op:int32,pos:33,val:+1024,+cov
index 754d878c6..754d878c6 100644
--- a/src/mint/afl-tests/id:000564,src:000000,op:int32,pos:33,val:+1024,+cov
+++ b/src/exchange/afl-tests/id:000564,src:000000,op:int32,pos:33,val:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000564,src:000000,op:int8,pos:140,val:+100,+cov b/src/exchange/afl-tests/id:000564,src:000000,op:int8,pos:140,val:+100,+cov
index 65c596600..65c596600 100644
--- a/src/mint/afl-tests/id:000564,src:000000,op:int8,pos:140,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000564,src:000000,op:int8,pos:140,val:+100,+cov
diff --git a/src/mint/afl-tests/id:000565,src:000000,op:int32,pos:33,val:be:-32769,+cov b/src/exchange/afl-tests/id:000565,src:000000,op:int32,pos:33,val:be:-32769,+cov
index 391df0563..391df0563 100644
--- a/src/mint/afl-tests/id:000565,src:000000,op:int32,pos:33,val:be:-32769,+cov
+++ b/src/exchange/afl-tests/id:000565,src:000000,op:int32,pos:33,val:be:-32769,+cov
diff --git a/src/mint/afl-tests/id:000565,src:000000,op:int8,pos:178,val:+100,+cov b/src/exchange/afl-tests/id:000565,src:000000,op:int8,pos:178,val:+100,+cov
index 2b5c674c0..2b5c674c0 100644
--- a/src/mint/afl-tests/id:000565,src:000000,op:int8,pos:178,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000565,src:000000,op:int8,pos:178,val:+100,+cov
diff --git a/src/mint/afl-tests/id:000566,src:000000,op:int16,pos:27,val:-128,+cov b/src/exchange/afl-tests/id:000566,src:000000,op:int16,pos:27,val:-128,+cov
index 2ad45c272..2ad45c272 100644
--- a/src/mint/afl-tests/id:000566,src:000000,op:int16,pos:27,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000566,src:000000,op:int16,pos:27,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000566,src:000000,op:int32,pos:39,val:be:+255,+cov b/src/exchange/afl-tests/id:000566,src:000000,op:int32,pos:39,val:be:+255,+cov
index 742b89c52..742b89c52 100644
--- a/src/mint/afl-tests/id:000566,src:000000,op:int32,pos:39,val:be:+255,+cov
+++ b/src/exchange/afl-tests/id:000566,src:000000,op:int32,pos:39,val:be:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000567,src:000000,op:int16,pos:28,val:be:+32,+cov b/src/exchange/afl-tests/id:000567,src:000000,op:int16,pos:28,val:be:+32,+cov
index 5728df48c..5728df48c 100644
--- a/src/mint/afl-tests/id:000567,src:000000,op:int16,pos:28,val:be:+32,+cov
+++ b/src/exchange/afl-tests/id:000567,src:000000,op:int16,pos:28,val:be:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000567,src:000000,op:int32,pos:40,val:+32767,+cov b/src/exchange/afl-tests/id:000567,src:000000,op:int32,pos:40,val:+32767,+cov
index 3c1d9f2c4..3c1d9f2c4 100644
--- a/src/mint/afl-tests/id:000567,src:000000,op:int32,pos:40,val:+32767,+cov
+++ b/src/exchange/afl-tests/id:000567,src:000000,op:int32,pos:40,val:+32767,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000568,src:000000,op:int16,pos:28,val:be:+127,+cov b/src/exchange/afl-tests/id:000568,src:000000,op:int16,pos:28,val:be:+127,+cov
index c6306744b..c6306744b 100644
--- a/src/mint/afl-tests/id:000568,src:000000,op:int16,pos:28,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000568,src:000000,op:int16,pos:28,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000568,src:000000,op:int32,pos:41,val:+16,+cov b/src/exchange/afl-tests/id:000568,src:000000,op:int32,pos:41,val:+16,+cov
index 465edd129..465edd129 100644
--- a/src/mint/afl-tests/id:000568,src:000000,op:int32,pos:41,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000568,src:000000,op:int32,pos:41,val:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000569,src:000000,op:int16,pos:33,val:be:+512,+cov b/src/exchange/afl-tests/id:000569,src:000000,op:int16,pos:33,val:be:+512,+cov
index 571fbb201..571fbb201 100644
--- a/src/mint/afl-tests/id:000569,src:000000,op:int16,pos:33,val:be:+512,+cov
+++ b/src/exchange/afl-tests/id:000569,src:000000,op:int16,pos:33,val:be:+512,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000569,src:000000,op:int32,pos:41,val:+1024,+cov b/src/exchange/afl-tests/id:000569,src:000000,op:int32,pos:41,val:+1024,+cov
index af9861b66..af9861b66 100644
--- a/src/mint/afl-tests/id:000569,src:000000,op:int32,pos:41,val:+1024,+cov
+++ b/src/exchange/afl-tests/id:000569,src:000000,op:int32,pos:41,val:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000570,src:000000,op:int16,pos:34,val:+1000,+cov b/src/exchange/afl-tests/id:000570,src:000000,op:int16,pos:34,val:+1000,+cov
index 77f2892f9..77f2892f9 100644
--- a/src/mint/afl-tests/id:000570,src:000000,op:int16,pos:34,val:+1000,+cov
+++ b/src/exchange/afl-tests/id:000570,src:000000,op:int16,pos:34,val:+1000,+cov
diff --git a/src/mint/afl-tests/id:000570,src:000000,op:int32,pos:44,val:-32769,+cov b/src/exchange/afl-tests/id:000570,src:000000,op:int32,pos:44,val:-32769,+cov
index 30e5e6da0..30e5e6da0 100644
--- a/src/mint/afl-tests/id:000570,src:000000,op:int32,pos:44,val:-32769,+cov
+++ b/src/exchange/afl-tests/id:000570,src:000000,op:int32,pos:44,val:-32769,+cov
diff --git a/src/mint/afl-tests/id:000571,src:000000,op:int16,pos:44,val:+512,+cov b/src/exchange/afl-tests/id:000571,src:000000,op:int16,pos:44,val:+512,+cov
index 6eed334c0..6eed334c0 100644
--- a/src/mint/afl-tests/id:000571,src:000000,op:int16,pos:44,val:+512,+cov
+++ b/src/exchange/afl-tests/id:000571,src:000000,op:int16,pos:44,val:+512,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000571,src:000000,op:int32,pos:45,val:be:+1024,+cov b/src/exchange/afl-tests/id:000571,src:000000,op:int32,pos:45,val:be:+1024,+cov
index 747b8e2c1..747b8e2c1 100644
--- a/src/mint/afl-tests/id:000571,src:000000,op:int32,pos:45,val:be:+1024,+cov
+++ b/src/exchange/afl-tests/id:000571,src:000000,op:int32,pos:45,val:be:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000572,src:000000,op:int16,pos:46,val:+100,+cov b/src/exchange/afl-tests/id:000572,src:000000,op:int16,pos:46,val:+100,+cov
index 7dd561e52..7dd561e52 100644
--- a/src/mint/afl-tests/id:000572,src:000000,op:int16,pos:46,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000572,src:000000,op:int16,pos:46,val:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000572,src:000000,op:int32,pos:48,val:+256,+cov b/src/exchange/afl-tests/id:000572,src:000000,op:int32,pos:48,val:+256,+cov
index 6760f794b..6760f794b 100644
--- a/src/mint/afl-tests/id:000572,src:000000,op:int32,pos:48,val:+256,+cov
+++ b/src/exchange/afl-tests/id:000572,src:000000,op:int32,pos:48,val:+256,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000573,src:000000,op:int16,pos:46,val:be:+512,+cov b/src/exchange/afl-tests/id:000573,src:000000,op:int16,pos:46,val:be:+512,+cov
index 77e3d2608..77e3d2608 100644
--- a/src/mint/afl-tests/id:000573,src:000000,op:int16,pos:46,val:be:+512,+cov
+++ b/src/exchange/afl-tests/id:000573,src:000000,op:int16,pos:46,val:be:+512,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000573,src:000000,op:int32,pos:53,val:+32768,+cov b/src/exchange/afl-tests/id:000573,src:000000,op:int32,pos:53,val:+32768,+cov
index 4949dcaed..4949dcaed 100644
--- a/src/mint/afl-tests/id:000573,src:000000,op:int32,pos:53,val:+32768,+cov
+++ b/src/exchange/afl-tests/id:000573,src:000000,op:int32,pos:53,val:+32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000574,src:000000,op:int16,pos:52,val:-128,+cov b/src/exchange/afl-tests/id:000574,src:000000,op:int16,pos:52,val:-128,+cov
index ca64ff5fc..ca64ff5fc 100644
--- a/src/mint/afl-tests/id:000574,src:000000,op:int16,pos:52,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000574,src:000000,op:int16,pos:52,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000574,src:000000,op:int32,pos:54,val:be:-32768,+cov b/src/exchange/afl-tests/id:000574,src:000000,op:int32,pos:54,val:be:-32768,+cov
index a5b19e279..a5b19e279 100644
--- a/src/mint/afl-tests/id:000574,src:000000,op:int32,pos:54,val:be:-32768,+cov
+++ b/src/exchange/afl-tests/id:000574,src:000000,op:int32,pos:54,val:be:-32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000575,src:000000,op:int16,pos:54,val:-128,+cov b/src/exchange/afl-tests/id:000575,src:000000,op:int16,pos:54,val:-128,+cov
index 94507ffbd..94507ffbd 100644
--- a/src/mint/afl-tests/id:000575,src:000000,op:int16,pos:54,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000575,src:000000,op:int16,pos:54,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000575,src:000000,op:int32,pos:54,val:-32769,+cov b/src/exchange/afl-tests/id:000575,src:000000,op:int32,pos:54,val:-32769,+cov
index bc9f24764..bc9f24764 100644
--- a/src/mint/afl-tests/id:000575,src:000000,op:int32,pos:54,val:-32769,+cov
+++ b/src/exchange/afl-tests/id:000575,src:000000,op:int32,pos:54,val:-32769,+cov
diff --git a/src/mint/afl-tests/id:000576,src:000000,op:int16,pos:54,val:+100,+cov b/src/exchange/afl-tests/id:000576,src:000000,op:int16,pos:54,val:+100,+cov
index 921167e4e..921167e4e 100644
--- a/src/mint/afl-tests/id:000576,src:000000,op:int16,pos:54,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000576,src:000000,op:int16,pos:54,val:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000576,src:000000,op:int32,pos:54,val:+2147483647,+cov b/src/exchange/afl-tests/id:000576,src:000000,op:int32,pos:54,val:+2147483647,+cov
index 0d5dc0309..0d5dc0309 100644
--- a/src/mint/afl-tests/id:000576,src:000000,op:int32,pos:54,val:+2147483647,+cov
+++ b/src/exchange/afl-tests/id:000576,src:000000,op:int32,pos:54,val:+2147483647,+cov
diff --git a/src/mint/afl-tests/id:000577,src:000000,op:int16,pos:54,val:+255,+cov b/src/exchange/afl-tests/id:000577,src:000000,op:int16,pos:54,val:+255,+cov
index 6ff059236..6ff059236 100644
--- a/src/mint/afl-tests/id:000577,src:000000,op:int16,pos:54,val:+255,+cov
+++ b/src/exchange/afl-tests/id:000577,src:000000,op:int16,pos:54,val:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000577,src:000000,op:int32,pos:63,val:-1,+cov b/src/exchange/afl-tests/id:000577,src:000000,op:int32,pos:63,val:-1,+cov
index adafedcc6..adafedcc6 100644
--- a/src/mint/afl-tests/id:000577,src:000000,op:int32,pos:63,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000577,src:000000,op:int32,pos:63,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000578,src:000000,op:int16,pos:62,val:+255,+cov b/src/exchange/afl-tests/id:000578,src:000000,op:int16,pos:62,val:+255,+cov
index 79dc26693..79dc26693 100644
--- a/src/mint/afl-tests/id:000578,src:000000,op:int16,pos:62,val:+255,+cov
+++ b/src/exchange/afl-tests/id:000578,src:000000,op:int16,pos:62,val:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000578,src:000000,op:int32,pos:64,val:-128,+cov b/src/exchange/afl-tests/id:000578,src:000000,op:int32,pos:64,val:-128,+cov
index fabc35eee..fabc35eee 100644
--- a/src/mint/afl-tests/id:000578,src:000000,op:int32,pos:64,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000578,src:000000,op:int32,pos:64,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000579,src:000000,op:int16,pos:63,val:+32,+cov b/src/exchange/afl-tests/id:000579,src:000000,op:int16,pos:63,val:+32,+cov
index 2e2992ab2..2e2992ab2 100644
--- a/src/mint/afl-tests/id:000579,src:000000,op:int16,pos:63,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000579,src:000000,op:int16,pos:63,val:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000579,src:000000,op:int32,pos:69,val:+128,+cov b/src/exchange/afl-tests/id:000579,src:000000,op:int32,pos:69,val:+128,+cov
index ef5185cac..ef5185cac 100644
--- a/src/mint/afl-tests/id:000579,src:000000,op:int32,pos:69,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000579,src:000000,op:int32,pos:69,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000580,src:000000,op:int16,pos:65,val:be:+100,+cov b/src/exchange/afl-tests/id:000580,src:000000,op:int16,pos:65,val:be:+100,+cov
index 9c55a5050..9c55a5050 100644
--- a/src/mint/afl-tests/id:000580,src:000000,op:int16,pos:65,val:be:+100,+cov
+++ b/src/exchange/afl-tests/id:000580,src:000000,op:int16,pos:65,val:be:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000580,src:000000,op:int32,pos:80,val:+1024,+cov b/src/exchange/afl-tests/id:000580,src:000000,op:int32,pos:80,val:+1024,+cov
index e28726550..e28726550 100644
--- a/src/mint/afl-tests/id:000580,src:000000,op:int32,pos:80,val:+1024,+cov
+++ b/src/exchange/afl-tests/id:000580,src:000000,op:int32,pos:80,val:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000581,src:000000,op:int16,pos:66,val:+0,+cov b/src/exchange/afl-tests/id:000581,src:000000,op:int16,pos:66,val:+0,+cov
index 1a79ad6d5..1a79ad6d5 100644
--- a/src/mint/afl-tests/id:000581,src:000000,op:int16,pos:66,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000581,src:000000,op:int16,pos:66,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000581,src:000000,op:int32,pos:80,val:+65535,+cov b/src/exchange/afl-tests/id:000581,src:000000,op:int32,pos:80,val:+65535,+cov
index 9fc87070c..9fc87070c 100644
--- a/src/mint/afl-tests/id:000581,src:000000,op:int32,pos:80,val:+65535,+cov
+++ b/src/exchange/afl-tests/id:000581,src:000000,op:int32,pos:80,val:+65535,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000582,src:000000,op:int16,pos:80,val:+1000,+cov b/src/exchange/afl-tests/id:000582,src:000000,op:int16,pos:80,val:+1000,+cov
index 7f3836487..7f3836487 100644
--- a/src/mint/afl-tests/id:000582,src:000000,op:int16,pos:80,val:+1000,+cov
+++ b/src/exchange/afl-tests/id:000582,src:000000,op:int16,pos:80,val:+1000,+cov
diff --git a/src/mint/afl-tests/id:000582,src:000000,op:int32,pos:82,val:be:+16,+cov b/src/exchange/afl-tests/id:000582,src:000000,op:int32,pos:82,val:be:+16,+cov
index 13152b78c..13152b78c 100644
--- a/src/mint/afl-tests/id:000582,src:000000,op:int32,pos:82,val:be:+16,+cov
+++ b/src/exchange/afl-tests/id:000582,src:000000,op:int32,pos:82,val:be:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000583,src:000000,op:int16,pos:82,val:+256,+cov b/src/exchange/afl-tests/id:000583,src:000000,op:int16,pos:82,val:+256,+cov
index 751d9c12d..751d9c12d 100644
--- a/src/mint/afl-tests/id:000583,src:000000,op:int16,pos:82,val:+256,+cov
+++ b/src/exchange/afl-tests/id:000583,src:000000,op:int16,pos:82,val:+256,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000583,src:000000,op:int32,pos:83,val:+100,+cov b/src/exchange/afl-tests/id:000583,src:000000,op:int32,pos:83,val:+100,+cov
index 6eb899317..6eb899317 100644
--- a/src/mint/afl-tests/id:000583,src:000000,op:int32,pos:83,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000583,src:000000,op:int32,pos:83,val:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000584,src:000000,op:int16,pos:83,val:be:+1024,+cov b/src/exchange/afl-tests/id:000584,src:000000,op:int16,pos:83,val:be:+1024,+cov
index ebe720427..ebe720427 100644
--- a/src/mint/afl-tests/id:000584,src:000000,op:int16,pos:83,val:be:+1024,+cov
+++ b/src/exchange/afl-tests/id:000584,src:000000,op:int16,pos:83,val:be:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000584,src:000000,op:int32,pos:84,val:+32,+cov b/src/exchange/afl-tests/id:000584,src:000000,op:int32,pos:84,val:+32,+cov
index 69437f933..69437f933 100644
--- a/src/mint/afl-tests/id:000584,src:000000,op:int32,pos:84,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000584,src:000000,op:int32,pos:84,val:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000585,src:000000,op:int16,pos:87,val:-128,+cov b/src/exchange/afl-tests/id:000585,src:000000,op:int16,pos:87,val:-128,+cov
index 7c484f64a..7c484f64a 100644
--- a/src/mint/afl-tests/id:000585,src:000000,op:int16,pos:87,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000585,src:000000,op:int16,pos:87,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000585,src:000000,op:int32,pos:84,val:+128,+cov b/src/exchange/afl-tests/id:000585,src:000000,op:int32,pos:84,val:+128,+cov
index 5316011f8..5316011f8 100644
--- a/src/mint/afl-tests/id:000585,src:000000,op:int32,pos:84,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000585,src:000000,op:int32,pos:84,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000586,src:000000,op:int16,pos:87,val:-32768,+cov b/src/exchange/afl-tests/id:000586,src:000000,op:int16,pos:87,val:-32768,+cov
index 55e87c367..55e87c367 100644
--- a/src/mint/afl-tests/id:000586,src:000000,op:int16,pos:87,val:-32768,+cov
+++ b/src/exchange/afl-tests/id:000586,src:000000,op:int16,pos:87,val:-32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000586,src:000000,op:int32,pos:87,val:be:-32768,+cov b/src/exchange/afl-tests/id:000586,src:000000,op:int32,pos:87,val:be:-32768,+cov
index 35481e3c9..35481e3c9 100644
--- a/src/mint/afl-tests/id:000586,src:000000,op:int32,pos:87,val:be:-32768,+cov
+++ b/src/exchange/afl-tests/id:000586,src:000000,op:int32,pos:87,val:be:-32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000587,src:000000,op:int16,pos:94,val:-129,+cov b/src/exchange/afl-tests/id:000587,src:000000,op:int16,pos:94,val:-129,+cov
index 1f2baabc1..1f2baabc1 100644
--- a/src/mint/afl-tests/id:000587,src:000000,op:int16,pos:94,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000587,src:000000,op:int16,pos:94,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000587,src:000000,op:int32,pos:88,val:be:-32769,+cov b/src/exchange/afl-tests/id:000587,src:000000,op:int32,pos:88,val:be:-32769,+cov
index 0a4d6a1ac..0a4d6a1ac 100644
--- a/src/mint/afl-tests/id:000587,src:000000,op:int32,pos:88,val:be:-32769,+cov
+++ b/src/exchange/afl-tests/id:000587,src:000000,op:int32,pos:88,val:be:-32769,+cov
diff --git a/src/mint/afl-tests/id:000588,src:000000,op:int16,pos:193,val:+16 b/src/exchange/afl-tests/id:000588,src:000000,op:int16,pos:193,val:+16
index febe97b29..febe97b29 100644
--- a/src/mint/afl-tests/id:000588,src:000000,op:int16,pos:193,val:+16
+++ b/src/exchange/afl-tests/id:000588,src:000000,op:int16,pos:193,val:+16
Binary files differ
diff --git a/src/mint/afl-tests/id:000588,src:000000,op:int32,pos:89,val:-128,+cov b/src/exchange/afl-tests/id:000588,src:000000,op:int32,pos:89,val:-128,+cov
index 9197ec60b..9197ec60b 100644
--- a/src/mint/afl-tests/id:000588,src:000000,op:int32,pos:89,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000588,src:000000,op:int32,pos:89,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000589,src:000000,op:int32,pos:0,val:be:+32767 b/src/exchange/afl-tests/id:000589,src:000000,op:int32,pos:0,val:be:+32767
index 00f53a7aa..00f53a7aa 100644
--- a/src/mint/afl-tests/id:000589,src:000000,op:int32,pos:0,val:be:+32767
+++ b/src/exchange/afl-tests/id:000589,src:000000,op:int32,pos:0,val:be:+32767
Binary files differ
diff --git a/src/mint/afl-tests/id:000589,src:000000,op:int32,pos:92,val:+32767,+cov b/src/exchange/afl-tests/id:000589,src:000000,op:int32,pos:92,val:+32767,+cov
index 62aef2aba..62aef2aba 100644
--- a/src/mint/afl-tests/id:000589,src:000000,op:int32,pos:92,val:+32767,+cov
+++ b/src/exchange/afl-tests/id:000589,src:000000,op:int32,pos:92,val:+32767,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000590,src:000000,op:int32,pos:164,val:+256,+cov b/src/exchange/afl-tests/id:000590,src:000000,op:int32,pos:164,val:+256,+cov
index b1460a557..b1460a557 100644
--- a/src/mint/afl-tests/id:000590,src:000000,op:int32,pos:164,val:+256,+cov
+++ b/src/exchange/afl-tests/id:000590,src:000000,op:int32,pos:164,val:+256,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000590,src:000000,op:int32,pos:2,val:+65535 b/src/exchange/afl-tests/id:000590,src:000000,op:int32,pos:2,val:+65535
index 44e89eef3..44e89eef3 100644
--- a/src/mint/afl-tests/id:000590,src:000000,op:int32,pos:2,val:+65535
+++ b/src/exchange/afl-tests/id:000590,src:000000,op:int32,pos:2,val:+65535
Binary files differ
diff --git a/src/mint/afl-tests/id:000591,src:000000,op:int32,pos:178,val:be:-32769,+cov b/src/exchange/afl-tests/id:000591,src:000000,op:int32,pos:178,val:be:-32769,+cov
index 478c22b4c..478c22b4c 100644
--- a/src/mint/afl-tests/id:000591,src:000000,op:int32,pos:178,val:be:-32769,+cov
+++ b/src/exchange/afl-tests/id:000591,src:000000,op:int32,pos:178,val:be:-32769,+cov
diff --git a/src/mint/afl-tests/id:000591,src:000000,op:int32,pos:7,val:-2147483648,+cov b/src/exchange/afl-tests/id:000591,src:000000,op:int32,pos:7,val:-2147483648,+cov
index f9ced7042..f9ced7042 100644
--- a/src/mint/afl-tests/id:000591,src:000000,op:int32,pos:7,val:-2147483648,+cov
+++ b/src/exchange/afl-tests/id:000591,src:000000,op:int32,pos:7,val:-2147483648,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000592,src:000000,op:int32,pos:232,val:be:+65535,+cov b/src/exchange/afl-tests/id:000592,src:000000,op:int32,pos:232,val:be:+65535,+cov
index 746f4b04d..746f4b04d 100644
--- a/src/mint/afl-tests/id:000592,src:000000,op:int32,pos:232,val:be:+65535,+cov
+++ b/src/exchange/afl-tests/id:000592,src:000000,op:int32,pos:232,val:be:+65535,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000592,src:000000,op:int32,pos:24,val:be:+32,+cov b/src/exchange/afl-tests/id:000592,src:000000,op:int32,pos:24,val:be:+32,+cov
index 43cf1a142..43cf1a142 100644
--- a/src/mint/afl-tests/id:000592,src:000000,op:int32,pos:24,val:be:+32,+cov
+++ b/src/exchange/afl-tests/id:000592,src:000000,op:int32,pos:24,val:be:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000593,src:000000,op:int32,pos:26,val:+255,+cov b/src/exchange/afl-tests/id:000593,src:000000,op:int32,pos:26,val:+255,+cov
index 5435ad66e..5435ad66e 100644
--- a/src/mint/afl-tests/id:000593,src:000000,op:int32,pos:26,val:+255,+cov
+++ b/src/exchange/afl-tests/id:000593,src:000000,op:int32,pos:26,val:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000593,src:000000,op:int32,pos:313,val:+1,+cov b/src/exchange/afl-tests/id:000593,src:000000,op:int32,pos:313,val:+1,+cov
index 6bb20ee80..6bb20ee80 100644
--- a/src/mint/afl-tests/id:000593,src:000000,op:int32,pos:313,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000593,src:000000,op:int32,pos:313,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000594,src:000000,op:int32,pos:27,val:be:+1,+cov b/src/exchange/afl-tests/id:000594,src:000000,op:int32,pos:27,val:be:+1,+cov
index 3873fa9ff..3873fa9ff 100644
--- a/src/mint/afl-tests/id:000594,src:000000,op:int32,pos:27,val:be:+1,+cov
+++ b/src/exchange/afl-tests/id:000594,src:000000,op:int32,pos:27,val:be:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000594,src:000000,op:int32,pos:333,val:be:+255,+cov b/src/exchange/afl-tests/id:000594,src:000000,op:int32,pos:333,val:be:+255,+cov
index 7d8809ce5..7d8809ce5 100644
--- a/src/mint/afl-tests/id:000594,src:000000,op:int32,pos:333,val:be:+255,+cov
+++ b/src/exchange/afl-tests/id:000594,src:000000,op:int32,pos:333,val:be:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000595,src:000000,op:ext_AO,pos:26,+cov b/src/exchange/afl-tests/id:000595,src:000000,op:ext_AO,pos:26,+cov
index 103515702..103515702 100644
--- a/src/mint/afl-tests/id:000595,src:000000,op:ext_AO,pos:26,+cov
+++ b/src/exchange/afl-tests/id:000595,src:000000,op:ext_AO,pos:26,+cov
diff --git a/src/mint/afl-tests/id:000595,src:000000,op:int32,pos:29,val:+1000,+cov b/src/exchange/afl-tests/id:000595,src:000000,op:int32,pos:29,val:+1000,+cov
index e15c60e4d..e15c60e4d 100644
--- a/src/mint/afl-tests/id:000595,src:000000,op:int32,pos:29,val:+1000,+cov
+++ b/src/exchange/afl-tests/id:000595,src:000000,op:int32,pos:29,val:+1000,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000596,src:000000,op:ext_AO,pos:43,+cov b/src/exchange/afl-tests/id:000596,src:000000,op:ext_AO,pos:43,+cov
index 9d2bcc80a..9d2bcc80a 100644
--- a/src/mint/afl-tests/id:000596,src:000000,op:ext_AO,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000596,src:000000,op:ext_AO,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000596,src:000000,op:int32,pos:30,val:be:+32 b/src/exchange/afl-tests/id:000596,src:000000,op:int32,pos:30,val:be:+32
index 3ba3a7670..3ba3a7670 100644
--- a/src/mint/afl-tests/id:000596,src:000000,op:int32,pos:30,val:be:+32
+++ b/src/exchange/afl-tests/id:000596,src:000000,op:int32,pos:30,val:be:+32
Binary files differ
diff --git a/src/mint/afl-tests/id:000597,src:000000,op:ext_AO,pos:49,+cov b/src/exchange/afl-tests/id:000597,src:000000,op:ext_AO,pos:49,+cov
index 87d6c3266..87d6c3266 100644
--- a/src/mint/afl-tests/id:000597,src:000000,op:ext_AO,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000597,src:000000,op:ext_AO,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000597,src:000000,op:int32,pos:30,val:be:+512,+cov b/src/exchange/afl-tests/id:000597,src:000000,op:int32,pos:30,val:be:+512,+cov
index 5e2f7a7af..5e2f7a7af 100644
--- a/src/mint/afl-tests/id:000597,src:000000,op:int32,pos:30,val:be:+512,+cov
+++ b/src/exchange/afl-tests/id:000597,src:000000,op:int32,pos:30,val:be:+512,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000598,src:000000,op:ext_AO,pos:52,+cov b/src/exchange/afl-tests/id:000598,src:000000,op:ext_AO,pos:52,+cov
index 47faf5c11..47faf5c11 100644
--- a/src/mint/afl-tests/id:000598,src:000000,op:ext_AO,pos:52,+cov
+++ b/src/exchange/afl-tests/id:000598,src:000000,op:ext_AO,pos:52,+cov
diff --git a/src/mint/afl-tests/id:000598,src:000000,op:int32,pos:39,val:be:+1,+cov b/src/exchange/afl-tests/id:000598,src:000000,op:int32,pos:39,val:be:+1,+cov
index 15ac59807..15ac59807 100644
--- a/src/mint/afl-tests/id:000598,src:000000,op:int32,pos:39,val:be:+1,+cov
+++ b/src/exchange/afl-tests/id:000598,src:000000,op:int32,pos:39,val:be:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000599,src:000000,op:ext_AO,pos:56,+cov b/src/exchange/afl-tests/id:000599,src:000000,op:ext_AO,pos:56,+cov
index 3e4c825d7..3e4c825d7 100644
--- a/src/mint/afl-tests/id:000599,src:000000,op:ext_AO,pos:56,+cov
+++ b/src/exchange/afl-tests/id:000599,src:000000,op:ext_AO,pos:56,+cov
diff --git a/src/mint/afl-tests/id:000599,src:000000,op:int32,pos:40,val:+1024,+cov b/src/exchange/afl-tests/id:000599,src:000000,op:int32,pos:40,val:+1024,+cov
index cd378ea3f..cd378ea3f 100644
--- a/src/mint/afl-tests/id:000599,src:000000,op:int32,pos:40,val:+1024,+cov
+++ b/src/exchange/afl-tests/id:000599,src:000000,op:int32,pos:40,val:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000600,src:000000,op:ext_AO,pos:64,+cov b/src/exchange/afl-tests/id:000600,src:000000,op:ext_AO,pos:64,+cov
index fca3af083..fca3af083 100644
--- a/src/mint/afl-tests/id:000600,src:000000,op:ext_AO,pos:64,+cov
+++ b/src/exchange/afl-tests/id:000600,src:000000,op:ext_AO,pos:64,+cov
diff --git a/src/mint/afl-tests/id:000600,src:000000,op:int32,pos:42,val:be:+16,+cov b/src/exchange/afl-tests/id:000600,src:000000,op:int32,pos:42,val:be:+16,+cov
index 6b1a622b7..6b1a622b7 100644
--- a/src/mint/afl-tests/id:000600,src:000000,op:int32,pos:42,val:be:+16,+cov
+++ b/src/exchange/afl-tests/id:000600,src:000000,op:int32,pos:42,val:be:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000601,src:000000,op:ext_AO,pos:65,+cov b/src/exchange/afl-tests/id:000601,src:000000,op:ext_AO,pos:65,+cov
index 8e195f763..8e195f763 100644
--- a/src/mint/afl-tests/id:000601,src:000000,op:ext_AO,pos:65,+cov
+++ b/src/exchange/afl-tests/id:000601,src:000000,op:ext_AO,pos:65,+cov
diff --git a/src/mint/afl-tests/id:000601,src:000000,op:int32,pos:48,val:+100663045,+cov b/src/exchange/afl-tests/id:000601,src:000000,op:int32,pos:48,val:+100663045,+cov
index ac1694648..ac1694648 100644
--- a/src/mint/afl-tests/id:000601,src:000000,op:int32,pos:48,val:+100663045,+cov
+++ b/src/exchange/afl-tests/id:000601,src:000000,op:int32,pos:48,val:+100663045,+cov
diff --git a/src/mint/afl-tests/id:000602,src:000000,op:ext_AO,pos:65,+cov b/src/exchange/afl-tests/id:000602,src:000000,op:ext_AO,pos:65,+cov
index 629e226ae..629e226ae 100644
--- a/src/mint/afl-tests/id:000602,src:000000,op:ext_AO,pos:65,+cov
+++ b/src/exchange/afl-tests/id:000602,src:000000,op:ext_AO,pos:65,+cov
diff --git a/src/mint/afl-tests/id:000602,src:000000,op:int32,pos:49,val:be:+4096,+cov b/src/exchange/afl-tests/id:000602,src:000000,op:int32,pos:49,val:be:+4096,+cov
index 9d3527ce4..9d3527ce4 100644
--- a/src/mint/afl-tests/id:000602,src:000000,op:int32,pos:49,val:be:+4096,+cov
+++ b/src/exchange/afl-tests/id:000602,src:000000,op:int32,pos:49,val:be:+4096,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000603,src:000000,op:ext_AO,pos:69,+cov b/src/exchange/afl-tests/id:000603,src:000000,op:ext_AO,pos:69,+cov
index ba7f01c78..ba7f01c78 100644
--- a/src/mint/afl-tests/id:000603,src:000000,op:ext_AO,pos:69,+cov
+++ b/src/exchange/afl-tests/id:000603,src:000000,op:ext_AO,pos:69,+cov
diff --git a/src/mint/afl-tests/id:000603,src:000000,op:int32,pos:51,val:+128,+cov b/src/exchange/afl-tests/id:000603,src:000000,op:int32,pos:51,val:+128,+cov
index 78894f1e0..78894f1e0 100644
--- a/src/mint/afl-tests/id:000603,src:000000,op:int32,pos:51,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000603,src:000000,op:int32,pos:51,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000604,src:000000,op:ext_AO,pos:69,+cov b/src/exchange/afl-tests/id:000604,src:000000,op:ext_AO,pos:69,+cov
index 3d9a8d7e7..3d9a8d7e7 100644
--- a/src/mint/afl-tests/id:000604,src:000000,op:ext_AO,pos:69,+cov
+++ b/src/exchange/afl-tests/id:000604,src:000000,op:ext_AO,pos:69,+cov
diff --git a/src/mint/afl-tests/id:000604,src:000000,op:int32,pos:53,val:-128,+cov b/src/exchange/afl-tests/id:000604,src:000000,op:int32,pos:53,val:-128,+cov
index 72378f03e..72378f03e 100644
--- a/src/mint/afl-tests/id:000604,src:000000,op:int32,pos:53,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000604,src:000000,op:int32,pos:53,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000605,src:000000,op:ext_AO,pos:72,+cov b/src/exchange/afl-tests/id:000605,src:000000,op:ext_AO,pos:72,+cov
index dbebfb4c8..dbebfb4c8 100644
--- a/src/mint/afl-tests/id:000605,src:000000,op:ext_AO,pos:72,+cov
+++ b/src/exchange/afl-tests/id:000605,src:000000,op:ext_AO,pos:72,+cov
diff --git a/src/mint/afl-tests/id:000605,src:000000,op:int32,pos:53,val:+128,+cov b/src/exchange/afl-tests/id:000605,src:000000,op:int32,pos:53,val:+128,+cov
index 0a874d5d1..0a874d5d1 100644
--- a/src/mint/afl-tests/id:000605,src:000000,op:int32,pos:53,val:+128,+cov
+++ b/src/exchange/afl-tests/id:000605,src:000000,op:int32,pos:53,val:+128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000606,src:000000,op:ext_AO,pos:72,+cov b/src/exchange/afl-tests/id:000606,src:000000,op:ext_AO,pos:72,+cov
index f99750333..f99750333 100644
--- a/src/mint/afl-tests/id:000606,src:000000,op:ext_AO,pos:72,+cov
+++ b/src/exchange/afl-tests/id:000606,src:000000,op:ext_AO,pos:72,+cov
diff --git a/src/mint/afl-tests/id:000606,src:000000,op:int32,pos:53,val:+1024,+cov b/src/exchange/afl-tests/id:000606,src:000000,op:int32,pos:53,val:+1024,+cov
index b2fcb0bef..b2fcb0bef 100644
--- a/src/mint/afl-tests/id:000606,src:000000,op:int32,pos:53,val:+1024,+cov
+++ b/src/exchange/afl-tests/id:000606,src:000000,op:int32,pos:53,val:+1024,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000607,src:000000,op:ext_AO,pos:76,+cov b/src/exchange/afl-tests/id:000607,src:000000,op:ext_AO,pos:76,+cov
index 822d46b46..822d46b46 100644
--- a/src/mint/afl-tests/id:000607,src:000000,op:ext_AO,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000607,src:000000,op:ext_AO,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000607,src:000000,op:int32,pos:64,val:+256,+cov b/src/exchange/afl-tests/id:000607,src:000000,op:int32,pos:64,val:+256,+cov
index 506b9b427..506b9b427 100644
--- a/src/mint/afl-tests/id:000607,src:000000,op:int32,pos:64,val:+256,+cov
+++ b/src/exchange/afl-tests/id:000607,src:000000,op:int32,pos:64,val:+256,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000608,src:000000,op:ext_AO,pos:81,+cov b/src/exchange/afl-tests/id:000608,src:000000,op:ext_AO,pos:81,+cov
index 6d94860bf..6d94860bf 100644
--- a/src/mint/afl-tests/id:000608,src:000000,op:ext_AO,pos:81,+cov
+++ b/src/exchange/afl-tests/id:000608,src:000000,op:ext_AO,pos:81,+cov
diff --git a/src/mint/afl-tests/id:000608,src:000000,op:int32,pos:65,val:+1,+cov b/src/exchange/afl-tests/id:000608,src:000000,op:int32,pos:65,val:+1,+cov
index 43888bcac..43888bcac 100644
--- a/src/mint/afl-tests/id:000608,src:000000,op:int32,pos:65,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000608,src:000000,op:int32,pos:65,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000609,src:000000,op:ext_AO,pos:90,+cov b/src/exchange/afl-tests/id:000609,src:000000,op:ext_AO,pos:90,+cov
index 23ecb3ea7..23ecb3ea7 100644
--- a/src/mint/afl-tests/id:000609,src:000000,op:ext_AO,pos:90,+cov
+++ b/src/exchange/afl-tests/id:000609,src:000000,op:ext_AO,pos:90,+cov
diff --git a/src/mint/afl-tests/id:000609,src:000000,op:int32,pos:65,val:be:+64,+cov b/src/exchange/afl-tests/id:000609,src:000000,op:int32,pos:65,val:be:+64,+cov
index 2374729a6..2374729a6 100644
--- a/src/mint/afl-tests/id:000609,src:000000,op:int32,pos:65,val:be:+64,+cov
+++ b/src/exchange/afl-tests/id:000609,src:000000,op:int32,pos:65,val:be:+64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000610,src:000000,op:ext_AO,pos:111,+cov b/src/exchange/afl-tests/id:000610,src:000000,op:ext_AO,pos:111,+cov
index 0df8e4a5b..0df8e4a5b 100644
--- a/src/mint/afl-tests/id:000610,src:000000,op:ext_AO,pos:111,+cov
+++ b/src/exchange/afl-tests/id:000610,src:000000,op:ext_AO,pos:111,+cov
diff --git a/src/mint/afl-tests/id:000610,src:000000,op:int32,pos:66,val:+16,+cov b/src/exchange/afl-tests/id:000610,src:000000,op:int32,pos:66,val:+16,+cov
index 3d1d5bd9b..3d1d5bd9b 100644
--- a/src/mint/afl-tests/id:000610,src:000000,op:int32,pos:66,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000610,src:000000,op:int32,pos:66,val:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000611,src:000000,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000611,src:000000,op:ext_AO,pos:135,+cov
index a52b61bf5..a52b61bf5 100644
--- a/src/mint/afl-tests/id:000611,src:000000,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000611,src:000000,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000611,src:000000,op:int32,pos:73,val:+100663045,+cov b/src/exchange/afl-tests/id:000611,src:000000,op:int32,pos:73,val:+100663045,+cov
index bdf37e2e6..bdf37e2e6 100644
--- a/src/mint/afl-tests/id:000611,src:000000,op:int32,pos:73,val:+100663045,+cov
+++ b/src/exchange/afl-tests/id:000611,src:000000,op:int32,pos:73,val:+100663045,+cov
diff --git a/src/mint/afl-tests/id:000612,src:000000,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000612,src:000000,op:ext_AO,pos:135,+cov
index 8976ef5a8..8976ef5a8 100644
--- a/src/mint/afl-tests/id:000612,src:000000,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000612,src:000000,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000612,src:000000,op:int32,pos:81,val:+0,+cov b/src/exchange/afl-tests/id:000612,src:000000,op:int32,pos:81,val:+0,+cov
index ea9511a37..ea9511a37 100644
--- a/src/mint/afl-tests/id:000612,src:000000,op:int32,pos:81,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000612,src:000000,op:int32,pos:81,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000613,src:000000,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000613,src:000000,op:ext_AO,pos:135,+cov
index 86def17de..86def17de 100644
--- a/src/mint/afl-tests/id:000613,src:000000,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000613,src:000000,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000613,src:000000,op:int32,pos:82,val:+32767,+cov b/src/exchange/afl-tests/id:000613,src:000000,op:int32,pos:82,val:+32767,+cov
index dbc4b58e7..dbc4b58e7 100644
--- a/src/mint/afl-tests/id:000613,src:000000,op:int32,pos:82,val:+32767,+cov
+++ b/src/exchange/afl-tests/id:000613,src:000000,op:int32,pos:82,val:+32767,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000614,src:000000,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000614,src:000000,op:ext_AO,pos:135,+cov
index 910303eb0..910303eb0 100644
--- a/src/mint/afl-tests/id:000614,src:000000,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000614,src:000000,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000614,src:000000,op:int32,pos:83,val:be:+1000,+cov b/src/exchange/afl-tests/id:000614,src:000000,op:int32,pos:83,val:be:+1000,+cov
index f2855853c..f2855853c 100644
--- a/src/mint/afl-tests/id:000614,src:000000,op:int32,pos:83,val:be:+1000,+cov
+++ b/src/exchange/afl-tests/id:000614,src:000000,op:int32,pos:83,val:be:+1000,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000615,src:000000,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000615,src:000000,op:ext_AO,pos:135,+cov
index d7ce79a99..d7ce79a99 100644
--- a/src/mint/afl-tests/id:000615,src:000000,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000615,src:000000,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000615,src:000000,op:int32,pos:84,val:-129,+cov b/src/exchange/afl-tests/id:000615,src:000000,op:int32,pos:84,val:-129,+cov
index e79eeeb42..e79eeeb42 100644
--- a/src/mint/afl-tests/id:000615,src:000000,op:int32,pos:84,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000615,src:000000,op:int32,pos:84,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000616,src:000000,op:ext_AO,pos:136,+cov b/src/exchange/afl-tests/id:000616,src:000000,op:ext_AO,pos:136,+cov
index e3035f2a4..e3035f2a4 100644
--- a/src/mint/afl-tests/id:000616,src:000000,op:ext_AO,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000616,src:000000,op:ext_AO,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000616,src:000000,op:int32,pos:84,val:+65536,+cov b/src/exchange/afl-tests/id:000616,src:000000,op:int32,pos:84,val:+65536,+cov
index cbce866f1..cbce866f1 100644
--- a/src/mint/afl-tests/id:000616,src:000000,op:int32,pos:84,val:+65536,+cov
+++ b/src/exchange/afl-tests/id:000616,src:000000,op:int32,pos:84,val:+65536,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000617,src:000000,op:ext_AO,pos:136,+cov b/src/exchange/afl-tests/id:000617,src:000000,op:ext_AO,pos:136,+cov
index 8a1d18005..8a1d18005 100644
--- a/src/mint/afl-tests/id:000617,src:000000,op:ext_AO,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000617,src:000000,op:ext_AO,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000617,src:000000,op:int32,pos:85,val:be:+255,+cov b/src/exchange/afl-tests/id:000617,src:000000,op:int32,pos:85,val:be:+255,+cov
index f8ed1b16b..f8ed1b16b 100644
--- a/src/mint/afl-tests/id:000617,src:000000,op:int32,pos:85,val:be:+255,+cov
+++ b/src/exchange/afl-tests/id:000617,src:000000,op:int32,pos:85,val:be:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000618,src:000000,op:ext_AO,pos:137,+cov b/src/exchange/afl-tests/id:000618,src:000000,op:ext_AO,pos:137,+cov
index 90f5e51fe..90f5e51fe 100644
--- a/src/mint/afl-tests/id:000618,src:000000,op:ext_AO,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000618,src:000000,op:ext_AO,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000618,src:000000,op:int32,pos:85,val:-32769,+cov b/src/exchange/afl-tests/id:000618,src:000000,op:int32,pos:85,val:-32769,+cov
index 12571166b..12571166b 100644
--- a/src/mint/afl-tests/id:000618,src:000000,op:int32,pos:85,val:-32769,+cov
+++ b/src/exchange/afl-tests/id:000618,src:000000,op:int32,pos:85,val:-32769,+cov
diff --git a/src/mint/afl-tests/id:000619,src:000000,op:ext_AO,pos:137,+cov b/src/exchange/afl-tests/id:000619,src:000000,op:ext_AO,pos:137,+cov
index e96ebd3f9..e96ebd3f9 100644
--- a/src/mint/afl-tests/id:000619,src:000000,op:ext_AO,pos:137,+cov
+++ b/src/exchange/afl-tests/id:000619,src:000000,op:ext_AO,pos:137,+cov
diff --git a/src/mint/afl-tests/id:000619,src:000000,op:int32,pos:88,val:be:-32768,+cov b/src/exchange/afl-tests/id:000619,src:000000,op:int32,pos:88,val:be:-32768,+cov
index 94ec74c42..94ec74c42 100644
--- a/src/mint/afl-tests/id:000619,src:000000,op:int32,pos:88,val:be:-32768,+cov
+++ b/src/exchange/afl-tests/id:000619,src:000000,op:int32,pos:88,val:be:-32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000620,src:000000,op:ext_AO,pos:138,+cov b/src/exchange/afl-tests/id:000620,src:000000,op:ext_AO,pos:138,+cov
index a3e1ef509..a3e1ef509 100644
--- a/src/mint/afl-tests/id:000620,src:000000,op:ext_AO,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000620,src:000000,op:ext_AO,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000620,src:000000,op:int32,pos:91,val:+127,+cov b/src/exchange/afl-tests/id:000620,src:000000,op:int32,pos:91,val:+127,+cov
index cb0fa5b95..cb0fa5b95 100644
--- a/src/mint/afl-tests/id:000620,src:000000,op:int32,pos:91,val:+127,+cov
+++ b/src/exchange/afl-tests/id:000620,src:000000,op:int32,pos:91,val:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000621,src:000000,op:ext_AO,pos:142,+cov b/src/exchange/afl-tests/id:000621,src:000000,op:ext_AO,pos:142,+cov
index e8ac2df9c..e8ac2df9c 100644
--- a/src/mint/afl-tests/id:000621,src:000000,op:ext_AO,pos:142,+cov
+++ b/src/exchange/afl-tests/id:000621,src:000000,op:ext_AO,pos:142,+cov
diff --git a/src/mint/afl-tests/id:000621,src:000000,op:int32,pos:92,val:-32768,+cov b/src/exchange/afl-tests/id:000621,src:000000,op:int32,pos:92,val:-32768,+cov
index b028d283c..b028d283c 100644
--- a/src/mint/afl-tests/id:000621,src:000000,op:int32,pos:92,val:-32768,+cov
+++ b/src/exchange/afl-tests/id:000621,src:000000,op:int32,pos:92,val:-32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000622,src:000000,op:ext_AO,pos:143,+cov b/src/exchange/afl-tests/id:000622,src:000000,op:ext_AO,pos:143,+cov
index 14f1add75..14f1add75 100644
--- a/src/mint/afl-tests/id:000622,src:000000,op:ext_AO,pos:143,+cov
+++ b/src/exchange/afl-tests/id:000622,src:000000,op:ext_AO,pos:143,+cov
diff --git a/src/mint/afl-tests/id:000622,src:000000,op:int32,pos:98,val:-129,+cov b/src/exchange/afl-tests/id:000622,src:000000,op:int32,pos:98,val:-129,+cov
index 7a3a4013d..7a3a4013d 100644
--- a/src/mint/afl-tests/id:000622,src:000000,op:int32,pos:98,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000622,src:000000,op:int32,pos:98,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000623,src:000000,op:ext_AO,pos:144,+cov b/src/exchange/afl-tests/id:000623,src:000000,op:ext_AO,pos:144,+cov
index dafecc248..dafecc248 100644
--- a/src/mint/afl-tests/id:000623,src:000000,op:ext_AO,pos:144,+cov
+++ b/src/exchange/afl-tests/id:000623,src:000000,op:ext_AO,pos:144,+cov
diff --git a/src/mint/afl-tests/id:000623,src:000000,op:int32,pos:128,val:-32769,+cov b/src/exchange/afl-tests/id:000623,src:000000,op:int32,pos:128,val:-32769,+cov
index 6f1390a02..6f1390a02 100644
--- a/src/mint/afl-tests/id:000623,src:000000,op:int32,pos:128,val:-32769,+cov
+++ b/src/exchange/afl-tests/id:000623,src:000000,op:int32,pos:128,val:-32769,+cov
diff --git a/src/mint/afl-tests/id:000624,src:000000,op:ext_AO,pos:144,+cov b/src/exchange/afl-tests/id:000624,src:000000,op:ext_AO,pos:144,+cov
index d6c83a418..d6c83a418 100644
--- a/src/mint/afl-tests/id:000624,src:000000,op:ext_AO,pos:144,+cov
+++ b/src/exchange/afl-tests/id:000624,src:000000,op:ext_AO,pos:144,+cov
diff --git a/src/mint/afl-tests/id:000624,src:000000,op:int32,pos:160,val:be:+512,+cov b/src/exchange/afl-tests/id:000624,src:000000,op:int32,pos:160,val:be:+512,+cov
index 1deea2e62..1deea2e62 100644
--- a/src/mint/afl-tests/id:000624,src:000000,op:int32,pos:160,val:be:+512,+cov
+++ b/src/exchange/afl-tests/id:000624,src:000000,op:int32,pos:160,val:be:+512,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000625,src:000000,op:ext_AO,pos:145,+cov b/src/exchange/afl-tests/id:000625,src:000000,op:ext_AO,pos:145,+cov
index 4b2cd1cdc..4b2cd1cdc 100644
--- a/src/mint/afl-tests/id:000625,src:000000,op:ext_AO,pos:145,+cov
+++ b/src/exchange/afl-tests/id:000625,src:000000,op:ext_AO,pos:145,+cov
diff --git a/src/mint/afl-tests/id:000625,src:000000,op:int32,pos:203,val:be:+1,+cov b/src/exchange/afl-tests/id:000625,src:000000,op:int32,pos:203,val:be:+1,+cov
index f6766c47e..f6766c47e 100644
--- a/src/mint/afl-tests/id:000625,src:000000,op:int32,pos:203,val:be:+1,+cov
+++ b/src/exchange/afl-tests/id:000625,src:000000,op:int32,pos:203,val:be:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000626,src:000000,op:ext_AO,pos:146,+cov b/src/exchange/afl-tests/id:000626,src:000000,op:ext_AO,pos:146,+cov
index 6e4a7a142..6e4a7a142 100644
--- a/src/mint/afl-tests/id:000626,src:000000,op:ext_AO,pos:146,+cov
+++ b/src/exchange/afl-tests/id:000626,src:000000,op:ext_AO,pos:146,+cov
diff --git a/src/mint/afl-tests/id:000626,src:000000,op:int32,pos:263,val:+0,+cov b/src/exchange/afl-tests/id:000626,src:000000,op:int32,pos:263,val:+0,+cov
index afbb36a51..afbb36a51 100644
--- a/src/mint/afl-tests/id:000626,src:000000,op:int32,pos:263,val:+0,+cov
+++ b/src/exchange/afl-tests/id:000626,src:000000,op:int32,pos:263,val:+0,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000627,src:000000,op:ext_AO,pos:146,+cov b/src/exchange/afl-tests/id:000627,src:000000,op:ext_AO,pos:146,+cov
index 0d7b09410..0d7b09410 100644
--- a/src/mint/afl-tests/id:000627,src:000000,op:ext_AO,pos:146,+cov
+++ b/src/exchange/afl-tests/id:000627,src:000000,op:ext_AO,pos:146,+cov
diff --git a/src/mint/afl-tests/id:000627,src:000000,op:int32,pos:264,val:be:-32769,+cov b/src/exchange/afl-tests/id:000627,src:000000,op:int32,pos:264,val:be:-32769,+cov
index 8cf21b635..8cf21b635 100644
--- a/src/mint/afl-tests/id:000627,src:000000,op:int32,pos:264,val:be:-32769,+cov
+++ b/src/exchange/afl-tests/id:000627,src:000000,op:int32,pos:264,val:be:-32769,+cov
diff --git a/src/mint/afl-tests/id:000628,src:000000,op:ext_AO,pos:147,+cov b/src/exchange/afl-tests/id:000628,src:000000,op:ext_AO,pos:147,+cov
index ff86f51a4..ff86f51a4 100644
--- a/src/mint/afl-tests/id:000628,src:000000,op:ext_AO,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000628,src:000000,op:ext_AO,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000628,src:000000,op:int32,pos:285,val:+100663045,+cov b/src/exchange/afl-tests/id:000628,src:000000,op:int32,pos:285,val:+100663045,+cov
index 0e675506a..0e675506a 100644
--- a/src/mint/afl-tests/id:000628,src:000000,op:int32,pos:285,val:+100663045,+cov
+++ b/src/exchange/afl-tests/id:000628,src:000000,op:int32,pos:285,val:+100663045,+cov
diff --git a/src/mint/afl-tests/id:000629,src:000000,op:ext_AO,pos:147,+cov b/src/exchange/afl-tests/id:000629,src:000000,op:ext_AO,pos:147,+cov
index ee843bb56..ee843bb56 100644
--- a/src/mint/afl-tests/id:000629,src:000000,op:ext_AO,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000629,src:000000,op:ext_AO,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000629,src:000000,op:ext_AO,pos:34,+cov b/src/exchange/afl-tests/id:000629,src:000000,op:ext_AO,pos:34,+cov
index cc3d06f93..cc3d06f93 100644
--- a/src/mint/afl-tests/id:000629,src:000000,op:ext_AO,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000629,src:000000,op:ext_AO,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000630,src:000000,op:ext_AO,pos:148,+cov b/src/exchange/afl-tests/id:000630,src:000000,op:ext_AO,pos:148,+cov
index f77decdbb..f77decdbb 100644
--- a/src/mint/afl-tests/id:000630,src:000000,op:ext_AO,pos:148,+cov
+++ b/src/exchange/afl-tests/id:000630,src:000000,op:ext_AO,pos:148,+cov
diff --git a/src/mint/afl-tests/id:000630,src:000000,op:ext_AO,pos:34,+cov b/src/exchange/afl-tests/id:000630,src:000000,op:ext_AO,pos:34,+cov
index 5cce5e9f4..5cce5e9f4 100644
--- a/src/mint/afl-tests/id:000630,src:000000,op:ext_AO,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000630,src:000000,op:ext_AO,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000631,src:000000,op:ext_AO,pos:148 b/src/exchange/afl-tests/id:000631,src:000000,op:ext_AO,pos:148
index 7e9a70a33..7e9a70a33 100644
--- a/src/mint/afl-tests/id:000631,src:000000,op:ext_AO,pos:148
+++ b/src/exchange/afl-tests/id:000631,src:000000,op:ext_AO,pos:148
diff --git a/src/mint/afl-tests/id:000631,src:000000,op:ext_AO,pos:37,+cov b/src/exchange/afl-tests/id:000631,src:000000,op:ext_AO,pos:37,+cov
index c9c21d4b6..c9c21d4b6 100644
--- a/src/mint/afl-tests/id:000631,src:000000,op:ext_AO,pos:37,+cov
+++ b/src/exchange/afl-tests/id:000631,src:000000,op:ext_AO,pos:37,+cov
diff --git a/src/mint/afl-tests/id:000632,src:000000,op:ext_AO,pos:149,+cov b/src/exchange/afl-tests/id:000632,src:000000,op:ext_AO,pos:149,+cov
index 94ab1358b..94ab1358b 100644
--- a/src/mint/afl-tests/id:000632,src:000000,op:ext_AO,pos:149,+cov
+++ b/src/exchange/afl-tests/id:000632,src:000000,op:ext_AO,pos:149,+cov
diff --git a/src/mint/afl-tests/id:000632,src:000000,op:ext_AO,pos:39,+cov b/src/exchange/afl-tests/id:000632,src:000000,op:ext_AO,pos:39,+cov
index 4d1eb5e56..4d1eb5e56 100644
--- a/src/mint/afl-tests/id:000632,src:000000,op:ext_AO,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000632,src:000000,op:ext_AO,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000633,src:000000,op:ext_AO,pos:152,+cov b/src/exchange/afl-tests/id:000633,src:000000,op:ext_AO,pos:152,+cov
index fe43072ea..fe43072ea 100644
--- a/src/mint/afl-tests/id:000633,src:000000,op:ext_AO,pos:152,+cov
+++ b/src/exchange/afl-tests/id:000633,src:000000,op:ext_AO,pos:152,+cov
diff --git a/src/mint/afl-tests/id:000633,src:000000,op:ext_AO,pos:49,+cov b/src/exchange/afl-tests/id:000633,src:000000,op:ext_AO,pos:49,+cov
index 847873c6a..847873c6a 100644
--- a/src/mint/afl-tests/id:000633,src:000000,op:ext_AO,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000633,src:000000,op:ext_AO,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000634,src:000000,op:ext_AO,pos:154 b/src/exchange/afl-tests/id:000634,src:000000,op:ext_AO,pos:154
index 8e81e7169..8e81e7169 100644
--- a/src/mint/afl-tests/id:000634,src:000000,op:ext_AO,pos:154
+++ b/src/exchange/afl-tests/id:000634,src:000000,op:ext_AO,pos:154
diff --git a/src/mint/afl-tests/id:000634,src:000000,op:ext_AO,pos:51,+cov b/src/exchange/afl-tests/id:000634,src:000000,op:ext_AO,pos:51,+cov
index ae5057d7a..ae5057d7a 100644
--- a/src/mint/afl-tests/id:000634,src:000000,op:ext_AO,pos:51,+cov
+++ b/src/exchange/afl-tests/id:000634,src:000000,op:ext_AO,pos:51,+cov
diff --git a/src/mint/afl-tests/id:000635,src:000000,op:ext_AO,pos:155,+cov b/src/exchange/afl-tests/id:000635,src:000000,op:ext_AO,pos:155,+cov
index 2c7f95073..2c7f95073 100644
--- a/src/mint/afl-tests/id:000635,src:000000,op:ext_AO,pos:155,+cov
+++ b/src/exchange/afl-tests/id:000635,src:000000,op:ext_AO,pos:155,+cov
diff --git a/src/mint/afl-tests/id:000635,src:000000,op:ext_AO,pos:52,+cov b/src/exchange/afl-tests/id:000635,src:000000,op:ext_AO,pos:52,+cov
index 78724df11..78724df11 100644
--- a/src/mint/afl-tests/id:000635,src:000000,op:ext_AO,pos:52,+cov
+++ b/src/exchange/afl-tests/id:000635,src:000000,op:ext_AO,pos:52,+cov
diff --git a/src/mint/afl-tests/id:000636,src:000000,op:ext_AO,pos:156,+cov b/src/exchange/afl-tests/id:000636,src:000000,op:ext_AO,pos:156,+cov
index 2720102ef..2720102ef 100644
--- a/src/mint/afl-tests/id:000636,src:000000,op:ext_AO,pos:156,+cov
+++ b/src/exchange/afl-tests/id:000636,src:000000,op:ext_AO,pos:156,+cov
diff --git a/src/mint/afl-tests/id:000636,src:000000,op:ext_AO,pos:52,+cov b/src/exchange/afl-tests/id:000636,src:000000,op:ext_AO,pos:52,+cov
index 46cd3c17c..46cd3c17c 100644
--- a/src/mint/afl-tests/id:000636,src:000000,op:ext_AO,pos:52,+cov
+++ b/src/exchange/afl-tests/id:000636,src:000000,op:ext_AO,pos:52,+cov
diff --git a/src/mint/afl-tests/id:000637,src:000000,op:ext_AO,pos:157 b/src/exchange/afl-tests/id:000637,src:000000,op:ext_AO,pos:157
index badf57384..badf57384 100644
--- a/src/mint/afl-tests/id:000637,src:000000,op:ext_AO,pos:157
+++ b/src/exchange/afl-tests/id:000637,src:000000,op:ext_AO,pos:157
diff --git a/src/mint/afl-tests/id:000637,src:000000,op:ext_AO,pos:58,+cov b/src/exchange/afl-tests/id:000637,src:000000,op:ext_AO,pos:58,+cov
index 70b4664ee..70b4664ee 100644
--- a/src/mint/afl-tests/id:000637,src:000000,op:ext_AO,pos:58,+cov
+++ b/src/exchange/afl-tests/id:000637,src:000000,op:ext_AO,pos:58,+cov
diff --git a/src/mint/afl-tests/id:000638,src:000000,op:ext_AO,pos:159,+cov b/src/exchange/afl-tests/id:000638,src:000000,op:ext_AO,pos:159,+cov
index 4d637f622..4d637f622 100644
--- a/src/mint/afl-tests/id:000638,src:000000,op:ext_AO,pos:159,+cov
+++ b/src/exchange/afl-tests/id:000638,src:000000,op:ext_AO,pos:159,+cov
diff --git a/src/mint/afl-tests/id:000638,src:000000,op:ext_AO,pos:64,+cov b/src/exchange/afl-tests/id:000638,src:000000,op:ext_AO,pos:64,+cov
index a4f0265ac..a4f0265ac 100644
--- a/src/mint/afl-tests/id:000638,src:000000,op:ext_AO,pos:64,+cov
+++ b/src/exchange/afl-tests/id:000638,src:000000,op:ext_AO,pos:64,+cov
diff --git a/src/mint/afl-tests/id:000639,src:000000,op:ext_AO,pos:161,+cov b/src/exchange/afl-tests/id:000639,src:000000,op:ext_AO,pos:161,+cov
index 834a625b2..834a625b2 100644
--- a/src/mint/afl-tests/id:000639,src:000000,op:ext_AO,pos:161,+cov
+++ b/src/exchange/afl-tests/id:000639,src:000000,op:ext_AO,pos:161,+cov
diff --git a/src/mint/afl-tests/id:000639,src:000000,op:ext_AO,pos:86,+cov b/src/exchange/afl-tests/id:000639,src:000000,op:ext_AO,pos:86,+cov
index e4e9bbcc2..e4e9bbcc2 100644
--- a/src/mint/afl-tests/id:000639,src:000000,op:ext_AO,pos:86,+cov
+++ b/src/exchange/afl-tests/id:000639,src:000000,op:ext_AO,pos:86,+cov
diff --git a/src/mint/afl-tests/id:000640,src:000000,op:ext_AO,pos:166,+cov b/src/exchange/afl-tests/id:000640,src:000000,op:ext_AO,pos:166,+cov
index 564a35643..564a35643 100644
--- a/src/mint/afl-tests/id:000640,src:000000,op:ext_AO,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000640,src:000000,op:ext_AO,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000640,src:000000,op:ext_AO,pos:88,+cov b/src/exchange/afl-tests/id:000640,src:000000,op:ext_AO,pos:88,+cov
index bcc90b4a5..bcc90b4a5 100644
--- a/src/mint/afl-tests/id:000640,src:000000,op:ext_AO,pos:88,+cov
+++ b/src/exchange/afl-tests/id:000640,src:000000,op:ext_AO,pos:88,+cov
diff --git a/src/mint/afl-tests/id:000641,src:000000,op:ext_AO,pos:168,+cov b/src/exchange/afl-tests/id:000641,src:000000,op:ext_AO,pos:168,+cov
index 09adf0f06..09adf0f06 100644
--- a/src/mint/afl-tests/id:000641,src:000000,op:ext_AO,pos:168,+cov
+++ b/src/exchange/afl-tests/id:000641,src:000000,op:ext_AO,pos:168,+cov
diff --git a/src/mint/afl-tests/id:000641,src:000000,op:ext_AO,pos:93,+cov b/src/exchange/afl-tests/id:000641,src:000000,op:ext_AO,pos:93,+cov
index f7c40c1ac..f7c40c1ac 100644
--- a/src/mint/afl-tests/id:000641,src:000000,op:ext_AO,pos:93,+cov
+++ b/src/exchange/afl-tests/id:000641,src:000000,op:ext_AO,pos:93,+cov
diff --git a/src/mint/afl-tests/id:000642,src:000000,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000642,src:000000,op:ext_AO,pos:135,+cov
index b84cd74b3..b84cd74b3 100644
--- a/src/mint/afl-tests/id:000642,src:000000,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000642,src:000000,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000642,src:000000,op:ext_AO,pos:169,+cov b/src/exchange/afl-tests/id:000642,src:000000,op:ext_AO,pos:169,+cov
index 86c01fb33..86c01fb33 100644
--- a/src/mint/afl-tests/id:000642,src:000000,op:ext_AO,pos:169,+cov
+++ b/src/exchange/afl-tests/id:000642,src:000000,op:ext_AO,pos:169,+cov
diff --git a/src/mint/afl-tests/id:000643,src:000000,op:ext_AO,pos:136,+cov b/src/exchange/afl-tests/id:000643,src:000000,op:ext_AO,pos:136,+cov
index cef8d7154..cef8d7154 100644
--- a/src/mint/afl-tests/id:000643,src:000000,op:ext_AO,pos:136,+cov
+++ b/src/exchange/afl-tests/id:000643,src:000000,op:ext_AO,pos:136,+cov
diff --git a/src/mint/afl-tests/id:000643,src:000000,op:ext_AO,pos:173,+cov b/src/exchange/afl-tests/id:000643,src:000000,op:ext_AO,pos:173,+cov
index ee287ac69..ee287ac69 100644
--- a/src/mint/afl-tests/id:000643,src:000000,op:ext_AO,pos:173,+cov
+++ b/src/exchange/afl-tests/id:000643,src:000000,op:ext_AO,pos:173,+cov
diff --git a/src/mint/afl-tests/id:000644,src:000000,op:ext_AO,pos:138,+cov b/src/exchange/afl-tests/id:000644,src:000000,op:ext_AO,pos:138,+cov
index 7c05ea6c7..7c05ea6c7 100644
--- a/src/mint/afl-tests/id:000644,src:000000,op:ext_AO,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000644,src:000000,op:ext_AO,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000644,src:000000,op:ext_AO,pos:174,+cov b/src/exchange/afl-tests/id:000644,src:000000,op:ext_AO,pos:174,+cov
index c8ecd5b05..c8ecd5b05 100644
--- a/src/mint/afl-tests/id:000644,src:000000,op:ext_AO,pos:174,+cov
+++ b/src/exchange/afl-tests/id:000644,src:000000,op:ext_AO,pos:174,+cov
diff --git a/src/mint/afl-tests/id:000645,src:000000,op:ext_AO,pos:140,+cov b/src/exchange/afl-tests/id:000645,src:000000,op:ext_AO,pos:140,+cov
index 69a20ba21..69a20ba21 100644
--- a/src/mint/afl-tests/id:000645,src:000000,op:ext_AO,pos:140,+cov
+++ b/src/exchange/afl-tests/id:000645,src:000000,op:ext_AO,pos:140,+cov
diff --git a/src/mint/afl-tests/id:000645,src:000000,op:ext_AO,pos:174,+cov b/src/exchange/afl-tests/id:000645,src:000000,op:ext_AO,pos:174,+cov
index e195384f7..e195384f7 100644
--- a/src/mint/afl-tests/id:000645,src:000000,op:ext_AO,pos:174,+cov
+++ b/src/exchange/afl-tests/id:000645,src:000000,op:ext_AO,pos:174,+cov
diff --git a/src/mint/afl-tests/id:000646,src:000000,op:ext_AO,pos:143,+cov b/src/exchange/afl-tests/id:000646,src:000000,op:ext_AO,pos:143,+cov
index 8e0f8560c..8e0f8560c 100644
--- a/src/mint/afl-tests/id:000646,src:000000,op:ext_AO,pos:143,+cov
+++ b/src/exchange/afl-tests/id:000646,src:000000,op:ext_AO,pos:143,+cov
diff --git a/src/mint/afl-tests/id:000646,src:000000,op:ext_AO,pos:184,+cov b/src/exchange/afl-tests/id:000646,src:000000,op:ext_AO,pos:184,+cov
index 8b17a9821..8b17a9821 100644
--- a/src/mint/afl-tests/id:000646,src:000000,op:ext_AO,pos:184,+cov
+++ b/src/exchange/afl-tests/id:000646,src:000000,op:ext_AO,pos:184,+cov
diff --git a/src/mint/afl-tests/id:000647,src:000000,op:ext_AO,pos:144,+cov b/src/exchange/afl-tests/id:000647,src:000000,op:ext_AO,pos:144,+cov
index f25b06780..f25b06780 100644
--- a/src/mint/afl-tests/id:000647,src:000000,op:ext_AO,pos:144,+cov
+++ b/src/exchange/afl-tests/id:000647,src:000000,op:ext_AO,pos:144,+cov
diff --git a/src/mint/afl-tests/id:000647,src:000000,op:ext_AO,pos:191,+cov b/src/exchange/afl-tests/id:000647,src:000000,op:ext_AO,pos:191,+cov
index 677678b5d..677678b5d 100644
--- a/src/mint/afl-tests/id:000647,src:000000,op:ext_AO,pos:191,+cov
+++ b/src/exchange/afl-tests/id:000647,src:000000,op:ext_AO,pos:191,+cov
diff --git a/src/mint/afl-tests/id:000648,src:000000,op:ext_AO,pos:155,+cov b/src/exchange/afl-tests/id:000648,src:000000,op:ext_AO,pos:155,+cov
index 06d082e76..06d082e76 100644
--- a/src/mint/afl-tests/id:000648,src:000000,op:ext_AO,pos:155,+cov
+++ b/src/exchange/afl-tests/id:000648,src:000000,op:ext_AO,pos:155,+cov
diff --git a/src/mint/afl-tests/id:000648,src:000000,op:ext_AO,pos:216,+cov b/src/exchange/afl-tests/id:000648,src:000000,op:ext_AO,pos:216,+cov
index b0bebb4df..b0bebb4df 100644
--- a/src/mint/afl-tests/id:000648,src:000000,op:ext_AO,pos:216,+cov
+++ b/src/exchange/afl-tests/id:000648,src:000000,op:ext_AO,pos:216,+cov
diff --git a/src/mint/afl-tests/id:000649,src:000000,op:ext_AO,pos:166,+cov b/src/exchange/afl-tests/id:000649,src:000000,op:ext_AO,pos:166,+cov
index 5cd10dd47..5cd10dd47 100644
--- a/src/mint/afl-tests/id:000649,src:000000,op:ext_AO,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000649,src:000000,op:ext_AO,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000649,src:000000,op:ext_AO,pos:236,+cov b/src/exchange/afl-tests/id:000649,src:000000,op:ext_AO,pos:236,+cov
index 718b3e801..718b3e801 100644
--- a/src/mint/afl-tests/id:000649,src:000000,op:ext_AO,pos:236,+cov
+++ b/src/exchange/afl-tests/id:000649,src:000000,op:ext_AO,pos:236,+cov
diff --git a/src/mint/afl-tests/id:000650,src:000000,op:ext_AO,pos:166,+cov b/src/exchange/afl-tests/id:000650,src:000000,op:ext_AO,pos:166,+cov
index ac8dcb24d..ac8dcb24d 100644
--- a/src/mint/afl-tests/id:000650,src:000000,op:ext_AO,pos:166,+cov
+++ b/src/exchange/afl-tests/id:000650,src:000000,op:ext_AO,pos:166,+cov
diff --git a/src/mint/afl-tests/id:000650,src:000000,op:ext_AO,pos:270,+cov b/src/exchange/afl-tests/id:000650,src:000000,op:ext_AO,pos:270,+cov
index dc4210b2d..dc4210b2d 100644
--- a/src/mint/afl-tests/id:000650,src:000000,op:ext_AO,pos:270,+cov
+++ b/src/exchange/afl-tests/id:000650,src:000000,op:ext_AO,pos:270,+cov
diff --git a/src/mint/afl-tests/id:000651,src:000000,op:ext_AO,pos:173,+cov b/src/exchange/afl-tests/id:000651,src:000000,op:ext_AO,pos:173,+cov
index 58291cb5a..58291cb5a 100644
--- a/src/mint/afl-tests/id:000651,src:000000,op:ext_AO,pos:173,+cov
+++ b/src/exchange/afl-tests/id:000651,src:000000,op:ext_AO,pos:173,+cov
diff --git a/src/mint/afl-tests/id:000651,src:000000,op:ext_AO,pos:270,+cov b/src/exchange/afl-tests/id:000651,src:000000,op:ext_AO,pos:270,+cov
index 2158953af..2158953af 100644
--- a/src/mint/afl-tests/id:000651,src:000000,op:ext_AO,pos:270,+cov
+++ b/src/exchange/afl-tests/id:000651,src:000000,op:ext_AO,pos:270,+cov
diff --git a/src/mint/afl-tests/id:000652,src:000000,op:ext_AO,pos:175,+cov b/src/exchange/afl-tests/id:000652,src:000000,op:ext_AO,pos:175,+cov
index 6824cf415..6824cf415 100644
--- a/src/mint/afl-tests/id:000652,src:000000,op:ext_AO,pos:175,+cov
+++ b/src/exchange/afl-tests/id:000652,src:000000,op:ext_AO,pos:175,+cov
diff --git a/src/mint/afl-tests/id:000652,src:000000,op:ext_AO,pos:272,+cov b/src/exchange/afl-tests/id:000652,src:000000,op:ext_AO,pos:272,+cov
index f0baddfe8..f0baddfe8 100644
--- a/src/mint/afl-tests/id:000652,src:000000,op:ext_AO,pos:272,+cov
+++ b/src/exchange/afl-tests/id:000652,src:000000,op:ext_AO,pos:272,+cov
diff --git a/src/mint/afl-tests/id:000653,src:000000,op:ext_AO,pos:176,+cov b/src/exchange/afl-tests/id:000653,src:000000,op:ext_AO,pos:176,+cov
index dc4bf4c2e..dc4bf4c2e 100644
--- a/src/mint/afl-tests/id:000653,src:000000,op:ext_AO,pos:176,+cov
+++ b/src/exchange/afl-tests/id:000653,src:000000,op:ext_AO,pos:176,+cov
diff --git a/src/mint/afl-tests/id:000653,src:000000,op:ext_AO,pos:283,+cov b/src/exchange/afl-tests/id:000653,src:000000,op:ext_AO,pos:283,+cov
index b936e800d..b936e800d 100644
--- a/src/mint/afl-tests/id:000653,src:000000,op:ext_AO,pos:283,+cov
+++ b/src/exchange/afl-tests/id:000653,src:000000,op:ext_AO,pos:283,+cov
diff --git a/src/mint/afl-tests/id:000654,src:000000,op:ext_AO,pos:177,+cov b/src/exchange/afl-tests/id:000654,src:000000,op:ext_AO,pos:177,+cov
index 95b9a73b5..95b9a73b5 100644
--- a/src/mint/afl-tests/id:000654,src:000000,op:ext_AO,pos:177,+cov
+++ b/src/exchange/afl-tests/id:000654,src:000000,op:ext_AO,pos:177,+cov
diff --git a/src/mint/afl-tests/id:000654,src:000000,op:ext_AO,pos:305,+cov b/src/exchange/afl-tests/id:000654,src:000000,op:ext_AO,pos:305,+cov
index addd57fea..addd57fea 100644
--- a/src/mint/afl-tests/id:000654,src:000000,op:ext_AO,pos:305,+cov
+++ b/src/exchange/afl-tests/id:000654,src:000000,op:ext_AO,pos:305,+cov
diff --git a/src/mint/afl-tests/id:000655,src:000000,op:ext_AO,pos:177,+cov b/src/exchange/afl-tests/id:000655,src:000000,op:ext_AO,pos:177,+cov
index 03fcb96d8..03fcb96d8 100644
--- a/src/mint/afl-tests/id:000655,src:000000,op:ext_AO,pos:177,+cov
+++ b/src/exchange/afl-tests/id:000655,src:000000,op:ext_AO,pos:177,+cov
diff --git a/src/mint/afl-tests/id:000655,src:000000,op:ext_AO,pos:305,+cov b/src/exchange/afl-tests/id:000655,src:000000,op:ext_AO,pos:305,+cov
index 20cfec7b0..20cfec7b0 100644
--- a/src/mint/afl-tests/id:000655,src:000000,op:ext_AO,pos:305,+cov
+++ b/src/exchange/afl-tests/id:000655,src:000000,op:ext_AO,pos:305,+cov
diff --git a/src/mint/afl-tests/id:000656,src:000000,op:ext_AO,pos:177,+cov b/src/exchange/afl-tests/id:000656,src:000000,op:ext_AO,pos:177,+cov
index a10edac6b..a10edac6b 100644
--- a/src/mint/afl-tests/id:000656,src:000000,op:ext_AO,pos:177,+cov
+++ b/src/exchange/afl-tests/id:000656,src:000000,op:ext_AO,pos:177,+cov
diff --git a/src/mint/afl-tests/id:000656,src:000000,op:ext_AO,pos:313,+cov b/src/exchange/afl-tests/id:000656,src:000000,op:ext_AO,pos:313,+cov
index a91439c67..a91439c67 100644
--- a/src/mint/afl-tests/id:000656,src:000000,op:ext_AO,pos:313,+cov
+++ b/src/exchange/afl-tests/id:000656,src:000000,op:ext_AO,pos:313,+cov
diff --git a/src/mint/afl-tests/id:000657,src:000000,op:ext_AO,pos:180,+cov b/src/exchange/afl-tests/id:000657,src:000000,op:ext_AO,pos:180,+cov
index cd808e41c..cd808e41c 100644
--- a/src/mint/afl-tests/id:000657,src:000000,op:ext_AO,pos:180,+cov
+++ b/src/exchange/afl-tests/id:000657,src:000000,op:ext_AO,pos:180,+cov
diff --git a/src/mint/afl-tests/id:000657,src:000000,op:ext_AO,pos:315,+cov b/src/exchange/afl-tests/id:000657,src:000000,op:ext_AO,pos:315,+cov
index 4ae499e68..4ae499e68 100644
--- a/src/mint/afl-tests/id:000657,src:000000,op:ext_AO,pos:315,+cov
+++ b/src/exchange/afl-tests/id:000657,src:000000,op:ext_AO,pos:315,+cov
diff --git a/src/mint/afl-tests/id:000658,src:000000,op:ext_AO,pos:182,+cov b/src/exchange/afl-tests/id:000658,src:000000,op:ext_AO,pos:182,+cov
index edbf60217..edbf60217 100644
--- a/src/mint/afl-tests/id:000658,src:000000,op:ext_AO,pos:182,+cov
+++ b/src/exchange/afl-tests/id:000658,src:000000,op:ext_AO,pos:182,+cov
diff --git a/src/mint/afl-tests/id:000658,src:000000,op:ext_AO,pos:326 b/src/exchange/afl-tests/id:000658,src:000000,op:ext_AO,pos:326
index 3041455e7..3041455e7 100644
--- a/src/mint/afl-tests/id:000658,src:000000,op:ext_AO,pos:326
+++ b/src/exchange/afl-tests/id:000658,src:000000,op:ext_AO,pos:326
diff --git a/src/mint/afl-tests/id:000659,src:000000,op:ext_AO,pos:269,+cov b/src/exchange/afl-tests/id:000659,src:000000,op:ext_AO,pos:269,+cov
index b376590f6..b376590f6 100644
--- a/src/mint/afl-tests/id:000659,src:000000,op:ext_AO,pos:269,+cov
+++ b/src/exchange/afl-tests/id:000659,src:000000,op:ext_AO,pos:269,+cov
diff --git a/src/mint/afl-tests/id:000659,src:000000,op:havoc,rep:4 b/src/exchange/afl-tests/id:000659,src:000000,op:havoc,rep:4
index 5dcfe5fdc..5dcfe5fdc 100644
--- a/src/mint/afl-tests/id:000659,src:000000,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000659,src:000000,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000660,src:000000,op:ext_AO,pos:270,+cov b/src/exchange/afl-tests/id:000660,src:000000,op:ext_AO,pos:270,+cov
index f0d727704..f0d727704 100644
--- a/src/mint/afl-tests/id:000660,src:000000,op:ext_AO,pos:270,+cov
+++ b/src/exchange/afl-tests/id:000660,src:000000,op:ext_AO,pos:270,+cov
diff --git a/src/mint/afl-tests/id:000660,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000660,src:000000,op:havoc,rep:32
index dd32b50cb..dd32b50cb 100644
--- a/src/mint/afl-tests/id:000660,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000660,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000661,src:000000,op:ext_AO,pos:271,+cov b/src/exchange/afl-tests/id:000661,src:000000,op:ext_AO,pos:271,+cov
index adcffb913..adcffb913 100644
--- a/src/mint/afl-tests/id:000661,src:000000,op:ext_AO,pos:271,+cov
+++ b/src/exchange/afl-tests/id:000661,src:000000,op:ext_AO,pos:271,+cov
diff --git a/src/mint/afl-tests/id:000661,src:000000,op:havoc,rep:4 b/src/exchange/afl-tests/id:000661,src:000000,op:havoc,rep:4
index 67e813dfc..67e813dfc 100644
--- a/src/mint/afl-tests/id:000661,src:000000,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000661,src:000000,op:havoc,rep:4
Binary files differ
diff --git a/src/mint/afl-tests/id:000662,src:000000,op:ext_AO,pos:274,+cov b/src/exchange/afl-tests/id:000662,src:000000,op:ext_AO,pos:274,+cov
index f37b3c188..f37b3c188 100644
--- a/src/mint/afl-tests/id:000662,src:000000,op:ext_AO,pos:274,+cov
+++ b/src/exchange/afl-tests/id:000662,src:000000,op:ext_AO,pos:274,+cov
diff --git a/src/mint/afl-tests/id:000662,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000662,src:000000,op:havoc,rep:128
index 0bee01e14..0bee01e14 100644
--- a/src/mint/afl-tests/id:000662,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000662,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000663,src:000000,op:ext_AO,pos:275,+cov b/src/exchange/afl-tests/id:000663,src:000000,op:ext_AO,pos:275,+cov
index 54388381f..54388381f 100644
--- a/src/mint/afl-tests/id:000663,src:000000,op:ext_AO,pos:275,+cov
+++ b/src/exchange/afl-tests/id:000663,src:000000,op:ext_AO,pos:275,+cov
diff --git a/src/mint/afl-tests/id:000663,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000663,src:000000,op:havoc,rep:32
index 123364746..123364746 100644
--- a/src/mint/afl-tests/id:000663,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000663,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000664,src:000000,op:ext_AO,pos:305,+cov b/src/exchange/afl-tests/id:000664,src:000000,op:ext_AO,pos:305,+cov
index b5739241d..b5739241d 100644
--- a/src/mint/afl-tests/id:000664,src:000000,op:ext_AO,pos:305,+cov
+++ b/src/exchange/afl-tests/id:000664,src:000000,op:ext_AO,pos:305,+cov
diff --git a/src/mint/afl-tests/id:000664,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000664,src:000000,op:havoc,rep:128
index a222c4d9a..a222c4d9a 100644
--- a/src/mint/afl-tests/id:000664,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000664,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000665,src:000000,op:ext_AO,pos:312,+cov b/src/exchange/afl-tests/id:000665,src:000000,op:ext_AO,pos:312,+cov
index bd28837ad..bd28837ad 100644
--- a/src/mint/afl-tests/id:000665,src:000000,op:ext_AO,pos:312,+cov
+++ b/src/exchange/afl-tests/id:000665,src:000000,op:ext_AO,pos:312,+cov
diff --git a/src/mint/afl-tests/id:000665,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000665,src:000000,op:havoc,rep:16,+cov
index b394befe3..b394befe3 100644
--- a/src/mint/afl-tests/id:000665,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000665,src:000000,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000666,src:000000,op:ext_AO,pos:314,+cov b/src/exchange/afl-tests/id:000666,src:000000,op:ext_AO,pos:314,+cov
index b09d7c472..b09d7c472 100644
--- a/src/mint/afl-tests/id:000666,src:000000,op:ext_AO,pos:314,+cov
+++ b/src/exchange/afl-tests/id:000666,src:000000,op:ext_AO,pos:314,+cov
diff --git a/src/mint/afl-tests/id:000666,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000666,src:000000,op:havoc,rep:64
index 1db866d51..1db866d51 100644
--- a/src/mint/afl-tests/id:000666,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000666,src:000000,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000667,src:000000,op:ext_AO,pos:319,+cov b/src/exchange/afl-tests/id:000667,src:000000,op:ext_AO,pos:319,+cov
index 1e66b4578..1e66b4578 100644
--- a/src/mint/afl-tests/id:000667,src:000000,op:ext_AO,pos:319,+cov
+++ b/src/exchange/afl-tests/id:000667,src:000000,op:ext_AO,pos:319,+cov
diff --git a/src/mint/afl-tests/id:000667,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000667,src:000000,op:havoc,rep:16
index bc2599f63..bc2599f63 100644
--- a/src/mint/afl-tests/id:000667,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000667,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000668,src:000000,op:ext_AO,pos:328,+cov b/src/exchange/afl-tests/id:000668,src:000000,op:ext_AO,pos:328,+cov
index 96f2d3424..96f2d3424 100644
--- a/src/mint/afl-tests/id:000668,src:000000,op:ext_AO,pos:328,+cov
+++ b/src/exchange/afl-tests/id:000668,src:000000,op:ext_AO,pos:328,+cov
diff --git a/src/mint/afl-tests/id:000668,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000668,src:000000,op:havoc,rep:128
index 5c4473469..5c4473469 100644
--- a/src/mint/afl-tests/id:000668,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000668,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000669,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000669,src:000000,op:havoc,rep:16
index 3ad7c2053..3ad7c2053 100644
--- a/src/mint/afl-tests/id:000669,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000669,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000669,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000669,src:000000,op:havoc,rep:64
index 8b274f7f1..8b274f7f1 100644
--- a/src/mint/afl-tests/id:000669,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000669,src:000000,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000670,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000670,src:000000,op:havoc,rep:32
index 247ef7e3c..247ef7e3c 100644
--- a/src/mint/afl-tests/id:000670,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000670,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000671,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000671,src:000000,op:havoc,rep:16
index 340f3d4c3..340f3d4c3 100644
--- a/src/mint/afl-tests/id:000671,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000671,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000671,src:000000,op:havoc,rep:8 b/src/exchange/afl-tests/id:000671,src:000000,op:havoc,rep:8
index c3e2f5893..c3e2f5893 100644
--- a/src/mint/afl-tests/id:000671,src:000000,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000671,src:000000,op:havoc,rep:8
diff --git a/src/mint/afl-tests/id:000672,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000672,src:000000,op:havoc,rep:16
index 6460e3c47..6460e3c47 100644
--- a/src/mint/afl-tests/id:000672,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000672,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000672,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000672,src:000000,op:havoc,rep:32
index a1c63c480..a1c63c480 100644
--- a/src/mint/afl-tests/id:000672,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000672,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000673,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000673,src:000000,op:havoc,rep:128
index d64636636..d64636636 100644
--- a/src/mint/afl-tests/id:000673,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000673,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000673,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000673,src:000000,op:havoc,rep:16
index 18f1c3a67..18f1c3a67 100644
--- a/src/mint/afl-tests/id:000673,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000673,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000674,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000674,src:000000,op:havoc,rep:32
index 846372ae2..846372ae2 100644
--- a/src/mint/afl-tests/id:000674,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000674,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000675,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000675,src:000000,op:havoc,rep:128
index dbb810ed3..dbb810ed3 100644
--- a/src/mint/afl-tests/id:000675,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000675,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000675,src:000000,op:havoc,rep:8 b/src/exchange/afl-tests/id:000675,src:000000,op:havoc,rep:8
index 269d6ad73..269d6ad73 100644
--- a/src/mint/afl-tests/id:000675,src:000000,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000675,src:000000,op:havoc,rep:8
diff --git a/src/mint/afl-tests/id:000676,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000676,src:000000,op:havoc,rep:32
index e09952bca..e09952bca 100644
--- a/src/mint/afl-tests/id:000676,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000676,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000677,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000677,src:000000,op:havoc,rep:64
index 8d0ddd10d..8d0ddd10d 100644
--- a/src/mint/afl-tests/id:000677,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000677,src:000000,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000677,src:000000,op:havoc,rep:8 b/src/exchange/afl-tests/id:000677,src:000000,op:havoc,rep:8
index c6ca41c38..c6ca41c38 100644
--- a/src/mint/afl-tests/id:000677,src:000000,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000677,src:000000,op:havoc,rep:8
Binary files differ
diff --git a/src/mint/afl-tests/id:000678,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000678,src:000000,op:havoc,rep:16
index f1d7065c2..f1d7065c2 100644
--- a/src/mint/afl-tests/id:000678,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000678,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000678,src:000000,op:havoc,rep:4 b/src/exchange/afl-tests/id:000678,src:000000,op:havoc,rep:4
index 88d7e0198..88d7e0198 100644
--- a/src/mint/afl-tests/id:000678,src:000000,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000678,src:000000,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000679,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000679,src:000000,op:havoc,rep:128
index 6ba2b42e7..6ba2b42e7 100644
--- a/src/mint/afl-tests/id:000679,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000679,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000679,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000679,src:000000,op:havoc,rep:16,+cov
index b01ea79ee..b01ea79ee 100644
--- a/src/mint/afl-tests/id:000679,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000679,src:000000,op:havoc,rep:16,+cov
diff --git a/src/mint/afl-tests/id:000680,src:000000,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000680,src:000000,op:havoc,rep:128,+cov
index 5954b4d4b..5954b4d4b 100644
--- a/src/mint/afl-tests/id:000680,src:000000,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000680,src:000000,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000680,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000680,src:000000,op:havoc,rep:32
index fe5268bbb..fe5268bbb 100644
--- a/src/mint/afl-tests/id:000680,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000680,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000681,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000681,src:000000,op:havoc,rep:16
index 4b5ee3229..4b5ee3229 100644
--- a/src/mint/afl-tests/id:000681,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000681,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000681,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000681,src:000000,op:havoc,rep:32
index 83d8366f8..83d8366f8 100644
--- a/src/mint/afl-tests/id:000681,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000681,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000682,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000682,src:000000,op:havoc,rep:16
index 67e7ce858..67e7ce858 100644
--- a/src/mint/afl-tests/id:000682,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000682,src:000000,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000682,src:000000,op:havoc,rep:64,+cov b/src/exchange/afl-tests/id:000682,src:000000,op:havoc,rep:64,+cov
index 8b0343ddc..8b0343ddc 100644
--- a/src/mint/afl-tests/id:000682,src:000000,op:havoc,rep:64,+cov
+++ b/src/exchange/afl-tests/id:000682,src:000000,op:havoc,rep:64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000683,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000683,src:000000,op:havoc,rep:16,+cov
index 1c10218e3..1c10218e3 100644
--- a/src/mint/afl-tests/id:000683,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000683,src:000000,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000683,src:000000,op:havoc,rep:32,+cov b/src/exchange/afl-tests/id:000683,src:000000,op:havoc,rep:32,+cov
index 0179e7517..0179e7517 100644
--- a/src/mint/afl-tests/id:000683,src:000000,op:havoc,rep:32,+cov
+++ b/src/exchange/afl-tests/id:000683,src:000000,op:havoc,rep:32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000684,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000684,src:000000,op:havoc,rep:16,+cov
index e87a27a22..e87a27a22 100644
--- a/src/mint/afl-tests/id:000684,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000684,src:000000,op:havoc,rep:16,+cov
diff --git a/src/mint/afl-tests/id:000684,src:000000,op:havoc,rep:8 b/src/exchange/afl-tests/id:000684,src:000000,op:havoc,rep:8
index 823ce3605..823ce3605 100644
--- a/src/mint/afl-tests/id:000684,src:000000,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000684,src:000000,op:havoc,rep:8
diff --git a/src/mint/afl-tests/id:000685,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000685,src:000000,op:havoc,rep:16
index 3079c2468..3079c2468 100644
--- a/src/mint/afl-tests/id:000685,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000685,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000685,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000685,src:000000,op:havoc,rep:16,+cov
index e3e8708d3..e3e8708d3 100644
--- a/src/mint/afl-tests/id:000685,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000685,src:000000,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000686,src:000000,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000686,src:000000,op:havoc,rep:128,+cov
index 832fa6763..832fa6763 100644
--- a/src/mint/afl-tests/id:000686,src:000000,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000686,src:000000,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000686,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000686,src:000000,op:havoc,rep:16,+cov
index b900efb73..b900efb73 100644
--- a/src/mint/afl-tests/id:000686,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000686,src:000000,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000687,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000687,src:000000,op:havoc,rep:16
index 75daa5182..75daa5182 100644
--- a/src/mint/afl-tests/id:000687,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000687,src:000000,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000687,src:000000,op:havoc,rep:32,+cov b/src/exchange/afl-tests/id:000687,src:000000,op:havoc,rep:32,+cov
index 08c85a084..08c85a084 100644
--- a/src/mint/afl-tests/id:000687,src:000000,op:havoc,rep:32,+cov
+++ b/src/exchange/afl-tests/id:000687,src:000000,op:havoc,rep:32,+cov
diff --git a/src/mint/afl-tests/id:000688,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000688,src:000000,op:havoc,rep:128
index 03a3844f9..03a3844f9 100644
--- a/src/mint/afl-tests/id:000688,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000688,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000689,src:000000,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000689,src:000000,op:havoc,rep:128,+cov
index 937ffe401..937ffe401 100644
--- a/src/mint/afl-tests/id:000689,src:000000,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000689,src:000000,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000689,src:000000,op:havoc,rep:64,+cov b/src/exchange/afl-tests/id:000689,src:000000,op:havoc,rep:64,+cov
index fb09f5f80..fb09f5f80 100644
--- a/src/mint/afl-tests/id:000689,src:000000,op:havoc,rep:64,+cov
+++ b/src/exchange/afl-tests/id:000689,src:000000,op:havoc,rep:64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000690,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000690,src:000000,op:havoc,rep:32
index cedca0a75..cedca0a75 100644
--- a/src/mint/afl-tests/id:000690,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000690,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000690,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000690,src:000000,op:havoc,rep:64
index c95782cbd..c95782cbd 100644
--- a/src/mint/afl-tests/id:000690,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000690,src:000000,op:havoc,rep:64
diff --git a/src/mint/afl-tests/id:000691,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000691,src:000000,op:havoc,rep:64
index 3a796fd2c..3a796fd2c 100644
--- a/src/mint/afl-tests/id:000691,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000691,src:000000,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000692,src:000000,op:havoc,rep:4,+cov b/src/exchange/afl-tests/id:000692,src:000000,op:havoc,rep:4,+cov
index 05d166eba..05d166eba 100644
--- a/src/mint/afl-tests/id:000692,src:000000,op:havoc,rep:4,+cov
+++ b/src/exchange/afl-tests/id:000692,src:000000,op:havoc,rep:4,+cov
diff --git a/src/mint/afl-tests/id:000693,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000693,src:000000,op:havoc,rep:16,+cov
index f7c18bf85..f7c18bf85 100644
--- a/src/mint/afl-tests/id:000693,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000693,src:000000,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000693,src:000000,op:havoc,rep:4,+cov b/src/exchange/afl-tests/id:000693,src:000000,op:havoc,rep:4,+cov
index a2ef4f56c..a2ef4f56c 100644
--- a/src/mint/afl-tests/id:000693,src:000000,op:havoc,rep:4,+cov
+++ b/src/exchange/afl-tests/id:000693,src:000000,op:havoc,rep:4,+cov
diff --git a/src/mint/afl-tests/id:000694,src:000000,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000694,src:000000,op:havoc,rep:2,+cov
index 7ac983447..7ac983447 100644
--- a/src/mint/afl-tests/id:000694,src:000000,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000694,src:000000,op:havoc,rep:2,+cov
diff --git a/src/mint/afl-tests/id:000694,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000694,src:000000,op:havoc,rep:32
index 0dcc737a3..0dcc737a3 100644
--- a/src/mint/afl-tests/id:000694,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000694,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000695,src:000000,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000695,src:000000,op:havoc,rep:128,+cov
index 0234182fe..0234182fe 100644
--- a/src/mint/afl-tests/id:000695,src:000000,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000695,src:000000,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000695,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000695,src:000000,op:havoc,rep:64
index a392fe9fc..a392fe9fc 100644
--- a/src/mint/afl-tests/id:000695,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000695,src:000000,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000696,src:000000,op:havoc,rep:16 b/src/exchange/afl-tests/id:000696,src:000000,op:havoc,rep:16
index fa8974211..fa8974211 100644
--- a/src/mint/afl-tests/id:000696,src:000000,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000696,src:000000,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000696,src:000000,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000696,src:000000,op:havoc,rep:2,+cov
index 884e2dd96..884e2dd96 100644
--- a/src/mint/afl-tests/id:000696,src:000000,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000696,src:000000,op:havoc,rep:2,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000697,src:000000,op:havoc,rep:64,+cov b/src/exchange/afl-tests/id:000697,src:000000,op:havoc,rep:64,+cov
index 2ac571d2e..2ac571d2e 100644
--- a/src/mint/afl-tests/id:000697,src:000000,op:havoc,rep:64,+cov
+++ b/src/exchange/afl-tests/id:000697,src:000000,op:havoc,rep:64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000697,src:000000,op:havoc,rep:8 b/src/exchange/afl-tests/id:000697,src:000000,op:havoc,rep:8
index 1f4c4b275..1f4c4b275 100644
--- a/src/mint/afl-tests/id:000697,src:000000,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000697,src:000000,op:havoc,rep:8
diff --git a/src/mint/afl-tests/id:000698,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000698,src:000000,op:havoc,rep:128
index dbaca8f22..dbaca8f22 100644
--- a/src/mint/afl-tests/id:000698,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000698,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000699,src:000000,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000699,src:000000,op:havoc,rep:2,+cov
index 2d5688ec3..2d5688ec3 100644
--- a/src/mint/afl-tests/id:000699,src:000000,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000699,src:000000,op:havoc,rep:2,+cov
diff --git a/src/mint/afl-tests/id:000699,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000699,src:000000,op:havoc,rep:32
index b46431bbf..b46431bbf 100644
--- a/src/mint/afl-tests/id:000699,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000699,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000700,src:000000,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000700,src:000000,op:havoc,rep:128,+cov
index c62e58c13..c62e58c13 100644
--- a/src/mint/afl-tests/id:000700,src:000000,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000700,src:000000,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000700,src:000000,op:havoc,rep:32,+cov b/src/exchange/afl-tests/id:000700,src:000000,op:havoc,rep:32,+cov
index cb8978d9b..cb8978d9b 100644
--- a/src/mint/afl-tests/id:000700,src:000000,op:havoc,rep:32,+cov
+++ b/src/exchange/afl-tests/id:000700,src:000000,op:havoc,rep:32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000701,src:000000,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000701,src:000000,op:havoc,rep:16,+cov
index aa3e7621e..aa3e7621e 100644
--- a/src/mint/afl-tests/id:000701,src:000000,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000701,src:000000,op:havoc,rep:16,+cov
diff --git a/src/mint/afl-tests/id:000701,src:000000,op:havoc,rep:2 b/src/exchange/afl-tests/id:000701,src:000000,op:havoc,rep:2
index 444782877..444782877 100644
--- a/src/mint/afl-tests/id:000701,src:000000,op:havoc,rep:2
+++ b/src/exchange/afl-tests/id:000701,src:000000,op:havoc,rep:2
Binary files differ
diff --git a/src/mint/afl-tests/id:000702,src:000000,op:havoc,rep:128 b/src/exchange/afl-tests/id:000702,src:000000,op:havoc,rep:128
index 649fd44f8..649fd44f8 100644
--- a/src/mint/afl-tests/id:000702,src:000000,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000702,src:000000,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000702,src:000000,op:havoc,rep:8 b/src/exchange/afl-tests/id:000702,src:000000,op:havoc,rep:8
index b85d4b872..b85d4b872 100644
--- a/src/mint/afl-tests/id:000702,src:000000,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000702,src:000000,op:havoc,rep:8
Binary files differ
diff --git a/src/mint/afl-tests/id:000703,src:000000,op:havoc,rep:32,+cov b/src/exchange/afl-tests/id:000703,src:000000,op:havoc,rep:32,+cov
index a2e94bbef..a2e94bbef 100644
--- a/src/mint/afl-tests/id:000703,src:000000,op:havoc,rep:32,+cov
+++ b/src/exchange/afl-tests/id:000703,src:000000,op:havoc,rep:32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000703,src:000001,op:flip1,pos:34,+cov b/src/exchange/afl-tests/id:000703,src:000001,op:flip1,pos:34,+cov
index 8b8afd5ce..8b8afd5ce 100644
--- a/src/mint/afl-tests/id:000703,src:000001,op:flip1,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000703,src:000001,op:flip1,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000704,src:000000,op:havoc,rep:64,+cov b/src/exchange/afl-tests/id:000704,src:000000,op:havoc,rep:64,+cov
index d6803b35b..d6803b35b 100644
--- a/src/mint/afl-tests/id:000704,src:000000,op:havoc,rep:64,+cov
+++ b/src/exchange/afl-tests/id:000704,src:000000,op:havoc,rep:64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000704,src:000001,op:flip1,pos:50,+cov b/src/exchange/afl-tests/id:000704,src:000001,op:flip1,pos:50,+cov
index 7a6dce8aa..7a6dce8aa 100644
--- a/src/mint/afl-tests/id:000704,src:000001,op:flip1,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000704,src:000001,op:flip1,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000705,src:000000,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000705,src:000000,op:havoc,rep:2,+cov
index 92322dd4f..92322dd4f 100644
--- a/src/mint/afl-tests/id:000705,src:000000,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000705,src:000000,op:havoc,rep:2,+cov
diff --git a/src/mint/afl-tests/id:000705,src:000001,op:flip1,pos:61,+cov b/src/exchange/afl-tests/id:000705,src:000001,op:flip1,pos:61,+cov
index 91834a952..91834a952 100644
--- a/src/mint/afl-tests/id:000705,src:000001,op:flip1,pos:61,+cov
+++ b/src/exchange/afl-tests/id:000705,src:000001,op:flip1,pos:61,+cov
diff --git a/src/mint/afl-tests/id:000706,src:000000,op:havoc,rep:32 b/src/exchange/afl-tests/id:000706,src:000000,op:havoc,rep:32
index b204b3695..b204b3695 100644
--- a/src/mint/afl-tests/id:000706,src:000000,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000706,src:000000,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000706,src:000001,op:flip1,pos:91 b/src/exchange/afl-tests/id:000706,src:000001,op:flip1,pos:91
index f0774c0d7..f0774c0d7 100644
--- a/src/mint/afl-tests/id:000706,src:000001,op:flip1,pos:91
+++ b/src/exchange/afl-tests/id:000706,src:000001,op:flip1,pos:91
diff --git a/src/mint/afl-tests/id:000707,src:000000,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000707,src:000000,op:havoc,rep:128,+cov
index a3b803dc8..a3b803dc8 100644
--- a/src/mint/afl-tests/id:000707,src:000000,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000707,src:000000,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000707,src:000001,op:flip1,pos:103,+cov b/src/exchange/afl-tests/id:000707,src:000001,op:flip1,pos:103,+cov
index 598ffc94a..598ffc94a 100644
--- a/src/mint/afl-tests/id:000707,src:000001,op:flip1,pos:103,+cov
+++ b/src/exchange/afl-tests/id:000707,src:000001,op:flip1,pos:103,+cov
diff --git a/src/mint/afl-tests/id:000708,src:000000,op:havoc,rep:2 b/src/exchange/afl-tests/id:000708,src:000000,op:havoc,rep:2
index 1cf4bd71c..1cf4bd71c 100644
--- a/src/mint/afl-tests/id:000708,src:000000,op:havoc,rep:2
+++ b/src/exchange/afl-tests/id:000708,src:000000,op:havoc,rep:2
diff --git a/src/mint/afl-tests/id:000708,src:000001,op:flip1,pos:120,+cov b/src/exchange/afl-tests/id:000708,src:000001,op:flip1,pos:120,+cov
index cd0877030..cd0877030 100644
--- a/src/mint/afl-tests/id:000708,src:000001,op:flip1,pos:120,+cov
+++ b/src/exchange/afl-tests/id:000708,src:000001,op:flip1,pos:120,+cov
diff --git a/src/mint/afl-tests/id:000709,src:000000,op:havoc,rep:64 b/src/exchange/afl-tests/id:000709,src:000000,op:havoc,rep:64
index 87c7a7065..87c7a7065 100644
--- a/src/mint/afl-tests/id:000709,src:000000,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000709,src:000000,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000709,src:000001,op:flip1,pos:129,+cov b/src/exchange/afl-tests/id:000709,src:000001,op:flip1,pos:129,+cov
index 427ee45a1..427ee45a1 100644
--- a/src/mint/afl-tests/id:000709,src:000001,op:flip1,pos:129,+cov
+++ b/src/exchange/afl-tests/id:000709,src:000001,op:flip1,pos:129,+cov
diff --git a/src/mint/afl-tests/id:000710,src:000000,op:havoc,rep:8,+cov b/src/exchange/afl-tests/id:000710,src:000000,op:havoc,rep:8,+cov
index 6191f7040..6191f7040 100644
--- a/src/mint/afl-tests/id:000710,src:000000,op:havoc,rep:8,+cov
+++ b/src/exchange/afl-tests/id:000710,src:000000,op:havoc,rep:8,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000710,src:000001,op:flip1,pos:129,+cov b/src/exchange/afl-tests/id:000710,src:000001,op:flip1,pos:129,+cov
index 546c225b3..546c225b3 100644
--- a/src/mint/afl-tests/id:000710,src:000001,op:flip1,pos:129,+cov
+++ b/src/exchange/afl-tests/id:000710,src:000001,op:flip1,pos:129,+cov
diff --git a/src/mint/afl-tests/id:000711,src:000000,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000711,src:000000,op:havoc,rep:2,+cov
index ab1663bab..ab1663bab 100644
--- a/src/mint/afl-tests/id:000711,src:000000,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000711,src:000000,op:havoc,rep:2,+cov
diff --git a/src/mint/afl-tests/id:000711,src:000001,op:flip1,pos:131,+cov b/src/exchange/afl-tests/id:000711,src:000001,op:flip1,pos:131,+cov
index b097e2a2b..b097e2a2b 100644
--- a/src/mint/afl-tests/id:000711,src:000001,op:flip1,pos:131,+cov
+++ b/src/exchange/afl-tests/id:000711,src:000001,op:flip1,pos:131,+cov
diff --git a/src/mint/afl-tests/id:000712,src:000000,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000712,src:000000,op:havoc,rep:2,+cov
index 0f49aaf93..0f49aaf93 100644
--- a/src/mint/afl-tests/id:000712,src:000000,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000712,src:000000,op:havoc,rep:2,+cov
diff --git a/src/mint/afl-tests/id:000712,src:000001,op:flip1,pos:139,+cov b/src/exchange/afl-tests/id:000712,src:000001,op:flip1,pos:139,+cov
index f3e292007..f3e292007 100644
--- a/src/mint/afl-tests/id:000712,src:000001,op:flip1,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000712,src:000001,op:flip1,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000713,src:000000,op:havoc,rep:64,+cov b/src/exchange/afl-tests/id:000713,src:000000,op:havoc,rep:64,+cov
index 4206ca60c..4206ca60c 100644
--- a/src/mint/afl-tests/id:000713,src:000000,op:havoc,rep:64,+cov
+++ b/src/exchange/afl-tests/id:000713,src:000000,op:havoc,rep:64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000713,src:000001,op:flip1,pos:197,+cov b/src/exchange/afl-tests/id:000713,src:000001,op:flip1,pos:197,+cov
index 74773e9c3..74773e9c3 100644
--- a/src/mint/afl-tests/id:000713,src:000001,op:flip1,pos:197,+cov
+++ b/src/exchange/afl-tests/id:000713,src:000001,op:flip1,pos:197,+cov
diff --git a/src/mint/afl-tests/id:000714,src:000000,op:havoc,rep:8,+cov b/src/exchange/afl-tests/id:000714,src:000000,op:havoc,rep:8,+cov
index aae44460a..aae44460a 100644
--- a/src/mint/afl-tests/id:000714,src:000000,op:havoc,rep:8,+cov
+++ b/src/exchange/afl-tests/id:000714,src:000000,op:havoc,rep:8,+cov
diff --git a/src/mint/afl-tests/id:000714,src:000001,op:flip1,pos:243,+cov b/src/exchange/afl-tests/id:000714,src:000001,op:flip1,pos:243,+cov
index 38b92321f..38b92321f 100644
--- a/src/mint/afl-tests/id:000714,src:000001,op:flip1,pos:243,+cov
+++ b/src/exchange/afl-tests/id:000714,src:000001,op:flip1,pos:243,+cov
diff --git a/src/mint/afl-tests/id:000715,src:000000,op:havoc,rep:8,+cov b/src/exchange/afl-tests/id:000715,src:000000,op:havoc,rep:8,+cov
index e6b08d6f9..e6b08d6f9 100644
--- a/src/mint/afl-tests/id:000715,src:000000,op:havoc,rep:8,+cov
+++ b/src/exchange/afl-tests/id:000715,src:000000,op:havoc,rep:8,+cov
diff --git a/src/mint/afl-tests/id:000715,src:000001,op:flip1,pos:365,+cov b/src/exchange/afl-tests/id:000715,src:000001,op:flip1,pos:365,+cov
index 8a5422a0d..8a5422a0d 100644
--- a/src/mint/afl-tests/id:000715,src:000001,op:flip1,pos:365,+cov
+++ b/src/exchange/afl-tests/id:000715,src:000001,op:flip1,pos:365,+cov
diff --git a/src/mint/afl-tests/id:000716,src:000001,op:flip1,pos:2 b/src/exchange/afl-tests/id:000716,src:000001,op:flip1,pos:2
index bfc0224a9..bfc0224a9 100644
--- a/src/mint/afl-tests/id:000716,src:000001,op:flip1,pos:2
+++ b/src/exchange/afl-tests/id:000716,src:000001,op:flip1,pos:2
diff --git a/src/mint/afl-tests/id:000716,src:000001,op:flip1,pos:456,+cov b/src/exchange/afl-tests/id:000716,src:000001,op:flip1,pos:456,+cov
index 90f879bab..90f879bab 100644
--- a/src/mint/afl-tests/id:000716,src:000001,op:flip1,pos:456,+cov
+++ b/src/exchange/afl-tests/id:000716,src:000001,op:flip1,pos:456,+cov
diff --git a/src/mint/afl-tests/id:000717,src:000001,op:flip1,pos:50,+cov b/src/exchange/afl-tests/id:000717,src:000001,op:flip1,pos:50,+cov
index 01aca8b31..01aca8b31 100644
--- a/src/mint/afl-tests/id:000717,src:000001,op:flip1,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000717,src:000001,op:flip1,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000717,src:000001,op:flip1,pos:596 b/src/exchange/afl-tests/id:000717,src:000001,op:flip1,pos:596
index e3265d2c5..e3265d2c5 100644
--- a/src/mint/afl-tests/id:000717,src:000001,op:flip1,pos:596
+++ b/src/exchange/afl-tests/id:000717,src:000001,op:flip1,pos:596
diff --git a/src/mint/afl-tests/id:000718,src:000001,op:flip1,pos:55,+cov b/src/exchange/afl-tests/id:000718,src:000001,op:flip1,pos:55,+cov
index 63295d571..63295d571 100644
--- a/src/mint/afl-tests/id:000718,src:000001,op:flip1,pos:55,+cov
+++ b/src/exchange/afl-tests/id:000718,src:000001,op:flip1,pos:55,+cov
diff --git a/src/mint/afl-tests/id:000718,src:000001,op:flip1,pos:614,+cov b/src/exchange/afl-tests/id:000718,src:000001,op:flip1,pos:614,+cov
index 37d818c94..37d818c94 100644
--- a/src/mint/afl-tests/id:000718,src:000001,op:flip1,pos:614,+cov
+++ b/src/exchange/afl-tests/id:000718,src:000001,op:flip1,pos:614,+cov
diff --git a/src/mint/afl-tests/id:000719,src:000001,op:flip1,pos:629,+cov b/src/exchange/afl-tests/id:000719,src:000001,op:flip1,pos:629,+cov
index 861e99c81..861e99c81 100644
--- a/src/mint/afl-tests/id:000719,src:000001,op:flip1,pos:629,+cov
+++ b/src/exchange/afl-tests/id:000719,src:000001,op:flip1,pos:629,+cov
diff --git a/src/mint/afl-tests/id:000719,src:000001,op:flip1,pos:95 b/src/exchange/afl-tests/id:000719,src:000001,op:flip1,pos:95
index 6f50c2ec0..6f50c2ec0 100644
--- a/src/mint/afl-tests/id:000719,src:000001,op:flip1,pos:95
+++ b/src/exchange/afl-tests/id:000719,src:000001,op:flip1,pos:95
diff --git a/src/mint/afl-tests/id:000720,src:000001,op:flip1,pos:102,+cov b/src/exchange/afl-tests/id:000720,src:000001,op:flip1,pos:102,+cov
index 9750ed4f5..9750ed4f5 100644
--- a/src/mint/afl-tests/id:000720,src:000001,op:flip1,pos:102,+cov
+++ b/src/exchange/afl-tests/id:000720,src:000001,op:flip1,pos:102,+cov
diff --git a/src/mint/afl-tests/id:000720,src:000001,op:flip1,pos:635,+cov b/src/exchange/afl-tests/id:000720,src:000001,op:flip1,pos:635,+cov
index faf9bbb0e..faf9bbb0e 100644
--- a/src/mint/afl-tests/id:000720,src:000001,op:flip1,pos:635,+cov
+++ b/src/exchange/afl-tests/id:000720,src:000001,op:flip1,pos:635,+cov
diff --git a/src/mint/afl-tests/id:000721,src:000001,op:flip1,pos:107,+cov b/src/exchange/afl-tests/id:000721,src:000001,op:flip1,pos:107,+cov
index 410ddd0b8..410ddd0b8 100644
--- a/src/mint/afl-tests/id:000721,src:000001,op:flip1,pos:107,+cov
+++ b/src/exchange/afl-tests/id:000721,src:000001,op:flip1,pos:107,+cov
diff --git a/src/mint/afl-tests/id:000721,src:000001,op:flip1,pos:683,+cov b/src/exchange/afl-tests/id:000721,src:000001,op:flip1,pos:683,+cov
index 73f524837..73f524837 100644
--- a/src/mint/afl-tests/id:000721,src:000001,op:flip1,pos:683,+cov
+++ b/src/exchange/afl-tests/id:000721,src:000001,op:flip1,pos:683,+cov
diff --git a/src/mint/afl-tests/id:000722,src:000001,op:flip1,pos:118,+cov b/src/exchange/afl-tests/id:000722,src:000001,op:flip1,pos:118,+cov
index b0c0d068d..b0c0d068d 100644
--- a/src/mint/afl-tests/id:000722,src:000001,op:flip1,pos:118,+cov
+++ b/src/exchange/afl-tests/id:000722,src:000001,op:flip1,pos:118,+cov
diff --git a/src/mint/afl-tests/id:000722,src:000001,op:flip1,pos:730,+cov b/src/exchange/afl-tests/id:000722,src:000001,op:flip1,pos:730,+cov
index 5d230cddb..5d230cddb 100644
--- a/src/mint/afl-tests/id:000722,src:000001,op:flip1,pos:730,+cov
+++ b/src/exchange/afl-tests/id:000722,src:000001,op:flip1,pos:730,+cov
diff --git a/src/mint/afl-tests/id:000723,src:000001,op:flip1,pos:124,+cov b/src/exchange/afl-tests/id:000723,src:000001,op:flip1,pos:124,+cov
index 3447e4b9a..3447e4b9a 100644
--- a/src/mint/afl-tests/id:000723,src:000001,op:flip1,pos:124,+cov
+++ b/src/exchange/afl-tests/id:000723,src:000001,op:flip1,pos:124,+cov
diff --git a/src/mint/afl-tests/id:000723,src:000001,op:flip1,pos:786,+cov b/src/exchange/afl-tests/id:000723,src:000001,op:flip1,pos:786,+cov
index e99546a66..e99546a66 100644
--- a/src/mint/afl-tests/id:000723,src:000001,op:flip1,pos:786,+cov
+++ b/src/exchange/afl-tests/id:000723,src:000001,op:flip1,pos:786,+cov
diff --git a/src/mint/afl-tests/id:000724,src:000001,op:flip1,pos:133,+cov b/src/exchange/afl-tests/id:000724,src:000001,op:flip1,pos:133,+cov
index b045d2d57..b045d2d57 100644
--- a/src/mint/afl-tests/id:000724,src:000001,op:flip1,pos:133,+cov
+++ b/src/exchange/afl-tests/id:000724,src:000001,op:flip1,pos:133,+cov
diff --git a/src/mint/afl-tests/id:000724,src:000001,op:flip1,pos:796 b/src/exchange/afl-tests/id:000724,src:000001,op:flip1,pos:796
index b989d1659..b989d1659 100644
--- a/src/mint/afl-tests/id:000724,src:000001,op:flip1,pos:796
+++ b/src/exchange/afl-tests/id:000724,src:000001,op:flip1,pos:796
diff --git a/src/mint/afl-tests/id:000725,src:000001,op:flip1,pos:133,+cov b/src/exchange/afl-tests/id:000725,src:000001,op:flip1,pos:133,+cov
index 36ad08e1e..36ad08e1e 100644
--- a/src/mint/afl-tests/id:000725,src:000001,op:flip1,pos:133,+cov
+++ b/src/exchange/afl-tests/id:000725,src:000001,op:flip1,pos:133,+cov
diff --git a/src/mint/afl-tests/id:000725,src:000001,op:flip1,pos:915,+cov b/src/exchange/afl-tests/id:000725,src:000001,op:flip1,pos:915,+cov
index f8d912731..f8d912731 100644
--- a/src/mint/afl-tests/id:000725,src:000001,op:flip1,pos:915,+cov
+++ b/src/exchange/afl-tests/id:000725,src:000001,op:flip1,pos:915,+cov
diff --git a/src/mint/afl-tests/id:000726,src:000001,op:flip1,pos:1112,+cov b/src/exchange/afl-tests/id:000726,src:000001,op:flip1,pos:1112,+cov
index c5a1fa771..c5a1fa771 100644
--- a/src/mint/afl-tests/id:000726,src:000001,op:flip1,pos:1112,+cov
+++ b/src/exchange/afl-tests/id:000726,src:000001,op:flip1,pos:1112,+cov
diff --git a/src/mint/afl-tests/id:000726,src:000001,op:flip1,pos:135,+cov b/src/exchange/afl-tests/id:000726,src:000001,op:flip1,pos:135,+cov
index b8423af6b..b8423af6b 100644
--- a/src/mint/afl-tests/id:000726,src:000001,op:flip1,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000726,src:000001,op:flip1,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000727,src:000001,op:flip1,pos:1112,+cov b/src/exchange/afl-tests/id:000727,src:000001,op:flip1,pos:1112,+cov
index 722f45bbf..722f45bbf 100644
--- a/src/mint/afl-tests/id:000727,src:000001,op:flip1,pos:1112,+cov
+++ b/src/exchange/afl-tests/id:000727,src:000001,op:flip1,pos:1112,+cov
diff --git a/src/mint/afl-tests/id:000727,src:000001,op:flip1,pos:457,+cov b/src/exchange/afl-tests/id:000727,src:000001,op:flip1,pos:457,+cov
index b66ec8250..b66ec8250 100644
--- a/src/mint/afl-tests/id:000727,src:000001,op:flip1,pos:457,+cov
+++ b/src/exchange/afl-tests/id:000727,src:000001,op:flip1,pos:457,+cov
diff --git a/src/mint/afl-tests/id:000728,src:000001,op:flip1,pos:1114,+cov b/src/exchange/afl-tests/id:000728,src:000001,op:flip1,pos:1114,+cov
index d096b97fe..d096b97fe 100644
--- a/src/mint/afl-tests/id:000728,src:000001,op:flip1,pos:1114,+cov
+++ b/src/exchange/afl-tests/id:000728,src:000001,op:flip1,pos:1114,+cov
diff --git a/src/mint/afl-tests/id:000728,src:000001,op:flip1,pos:469,+cov b/src/exchange/afl-tests/id:000728,src:000001,op:flip1,pos:469,+cov
index 394a850a4..394a850a4 100644
--- a/src/mint/afl-tests/id:000728,src:000001,op:flip1,pos:469,+cov
+++ b/src/exchange/afl-tests/id:000728,src:000001,op:flip1,pos:469,+cov
diff --git a/src/mint/afl-tests/id:000729,src:000001,op:flip1,pos:1215,+cov b/src/exchange/afl-tests/id:000729,src:000001,op:flip1,pos:1215,+cov
index 830a76c11..830a76c11 100644
--- a/src/mint/afl-tests/id:000729,src:000001,op:flip1,pos:1215,+cov
+++ b/src/exchange/afl-tests/id:000729,src:000001,op:flip1,pos:1215,+cov
diff --git a/src/mint/afl-tests/id:000729,src:000001,op:flip1,pos:508,+cov b/src/exchange/afl-tests/id:000729,src:000001,op:flip1,pos:508,+cov
index e82a8288d..e82a8288d 100644
--- a/src/mint/afl-tests/id:000729,src:000001,op:flip1,pos:508,+cov
+++ b/src/exchange/afl-tests/id:000729,src:000001,op:flip1,pos:508,+cov
diff --git a/src/mint/afl-tests/id:000730,src:000001,op:flip1,pos:1353,+cov b/src/exchange/afl-tests/id:000730,src:000001,op:flip1,pos:1353,+cov
index 6c9c4bef8..6c9c4bef8 100644
--- a/src/mint/afl-tests/id:000730,src:000001,op:flip1,pos:1353,+cov
+++ b/src/exchange/afl-tests/id:000730,src:000001,op:flip1,pos:1353,+cov
diff --git a/src/mint/afl-tests/id:000730,src:000001,op:flip1,pos:600 b/src/exchange/afl-tests/id:000730,src:000001,op:flip1,pos:600
index 561d9b67a..561d9b67a 100644
--- a/src/mint/afl-tests/id:000730,src:000001,op:flip1,pos:600
+++ b/src/exchange/afl-tests/id:000730,src:000001,op:flip1,pos:600
diff --git a/src/mint/afl-tests/id:000731,src:000001,op:flip1,pos:1453,+cov b/src/exchange/afl-tests/id:000731,src:000001,op:flip1,pos:1453,+cov
index f39d1a432..f39d1a432 100644
--- a/src/mint/afl-tests/id:000731,src:000001,op:flip1,pos:1453,+cov
+++ b/src/exchange/afl-tests/id:000731,src:000001,op:flip1,pos:1453,+cov
diff --git a/src/mint/afl-tests/id:000731,src:000001,op:flip1,pos:618,+cov b/src/exchange/afl-tests/id:000731,src:000001,op:flip1,pos:618,+cov
index 07575f9e3..07575f9e3 100644
--- a/src/mint/afl-tests/id:000731,src:000001,op:flip1,pos:618,+cov
+++ b/src/exchange/afl-tests/id:000731,src:000001,op:flip1,pos:618,+cov
diff --git a/src/mint/afl-tests/id:000732,src:000001,op:flip1,pos:1574,+cov b/src/exchange/afl-tests/id:000732,src:000001,op:flip1,pos:1574,+cov
index a80fb94b8..a80fb94b8 100644
--- a/src/mint/afl-tests/id:000732,src:000001,op:flip1,pos:1574,+cov
+++ b/src/exchange/afl-tests/id:000732,src:000001,op:flip1,pos:1574,+cov
diff --git a/src/mint/afl-tests/id:000732,src:000001,op:flip1,pos:633,+cov b/src/exchange/afl-tests/id:000732,src:000001,op:flip1,pos:633,+cov
index 84c29c53c..84c29c53c 100644
--- a/src/mint/afl-tests/id:000732,src:000001,op:flip1,pos:633,+cov
+++ b/src/exchange/afl-tests/id:000732,src:000001,op:flip1,pos:633,+cov
diff --git a/src/mint/afl-tests/id:000733,src:000001,op:flip1,pos:1630 b/src/exchange/afl-tests/id:000733,src:000001,op:flip1,pos:1630
index e84d89daf..e84d89daf 100644
--- a/src/mint/afl-tests/id:000733,src:000001,op:flip1,pos:1630
+++ b/src/exchange/afl-tests/id:000733,src:000001,op:flip1,pos:1630
diff --git a/src/mint/afl-tests/id:000733,src:000001,op:flip1,pos:687,+cov b/src/exchange/afl-tests/id:000733,src:000001,op:flip1,pos:687,+cov
index b12b1ecdc..b12b1ecdc 100644
--- a/src/mint/afl-tests/id:000733,src:000001,op:flip1,pos:687,+cov
+++ b/src/exchange/afl-tests/id:000733,src:000001,op:flip1,pos:687,+cov
diff --git a/src/mint/afl-tests/id:000734,src:000001,op:flip1,pos:722,+cov b/src/exchange/afl-tests/id:000734,src:000001,op:flip1,pos:722,+cov
index 63cf05fe4..63cf05fe4 100644
--- a/src/mint/afl-tests/id:000734,src:000001,op:flip1,pos:722,+cov
+++ b/src/exchange/afl-tests/id:000734,src:000001,op:flip1,pos:722,+cov
diff --git a/src/mint/afl-tests/id:000734,src:000001,op:flip2,pos:453,+cov b/src/exchange/afl-tests/id:000734,src:000001,op:flip2,pos:453,+cov
index 0e23b0018..0e23b0018 100644
--- a/src/mint/afl-tests/id:000734,src:000001,op:flip2,pos:453,+cov
+++ b/src/exchange/afl-tests/id:000734,src:000001,op:flip2,pos:453,+cov
diff --git a/src/mint/afl-tests/id:000735,src:000001,op:flip1,pos:734,+cov b/src/exchange/afl-tests/id:000735,src:000001,op:flip1,pos:734,+cov
index 6cf6656e0..6cf6656e0 100644
--- a/src/mint/afl-tests/id:000735,src:000001,op:flip1,pos:734,+cov
+++ b/src/exchange/afl-tests/id:000735,src:000001,op:flip1,pos:734,+cov
diff --git a/src/mint/afl-tests/id:000735,src:000001,op:flip2,pos:484,+cov b/src/exchange/afl-tests/id:000735,src:000001,op:flip2,pos:484,+cov
index 807f2a703..807f2a703 100644
--- a/src/mint/afl-tests/id:000735,src:000001,op:flip2,pos:484,+cov
+++ b/src/exchange/afl-tests/id:000735,src:000001,op:flip2,pos:484,+cov
diff --git a/src/mint/afl-tests/id:000736,src:000001,op:flip1,pos:800 b/src/exchange/afl-tests/id:000736,src:000001,op:flip1,pos:800
index 1b631b8c3..1b631b8c3 100644
--- a/src/mint/afl-tests/id:000736,src:000001,op:flip1,pos:800
+++ b/src/exchange/afl-tests/id:000736,src:000001,op:flip1,pos:800
diff --git a/src/mint/afl-tests/id:000736,src:000001,op:flip2,pos:696,+cov b/src/exchange/afl-tests/id:000736,src:000001,op:flip2,pos:696,+cov
index 2014e2107..2014e2107 100644
--- a/src/mint/afl-tests/id:000736,src:000001,op:flip2,pos:696,+cov
+++ b/src/exchange/afl-tests/id:000736,src:000001,op:flip2,pos:696,+cov
diff --git a/src/mint/afl-tests/id:000737,src:000001,op:flip1,pos:888,+cov b/src/exchange/afl-tests/id:000737,src:000001,op:flip1,pos:888,+cov
index 04e588c34..04e588c34 100644
--- a/src/mint/afl-tests/id:000737,src:000001,op:flip1,pos:888,+cov
+++ b/src/exchange/afl-tests/id:000737,src:000001,op:flip1,pos:888,+cov
diff --git a/src/mint/afl-tests/id:000737,src:000001,op:flip2,pos:843,+cov b/src/exchange/afl-tests/id:000737,src:000001,op:flip2,pos:843,+cov
index ba306ceac..ba306ceac 100644
--- a/src/mint/afl-tests/id:000737,src:000001,op:flip2,pos:843,+cov
+++ b/src/exchange/afl-tests/id:000737,src:000001,op:flip2,pos:843,+cov
diff --git a/src/mint/afl-tests/id:000738,src:000001,op:flip1,pos:893,+cov b/src/exchange/afl-tests/id:000738,src:000001,op:flip1,pos:893,+cov
index f56cf52cc..f56cf52cc 100644
--- a/src/mint/afl-tests/id:000738,src:000001,op:flip1,pos:893,+cov
+++ b/src/exchange/afl-tests/id:000738,src:000001,op:flip1,pos:893,+cov
diff --git a/src/mint/afl-tests/id:000738,src:000001,op:flip2,pos:845,+cov b/src/exchange/afl-tests/id:000738,src:000001,op:flip2,pos:845,+cov
index 007d58e89..007d58e89 100644
--- a/src/mint/afl-tests/id:000738,src:000001,op:flip2,pos:845,+cov
+++ b/src/exchange/afl-tests/id:000738,src:000001,op:flip2,pos:845,+cov
diff --git a/src/mint/afl-tests/id:000739,src:000001,op:flip1,pos:1116,+cov b/src/exchange/afl-tests/id:000739,src:000001,op:flip1,pos:1116,+cov
index a91117870..a91117870 100644
--- a/src/mint/afl-tests/id:000739,src:000001,op:flip1,pos:1116,+cov
+++ b/src/exchange/afl-tests/id:000739,src:000001,op:flip1,pos:1116,+cov
diff --git a/src/mint/afl-tests/id:000739,src:000001,op:flip2,pos:917,+cov b/src/exchange/afl-tests/id:000739,src:000001,op:flip2,pos:917,+cov
index e54b63201..e54b63201 100644
--- a/src/mint/afl-tests/id:000739,src:000001,op:flip2,pos:917,+cov
+++ b/src/exchange/afl-tests/id:000739,src:000001,op:flip2,pos:917,+cov
diff --git a/src/mint/afl-tests/id:000740,src:000001,op:flip1,pos:1116,+cov b/src/exchange/afl-tests/id:000740,src:000001,op:flip1,pos:1116,+cov
index ab1a92edc..ab1a92edc 100644
--- a/src/mint/afl-tests/id:000740,src:000001,op:flip1,pos:1116,+cov
+++ b/src/exchange/afl-tests/id:000740,src:000001,op:flip1,pos:1116,+cov
diff --git a/src/mint/afl-tests/id:000740,src:000001,op:flip2,pos:995,+cov b/src/exchange/afl-tests/id:000740,src:000001,op:flip2,pos:995,+cov
index 31437d715..31437d715 100644
--- a/src/mint/afl-tests/id:000740,src:000001,op:flip2,pos:995,+cov
+++ b/src/exchange/afl-tests/id:000740,src:000001,op:flip2,pos:995,+cov
diff --git a/src/mint/afl-tests/id:000741,src:000001,op:flip1,pos:1118,+cov b/src/exchange/afl-tests/id:000741,src:000001,op:flip1,pos:1118,+cov
index 0af793310..0af793310 100644
--- a/src/mint/afl-tests/id:000741,src:000001,op:flip1,pos:1118,+cov
+++ b/src/exchange/afl-tests/id:000741,src:000001,op:flip1,pos:1118,+cov
diff --git a/src/mint/afl-tests/id:000741,src:000001,op:flip2,pos:1031,+cov b/src/exchange/afl-tests/id:000741,src:000001,op:flip2,pos:1031,+cov
index 51fc01b75..51fc01b75 100644
--- a/src/mint/afl-tests/id:000741,src:000001,op:flip2,pos:1031,+cov
+++ b/src/exchange/afl-tests/id:000741,src:000001,op:flip2,pos:1031,+cov
diff --git a/src/mint/afl-tests/id:000742,src:000001,op:flip1,pos:1170,+cov b/src/exchange/afl-tests/id:000742,src:000001,op:flip1,pos:1170,+cov
index 2907e71ea..2907e71ea 100644
--- a/src/mint/afl-tests/id:000742,src:000001,op:flip1,pos:1170,+cov
+++ b/src/exchange/afl-tests/id:000742,src:000001,op:flip1,pos:1170,+cov
diff --git a/src/mint/afl-tests/id:000742,src:000001,op:flip2,pos:1135,+cov b/src/exchange/afl-tests/id:000742,src:000001,op:flip2,pos:1135,+cov
index 802374512..802374512 100644
--- a/src/mint/afl-tests/id:000742,src:000001,op:flip2,pos:1135,+cov
+++ b/src/exchange/afl-tests/id:000742,src:000001,op:flip2,pos:1135,+cov
diff --git a/src/mint/afl-tests/id:000743,src:000001,op:flip1,pos:1205,+cov b/src/exchange/afl-tests/id:000743,src:000001,op:flip1,pos:1205,+cov
index 21fa76491..21fa76491 100644
--- a/src/mint/afl-tests/id:000743,src:000001,op:flip1,pos:1205,+cov
+++ b/src/exchange/afl-tests/id:000743,src:000001,op:flip1,pos:1205,+cov
diff --git a/src/mint/afl-tests/id:000743,src:000001,op:flip2,pos:1286,+cov b/src/exchange/afl-tests/id:000743,src:000001,op:flip2,pos:1286,+cov
index 8db7aad8e..8db7aad8e 100644
--- a/src/mint/afl-tests/id:000743,src:000001,op:flip2,pos:1286,+cov
+++ b/src/exchange/afl-tests/id:000743,src:000001,op:flip2,pos:1286,+cov
diff --git a/src/mint/afl-tests/id:000744,src:000001,op:flip1,pos:1301,+cov b/src/exchange/afl-tests/id:000744,src:000001,op:flip1,pos:1301,+cov
index fa0448f40..fa0448f40 100644
--- a/src/mint/afl-tests/id:000744,src:000001,op:flip1,pos:1301,+cov
+++ b/src/exchange/afl-tests/id:000744,src:000001,op:flip1,pos:1301,+cov
diff --git a/src/mint/afl-tests/id:000744,src:000001,op:flip2,pos:1655,+cov b/src/exchange/afl-tests/id:000744,src:000001,op:flip2,pos:1655,+cov
index 127b0f508..127b0f508 100644
--- a/src/mint/afl-tests/id:000744,src:000001,op:flip2,pos:1655,+cov
+++ b/src/exchange/afl-tests/id:000744,src:000001,op:flip2,pos:1655,+cov
diff --git a/src/mint/afl-tests/id:000745,src:000001,op:flip1,pos:1369,+cov b/src/exchange/afl-tests/id:000745,src:000001,op:flip1,pos:1369,+cov
index 03a4527fe..03a4527fe 100644
--- a/src/mint/afl-tests/id:000745,src:000001,op:flip1,pos:1369,+cov
+++ b/src/exchange/afl-tests/id:000745,src:000001,op:flip1,pos:1369,+cov
diff --git a/src/mint/afl-tests/id:000745,src:000001,op:flip4,pos:50,+cov b/src/exchange/afl-tests/id:000745,src:000001,op:flip4,pos:50,+cov
index 76d7a5e66..76d7a5e66 100644
--- a/src/mint/afl-tests/id:000745,src:000001,op:flip4,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000745,src:000001,op:flip4,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000746,src:000001,op:flip1,pos:1378,+cov b/src/exchange/afl-tests/id:000746,src:000001,op:flip1,pos:1378,+cov
index f6dacce49..f6dacce49 100644
--- a/src/mint/afl-tests/id:000746,src:000001,op:flip1,pos:1378,+cov
+++ b/src/exchange/afl-tests/id:000746,src:000001,op:flip1,pos:1378,+cov
diff --git a/src/mint/afl-tests/id:000746,src:000001,op:flip4,pos:122,+cov b/src/exchange/afl-tests/id:000746,src:000001,op:flip4,pos:122,+cov
index 60bf24fc1..60bf24fc1 100644
--- a/src/mint/afl-tests/id:000746,src:000001,op:flip4,pos:122,+cov
+++ b/src/exchange/afl-tests/id:000746,src:000001,op:flip4,pos:122,+cov
diff --git a/src/mint/afl-tests/id:000747,src:000001,op:flip1,pos:1474,+cov b/src/exchange/afl-tests/id:000747,src:000001,op:flip1,pos:1474,+cov
index 9c51034e3..9c51034e3 100644
--- a/src/mint/afl-tests/id:000747,src:000001,op:flip1,pos:1474,+cov
+++ b/src/exchange/afl-tests/id:000747,src:000001,op:flip1,pos:1474,+cov
diff --git a/src/mint/afl-tests/id:000747,src:000001,op:flip4,pos:351,+cov b/src/exchange/afl-tests/id:000747,src:000001,op:flip4,pos:351,+cov
index a0878cb07..a0878cb07 100644
--- a/src/mint/afl-tests/id:000747,src:000001,op:flip4,pos:351,+cov
+++ b/src/exchange/afl-tests/id:000747,src:000001,op:flip4,pos:351,+cov
diff --git a/src/mint/afl-tests/id:000748,src:000001,op:flip1,pos:1510,+cov b/src/exchange/afl-tests/id:000748,src:000001,op:flip1,pos:1510,+cov
index 6e75c966c..6e75c966c 100644
--- a/src/mint/afl-tests/id:000748,src:000001,op:flip1,pos:1510,+cov
+++ b/src/exchange/afl-tests/id:000748,src:000001,op:flip1,pos:1510,+cov
diff --git a/src/mint/afl-tests/id:000748,src:000001,op:flip4,pos:569,+cov b/src/exchange/afl-tests/id:000748,src:000001,op:flip4,pos:569,+cov
index 61eaeaccf..61eaeaccf 100644
--- a/src/mint/afl-tests/id:000748,src:000001,op:flip4,pos:569,+cov
+++ b/src/exchange/afl-tests/id:000748,src:000001,op:flip4,pos:569,+cov
diff --git a/src/mint/afl-tests/id:000749,src:000001,op:flip1,pos:1634 b/src/exchange/afl-tests/id:000749,src:000001,op:flip1,pos:1634
index cb0f68dee..cb0f68dee 100644
--- a/src/mint/afl-tests/id:000749,src:000001,op:flip1,pos:1634
+++ b/src/exchange/afl-tests/id:000749,src:000001,op:flip1,pos:1634
diff --git a/src/mint/afl-tests/id:000749,src:000001,op:flip4,pos:788,+cov b/src/exchange/afl-tests/id:000749,src:000001,op:flip4,pos:788,+cov
index ba918f16e..ba918f16e 100644
--- a/src/mint/afl-tests/id:000749,src:000001,op:flip4,pos:788,+cov
+++ b/src/exchange/afl-tests/id:000749,src:000001,op:flip4,pos:788,+cov
diff --git a/src/mint/afl-tests/id:000750,src:000001,op:flip1,pos:1657,+cov b/src/exchange/afl-tests/id:000750,src:000001,op:flip1,pos:1657,+cov
index f502490a4..f502490a4 100644
--- a/src/mint/afl-tests/id:000750,src:000001,op:flip1,pos:1657,+cov
+++ b/src/exchange/afl-tests/id:000750,src:000001,op:flip1,pos:1657,+cov
diff --git a/src/mint/afl-tests/id:000750,src:000001,op:flip4,pos:1198,+cov b/src/exchange/afl-tests/id:000750,src:000001,op:flip4,pos:1198,+cov
index b463b75f9..b463b75f9 100644
--- a/src/mint/afl-tests/id:000750,src:000001,op:flip4,pos:1198,+cov
+++ b/src/exchange/afl-tests/id:000750,src:000001,op:flip4,pos:1198,+cov
diff --git a/src/mint/afl-tests/id:000751,src:000001,op:flip1,pos:1712,+cov b/src/exchange/afl-tests/id:000751,src:000001,op:flip1,pos:1712,+cov
index ed22ac28c..ed22ac28c 100644
--- a/src/mint/afl-tests/id:000751,src:000001,op:flip1,pos:1712,+cov
+++ b/src/exchange/afl-tests/id:000751,src:000001,op:flip1,pos:1712,+cov
diff --git a/src/mint/afl-tests/id:000751,src:000001,op:flip8,pos:67,+cov b/src/exchange/afl-tests/id:000751,src:000001,op:flip8,pos:67,+cov
index 48167b48c..48167b48c 100644
--- a/src/mint/afl-tests/id:000751,src:000001,op:flip8,pos:67,+cov
+++ b/src/exchange/afl-tests/id:000751,src:000001,op:flip8,pos:67,+cov
diff --git a/src/mint/afl-tests/id:000752,src:000001,op:flip2,pos:21,+cov b/src/exchange/afl-tests/id:000752,src:000001,op:flip2,pos:21,+cov
index 95dde0c90..95dde0c90 100644
--- a/src/mint/afl-tests/id:000752,src:000001,op:flip2,pos:21,+cov
+++ b/src/exchange/afl-tests/id:000752,src:000001,op:flip2,pos:21,+cov
diff --git a/src/mint/afl-tests/id:000752,src:000001,op:flip8,pos:1661,+cov b/src/exchange/afl-tests/id:000752,src:000001,op:flip8,pos:1661,+cov
index 7a749970d..7a749970d 100644
--- a/src/mint/afl-tests/id:000752,src:000001,op:flip8,pos:1661,+cov
+++ b/src/exchange/afl-tests/id:000752,src:000001,op:flip8,pos:1661,+cov
diff --git a/src/mint/afl-tests/id:000753,src:000001,op:flip16,pos:390,+cov b/src/exchange/afl-tests/id:000753,src:000001,op:flip16,pos:390,+cov
index 4088f86e9..4088f86e9 100644
--- a/src/mint/afl-tests/id:000753,src:000001,op:flip16,pos:390,+cov
+++ b/src/exchange/afl-tests/id:000753,src:000001,op:flip16,pos:390,+cov
diff --git a/src/mint/afl-tests/id:000753,src:000001,op:flip2,pos:39,+cov b/src/exchange/afl-tests/id:000753,src:000001,op:flip2,pos:39,+cov
index 63802d8b9..63802d8b9 100644
--- a/src/mint/afl-tests/id:000753,src:000001,op:flip2,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000753,src:000001,op:flip2,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000754,src:000001,op:flip2,pos:105,+cov b/src/exchange/afl-tests/id:000754,src:000001,op:flip2,pos:105,+cov
index 61d14841d..61d14841d 100644
--- a/src/mint/afl-tests/id:000754,src:000001,op:flip2,pos:105,+cov
+++ b/src/exchange/afl-tests/id:000754,src:000001,op:flip2,pos:105,+cov
diff --git a/src/mint/afl-tests/id:000754,src:000001,op:flip32,pos:339,+cov b/src/exchange/afl-tests/id:000754,src:000001,op:flip32,pos:339,+cov
index e33270ceb..e33270ceb 100644
--- a/src/mint/afl-tests/id:000754,src:000001,op:flip32,pos:339,+cov
+++ b/src/exchange/afl-tests/id:000754,src:000001,op:flip32,pos:339,+cov
diff --git a/src/mint/afl-tests/id:000755,src:000001,op:flip2,pos:890,+cov b/src/exchange/afl-tests/id:000755,src:000001,op:flip2,pos:890,+cov
index 4021f8c6b..4021f8c6b 100644
--- a/src/mint/afl-tests/id:000755,src:000001,op:flip2,pos:890,+cov
+++ b/src/exchange/afl-tests/id:000755,src:000001,op:flip2,pos:890,+cov
diff --git a/src/mint/afl-tests/id:000755,src:000001,op:flip32,pos:975,+cov b/src/exchange/afl-tests/id:000755,src:000001,op:flip32,pos:975,+cov
index f0676060f..f0676060f 100644
--- a/src/mint/afl-tests/id:000755,src:000001,op:flip32,pos:975,+cov
+++ b/src/exchange/afl-tests/id:000755,src:000001,op:flip32,pos:975,+cov
diff --git a/src/mint/afl-tests/id:000756,src:000001,op:arith8,pos:10,val:-30,+cov b/src/exchange/afl-tests/id:000756,src:000001,op:arith8,pos:10,val:-30,+cov
index f01f71ec9..f01f71ec9 100644
--- a/src/mint/afl-tests/id:000756,src:000001,op:arith8,pos:10,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000756,src:000001,op:arith8,pos:10,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000756,src:000001,op:flip2,pos:975,+cov b/src/exchange/afl-tests/id:000756,src:000001,op:flip2,pos:975,+cov
index 3bb81fc65..3bb81fc65 100644
--- a/src/mint/afl-tests/id:000756,src:000001,op:flip2,pos:975,+cov
+++ b/src/exchange/afl-tests/id:000756,src:000001,op:flip2,pos:975,+cov
diff --git a/src/mint/afl-tests/id:000757,src:000001,op:arith8,pos:46,val:+9,+cov b/src/exchange/afl-tests/id:000757,src:000001,op:arith8,pos:46,val:+9,+cov
index e94ab3dd4..e94ab3dd4 100644
--- a/src/mint/afl-tests/id:000757,src:000001,op:arith8,pos:46,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000757,src:000001,op:arith8,pos:46,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000757,src:000001,op:flip2,pos:1509,+cov b/src/exchange/afl-tests/id:000757,src:000001,op:flip2,pos:1509,+cov
index f237a8951..f237a8951 100644
--- a/src/mint/afl-tests/id:000757,src:000001,op:flip2,pos:1509,+cov
+++ b/src/exchange/afl-tests/id:000757,src:000001,op:flip2,pos:1509,+cov
diff --git a/src/mint/afl-tests/id:000758,src:000001,op:arith8,pos:72,val:+5,+cov b/src/exchange/afl-tests/id:000758,src:000001,op:arith8,pos:72,val:+5,+cov
index 4e956d1e1..4e956d1e1 100644
--- a/src/mint/afl-tests/id:000758,src:000001,op:arith8,pos:72,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000758,src:000001,op:arith8,pos:72,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000758,src:000001,op:flip2,pos:1662,+cov b/src/exchange/afl-tests/id:000758,src:000001,op:flip2,pos:1662,+cov
index 725d382ed..725d382ed 100644
--- a/src/mint/afl-tests/id:000758,src:000001,op:flip2,pos:1662,+cov
+++ b/src/exchange/afl-tests/id:000758,src:000001,op:flip2,pos:1662,+cov
diff --git a/src/mint/afl-tests/id:000759,src:000001,op:flip4,pos:32,+cov b/src/exchange/afl-tests/id:000759,src:000001,op:flip4,pos:32,+cov
index 1641ffdbe..1641ffdbe 100644
--- a/src/mint/afl-tests/id:000759,src:000001,op:flip4,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000759,src:000001,op:flip4,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000759,src:000002,op:flip1,pos:30 b/src/exchange/afl-tests/id:000759,src:000002,op:flip1,pos:30
index 855862e8a..855862e8a 100644
--- a/src/mint/afl-tests/id:000759,src:000002,op:flip1,pos:30
+++ b/src/exchange/afl-tests/id:000759,src:000002,op:flip1,pos:30
diff --git a/src/mint/afl-tests/id:000760,src:000001,op:flip4,pos:300,+cov b/src/exchange/afl-tests/id:000760,src:000001,op:flip4,pos:300,+cov
index 7ab6d56b3..7ab6d56b3 100644
--- a/src/mint/afl-tests/id:000760,src:000001,op:flip4,pos:300,+cov
+++ b/src/exchange/afl-tests/id:000760,src:000001,op:flip4,pos:300,+cov
diff --git a/src/mint/afl-tests/id:000760,src:000002,op:flip1,pos:50 b/src/exchange/afl-tests/id:000760,src:000002,op:flip1,pos:50
index 934dffa81..934dffa81 100644
--- a/src/mint/afl-tests/id:000760,src:000002,op:flip1,pos:50
+++ b/src/exchange/afl-tests/id:000760,src:000002,op:flip1,pos:50
diff --git a/src/mint/afl-tests/id:000761,src:000001,op:flip4,pos:457,+cov b/src/exchange/afl-tests/id:000761,src:000001,op:flip4,pos:457,+cov
index 31745f548..31745f548 100644
--- a/src/mint/afl-tests/id:000761,src:000001,op:flip4,pos:457,+cov
+++ b/src/exchange/afl-tests/id:000761,src:000001,op:flip4,pos:457,+cov
diff --git a/src/mint/afl-tests/id:000761,src:000002,op:flip1,pos:50,+cov b/src/exchange/afl-tests/id:000761,src:000002,op:flip1,pos:50,+cov
index b4a99b0f7..b4a99b0f7 100644
--- a/src/mint/afl-tests/id:000761,src:000002,op:flip1,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000761,src:000002,op:flip1,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000762,src:000001,op:flip4,pos:1507,+cov b/src/exchange/afl-tests/id:000762,src:000001,op:flip4,pos:1507,+cov
index c5eb14246..c5eb14246 100644
--- a/src/mint/afl-tests/id:000762,src:000001,op:flip4,pos:1507,+cov
+++ b/src/exchange/afl-tests/id:000762,src:000001,op:flip4,pos:1507,+cov
diff --git a/src/mint/afl-tests/id:000762,src:000002,op:flip1,pos:63 b/src/exchange/afl-tests/id:000762,src:000002,op:flip1,pos:63
index 3d68144a1..3d68144a1 100644
--- a/src/mint/afl-tests/id:000762,src:000002,op:flip1,pos:63
+++ b/src/exchange/afl-tests/id:000762,src:000002,op:flip1,pos:63
diff --git a/src/mint/afl-tests/id:000763,src:000001,op:flip4,pos:1549,+cov b/src/exchange/afl-tests/id:000763,src:000001,op:flip4,pos:1549,+cov
index 775a9f9bb..775a9f9bb 100644
--- a/src/mint/afl-tests/id:000763,src:000001,op:flip4,pos:1549,+cov
+++ b/src/exchange/afl-tests/id:000763,src:000001,op:flip4,pos:1549,+cov
diff --git a/src/mint/afl-tests/id:000763,src:000002,op:flip1,pos:76 b/src/exchange/afl-tests/id:000763,src:000002,op:flip1,pos:76
index 1146573f4..1146573f4 100644
--- a/src/mint/afl-tests/id:000763,src:000002,op:flip1,pos:76
+++ b/src/exchange/afl-tests/id:000763,src:000002,op:flip1,pos:76
diff --git a/src/mint/afl-tests/id:000764,src:000001,op:flip4,pos:1577,+cov b/src/exchange/afl-tests/id:000764,src:000001,op:flip4,pos:1577,+cov
index dc3378082..dc3378082 100644
--- a/src/mint/afl-tests/id:000764,src:000001,op:flip4,pos:1577,+cov
+++ b/src/exchange/afl-tests/id:000764,src:000001,op:flip4,pos:1577,+cov
diff --git a/src/mint/afl-tests/id:000764,src:000002,op:flip1,pos:135 b/src/exchange/afl-tests/id:000764,src:000002,op:flip1,pos:135
index 9d9b261b0..9d9b261b0 100644
--- a/src/mint/afl-tests/id:000764,src:000002,op:flip1,pos:135
+++ b/src/exchange/afl-tests/id:000764,src:000002,op:flip1,pos:135
diff --git a/src/mint/afl-tests/id:000765,src:000001,op:flip8,pos:899,+cov b/src/exchange/afl-tests/id:000765,src:000001,op:flip8,pos:899,+cov
index 5046a0a2e..5046a0a2e 100644
--- a/src/mint/afl-tests/id:000765,src:000001,op:flip8,pos:899,+cov
+++ b/src/exchange/afl-tests/id:000765,src:000001,op:flip8,pos:899,+cov
diff --git a/src/mint/afl-tests/id:000765,src:000002,op:flip1,pos:143,+cov b/src/exchange/afl-tests/id:000765,src:000002,op:flip1,pos:143,+cov
index 31441e1bd..31441e1bd 100644
--- a/src/mint/afl-tests/id:000765,src:000002,op:flip1,pos:143,+cov
+++ b/src/exchange/afl-tests/id:000765,src:000002,op:flip1,pos:143,+cov
diff --git a/src/mint/afl-tests/id:000766,src:000001,op:flip8,pos:1457,+cov b/src/exchange/afl-tests/id:000766,src:000001,op:flip8,pos:1457,+cov
index a18b0272b..a18b0272b 100644
--- a/src/mint/afl-tests/id:000766,src:000001,op:flip8,pos:1457,+cov
+++ b/src/exchange/afl-tests/id:000766,src:000001,op:flip8,pos:1457,+cov
diff --git a/src/mint/afl-tests/id:000766,src:000002,op:flip4,pos:8,+cov b/src/exchange/afl-tests/id:000766,src:000002,op:flip4,pos:8,+cov
index b4feccce4..b4feccce4 100644
--- a/src/mint/afl-tests/id:000766,src:000002,op:flip4,pos:8,+cov
+++ b/src/exchange/afl-tests/id:000766,src:000002,op:flip4,pos:8,+cov
diff --git a/src/mint/afl-tests/id:000767,src:000001,op:flip32,pos:301,+cov b/src/exchange/afl-tests/id:000767,src:000001,op:flip32,pos:301,+cov
index 03c18d5d4..03c18d5d4 100644
--- a/src/mint/afl-tests/id:000767,src:000001,op:flip32,pos:301,+cov
+++ b/src/exchange/afl-tests/id:000767,src:000001,op:flip32,pos:301,+cov
diff --git a/src/mint/afl-tests/id:000767,src:000002,op:flip4,pos:117,+cov b/src/exchange/afl-tests/id:000767,src:000002,op:flip4,pos:117,+cov
index 63b3ddf08..63b3ddf08 100644
--- a/src/mint/afl-tests/id:000767,src:000002,op:flip4,pos:117,+cov
+++ b/src/exchange/afl-tests/id:000767,src:000002,op:flip4,pos:117,+cov
diff --git a/src/mint/afl-tests/id:000768,src:000001,op:arith8,pos:18,val:+11,+cov b/src/exchange/afl-tests/id:000768,src:000001,op:arith8,pos:18,val:+11,+cov
index 96c53e4ac..96c53e4ac 100644
--- a/src/mint/afl-tests/id:000768,src:000001,op:arith8,pos:18,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000768,src:000001,op:arith8,pos:18,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000768,src:000002,op:arith8,pos:11,val:-1,+cov b/src/exchange/afl-tests/id:000768,src:000002,op:arith8,pos:11,val:-1,+cov
index 3e6a434b9..3e6a434b9 100644
--- a/src/mint/afl-tests/id:000768,src:000002,op:arith8,pos:11,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000768,src:000002,op:arith8,pos:11,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000769,src:000001,op:arith8,pos:33,val:+17,+cov b/src/exchange/afl-tests/id:000769,src:000001,op:arith8,pos:33,val:+17,+cov
index 52829db06..52829db06 100644
--- a/src/mint/afl-tests/id:000769,src:000001,op:arith8,pos:33,val:+17,+cov
+++ b/src/exchange/afl-tests/id:000769,src:000001,op:arith8,pos:33,val:+17,+cov
diff --git a/src/mint/afl-tests/id:000769,src:000002,op:arith8,pos:20,val:+13,+cov b/src/exchange/afl-tests/id:000769,src:000002,op:arith8,pos:20,val:+13,+cov
index 13df3f9f3..13df3f9f3 100644
--- a/src/mint/afl-tests/id:000769,src:000002,op:arith8,pos:20,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000769,src:000002,op:arith8,pos:20,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000770,src:000002,op:arith8,pos:34,val:-6,+cov b/src/exchange/afl-tests/id:000770,src:000002,op:arith8,pos:34,val:-6,+cov
index d43c50e81..d43c50e81 100644
--- a/src/mint/afl-tests/id:000770,src:000002,op:arith8,pos:34,val:-6,+cov
+++ b/src/exchange/afl-tests/id:000770,src:000002,op:arith8,pos:34,val:-6,+cov
diff --git a/src/mint/afl-tests/id:000770,src:000002,op:flip1,pos:30 b/src/exchange/afl-tests/id:000770,src:000002,op:flip1,pos:30
index 855862e8a..855862e8a 100644
--- a/src/mint/afl-tests/id:000770,src:000002,op:flip1,pos:30
+++ b/src/exchange/afl-tests/id:000770,src:000002,op:flip1,pos:30
diff --git a/src/mint/afl-tests/id:000771,src:000002,op:arith8,pos:105,val:+35,+cov b/src/exchange/afl-tests/id:000771,src:000002,op:arith8,pos:105,val:+35,+cov
index d7e5b953e..d7e5b953e 100644
--- a/src/mint/afl-tests/id:000771,src:000002,op:arith8,pos:105,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000771,src:000002,op:arith8,pos:105,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000771,src:000002,op:flip1,pos:45,+cov b/src/exchange/afl-tests/id:000771,src:000002,op:flip1,pos:45,+cov
index 53ea0df40..53ea0df40 100644
--- a/src/mint/afl-tests/id:000771,src:000002,op:flip1,pos:45,+cov
+++ b/src/exchange/afl-tests/id:000771,src:000002,op:flip1,pos:45,+cov
diff --git a/src/mint/afl-tests/id:000772,src:000002,op:arith8,pos:109,val:-35 b/src/exchange/afl-tests/id:000772,src:000002,op:arith8,pos:109,val:-35
index 627cf273f..627cf273f 100644
--- a/src/mint/afl-tests/id:000772,src:000002,op:arith8,pos:109,val:-35
+++ b/src/exchange/afl-tests/id:000772,src:000002,op:arith8,pos:109,val:-35
diff --git a/src/mint/afl-tests/id:000772,src:000002,op:flip1,pos:50 b/src/exchange/afl-tests/id:000772,src:000002,op:flip1,pos:50
index 934dffa81..934dffa81 100644
--- a/src/mint/afl-tests/id:000772,src:000002,op:flip1,pos:50
+++ b/src/exchange/afl-tests/id:000772,src:000002,op:flip1,pos:50
diff --git a/src/mint/afl-tests/id:000773,src:000002,op:arith8,pos:131,val:+5,+cov b/src/exchange/afl-tests/id:000773,src:000002,op:arith8,pos:131,val:+5,+cov
index 299d0445c..299d0445c 100644
--- a/src/mint/afl-tests/id:000773,src:000002,op:arith8,pos:131,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000773,src:000002,op:arith8,pos:131,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000773,src:000002,op:flip1,pos:63 b/src/exchange/afl-tests/id:000773,src:000002,op:flip1,pos:63
index 3d68144a1..3d68144a1 100644
--- a/src/mint/afl-tests/id:000773,src:000002,op:flip1,pos:63
+++ b/src/exchange/afl-tests/id:000773,src:000002,op:flip1,pos:63
diff --git a/src/mint/afl-tests/id:000774,src:000002,op:arith8,pos:137,val:+9,+cov b/src/exchange/afl-tests/id:000774,src:000002,op:arith8,pos:137,val:+9,+cov
index ab1429558..ab1429558 100644
--- a/src/mint/afl-tests/id:000774,src:000002,op:arith8,pos:137,val:+9,+cov
+++ b/src/exchange/afl-tests/id:000774,src:000002,op:arith8,pos:137,val:+9,+cov
diff --git a/src/mint/afl-tests/id:000774,src:000002,op:flip1,pos:76 b/src/exchange/afl-tests/id:000774,src:000002,op:flip1,pos:76
index 1146573f4..1146573f4 100644
--- a/src/mint/afl-tests/id:000774,src:000002,op:flip1,pos:76
+++ b/src/exchange/afl-tests/id:000774,src:000002,op:flip1,pos:76
diff --git a/src/mint/afl-tests/id:000775,src:000002,op:arith16,pos:55,val:-29,+cov b/src/exchange/afl-tests/id:000775,src:000002,op:arith16,pos:55,val:-29,+cov
index 064c3d270..064c3d270 100644
--- a/src/mint/afl-tests/id:000775,src:000002,op:arith16,pos:55,val:-29,+cov
+++ b/src/exchange/afl-tests/id:000775,src:000002,op:arith16,pos:55,val:-29,+cov
diff --git a/src/mint/afl-tests/id:000775,src:000002,op:flip1,pos:107,+cov b/src/exchange/afl-tests/id:000775,src:000002,op:flip1,pos:107,+cov
index 8ef36b06e..8ef36b06e 100644
--- a/src/mint/afl-tests/id:000775,src:000002,op:flip1,pos:107,+cov
+++ b/src/exchange/afl-tests/id:000775,src:000002,op:flip1,pos:107,+cov
diff --git a/src/mint/afl-tests/id:000776,src:000002,op:flip1,pos:135 b/src/exchange/afl-tests/id:000776,src:000002,op:flip1,pos:135
index 9d9b261b0..9d9b261b0 100644
--- a/src/mint/afl-tests/id:000776,src:000002,op:flip1,pos:135
+++ b/src/exchange/afl-tests/id:000776,src:000002,op:flip1,pos:135
diff --git a/src/mint/afl-tests/id:000776,src:000002,op:int16,pos:27,val:+16,+cov b/src/exchange/afl-tests/id:000776,src:000002,op:int16,pos:27,val:+16,+cov
index 0edb0bad8..0edb0bad8 100644
--- a/src/mint/afl-tests/id:000776,src:000002,op:int16,pos:27,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000776,src:000002,op:int16,pos:27,val:+16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000777,src:000002,op:flip2,pos:56,+cov b/src/exchange/afl-tests/id:000777,src:000002,op:flip2,pos:56,+cov
index fe3a2e211..fe3a2e211 100644
--- a/src/mint/afl-tests/id:000777,src:000002,op:flip2,pos:56,+cov
+++ b/src/exchange/afl-tests/id:000777,src:000002,op:flip2,pos:56,+cov
diff --git a/src/mint/afl-tests/id:000777,src:000002,op:int16,pos:96,val:+32 b/src/exchange/afl-tests/id:000777,src:000002,op:int16,pos:96,val:+32
index 67cd9e4b7..67cd9e4b7 100644
--- a/src/mint/afl-tests/id:000777,src:000002,op:int16,pos:96,val:+32
+++ b/src/exchange/afl-tests/id:000777,src:000002,op:int16,pos:96,val:+32
Binary files differ
diff --git a/src/mint/afl-tests/id:000778,src:000002,op:flip2,pos:113,+cov b/src/exchange/afl-tests/id:000778,src:000002,op:flip2,pos:113,+cov
index f57a19b93..f57a19b93 100644
--- a/src/mint/afl-tests/id:000778,src:000002,op:flip2,pos:113,+cov
+++ b/src/exchange/afl-tests/id:000778,src:000002,op:flip2,pos:113,+cov
diff --git a/src/mint/afl-tests/id:000778,src:000002,op:int32,pos:53,val:be:+32767,+cov b/src/exchange/afl-tests/id:000778,src:000002,op:int32,pos:53,val:be:+32767,+cov
index de506476c..de506476c 100644
--- a/src/mint/afl-tests/id:000778,src:000002,op:int32,pos:53,val:be:+32767,+cov
+++ b/src/exchange/afl-tests/id:000778,src:000002,op:int32,pos:53,val:be:+32767,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000779,src:000002,op:ext_AO,pos:22,+cov b/src/exchange/afl-tests/id:000779,src:000002,op:ext_AO,pos:22,+cov
index c63475cbd..c63475cbd 100644
--- a/src/mint/afl-tests/id:000779,src:000002,op:ext_AO,pos:22,+cov
+++ b/src/exchange/afl-tests/id:000779,src:000002,op:ext_AO,pos:22,+cov
diff --git a/src/mint/afl-tests/id:000779,src:000002,op:flip4,pos:15,+cov b/src/exchange/afl-tests/id:000779,src:000002,op:flip4,pos:15,+cov
index 6eba8b7ad..6eba8b7ad 100644
--- a/src/mint/afl-tests/id:000779,src:000002,op:flip4,pos:15,+cov
+++ b/src/exchange/afl-tests/id:000779,src:000002,op:flip4,pos:15,+cov
diff --git a/src/mint/afl-tests/id:000780,src:000002,op:arith8,pos:10,val:-7,+cov b/src/exchange/afl-tests/id:000780,src:000002,op:arith8,pos:10,val:-7,+cov
index ee27cb8a0..ee27cb8a0 100644
--- a/src/mint/afl-tests/id:000780,src:000002,op:arith8,pos:10,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000780,src:000002,op:arith8,pos:10,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000780,src:000002,op:ext_AO,pos:130,+cov b/src/exchange/afl-tests/id:000780,src:000002,op:ext_AO,pos:130,+cov
index ff74e883e..ff74e883e 100644
--- a/src/mint/afl-tests/id:000780,src:000002,op:ext_AO,pos:130,+cov
+++ b/src/exchange/afl-tests/id:000780,src:000002,op:ext_AO,pos:130,+cov
diff --git a/src/mint/afl-tests/id:000781,src:000002,op:arith8,pos:29,val:+21,+cov b/src/exchange/afl-tests/id:000781,src:000002,op:arith8,pos:29,val:+21,+cov
index 7f575f41f..7f575f41f 100644
--- a/src/mint/afl-tests/id:000781,src:000002,op:arith8,pos:29,val:+21,+cov
+++ b/src/exchange/afl-tests/id:000781,src:000002,op:arith8,pos:29,val:+21,+cov
diff --git a/src/mint/afl-tests/id:000781,src:000002,op:havoc,rep:8 b/src/exchange/afl-tests/id:000781,src:000002,op:havoc,rep:8
index e8b3e6341..e8b3e6341 100644
--- a/src/mint/afl-tests/id:000781,src:000002,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000781,src:000002,op:havoc,rep:8
diff --git a/src/mint/afl-tests/id:000782,src:000002,op:arith8,pos:109,val:-35 b/src/exchange/afl-tests/id:000782,src:000002,op:arith8,pos:109,val:-35
index 627cf273f..627cf273f 100644
--- a/src/mint/afl-tests/id:000782,src:000002,op:arith8,pos:109,val:-35
+++ b/src/exchange/afl-tests/id:000782,src:000002,op:arith8,pos:109,val:-35
diff --git a/src/mint/afl-tests/id:000782,src:000002,op:havoc,rep:2 b/src/exchange/afl-tests/id:000782,src:000002,op:havoc,rep:2
index a3f552d8a..a3f552d8a 100644
--- a/src/mint/afl-tests/id:000782,src:000002,op:havoc,rep:2
+++ b/src/exchange/afl-tests/id:000782,src:000002,op:havoc,rep:2
diff --git a/src/mint/afl-tests/id:000783,src:000002,op:arith8,pos:132,val:+34,+cov b/src/exchange/afl-tests/id:000783,src:000002,op:arith8,pos:132,val:+34,+cov
index 8f2ddd856..8f2ddd856 100644
--- a/src/mint/afl-tests/id:000783,src:000002,op:arith8,pos:132,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000783,src:000002,op:arith8,pos:132,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000783,src:000002,op:havoc,rep:4 b/src/exchange/afl-tests/id:000783,src:000002,op:havoc,rep:4
index 95f0a4562..95f0a4562 100644
--- a/src/mint/afl-tests/id:000783,src:000002,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000783,src:000002,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000784,src:000002,op:havoc,rep:64,+cov b/src/exchange/afl-tests/id:000784,src:000002,op:havoc,rep:64,+cov
index 8e1eac4ff..8e1eac4ff 100644
--- a/src/mint/afl-tests/id:000784,src:000002,op:havoc,rep:64,+cov
+++ b/src/exchange/afl-tests/id:000784,src:000002,op:havoc,rep:64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000784,src:000002,op:int16,pos:20,val:-129,+cov b/src/exchange/afl-tests/id:000784,src:000002,op:int16,pos:20,val:-129,+cov
index 3911ed7d0..3911ed7d0 100644
--- a/src/mint/afl-tests/id:000784,src:000002,op:int16,pos:20,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000784,src:000002,op:int16,pos:20,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000785,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000785,src:000002,op:havoc,rep:64
index 81b62b019..81b62b019 100644
--- a/src/mint/afl-tests/id:000785,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000785,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000785,src:000002,op:int16,pos:82,val:+64,+cov b/src/exchange/afl-tests/id:000785,src:000002,op:int16,pos:82,val:+64,+cov
index d619296e0..d619296e0 100644
--- a/src/mint/afl-tests/id:000785,src:000002,op:int16,pos:82,val:+64,+cov
+++ b/src/exchange/afl-tests/id:000785,src:000002,op:int16,pos:82,val:+64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000786,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000786,src:000002,op:havoc,rep:16
index 1130f1233..1130f1233 100644
--- a/src/mint/afl-tests/id:000786,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000786,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000786,src:000002,op:int16,pos:96,val:+32 b/src/exchange/afl-tests/id:000786,src:000002,op:int16,pos:96,val:+32
index 67cd9e4b7..67cd9e4b7 100644
--- a/src/mint/afl-tests/id:000786,src:000002,op:int16,pos:96,val:+32
+++ b/src/exchange/afl-tests/id:000786,src:000002,op:int16,pos:96,val:+32
Binary files differ
diff --git a/src/mint/afl-tests/id:000787,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000787,src:000002,op:havoc,rep:64
index f2779a35d..f2779a35d 100644
--- a/src/mint/afl-tests/id:000787,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000787,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000787,src:000002,op:int16,pos:112,val:be:-128,+cov b/src/exchange/afl-tests/id:000787,src:000002,op:int16,pos:112,val:be:-128,+cov
index 9f708aba8..9f708aba8 100644
--- a/src/mint/afl-tests/id:000787,src:000002,op:int16,pos:112,val:be:-128,+cov
+++ b/src/exchange/afl-tests/id:000787,src:000002,op:int16,pos:112,val:be:-128,+cov
diff --git a/src/mint/afl-tests/id:000788,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000788,src:000002,op:havoc,rep:16
index 66aaf73b2..66aaf73b2 100644
--- a/src/mint/afl-tests/id:000788,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000788,src:000002,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000788,src:000002,op:int32,pos:26,val:+65536,+cov b/src/exchange/afl-tests/id:000788,src:000002,op:int32,pos:26,val:+65536,+cov
index 0fec60a6a..0fec60a6a 100644
--- a/src/mint/afl-tests/id:000788,src:000002,op:int32,pos:26,val:+65536,+cov
+++ b/src/exchange/afl-tests/id:000788,src:000002,op:int32,pos:26,val:+65536,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000789,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000789,src:000002,op:havoc,rep:16
index 841dfc97f..841dfc97f 100644
--- a/src/mint/afl-tests/id:000789,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000789,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000789,src:000002,op:int32,pos:54,val:+32,+cov b/src/exchange/afl-tests/id:000789,src:000002,op:int32,pos:54,val:+32,+cov
index 74c8b8935..74c8b8935 100644
--- a/src/mint/afl-tests/id:000789,src:000002,op:int32,pos:54,val:+32,+cov
+++ b/src/exchange/afl-tests/id:000789,src:000002,op:int32,pos:54,val:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000790,src:000002,op:ext_AO,pos:95,+cov b/src/exchange/afl-tests/id:000790,src:000002,op:ext_AO,pos:95,+cov
index b335e090c..b335e090c 100644
--- a/src/mint/afl-tests/id:000790,src:000002,op:ext_AO,pos:95,+cov
+++ b/src/exchange/afl-tests/id:000790,src:000002,op:ext_AO,pos:95,+cov
diff --git a/src/mint/afl-tests/id:000790,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000790,src:000002,op:havoc,rep:64
index 67e5fb73d..67e5fb73d 100644
--- a/src/mint/afl-tests/id:000790,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000790,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000791,src:000002,op:ext_AO,pos:98,+cov b/src/exchange/afl-tests/id:000791,src:000002,op:ext_AO,pos:98,+cov
index 348df62f1..348df62f1 100644
--- a/src/mint/afl-tests/id:000791,src:000002,op:ext_AO,pos:98,+cov
+++ b/src/exchange/afl-tests/id:000791,src:000002,op:ext_AO,pos:98,+cov
diff --git a/src/mint/afl-tests/id:000791,src:000002,op:havoc,rep:4 b/src/exchange/afl-tests/id:000791,src:000002,op:havoc,rep:4
index e220de606..e220de606 100644
--- a/src/mint/afl-tests/id:000791,src:000002,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000791,src:000002,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000792,src:000002,op:ext_AO,pos:130,+cov b/src/exchange/afl-tests/id:000792,src:000002,op:ext_AO,pos:130,+cov
index 470c57813..470c57813 100644
--- a/src/mint/afl-tests/id:000792,src:000002,op:ext_AO,pos:130,+cov
+++ b/src/exchange/afl-tests/id:000792,src:000002,op:ext_AO,pos:130,+cov
diff --git a/src/mint/afl-tests/id:000792,src:000002,op:havoc,rep:8 b/src/exchange/afl-tests/id:000792,src:000002,op:havoc,rep:8
index fd60811be..fd60811be 100644
--- a/src/mint/afl-tests/id:000792,src:000002,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000792,src:000002,op:havoc,rep:8
Binary files differ
diff --git a/src/mint/afl-tests/id:000793,src:000002,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:000793,src:000002,op:ext_AO,pos:135,+cov
index 5a597015f..5a597015f 100644
--- a/src/mint/afl-tests/id:000793,src:000002,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:000793,src:000002,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:000793,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000793,src:000002,op:havoc,rep:64
index a948c7105..a948c7105 100644
--- a/src/mint/afl-tests/id:000793,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000793,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000794,src:000002,op:ext_AO,pos:138,+cov b/src/exchange/afl-tests/id:000794,src:000002,op:ext_AO,pos:138,+cov
index 630f672a4..630f672a4 100644
--- a/src/mint/afl-tests/id:000794,src:000002,op:ext_AO,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000794,src:000002,op:ext_AO,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000794,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000794,src:000002,op:havoc,rep:64
index 6b9d8bf0f..6b9d8bf0f 100644
--- a/src/mint/afl-tests/id:000794,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000794,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000795,src:000002,op:havoc,rep:4 b/src/exchange/afl-tests/id:000795,src:000002,op:havoc,rep:4
index 2c23bdfd2..2c23bdfd2 100644
--- a/src/mint/afl-tests/id:000795,src:000002,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000795,src:000002,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000795,src:000002,op:havoc,rep:8 b/src/exchange/afl-tests/id:000795,src:000002,op:havoc,rep:8
index 21d5bb40e..21d5bb40e 100644
--- a/src/mint/afl-tests/id:000795,src:000002,op:havoc,rep:8
+++ b/src/exchange/afl-tests/id:000795,src:000002,op:havoc,rep:8
Binary files differ
diff --git a/src/mint/afl-tests/id:000796,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000796,src:000002,op:havoc,rep:16
index afcb1ee34..afcb1ee34 100644
--- a/src/mint/afl-tests/id:000796,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000796,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000796,src:000002,op:havoc,rep:32,+cov b/src/exchange/afl-tests/id:000796,src:000002,op:havoc,rep:32,+cov
index e1c924b3d..e1c924b3d 100644
--- a/src/mint/afl-tests/id:000796,src:000002,op:havoc,rep:32,+cov
+++ b/src/exchange/afl-tests/id:000796,src:000002,op:havoc,rep:32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000797,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000797,src:000002,op:havoc,rep:16
index d4b3c0e6f..d4b3c0e6f 100644
--- a/src/mint/afl-tests/id:000797,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000797,src:000002,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000797,src:000002,op:havoc,rep:2 b/src/exchange/afl-tests/id:000797,src:000002,op:havoc,rep:2
index 106d1dc4c..106d1dc4c 100644
--- a/src/mint/afl-tests/id:000797,src:000002,op:havoc,rep:2
+++ b/src/exchange/afl-tests/id:000797,src:000002,op:havoc,rep:2
diff --git a/src/mint/afl-tests/id:000798,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000798,src:000002,op:havoc,rep:16
index b30460598..b30460598 100644
--- a/src/mint/afl-tests/id:000798,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000798,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000798,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000798,src:000002,op:havoc,rep:64
index 5424d7e8c..5424d7e8c 100644
--- a/src/mint/afl-tests/id:000798,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000798,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000799,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000799,src:000002,op:havoc,rep:16
index 492a1913b..492a1913b 100644
--- a/src/mint/afl-tests/id:000799,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000799,src:000002,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000799,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000799,src:000002,op:havoc,rep:64
index 65dedeab6..65dedeab6 100644
--- a/src/mint/afl-tests/id:000799,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000799,src:000002,op:havoc,rep:64
diff --git a/src/mint/afl-tests/id:000800,src:000002,op:havoc,rep:4 b/src/exchange/afl-tests/id:000800,src:000002,op:havoc,rep:4
index 435ce5ea3..435ce5ea3 100644
--- a/src/mint/afl-tests/id:000800,src:000002,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000800,src:000002,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000801,src:000002,op:havoc,rep:128 b/src/exchange/afl-tests/id:000801,src:000002,op:havoc,rep:128
index 8d62efcab..8d62efcab 100644
--- a/src/mint/afl-tests/id:000801,src:000002,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000801,src:000002,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000801,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000801,src:000002,op:havoc,rep:64
index b1935635a..b1935635a 100644
--- a/src/mint/afl-tests/id:000801,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000801,src:000002,op:havoc,rep:64
Binary files differ
diff --git a/src/mint/afl-tests/id:000802,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000802,src:000002,op:havoc,rep:16
index 74b1f2cd0..74b1f2cd0 100644
--- a/src/mint/afl-tests/id:000802,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000802,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000802,src:000002,op:havoc,rep:4 b/src/exchange/afl-tests/id:000802,src:000002,op:havoc,rep:4
index 197ddcc95..197ddcc95 100644
--- a/src/mint/afl-tests/id:000802,src:000002,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000802,src:000002,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000803,src:000002,op:havoc,rep:128,+cov b/src/exchange/afl-tests/id:000803,src:000002,op:havoc,rep:128,+cov
index 2988eafb6..2988eafb6 100644
--- a/src/mint/afl-tests/id:000803,src:000002,op:havoc,rep:128,+cov
+++ b/src/exchange/afl-tests/id:000803,src:000002,op:havoc,rep:128,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000803,src:000002,op:havoc,rep:2 b/src/exchange/afl-tests/id:000803,src:000002,op:havoc,rep:2
index ba9a049aa..ba9a049aa 100644
--- a/src/mint/afl-tests/id:000803,src:000002,op:havoc,rep:2
+++ b/src/exchange/afl-tests/id:000803,src:000002,op:havoc,rep:2
diff --git a/src/mint/afl-tests/id:000804,src:000002,op:havoc,rep:32 b/src/exchange/afl-tests/id:000804,src:000002,op:havoc,rep:32
index d33b92437..d33b92437 100644
--- a/src/mint/afl-tests/id:000804,src:000002,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000804,src:000002,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000804,src:000002,op:havoc,rep:64 b/src/exchange/afl-tests/id:000804,src:000002,op:havoc,rep:64
index a852f63cb..a852f63cb 100644
--- a/src/mint/afl-tests/id:000804,src:000002,op:havoc,rep:64
+++ b/src/exchange/afl-tests/id:000804,src:000002,op:havoc,rep:64
diff --git a/src/mint/afl-tests/id:000805,src:000002,op:havoc,rep:4 b/src/exchange/afl-tests/id:000805,src:000002,op:havoc,rep:4
index 65ebe63b0..65ebe63b0 100644
--- a/src/mint/afl-tests/id:000805,src:000002,op:havoc,rep:4
+++ b/src/exchange/afl-tests/id:000805,src:000002,op:havoc,rep:4
diff --git a/src/mint/afl-tests/id:000805,src:000003,op:flip1,pos:0,+cov b/src/exchange/afl-tests/id:000805,src:000003,op:flip1,pos:0,+cov
index 3ee9a8173..3ee9a8173 100644
--- a/src/mint/afl-tests/id:000805,src:000003,op:flip1,pos:0,+cov
+++ b/src/exchange/afl-tests/id:000805,src:000003,op:flip1,pos:0,+cov
diff --git a/src/mint/afl-tests/id:000806,src:000002,op:havoc,rep:32 b/src/exchange/afl-tests/id:000806,src:000002,op:havoc,rep:32
index c61ce74ed..c61ce74ed 100644
--- a/src/mint/afl-tests/id:000806,src:000002,op:havoc,rep:32
+++ b/src/exchange/afl-tests/id:000806,src:000002,op:havoc,rep:32
Binary files differ
diff --git a/src/mint/afl-tests/id:000806,src:000003,op:flip1,pos:13,+cov b/src/exchange/afl-tests/id:000806,src:000003,op:flip1,pos:13,+cov
index f0652d011..f0652d011 100644
--- a/src/mint/afl-tests/id:000806,src:000003,op:flip1,pos:13,+cov
+++ b/src/exchange/afl-tests/id:000806,src:000003,op:flip1,pos:13,+cov
diff --git a/src/mint/afl-tests/id:000807,src:000002,op:havoc,rep:128 b/src/exchange/afl-tests/id:000807,src:000002,op:havoc,rep:128
index 94795fd76..94795fd76 100644
--- a/src/mint/afl-tests/id:000807,src:000002,op:havoc,rep:128
+++ b/src/exchange/afl-tests/id:000807,src:000002,op:havoc,rep:128
Binary files differ
diff --git a/src/mint/afl-tests/id:000807,src:000003,op:flip1,pos:18,+cov b/src/exchange/afl-tests/id:000807,src:000003,op:flip1,pos:18,+cov
index 2ff4eacac..2ff4eacac 100644
--- a/src/mint/afl-tests/id:000807,src:000003,op:flip1,pos:18,+cov
+++ b/src/exchange/afl-tests/id:000807,src:000003,op:flip1,pos:18,+cov
diff --git a/src/mint/afl-tests/id:000808,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000808,src:000002,op:havoc,rep:16
index 31162d76e..31162d76e 100644
--- a/src/mint/afl-tests/id:000808,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000808,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000808,src:000003,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000808,src:000003,op:flip1,pos:27,+cov
index f4f567642..f4f567642 100644
--- a/src/mint/afl-tests/id:000808,src:000003,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000808,src:000003,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000809,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000809,src:000002,op:havoc,rep:16
index 3e4948309..3e4948309 100644
--- a/src/mint/afl-tests/id:000809,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000809,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000809,src:000003,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000809,src:000003,op:flip1,pos:27,+cov
index 1b7007934..1b7007934 100644
--- a/src/mint/afl-tests/id:000809,src:000003,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000809,src:000003,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000810,src:000002,op:havoc,rep:32,+cov b/src/exchange/afl-tests/id:000810,src:000002,op:havoc,rep:32,+cov
index abd2893da..abd2893da 100644
--- a/src/mint/afl-tests/id:000810,src:000002,op:havoc,rep:32,+cov
+++ b/src/exchange/afl-tests/id:000810,src:000002,op:havoc,rep:32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000810,src:000003,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000810,src:000003,op:flip1,pos:30,+cov
index 6835567b0..6835567b0 100644
--- a/src/mint/afl-tests/id:000810,src:000003,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000810,src:000003,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000811,src:000002,op:havoc,rep:2,+cov b/src/exchange/afl-tests/id:000811,src:000002,op:havoc,rep:2,+cov
index f17a1c6ec..f17a1c6ec 100644
--- a/src/mint/afl-tests/id:000811,src:000002,op:havoc,rep:2,+cov
+++ b/src/exchange/afl-tests/id:000811,src:000002,op:havoc,rep:2,+cov
diff --git a/src/mint/afl-tests/id:000811,src:000003,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000811,src:000003,op:flip1,pos:30,+cov
index 5b5904e33..5b5904e33 100644
--- a/src/mint/afl-tests/id:000811,src:000003,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000811,src:000003,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000812,src:000002,op:havoc,rep:4,+cov b/src/exchange/afl-tests/id:000812,src:000002,op:havoc,rep:4,+cov
index af2c17d9b..af2c17d9b 100644
--- a/src/mint/afl-tests/id:000812,src:000002,op:havoc,rep:4,+cov
+++ b/src/exchange/afl-tests/id:000812,src:000002,op:havoc,rep:4,+cov
diff --git a/src/mint/afl-tests/id:000812,src:000003,op:flip1,pos:32,+cov b/src/exchange/afl-tests/id:000812,src:000003,op:flip1,pos:32,+cov
index c38376946..c38376946 100644
--- a/src/mint/afl-tests/id:000812,src:000003,op:flip1,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000812,src:000003,op:flip1,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000813,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000813,src:000002,op:havoc,rep:16
index 97e61dbc7..97e61dbc7 100644
--- a/src/mint/afl-tests/id:000813,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000813,src:000002,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000813,src:000003,op:flip1,pos:34,+cov b/src/exchange/afl-tests/id:000813,src:000003,op:flip1,pos:34,+cov
index 66a4407c9..66a4407c9 100644
--- a/src/mint/afl-tests/id:000813,src:000003,op:flip1,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000813,src:000003,op:flip1,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000814,src:000002,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000814,src:000002,op:havoc,rep:16,+cov
index d613c78f6..d613c78f6 100644
--- a/src/mint/afl-tests/id:000814,src:000002,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000814,src:000002,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000814,src:000003,op:flip1,pos:40,+cov b/src/exchange/afl-tests/id:000814,src:000003,op:flip1,pos:40,+cov
index 26c2c08bd..26c2c08bd 100644
--- a/src/mint/afl-tests/id:000814,src:000003,op:flip1,pos:40,+cov
+++ b/src/exchange/afl-tests/id:000814,src:000003,op:flip1,pos:40,+cov
diff --git a/src/mint/afl-tests/id:000815,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000815,src:000002,op:havoc,rep:16
index ea342a199..ea342a199 100644
--- a/src/mint/afl-tests/id:000815,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000815,src:000002,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000815,src:000003,op:flip1,pos:42,+cov b/src/exchange/afl-tests/id:000815,src:000003,op:flip1,pos:42,+cov
index 2f5eac286..2f5eac286 100644
--- a/src/mint/afl-tests/id:000815,src:000003,op:flip1,pos:42,+cov
+++ b/src/exchange/afl-tests/id:000815,src:000003,op:flip1,pos:42,+cov
diff --git a/src/mint/afl-tests/id:000816,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000816,src:000002,op:havoc,rep:16
index def699478..def699478 100644
--- a/src/mint/afl-tests/id:000816,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000816,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000816,src:000003,op:flip1,pos:43,+cov b/src/exchange/afl-tests/id:000816,src:000003,op:flip1,pos:43,+cov
index 45f03b258..45f03b258 100644
--- a/src/mint/afl-tests/id:000816,src:000003,op:flip1,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000816,src:000003,op:flip1,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000817,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000817,src:000002,op:havoc,rep:16
index 968949243..968949243 100644
--- a/src/mint/afl-tests/id:000817,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000817,src:000002,op:havoc,rep:16
diff --git a/src/mint/afl-tests/id:000817,src:000003,op:flip1,pos:48,+cov b/src/exchange/afl-tests/id:000817,src:000003,op:flip1,pos:48,+cov
index 9f7aadd96..9f7aadd96 100644
--- a/src/mint/afl-tests/id:000817,src:000003,op:flip1,pos:48,+cov
+++ b/src/exchange/afl-tests/id:000817,src:000003,op:flip1,pos:48,+cov
diff --git a/src/mint/afl-tests/id:000818,src:000002,op:havoc,rep:16 b/src/exchange/afl-tests/id:000818,src:000002,op:havoc,rep:16
index 41ab7c8bf..41ab7c8bf 100644
--- a/src/mint/afl-tests/id:000818,src:000002,op:havoc,rep:16
+++ b/src/exchange/afl-tests/id:000818,src:000002,op:havoc,rep:16
Binary files differ
diff --git a/src/mint/afl-tests/id:000818,src:000003,op:flip1,pos:50,+cov b/src/exchange/afl-tests/id:000818,src:000003,op:flip1,pos:50,+cov
index df50c011d..df50c011d 100644
--- a/src/mint/afl-tests/id:000818,src:000003,op:flip1,pos:50,+cov
+++ b/src/exchange/afl-tests/id:000818,src:000003,op:flip1,pos:50,+cov
diff --git a/src/mint/afl-tests/id:000819,src:000002,op:havoc,rep:16,+cov b/src/exchange/afl-tests/id:000819,src:000002,op:havoc,rep:16,+cov
index 72257d195..72257d195 100644
--- a/src/mint/afl-tests/id:000819,src:000002,op:havoc,rep:16,+cov
+++ b/src/exchange/afl-tests/id:000819,src:000002,op:havoc,rep:16,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000819,src:000003,op:flip1,pos:61,+cov b/src/exchange/afl-tests/id:000819,src:000003,op:flip1,pos:61,+cov
index df9b8d428..df9b8d428 100644
--- a/src/mint/afl-tests/id:000819,src:000003,op:flip1,pos:61,+cov
+++ b/src/exchange/afl-tests/id:000819,src:000003,op:flip1,pos:61,+cov
diff --git a/src/mint/afl-tests/id:000820,src:000002,op:havoc,rep:2 b/src/exchange/afl-tests/id:000820,src:000002,op:havoc,rep:2
index cff7cdf38..cff7cdf38 100644
--- a/src/mint/afl-tests/id:000820,src:000002,op:havoc,rep:2
+++ b/src/exchange/afl-tests/id:000820,src:000002,op:havoc,rep:2
diff --git a/src/mint/afl-tests/id:000820,src:000003,op:flip1,pos:67,+cov b/src/exchange/afl-tests/id:000820,src:000003,op:flip1,pos:67,+cov
index a8085ea09..a8085ea09 100644
--- a/src/mint/afl-tests/id:000820,src:000003,op:flip1,pos:67,+cov
+++ b/src/exchange/afl-tests/id:000820,src:000003,op:flip1,pos:67,+cov
diff --git a/src/mint/afl-tests/id:000821,src:000003,op:flip1,pos:18,+cov b/src/exchange/afl-tests/id:000821,src:000003,op:flip1,pos:18,+cov
index 2ff4eacac..2ff4eacac 100644
--- a/src/mint/afl-tests/id:000821,src:000003,op:flip1,pos:18,+cov
+++ b/src/exchange/afl-tests/id:000821,src:000003,op:flip1,pos:18,+cov
diff --git a/src/mint/afl-tests/id:000821,src:000003,op:flip1,pos:70 b/src/exchange/afl-tests/id:000821,src:000003,op:flip1,pos:70
index 2344e5a0f..2344e5a0f 100644
--- a/src/mint/afl-tests/id:000821,src:000003,op:flip1,pos:70
+++ b/src/exchange/afl-tests/id:000821,src:000003,op:flip1,pos:70
diff --git a/src/mint/afl-tests/id:000822,src:000003,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000822,src:000003,op:flip1,pos:27,+cov
index f4f567642..f4f567642 100644
--- a/src/mint/afl-tests/id:000822,src:000003,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000822,src:000003,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000822,src:000003,op:flip1,pos:73,+cov b/src/exchange/afl-tests/id:000822,src:000003,op:flip1,pos:73,+cov
index 4cee30da6..4cee30da6 100644
--- a/src/mint/afl-tests/id:000822,src:000003,op:flip1,pos:73,+cov
+++ b/src/exchange/afl-tests/id:000822,src:000003,op:flip1,pos:73,+cov
diff --git a/src/mint/afl-tests/id:000823,src:000003,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000823,src:000003,op:flip1,pos:27,+cov
index 1b7007934..1b7007934 100644
--- a/src/mint/afl-tests/id:000823,src:000003,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000823,src:000003,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000823,src:000003,op:flip1,pos:77,+cov b/src/exchange/afl-tests/id:000823,src:000003,op:flip1,pos:77,+cov
index bab772e40..bab772e40 100644
--- a/src/mint/afl-tests/id:000823,src:000003,op:flip1,pos:77,+cov
+++ b/src/exchange/afl-tests/id:000823,src:000003,op:flip1,pos:77,+cov
diff --git a/src/mint/afl-tests/id:000824,src:000003,op:flip1,pos:27,+cov b/src/exchange/afl-tests/id:000824,src:000003,op:flip1,pos:27,+cov
index 4546d0f9b..4546d0f9b 100644
--- a/src/mint/afl-tests/id:000824,src:000003,op:flip1,pos:27,+cov
+++ b/src/exchange/afl-tests/id:000824,src:000003,op:flip1,pos:27,+cov
diff --git a/src/mint/afl-tests/id:000824,src:000003,op:flip1,pos:83,+cov b/src/exchange/afl-tests/id:000824,src:000003,op:flip1,pos:83,+cov
index da88eb2b4..da88eb2b4 100644
--- a/src/mint/afl-tests/id:000824,src:000003,op:flip1,pos:83,+cov
+++ b/src/exchange/afl-tests/id:000824,src:000003,op:flip1,pos:83,+cov
diff --git a/src/mint/afl-tests/id:000825,src:000003,op:flip1,pos:28,+cov b/src/exchange/afl-tests/id:000825,src:000003,op:flip1,pos:28,+cov
index 29a72e43d..29a72e43d 100644
--- a/src/mint/afl-tests/id:000825,src:000003,op:flip1,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000825,src:000003,op:flip1,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000825,src:000003,op:flip1,pos:85,+cov b/src/exchange/afl-tests/id:000825,src:000003,op:flip1,pos:85,+cov
index c5151a90f..c5151a90f 100644
--- a/src/mint/afl-tests/id:000825,src:000003,op:flip1,pos:85,+cov
+++ b/src/exchange/afl-tests/id:000825,src:000003,op:flip1,pos:85,+cov
diff --git a/src/mint/afl-tests/id:000826,src:000003,op:flip1,pos:28,+cov b/src/exchange/afl-tests/id:000826,src:000003,op:flip1,pos:28,+cov
index edb70d3c4..edb70d3c4 100644
--- a/src/mint/afl-tests/id:000826,src:000003,op:flip1,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000826,src:000003,op:flip1,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000826,src:000003,op:flip1,pos:85,+cov b/src/exchange/afl-tests/id:000826,src:000003,op:flip1,pos:85,+cov
index f8b7b8bf8..f8b7b8bf8 100644
--- a/src/mint/afl-tests/id:000826,src:000003,op:flip1,pos:85,+cov
+++ b/src/exchange/afl-tests/id:000826,src:000003,op:flip1,pos:85,+cov
diff --git a/src/mint/afl-tests/id:000827,src:000003,op:flip1,pos:29,+cov b/src/exchange/afl-tests/id:000827,src:000003,op:flip1,pos:29,+cov
index 37497a717..37497a717 100644
--- a/src/mint/afl-tests/id:000827,src:000003,op:flip1,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000827,src:000003,op:flip1,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000827,src:000003,op:flip1,pos:88,+cov b/src/exchange/afl-tests/id:000827,src:000003,op:flip1,pos:88,+cov
index 78e0e4beb..78e0e4beb 100644
--- a/src/mint/afl-tests/id:000827,src:000003,op:flip1,pos:88,+cov
+++ b/src/exchange/afl-tests/id:000827,src:000003,op:flip1,pos:88,+cov
diff --git a/src/mint/afl-tests/id:000828,src:000003,op:flip1,pos:29,+cov b/src/exchange/afl-tests/id:000828,src:000003,op:flip1,pos:29,+cov
index 78d7dccb7..78d7dccb7 100644
--- a/src/mint/afl-tests/id:000828,src:000003,op:flip1,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000828,src:000003,op:flip1,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000828,src:000003,op:flip1,pos:89 b/src/exchange/afl-tests/id:000828,src:000003,op:flip1,pos:89
index fd0398da2..fd0398da2 100644
--- a/src/mint/afl-tests/id:000828,src:000003,op:flip1,pos:89
+++ b/src/exchange/afl-tests/id:000828,src:000003,op:flip1,pos:89
diff --git a/src/mint/afl-tests/id:000829,src:000003,op:flip1,pos:29,+cov b/src/exchange/afl-tests/id:000829,src:000003,op:flip1,pos:29,+cov
index 71a014055..71a014055 100644
--- a/src/mint/afl-tests/id:000829,src:000003,op:flip1,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000829,src:000003,op:flip1,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000829,src:000003,op:flip1,pos:91,+cov b/src/exchange/afl-tests/id:000829,src:000003,op:flip1,pos:91,+cov
index fb9bdc46f..fb9bdc46f 100644
--- a/src/mint/afl-tests/id:000829,src:000003,op:flip1,pos:91,+cov
+++ b/src/exchange/afl-tests/id:000829,src:000003,op:flip1,pos:91,+cov
diff --git a/src/mint/afl-tests/id:000830,src:000003,op:flip1,pos:30,+cov b/src/exchange/afl-tests/id:000830,src:000003,op:flip1,pos:30,+cov
index 5b5904e33..5b5904e33 100644
--- a/src/mint/afl-tests/id:000830,src:000003,op:flip1,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000830,src:000003,op:flip1,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000830,src:000003,op:flip1,pos:93,+cov b/src/exchange/afl-tests/id:000830,src:000003,op:flip1,pos:93,+cov
index ef48a505f..ef48a505f 100644
--- a/src/mint/afl-tests/id:000830,src:000003,op:flip1,pos:93,+cov
+++ b/src/exchange/afl-tests/id:000830,src:000003,op:flip1,pos:93,+cov
diff --git a/src/mint/afl-tests/id:000831,src:000003,op:flip1,pos:32,+cov b/src/exchange/afl-tests/id:000831,src:000003,op:flip1,pos:32,+cov
index e6a9d3efb..e6a9d3efb 100644
--- a/src/mint/afl-tests/id:000831,src:000003,op:flip1,pos:32,+cov
+++ b/src/exchange/afl-tests/id:000831,src:000003,op:flip1,pos:32,+cov
diff --git a/src/mint/afl-tests/id:000831,src:000003,op:flip1,pos:93,+cov b/src/exchange/afl-tests/id:000831,src:000003,op:flip1,pos:93,+cov
index 263877b92..263877b92 100644
--- a/src/mint/afl-tests/id:000831,src:000003,op:flip1,pos:93,+cov
+++ b/src/exchange/afl-tests/id:000831,src:000003,op:flip1,pos:93,+cov
diff --git a/src/mint/afl-tests/id:000832,src:000003,op:flip1,pos:34,+cov b/src/exchange/afl-tests/id:000832,src:000003,op:flip1,pos:34,+cov
index de835991f..de835991f 100644
--- a/src/mint/afl-tests/id:000832,src:000003,op:flip1,pos:34,+cov
+++ b/src/exchange/afl-tests/id:000832,src:000003,op:flip1,pos:34,+cov
diff --git a/src/mint/afl-tests/id:000832,src:000003,op:flip1,pos:97,+cov b/src/exchange/afl-tests/id:000832,src:000003,op:flip1,pos:97,+cov
index a5541a08a..a5541a08a 100644
--- a/src/mint/afl-tests/id:000832,src:000003,op:flip1,pos:97,+cov
+++ b/src/exchange/afl-tests/id:000832,src:000003,op:flip1,pos:97,+cov
diff --git a/src/mint/afl-tests/id:000833,src:000003,op:flip1,pos:109,+cov b/src/exchange/afl-tests/id:000833,src:000003,op:flip1,pos:109,+cov
index aa29825c3..aa29825c3 100644
--- a/src/mint/afl-tests/id:000833,src:000003,op:flip1,pos:109,+cov
+++ b/src/exchange/afl-tests/id:000833,src:000003,op:flip1,pos:109,+cov
diff --git a/src/mint/afl-tests/id:000833,src:000003,op:flip1,pos:36,+cov b/src/exchange/afl-tests/id:000833,src:000003,op:flip1,pos:36,+cov
index 075388228..075388228 100644
--- a/src/mint/afl-tests/id:000833,src:000003,op:flip1,pos:36,+cov
+++ b/src/exchange/afl-tests/id:000833,src:000003,op:flip1,pos:36,+cov
diff --git a/src/mint/afl-tests/id:000834,src:000003,op:flip1,pos:111,+cov b/src/exchange/afl-tests/id:000834,src:000003,op:flip1,pos:111,+cov
index bd49be435..bd49be435 100644
--- a/src/mint/afl-tests/id:000834,src:000003,op:flip1,pos:111,+cov
+++ b/src/exchange/afl-tests/id:000834,src:000003,op:flip1,pos:111,+cov
diff --git a/src/mint/afl-tests/id:000834,src:000003,op:flip1,pos:39 b/src/exchange/afl-tests/id:000834,src:000003,op:flip1,pos:39
index 12ae9586e..12ae9586e 100644
--- a/src/mint/afl-tests/id:000834,src:000003,op:flip1,pos:39
+++ b/src/exchange/afl-tests/id:000834,src:000003,op:flip1,pos:39
diff --git a/src/mint/afl-tests/id:000835,src:000003,op:flip1,pos:113,+cov b/src/exchange/afl-tests/id:000835,src:000003,op:flip1,pos:113,+cov
index ea5f45bec..ea5f45bec 100644
--- a/src/mint/afl-tests/id:000835,src:000003,op:flip1,pos:113,+cov
+++ b/src/exchange/afl-tests/id:000835,src:000003,op:flip1,pos:113,+cov
diff --git a/src/mint/afl-tests/id:000835,src:000003,op:flip1,pos:39,+cov b/src/exchange/afl-tests/id:000835,src:000003,op:flip1,pos:39,+cov
index acbaaebf1..acbaaebf1 100644
--- a/src/mint/afl-tests/id:000835,src:000003,op:flip1,pos:39,+cov
+++ b/src/exchange/afl-tests/id:000835,src:000003,op:flip1,pos:39,+cov
diff --git a/src/mint/afl-tests/id:000836,src:000003,op:flip1,pos:114,+cov b/src/exchange/afl-tests/id:000836,src:000003,op:flip1,pos:114,+cov
index 8ae254ae6..8ae254ae6 100644
--- a/src/mint/afl-tests/id:000836,src:000003,op:flip1,pos:114,+cov
+++ b/src/exchange/afl-tests/id:000836,src:000003,op:flip1,pos:114,+cov
diff --git a/src/mint/afl-tests/id:000836,src:000003,op:flip1,pos:40,+cov b/src/exchange/afl-tests/id:000836,src:000003,op:flip1,pos:40,+cov
index d62528541..d62528541 100644
--- a/src/mint/afl-tests/id:000836,src:000003,op:flip1,pos:40,+cov
+++ b/src/exchange/afl-tests/id:000836,src:000003,op:flip1,pos:40,+cov
diff --git a/src/mint/afl-tests/id:000837,src:000003,op:flip1,pos:119,+cov b/src/exchange/afl-tests/id:000837,src:000003,op:flip1,pos:119,+cov
index cec33d9dc..cec33d9dc 100644
--- a/src/mint/afl-tests/id:000837,src:000003,op:flip1,pos:119,+cov
+++ b/src/exchange/afl-tests/id:000837,src:000003,op:flip1,pos:119,+cov
diff --git a/src/mint/afl-tests/id:000837,src:000003,op:flip1,pos:41,+cov b/src/exchange/afl-tests/id:000837,src:000003,op:flip1,pos:41,+cov
index 74d55a8df..74d55a8df 100644
--- a/src/mint/afl-tests/id:000837,src:000003,op:flip1,pos:41,+cov
+++ b/src/exchange/afl-tests/id:000837,src:000003,op:flip1,pos:41,+cov
diff --git a/src/mint/afl-tests/id:000838,src:000003,op:flip1,pos:120,+cov b/src/exchange/afl-tests/id:000838,src:000003,op:flip1,pos:120,+cov
index f14de28c6..f14de28c6 100644
--- a/src/mint/afl-tests/id:000838,src:000003,op:flip1,pos:120,+cov
+++ b/src/exchange/afl-tests/id:000838,src:000003,op:flip1,pos:120,+cov
diff --git a/src/mint/afl-tests/id:000838,src:000003,op:flip1,pos:44,+cov b/src/exchange/afl-tests/id:000838,src:000003,op:flip1,pos:44,+cov
index caa7dcbe4..caa7dcbe4 100644
--- a/src/mint/afl-tests/id:000838,src:000003,op:flip1,pos:44,+cov
+++ b/src/exchange/afl-tests/id:000838,src:000003,op:flip1,pos:44,+cov
diff --git a/src/mint/afl-tests/id:000839,src:000003,op:flip1,pos:128,+cov b/src/exchange/afl-tests/id:000839,src:000003,op:flip1,pos:128,+cov
index ede404b50..ede404b50 100644
--- a/src/mint/afl-tests/id:000839,src:000003,op:flip1,pos:128,+cov
+++ b/src/exchange/afl-tests/id:000839,src:000003,op:flip1,pos:128,+cov
diff --git a/src/mint/afl-tests/id:000839,src:000003,op:flip1,pos:46,+cov b/src/exchange/afl-tests/id:000839,src:000003,op:flip1,pos:46,+cov
index 80ae58cd0..80ae58cd0 100644
--- a/src/mint/afl-tests/id:000839,src:000003,op:flip1,pos:46,+cov
+++ b/src/exchange/afl-tests/id:000839,src:000003,op:flip1,pos:46,+cov
diff --git a/src/mint/afl-tests/id:000840,src:000003,op:flip1,pos:141,+cov b/src/exchange/afl-tests/id:000840,src:000003,op:flip1,pos:141,+cov
index 289bb57d1..289bb57d1 100644
--- a/src/mint/afl-tests/id:000840,src:000003,op:flip1,pos:141,+cov
+++ b/src/exchange/afl-tests/id:000840,src:000003,op:flip1,pos:141,+cov
diff --git a/src/mint/afl-tests/id:000840,src:000003,op:flip1,pos:48,+cov b/src/exchange/afl-tests/id:000840,src:000003,op:flip1,pos:48,+cov
index dd1d1c3aa..dd1d1c3aa 100644
--- a/src/mint/afl-tests/id:000840,src:000003,op:flip1,pos:48,+cov
+++ b/src/exchange/afl-tests/id:000840,src:000003,op:flip1,pos:48,+cov
diff --git a/src/mint/afl-tests/id:000841,src:000003,op:flip1,pos:145,+cov b/src/exchange/afl-tests/id:000841,src:000003,op:flip1,pos:145,+cov
index 1e1baa47f..1e1baa47f 100644
--- a/src/mint/afl-tests/id:000841,src:000003,op:flip1,pos:145,+cov
+++ b/src/exchange/afl-tests/id:000841,src:000003,op:flip1,pos:145,+cov
diff --git a/src/mint/afl-tests/id:000841,src:000003,op:flip1,pos:48,+cov b/src/exchange/afl-tests/id:000841,src:000003,op:flip1,pos:48,+cov
index 9f7aadd96..9f7aadd96 100644
--- a/src/mint/afl-tests/id:000841,src:000003,op:flip1,pos:48,+cov
+++ b/src/exchange/afl-tests/id:000841,src:000003,op:flip1,pos:48,+cov
diff --git a/src/mint/afl-tests/id:000842,src:000003,op:flip1,pos:147,+cov b/src/exchange/afl-tests/id:000842,src:000003,op:flip1,pos:147,+cov
index e0acaa3dc..e0acaa3dc 100644
--- a/src/mint/afl-tests/id:000842,src:000003,op:flip1,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000842,src:000003,op:flip1,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000842,src:000003,op:flip1,pos:51 b/src/exchange/afl-tests/id:000842,src:000003,op:flip1,pos:51
index 77e17fccf..77e17fccf 100644
--- a/src/mint/afl-tests/id:000842,src:000003,op:flip1,pos:51
+++ b/src/exchange/afl-tests/id:000842,src:000003,op:flip1,pos:51
diff --git a/src/mint/afl-tests/id:000843,src:000003,op:flip1,pos:150,+cov b/src/exchange/afl-tests/id:000843,src:000003,op:flip1,pos:150,+cov
index a09cd7099..a09cd7099 100644
--- a/src/mint/afl-tests/id:000843,src:000003,op:flip1,pos:150,+cov
+++ b/src/exchange/afl-tests/id:000843,src:000003,op:flip1,pos:150,+cov
diff --git a/src/mint/afl-tests/id:000843,src:000003,op:flip1,pos:51,+cov b/src/exchange/afl-tests/id:000843,src:000003,op:flip1,pos:51,+cov
index 194370804..194370804 100644
--- a/src/mint/afl-tests/id:000843,src:000003,op:flip1,pos:51,+cov
+++ b/src/exchange/afl-tests/id:000843,src:000003,op:flip1,pos:51,+cov
diff --git a/src/mint/afl-tests/id:000844,src:000003,op:flip1,pos:150,+cov b/src/exchange/afl-tests/id:000844,src:000003,op:flip1,pos:150,+cov
index d0394a40e..d0394a40e 100644
--- a/src/mint/afl-tests/id:000844,src:000003,op:flip1,pos:150,+cov
+++ b/src/exchange/afl-tests/id:000844,src:000003,op:flip1,pos:150,+cov
diff --git a/src/mint/afl-tests/id:000844,src:000003,op:flip1,pos:54,+cov b/src/exchange/afl-tests/id:000844,src:000003,op:flip1,pos:54,+cov
index 13f3df73c..13f3df73c 100644
--- a/src/mint/afl-tests/id:000844,src:000003,op:flip1,pos:54,+cov
+++ b/src/exchange/afl-tests/id:000844,src:000003,op:flip1,pos:54,+cov
diff --git a/src/mint/afl-tests/id:000845,src:000003,op:flip1,pos:58,+cov b/src/exchange/afl-tests/id:000845,src:000003,op:flip1,pos:58,+cov
index e065bd467..e065bd467 100644
--- a/src/mint/afl-tests/id:000845,src:000003,op:flip1,pos:58,+cov
+++ b/src/exchange/afl-tests/id:000845,src:000003,op:flip1,pos:58,+cov
diff --git a/src/mint/afl-tests/id:000845,src:000003,op:flip2,pos:65,+cov b/src/exchange/afl-tests/id:000845,src:000003,op:flip2,pos:65,+cov
index efa43aff6..efa43aff6 100644
--- a/src/mint/afl-tests/id:000845,src:000003,op:flip2,pos:65,+cov
+++ b/src/exchange/afl-tests/id:000845,src:000003,op:flip2,pos:65,+cov
diff --git a/src/mint/afl-tests/id:000846,src:000003,op:flip1,pos:64,+cov b/src/exchange/afl-tests/id:000846,src:000003,op:flip1,pos:64,+cov
index 2e1112a02..2e1112a02 100644
--- a/src/mint/afl-tests/id:000846,src:000003,op:flip1,pos:64,+cov
+++ b/src/exchange/afl-tests/id:000846,src:000003,op:flip1,pos:64,+cov
diff --git a/src/mint/afl-tests/id:000846,src:000003,op:flip2,pos:84,+cov b/src/exchange/afl-tests/id:000846,src:000003,op:flip2,pos:84,+cov
index a7c7ab3cf..a7c7ab3cf 100644
--- a/src/mint/afl-tests/id:000846,src:000003,op:flip2,pos:84,+cov
+++ b/src/exchange/afl-tests/id:000846,src:000003,op:flip2,pos:84,+cov
diff --git a/src/mint/afl-tests/id:000847,src:000003,op:flip1,pos:64,+cov b/src/exchange/afl-tests/id:000847,src:000003,op:flip1,pos:64,+cov
index ed38d0665..ed38d0665 100644
--- a/src/mint/afl-tests/id:000847,src:000003,op:flip1,pos:64,+cov
+++ b/src/exchange/afl-tests/id:000847,src:000003,op:flip1,pos:64,+cov
diff --git a/src/mint/afl-tests/id:000847,src:000003,op:flip2,pos:99,+cov b/src/exchange/afl-tests/id:000847,src:000003,op:flip2,pos:99,+cov
index 878bb6e45..878bb6e45 100644
--- a/src/mint/afl-tests/id:000847,src:000003,op:flip2,pos:99,+cov
+++ b/src/exchange/afl-tests/id:000847,src:000003,op:flip2,pos:99,+cov
diff --git a/src/mint/afl-tests/id:000848,src:000003,op:flip1,pos:66,+cov b/src/exchange/afl-tests/id:000848,src:000003,op:flip1,pos:66,+cov
index f72819f22..f72819f22 100644
--- a/src/mint/afl-tests/id:000848,src:000003,op:flip1,pos:66,+cov
+++ b/src/exchange/afl-tests/id:000848,src:000003,op:flip1,pos:66,+cov
diff --git a/src/mint/afl-tests/id:000848,src:000003,op:flip2,pos:102,+cov b/src/exchange/afl-tests/id:000848,src:000003,op:flip2,pos:102,+cov
index cba7d4e11..cba7d4e11 100644
--- a/src/mint/afl-tests/id:000848,src:000003,op:flip2,pos:102,+cov
+++ b/src/exchange/afl-tests/id:000848,src:000003,op:flip2,pos:102,+cov
diff --git a/src/mint/afl-tests/id:000849,src:000003,op:flip1,pos:67,+cov b/src/exchange/afl-tests/id:000849,src:000003,op:flip1,pos:67,+cov
index 689a00629..689a00629 100644
--- a/src/mint/afl-tests/id:000849,src:000003,op:flip1,pos:67,+cov
+++ b/src/exchange/afl-tests/id:000849,src:000003,op:flip1,pos:67,+cov
diff --git a/src/mint/afl-tests/id:000849,src:000003,op:flip2,pos:115,+cov b/src/exchange/afl-tests/id:000849,src:000003,op:flip2,pos:115,+cov
index 13032d4de..13032d4de 100644
--- a/src/mint/afl-tests/id:000849,src:000003,op:flip2,pos:115,+cov
+++ b/src/exchange/afl-tests/id:000849,src:000003,op:flip2,pos:115,+cov
diff --git a/src/mint/afl-tests/id:000850,src:000003,op:flip1,pos:67,+cov b/src/exchange/afl-tests/id:000850,src:000003,op:flip1,pos:67,+cov
index a8085ea09..a8085ea09 100644
--- a/src/mint/afl-tests/id:000850,src:000003,op:flip1,pos:67,+cov
+++ b/src/exchange/afl-tests/id:000850,src:000003,op:flip1,pos:67,+cov
diff --git a/src/mint/afl-tests/id:000850,src:000003,op:flip2,pos:132,+cov b/src/exchange/afl-tests/id:000850,src:000003,op:flip2,pos:132,+cov
index 1d4863524..1d4863524 100644
--- a/src/mint/afl-tests/id:000850,src:000003,op:flip2,pos:132,+cov
+++ b/src/exchange/afl-tests/id:000850,src:000003,op:flip2,pos:132,+cov
diff --git a/src/mint/afl-tests/id:000851,src:000003,op:flip1,pos:74,+cov b/src/exchange/afl-tests/id:000851,src:000003,op:flip1,pos:74,+cov
index 87f9fdee9..87f9fdee9 100644
--- a/src/mint/afl-tests/id:000851,src:000003,op:flip1,pos:74,+cov
+++ b/src/exchange/afl-tests/id:000851,src:000003,op:flip1,pos:74,+cov
diff --git a/src/mint/afl-tests/id:000851,src:000003,op:flip2,pos:133,+cov b/src/exchange/afl-tests/id:000851,src:000003,op:flip2,pos:133,+cov
index 9344bb2ce..9344bb2ce 100644
--- a/src/mint/afl-tests/id:000851,src:000003,op:flip2,pos:133,+cov
+++ b/src/exchange/afl-tests/id:000851,src:000003,op:flip2,pos:133,+cov
diff --git a/src/mint/afl-tests/id:000852,src:000003,op:flip1,pos:76,+cov b/src/exchange/afl-tests/id:000852,src:000003,op:flip1,pos:76,+cov
index 4144c2035..4144c2035 100644
--- a/src/mint/afl-tests/id:000852,src:000003,op:flip1,pos:76,+cov
+++ b/src/exchange/afl-tests/id:000852,src:000003,op:flip1,pos:76,+cov
diff --git a/src/mint/afl-tests/id:000852,src:000003,op:flip2,pos:139,+cov b/src/exchange/afl-tests/id:000852,src:000003,op:flip2,pos:139,+cov
index 736bf81e2..736bf81e2 100644
--- a/src/mint/afl-tests/id:000852,src:000003,op:flip2,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000852,src:000003,op:flip2,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000853,src:000003,op:flip1,pos:78,+cov b/src/exchange/afl-tests/id:000853,src:000003,op:flip1,pos:78,+cov
index b05e0b3dd..b05e0b3dd 100644
--- a/src/mint/afl-tests/id:000853,src:000003,op:flip1,pos:78,+cov
+++ b/src/exchange/afl-tests/id:000853,src:000003,op:flip1,pos:78,+cov
diff --git a/src/mint/afl-tests/id:000853,src:000003,op:flip2,pos:139,+cov b/src/exchange/afl-tests/id:000853,src:000003,op:flip2,pos:139,+cov
index c5a420b72..c5a420b72 100644
--- a/src/mint/afl-tests/id:000853,src:000003,op:flip2,pos:139,+cov
+++ b/src/exchange/afl-tests/id:000853,src:000003,op:flip2,pos:139,+cov
diff --git a/src/mint/afl-tests/id:000854,src:000003,op:flip2,pos:145,+cov b/src/exchange/afl-tests/id:000854,src:000003,op:flip2,pos:145,+cov
index fb40127e5..fb40127e5 100644
--- a/src/mint/afl-tests/id:000854,src:000003,op:flip2,pos:145,+cov
+++ b/src/exchange/afl-tests/id:000854,src:000003,op:flip2,pos:145,+cov
diff --git a/src/mint/afl-tests/id:000854,src:000003,op:flip2,pos:28,+cov b/src/exchange/afl-tests/id:000854,src:000003,op:flip2,pos:28,+cov
index 28576490a..28576490a 100644
--- a/src/mint/afl-tests/id:000854,src:000003,op:flip2,pos:28,+cov
+++ b/src/exchange/afl-tests/id:000854,src:000003,op:flip2,pos:28,+cov
diff --git a/src/mint/afl-tests/id:000855,src:000003,op:flip2,pos:147,+cov b/src/exchange/afl-tests/id:000855,src:000003,op:flip2,pos:147,+cov
index 21d6cafd7..21d6cafd7 100644
--- a/src/mint/afl-tests/id:000855,src:000003,op:flip2,pos:147,+cov
+++ b/src/exchange/afl-tests/id:000855,src:000003,op:flip2,pos:147,+cov
diff --git a/src/mint/afl-tests/id:000855,src:000003,op:flip2,pos:29,+cov b/src/exchange/afl-tests/id:000855,src:000003,op:flip2,pos:29,+cov
index 05cc1b7e7..05cc1b7e7 100644
--- a/src/mint/afl-tests/id:000855,src:000003,op:flip2,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000855,src:000003,op:flip2,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000856,src:000003,op:flip2,pos:151,+cov b/src/exchange/afl-tests/id:000856,src:000003,op:flip2,pos:151,+cov
index 28eec12cc..28eec12cc 100644
--- a/src/mint/afl-tests/id:000856,src:000003,op:flip2,pos:151,+cov
+++ b/src/exchange/afl-tests/id:000856,src:000003,op:flip2,pos:151,+cov
diff --git a/src/mint/afl-tests/id:000856,src:000003,op:flip2,pos:29,+cov b/src/exchange/afl-tests/id:000856,src:000003,op:flip2,pos:29,+cov
index 8b54d1c33..8b54d1c33 100644
--- a/src/mint/afl-tests/id:000856,src:000003,op:flip2,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000856,src:000003,op:flip2,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000857,src:000003,op:flip2,pos:30,+cov b/src/exchange/afl-tests/id:000857,src:000003,op:flip2,pos:30,+cov
index df87342ba..df87342ba 100644
--- a/src/mint/afl-tests/id:000857,src:000003,op:flip2,pos:30,+cov
+++ b/src/exchange/afl-tests/id:000857,src:000003,op:flip2,pos:30,+cov
diff --git a/src/mint/afl-tests/id:000857,src:000003,op:flip4,pos:110,+cov b/src/exchange/afl-tests/id:000857,src:000003,op:flip4,pos:110,+cov
index c3943cede..c3943cede 100644
--- a/src/mint/afl-tests/id:000857,src:000003,op:flip4,pos:110,+cov
+++ b/src/exchange/afl-tests/id:000857,src:000003,op:flip4,pos:110,+cov
diff --git a/src/mint/afl-tests/id:000858,src:000003,op:flip2,pos:35 b/src/exchange/afl-tests/id:000858,src:000003,op:flip2,pos:35
index 10bba0888..10bba0888 100644
--- a/src/mint/afl-tests/id:000858,src:000003,op:flip2,pos:35
+++ b/src/exchange/afl-tests/id:000858,src:000003,op:flip2,pos:35
diff --git a/src/mint/afl-tests/id:000858,src:000003,op:flip4,pos:120,+cov b/src/exchange/afl-tests/id:000858,src:000003,op:flip4,pos:120,+cov
index 0d1cd2f63..0d1cd2f63 100644
--- a/src/mint/afl-tests/id:000858,src:000003,op:flip4,pos:120,+cov
+++ b/src/exchange/afl-tests/id:000858,src:000003,op:flip4,pos:120,+cov
diff --git a/src/mint/afl-tests/id:000859,src:000003,op:flip2,pos:37,+cov b/src/exchange/afl-tests/id:000859,src:000003,op:flip2,pos:37,+cov
index cae730c0b..cae730c0b 100644
--- a/src/mint/afl-tests/id:000859,src:000003,op:flip2,pos:37,+cov
+++ b/src/exchange/afl-tests/id:000859,src:000003,op:flip2,pos:37,+cov
diff --git a/src/mint/afl-tests/id:000859,src:000003,op:flip4,pos:123,+cov b/src/exchange/afl-tests/id:000859,src:000003,op:flip4,pos:123,+cov
index 4ab0fb575..4ab0fb575 100644
--- a/src/mint/afl-tests/id:000859,src:000003,op:flip4,pos:123,+cov
+++ b/src/exchange/afl-tests/id:000859,src:000003,op:flip4,pos:123,+cov
diff --git a/src/mint/afl-tests/id:000860,src:000003,op:flip2,pos:41,+cov b/src/exchange/afl-tests/id:000860,src:000003,op:flip2,pos:41,+cov
index 8588854d5..8588854d5 100644
--- a/src/mint/afl-tests/id:000860,src:000003,op:flip2,pos:41,+cov
+++ b/src/exchange/afl-tests/id:000860,src:000003,op:flip2,pos:41,+cov
diff --git a/src/mint/afl-tests/id:000860,src:000003,op:flip4,pos:124,+cov b/src/exchange/afl-tests/id:000860,src:000003,op:flip4,pos:124,+cov
index 4cb051502..4cb051502 100644
--- a/src/mint/afl-tests/id:000860,src:000003,op:flip4,pos:124,+cov
+++ b/src/exchange/afl-tests/id:000860,src:000003,op:flip4,pos:124,+cov
diff --git a/src/mint/afl-tests/id:000861,src:000003,op:flip2,pos:42,+cov b/src/exchange/afl-tests/id:000861,src:000003,op:flip2,pos:42,+cov
index 945d559d0..945d559d0 100644
--- a/src/mint/afl-tests/id:000861,src:000003,op:flip2,pos:42,+cov
+++ b/src/exchange/afl-tests/id:000861,src:000003,op:flip2,pos:42,+cov
diff --git a/src/mint/afl-tests/id:000861,src:000003,op:flip4,pos:124,+cov b/src/exchange/afl-tests/id:000861,src:000003,op:flip4,pos:124,+cov
index d1f8846ed..d1f8846ed 100644
--- a/src/mint/afl-tests/id:000861,src:000003,op:flip4,pos:124,+cov
+++ b/src/exchange/afl-tests/id:000861,src:000003,op:flip4,pos:124,+cov
diff --git a/src/mint/afl-tests/id:000862,src:000003,op:flip2,pos:43,+cov b/src/exchange/afl-tests/id:000862,src:000003,op:flip2,pos:43,+cov
index b9359c59e..b9359c59e 100644
--- a/src/mint/afl-tests/id:000862,src:000003,op:flip2,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000862,src:000003,op:flip2,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000862,src:000003,op:flip4,pos:124,+cov b/src/exchange/afl-tests/id:000862,src:000003,op:flip4,pos:124,+cov
index 9bbc0909a..9bbc0909a 100644
--- a/src/mint/afl-tests/id:000862,src:000003,op:flip4,pos:124,+cov
+++ b/src/exchange/afl-tests/id:000862,src:000003,op:flip4,pos:124,+cov
diff --git a/src/mint/afl-tests/id:000863,src:000003,op:flip2,pos:43,+cov b/src/exchange/afl-tests/id:000863,src:000003,op:flip2,pos:43,+cov
index af374a964..af374a964 100644
--- a/src/mint/afl-tests/id:000863,src:000003,op:flip2,pos:43,+cov
+++ b/src/exchange/afl-tests/id:000863,src:000003,op:flip2,pos:43,+cov
diff --git a/src/mint/afl-tests/id:000863,src:000003,op:flip4,pos:129,+cov b/src/exchange/afl-tests/id:000863,src:000003,op:flip4,pos:129,+cov
index db5a8872f..db5a8872f 100644
--- a/src/mint/afl-tests/id:000863,src:000003,op:flip4,pos:129,+cov
+++ b/src/exchange/afl-tests/id:000863,src:000003,op:flip4,pos:129,+cov
diff --git a/src/mint/afl-tests/id:000864,src:000003,op:flip2,pos:43 b/src/exchange/afl-tests/id:000864,src:000003,op:flip2,pos:43
index aa6161730..aa6161730 100644
--- a/src/mint/afl-tests/id:000864,src:000003,op:flip2,pos:43
+++ b/src/exchange/afl-tests/id:000864,src:000003,op:flip2,pos:43
diff --git a/src/mint/afl-tests/id:000864,src:000003,op:flip4,pos:138,+cov b/src/exchange/afl-tests/id:000864,src:000003,op:flip4,pos:138,+cov
index bc062ea11..bc062ea11 100644
--- a/src/mint/afl-tests/id:000864,src:000003,op:flip4,pos:138,+cov
+++ b/src/exchange/afl-tests/id:000864,src:000003,op:flip4,pos:138,+cov
diff --git a/src/mint/afl-tests/id:000865,src:000003,op:flip2,pos:45,+cov b/src/exchange/afl-tests/id:000865,src:000003,op:flip2,pos:45,+cov
index 0e80c565f..0e80c565f 100644
--- a/src/mint/afl-tests/id:000865,src:000003,op:flip2,pos:45,+cov
+++ b/src/exchange/afl-tests/id:000865,src:000003,op:flip2,pos:45,+cov
diff --git a/src/mint/afl-tests/id:000865,src:000003,op:flip8,pos:118,+cov b/src/exchange/afl-tests/id:000865,src:000003,op:flip8,pos:118,+cov
index 7aeee844a..7aeee844a 100644
--- a/src/mint/afl-tests/id:000865,src:000003,op:flip8,pos:118,+cov
+++ b/src/exchange/afl-tests/id:000865,src:000003,op:flip8,pos:118,+cov
diff --git a/src/mint/afl-tests/id:000866,src:000003,op:flip2,pos:47,+cov b/src/exchange/afl-tests/id:000866,src:000003,op:flip2,pos:47,+cov
index 3f3e88686..3f3e88686 100644
--- a/src/mint/afl-tests/id:000866,src:000003,op:flip2,pos:47,+cov
+++ b/src/exchange/afl-tests/id:000866,src:000003,op:flip2,pos:47,+cov
diff --git a/src/mint/afl-tests/id:000866,src:000003,op:flip8,pos:129,+cov b/src/exchange/afl-tests/id:000866,src:000003,op:flip8,pos:129,+cov
index e86650f62..e86650f62 100644
--- a/src/mint/afl-tests/id:000866,src:000003,op:flip8,pos:129,+cov
+++ b/src/exchange/afl-tests/id:000866,src:000003,op:flip8,pos:129,+cov
diff --git a/src/mint/afl-tests/id:000867,src:000003,op:flip2,pos:49,+cov b/src/exchange/afl-tests/id:000867,src:000003,op:flip2,pos:49,+cov
index 76ef26a57..76ef26a57 100644
--- a/src/mint/afl-tests/id:000867,src:000003,op:flip2,pos:49,+cov
+++ b/src/exchange/afl-tests/id:000867,src:000003,op:flip2,pos:49,+cov
diff --git a/src/mint/afl-tests/id:000867,src:000003,op:flip8,pos:130,+cov b/src/exchange/afl-tests/id:000867,src:000003,op:flip8,pos:130,+cov
index d8f4bb5f2..d8f4bb5f2 100644
--- a/src/mint/afl-tests/id:000867,src:000003,op:flip8,pos:130,+cov
+++ b/src/exchange/afl-tests/id:000867,src:000003,op:flip8,pos:130,+cov
diff --git a/src/mint/afl-tests/id:000868,src:000003,op:flip2,pos:54,+cov b/src/exchange/afl-tests/id:000868,src:000003,op:flip2,pos:54,+cov
index 035f944eb..035f944eb 100644
--- a/src/mint/afl-tests/id:000868,src:000003,op:flip2,pos:54,+cov
+++ b/src/exchange/afl-tests/id:000868,src:000003,op:flip2,pos:54,+cov
diff --git a/src/mint/afl-tests/id:000868,src:000003,op:flip8,pos:132,+cov b/src/exchange/afl-tests/id:000868,src:000003,op:flip8,pos:132,+cov
index 756516ccf..756516ccf 100644
--- a/src/mint/afl-tests/id:000868,src:000003,op:flip8,pos:132,+cov
+++ b/src/exchange/afl-tests/id:000868,src:000003,op:flip8,pos:132,+cov
diff --git a/src/mint/afl-tests/id:000869,src:000003,op:arith8,pos:17,val:-31 b/src/exchange/afl-tests/id:000869,src:000003,op:arith8,pos:17,val:-31
index db4663753..db4663753 100644
--- a/src/mint/afl-tests/id:000869,src:000003,op:arith8,pos:17,val:-31
+++ b/src/exchange/afl-tests/id:000869,src:000003,op:arith8,pos:17,val:-31
diff --git a/src/mint/afl-tests/id:000869,src:000003,op:flip2,pos:62,+cov b/src/exchange/afl-tests/id:000869,src:000003,op:flip2,pos:62,+cov
index d3afd0c3e..d3afd0c3e 100644
--- a/src/mint/afl-tests/id:000869,src:000003,op:flip2,pos:62,+cov
+++ b/src/exchange/afl-tests/id:000869,src:000003,op:flip2,pos:62,+cov
diff --git a/src/mint/afl-tests/id:000870,src:000003,op:arith8,pos:27,val:+26,+cov b/src/exchange/afl-tests/id:000870,src:000003,op:arith8,pos:27,val:+26,+cov
index 711cace75..711cace75 100644
--- a/src/mint/afl-tests/id:000870,src:000003,op:arith8,pos:27,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000870,src:000003,op:arith8,pos:27,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000870,src:000003,op:flip2,pos:63,+cov b/src/exchange/afl-tests/id:000870,src:000003,op:flip2,pos:63,+cov
index 5de810226..5de810226 100644
--- a/src/mint/afl-tests/id:000870,src:000003,op:flip2,pos:63,+cov
+++ b/src/exchange/afl-tests/id:000870,src:000003,op:flip2,pos:63,+cov
diff --git a/src/mint/afl-tests/id:000871,src:000003,op:arith8,pos:29,val:+11,+cov b/src/exchange/afl-tests/id:000871,src:000003,op:arith8,pos:29,val:+11,+cov
index 14e724e00..14e724e00 100644
--- a/src/mint/afl-tests/id:000871,src:000003,op:arith8,pos:29,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000871,src:000003,op:arith8,pos:29,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000871,src:000003,op:flip2,pos:68,+cov b/src/exchange/afl-tests/id:000871,src:000003,op:flip2,pos:68,+cov
index dd79ab79e..dd79ab79e 100644
--- a/src/mint/afl-tests/id:000871,src:000003,op:flip2,pos:68,+cov
+++ b/src/exchange/afl-tests/id:000871,src:000003,op:flip2,pos:68,+cov
diff --git a/src/mint/afl-tests/id:000872,src:000003,op:arith8,pos:29,val:+33 b/src/exchange/afl-tests/id:000872,src:000003,op:arith8,pos:29,val:+33
index b17ced580..b17ced580 100644
--- a/src/mint/afl-tests/id:000872,src:000003,op:arith8,pos:29,val:+33
+++ b/src/exchange/afl-tests/id:000872,src:000003,op:arith8,pos:29,val:+33
diff --git a/src/mint/afl-tests/id:000873,src:000003,op:arith8,pos:30,val:-14,+cov b/src/exchange/afl-tests/id:000873,src:000003,op:arith8,pos:30,val:-14,+cov
index 84c179051..84c179051 100644
--- a/src/mint/afl-tests/id:000873,src:000003,op:arith8,pos:30,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000873,src:000003,op:arith8,pos:30,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000874,src:000003,op:arith8,pos:30,val:+28,+cov b/src/exchange/afl-tests/id:000874,src:000003,op:arith8,pos:30,val:+28,+cov
index d46b6c12e..d46b6c12e 100644
--- a/src/mint/afl-tests/id:000874,src:000003,op:arith8,pos:30,val:+28,+cov
+++ b/src/exchange/afl-tests/id:000874,src:000003,op:arith8,pos:30,val:+28,+cov
diff --git a/src/mint/afl-tests/id:000875,src:000003,op:arith8,pos:35,val:+18,+cov b/src/exchange/afl-tests/id:000875,src:000003,op:arith8,pos:35,val:+18,+cov
index 533b19061..533b19061 100644
--- a/src/mint/afl-tests/id:000875,src:000003,op:arith8,pos:35,val:+18,+cov
+++ b/src/exchange/afl-tests/id:000875,src:000003,op:arith8,pos:35,val:+18,+cov
diff --git a/src/mint/afl-tests/id:000876,src:000003,op:arith8,pos:35,val:+26,+cov b/src/exchange/afl-tests/id:000876,src:000003,op:arith8,pos:35,val:+26,+cov
index 53519e2c7..53519e2c7 100644
--- a/src/mint/afl-tests/id:000876,src:000003,op:arith8,pos:35,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000876,src:000003,op:arith8,pos:35,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000877,src:000003,op:arith8,pos:36,val:-23,+cov b/src/exchange/afl-tests/id:000877,src:000003,op:arith8,pos:36,val:-23,+cov
index 7f4877bd1..7f4877bd1 100644
--- a/src/mint/afl-tests/id:000877,src:000003,op:arith8,pos:36,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000877,src:000003,op:arith8,pos:36,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000878,src:000003,op:arith8,pos:37,val:+20,+cov b/src/exchange/afl-tests/id:000878,src:000003,op:arith8,pos:37,val:+20,+cov
index 806271714..806271714 100644
--- a/src/mint/afl-tests/id:000878,src:000003,op:arith8,pos:37,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000878,src:000003,op:arith8,pos:37,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000879,src:000003,op:arith8,pos:37,val:-27,+cov b/src/exchange/afl-tests/id:000879,src:000003,op:arith8,pos:37,val:-27,+cov
index 365152f67..365152f67 100644
--- a/src/mint/afl-tests/id:000879,src:000003,op:arith8,pos:37,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000879,src:000003,op:arith8,pos:37,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000880,src:000003,op:arith8,pos:42,val:+31,+cov b/src/exchange/afl-tests/id:000880,src:000003,op:arith8,pos:42,val:+31,+cov
index d0fb09b9a..d0fb09b9a 100644
--- a/src/mint/afl-tests/id:000880,src:000003,op:arith8,pos:42,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000880,src:000003,op:arith8,pos:42,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000881,src:000003,op:arith8,pos:46,val:+26,+cov b/src/exchange/afl-tests/id:000881,src:000003,op:arith8,pos:46,val:+26,+cov
index e5f08ec8d..e5f08ec8d 100644
--- a/src/mint/afl-tests/id:000881,src:000003,op:arith8,pos:46,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000881,src:000003,op:arith8,pos:46,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000882,src:000003,op:arith8,pos:47,val:-35,+cov b/src/exchange/afl-tests/id:000882,src:000003,op:arith8,pos:47,val:-35,+cov
index cc7f2172e..cc7f2172e 100644
--- a/src/mint/afl-tests/id:000882,src:000003,op:arith8,pos:47,val:-35,+cov
+++ b/src/exchange/afl-tests/id:000882,src:000003,op:arith8,pos:47,val:-35,+cov
diff --git a/src/mint/afl-tests/id:000883,src:000003,op:arith8,pos:49,val:-2,+cov b/src/exchange/afl-tests/id:000883,src:000003,op:arith8,pos:49,val:-2,+cov
index 489a86bbb..489a86bbb 100644
--- a/src/mint/afl-tests/id:000883,src:000003,op:arith8,pos:49,val:-2,+cov
+++ b/src/exchange/afl-tests/id:000883,src:000003,op:arith8,pos:49,val:-2,+cov
diff --git a/src/mint/afl-tests/id:000884,src:000003,op:arith8,pos:51,val:+15,+cov b/src/exchange/afl-tests/id:000884,src:000003,op:arith8,pos:51,val:+15,+cov
index 2a4f9a6de..2a4f9a6de 100644
--- a/src/mint/afl-tests/id:000884,src:000003,op:arith8,pos:51,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000884,src:000003,op:arith8,pos:51,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000885,src:000003,op:arith8,pos:52,val:+11,+cov b/src/exchange/afl-tests/id:000885,src:000003,op:arith8,pos:52,val:+11,+cov
index 8b0866a62..8b0866a62 100644
--- a/src/mint/afl-tests/id:000885,src:000003,op:arith8,pos:52,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000885,src:000003,op:arith8,pos:52,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000886,src:000003,op:arith8,pos:61,val:+34 b/src/exchange/afl-tests/id:000886,src:000003,op:arith8,pos:61,val:+34
index b2d267df5..b2d267df5 100644
--- a/src/mint/afl-tests/id:000886,src:000003,op:arith8,pos:61,val:+34
+++ b/src/exchange/afl-tests/id:000886,src:000003,op:arith8,pos:61,val:+34
diff --git a/src/mint/afl-tests/id:000887,src:000003,op:arith8,pos:62,val:-18,+cov b/src/exchange/afl-tests/id:000887,src:000003,op:arith8,pos:62,val:-18,+cov
index 3388fe404..3388fe404 100644
--- a/src/mint/afl-tests/id:000887,src:000003,op:arith8,pos:62,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000887,src:000003,op:arith8,pos:62,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000888,src:000003,op:arith8,pos:68,val:+21,+cov b/src/exchange/afl-tests/id:000888,src:000003,op:arith8,pos:68,val:+21,+cov
index 7b33d73fd..7b33d73fd 100644
--- a/src/mint/afl-tests/id:000888,src:000003,op:arith8,pos:68,val:+21,+cov
+++ b/src/exchange/afl-tests/id:000888,src:000003,op:arith8,pos:68,val:+21,+cov
diff --git a/src/mint/afl-tests/id:000889,src:000003,op:arith8,pos:71,val:-12,+cov b/src/exchange/afl-tests/id:000889,src:000003,op:arith8,pos:71,val:-12,+cov
index e9c662569..e9c662569 100644
--- a/src/mint/afl-tests/id:000889,src:000003,op:arith8,pos:71,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000889,src:000003,op:arith8,pos:71,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000890,src:000003,op:arith8,pos:75,val:+15,+cov b/src/exchange/afl-tests/id:000890,src:000003,op:arith8,pos:75,val:+15,+cov
index 375a480fc..375a480fc 100644
--- a/src/mint/afl-tests/id:000890,src:000003,op:arith8,pos:75,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000890,src:000003,op:arith8,pos:75,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000891,src:000003,op:arith8,pos:77,val:+13,+cov b/src/exchange/afl-tests/id:000891,src:000003,op:arith8,pos:77,val:+13,+cov
index b5ec50f77..b5ec50f77 100644
--- a/src/mint/afl-tests/id:000891,src:000003,op:arith8,pos:77,val:+13,+cov
+++ b/src/exchange/afl-tests/id:000891,src:000003,op:arith8,pos:77,val:+13,+cov
diff --git a/src/mint/afl-tests/id:000892,src:000003,op:arith8,pos:80,val:-17,+cov b/src/exchange/afl-tests/id:000892,src:000003,op:arith8,pos:80,val:-17,+cov
index ba4342848..ba4342848 100644
--- a/src/mint/afl-tests/id:000892,src:000003,op:arith8,pos:80,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000892,src:000003,op:arith8,pos:80,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000893,src:000003,op:arith8,pos:80,val:-23,+cov b/src/exchange/afl-tests/id:000893,src:000003,op:arith8,pos:80,val:-23,+cov
index d3873f902..d3873f902 100644
--- a/src/mint/afl-tests/id:000893,src:000003,op:arith8,pos:80,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000893,src:000003,op:arith8,pos:80,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000894,src:000003,op:arith8,pos:81,val:-9,+cov b/src/exchange/afl-tests/id:000894,src:000003,op:arith8,pos:81,val:-9,+cov
index 983f70606..983f70606 100644
--- a/src/mint/afl-tests/id:000894,src:000003,op:arith8,pos:81,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000894,src:000003,op:arith8,pos:81,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000895,src:000003,op:arith8,pos:83,val:-18,+cov b/src/exchange/afl-tests/id:000895,src:000003,op:arith8,pos:83,val:-18,+cov
index 8f7f08ae9..8f7f08ae9 100644
--- a/src/mint/afl-tests/id:000895,src:000003,op:arith8,pos:83,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000895,src:000003,op:arith8,pos:83,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000896,src:000003,op:arith8,pos:83,val:+25,+cov b/src/exchange/afl-tests/id:000896,src:000003,op:arith8,pos:83,val:+25,+cov
index b1d9e26b5..b1d9e26b5 100644
--- a/src/mint/afl-tests/id:000896,src:000003,op:arith8,pos:83,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000896,src:000003,op:arith8,pos:83,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000897,src:000003,op:arith8,pos:84,val:-18,+cov b/src/exchange/afl-tests/id:000897,src:000003,op:arith8,pos:84,val:-18,+cov
index a29110bb6..a29110bb6 100644
--- a/src/mint/afl-tests/id:000897,src:000003,op:arith8,pos:84,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000897,src:000003,op:arith8,pos:84,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000898,src:000003,op:arith8,pos:86,val:+11,+cov b/src/exchange/afl-tests/id:000898,src:000003,op:arith8,pos:86,val:+11,+cov
index 6dcd140db..6dcd140db 100644
--- a/src/mint/afl-tests/id:000898,src:000003,op:arith8,pos:86,val:+11,+cov
+++ b/src/exchange/afl-tests/id:000898,src:000003,op:arith8,pos:86,val:+11,+cov
diff --git a/src/mint/afl-tests/id:000899,src:000003,op:arith8,pos:86,val:+27,+cov b/src/exchange/afl-tests/id:000899,src:000003,op:arith8,pos:86,val:+27,+cov
index 8089c95f5..8089c95f5 100644
--- a/src/mint/afl-tests/id:000899,src:000003,op:arith8,pos:86,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000899,src:000003,op:arith8,pos:86,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000900,src:000003,op:arith8,pos:87,val:-23,+cov b/src/exchange/afl-tests/id:000900,src:000003,op:arith8,pos:87,val:-23,+cov
index 291828478..291828478 100644
--- a/src/mint/afl-tests/id:000900,src:000003,op:arith8,pos:87,val:-23,+cov
+++ b/src/exchange/afl-tests/id:000900,src:000003,op:arith8,pos:87,val:-23,+cov
diff --git a/src/mint/afl-tests/id:000901,src:000003,op:arith8,pos:88,val:+35,+cov b/src/exchange/afl-tests/id:000901,src:000003,op:arith8,pos:88,val:+35,+cov
index 40338ae4d..40338ae4d 100644
--- a/src/mint/afl-tests/id:000901,src:000003,op:arith8,pos:88,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000901,src:000003,op:arith8,pos:88,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000902,src:000003,op:arith8,pos:89,val:-14,+cov b/src/exchange/afl-tests/id:000902,src:000003,op:arith8,pos:89,val:-14,+cov
index 78a5ccbed..78a5ccbed 100644
--- a/src/mint/afl-tests/id:000902,src:000003,op:arith8,pos:89,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000902,src:000003,op:arith8,pos:89,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000903,src:000003,op:arith8,pos:89,val:-33,+cov b/src/exchange/afl-tests/id:000903,src:000003,op:arith8,pos:89,val:-33,+cov
index af5afac60..af5afac60 100644
--- a/src/mint/afl-tests/id:000903,src:000003,op:arith8,pos:89,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000903,src:000003,op:arith8,pos:89,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000904,src:000003,op:arith8,pos:90,val:-25,+cov b/src/exchange/afl-tests/id:000904,src:000003,op:arith8,pos:90,val:-25,+cov
index 12b346043..12b346043 100644
--- a/src/mint/afl-tests/id:000904,src:000003,op:arith8,pos:90,val:-25,+cov
+++ b/src/exchange/afl-tests/id:000904,src:000003,op:arith8,pos:90,val:-25,+cov
diff --git a/src/mint/afl-tests/id:000905,src:000003,op:arith8,pos:92,val:-25,+cov b/src/exchange/afl-tests/id:000905,src:000003,op:arith8,pos:92,val:-25,+cov
index 6e4c64fbd..6e4c64fbd 100644
--- a/src/mint/afl-tests/id:000905,src:000003,op:arith8,pos:92,val:-25,+cov
+++ b/src/exchange/afl-tests/id:000905,src:000003,op:arith8,pos:92,val:-25,+cov
diff --git a/src/mint/afl-tests/id:000906,src:000003,op:arith8,pos:96,val:+10,+cov b/src/exchange/afl-tests/id:000906,src:000003,op:arith8,pos:96,val:+10,+cov
index 0b773a1ca..0b773a1ca 100644
--- a/src/mint/afl-tests/id:000906,src:000003,op:arith8,pos:96,val:+10,+cov
+++ b/src/exchange/afl-tests/id:000906,src:000003,op:arith8,pos:96,val:+10,+cov
diff --git a/src/mint/afl-tests/id:000907,src:000003,op:arith8,pos:96,val:-19,+cov b/src/exchange/afl-tests/id:000907,src:000003,op:arith8,pos:96,val:-19,+cov
index aab442117..aab442117 100644
--- a/src/mint/afl-tests/id:000907,src:000003,op:arith8,pos:96,val:-19,+cov
+++ b/src/exchange/afl-tests/id:000907,src:000003,op:arith8,pos:96,val:-19,+cov
diff --git a/src/mint/afl-tests/id:000908,src:000003,op:arith8,pos:96,val:+25,+cov b/src/exchange/afl-tests/id:000908,src:000003,op:arith8,pos:96,val:+25,+cov
index c32634bb2..c32634bb2 100644
--- a/src/mint/afl-tests/id:000908,src:000003,op:arith8,pos:96,val:+25,+cov
+++ b/src/exchange/afl-tests/id:000908,src:000003,op:arith8,pos:96,val:+25,+cov
diff --git a/src/mint/afl-tests/id:000909,src:000003,op:arith8,pos:97,val:-17,+cov b/src/exchange/afl-tests/id:000909,src:000003,op:arith8,pos:97,val:-17,+cov
index bc394e407..bc394e407 100644
--- a/src/mint/afl-tests/id:000909,src:000003,op:arith8,pos:97,val:-17,+cov
+++ b/src/exchange/afl-tests/id:000909,src:000003,op:arith8,pos:97,val:-17,+cov
diff --git a/src/mint/afl-tests/id:000910,src:000003,op:arith8,pos:100,val:-15,+cov b/src/exchange/afl-tests/id:000910,src:000003,op:arith8,pos:100,val:-15,+cov
index 28d2cb420..28d2cb420 100644
--- a/src/mint/afl-tests/id:000910,src:000003,op:arith8,pos:100,val:-15,+cov
+++ b/src/exchange/afl-tests/id:000910,src:000003,op:arith8,pos:100,val:-15,+cov
diff --git a/src/mint/afl-tests/id:000911,src:000003,op:arith8,pos:102,val:-27,+cov b/src/exchange/afl-tests/id:000911,src:000003,op:arith8,pos:102,val:-27,+cov
index c32efa665..c32efa665 100644
--- a/src/mint/afl-tests/id:000911,src:000003,op:arith8,pos:102,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000911,src:000003,op:arith8,pos:102,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000912,src:000003,op:arith8,pos:102,val:-34,+cov b/src/exchange/afl-tests/id:000912,src:000003,op:arith8,pos:102,val:-34,+cov
index 2dc72c228..2dc72c228 100644
--- a/src/mint/afl-tests/id:000912,src:000003,op:arith8,pos:102,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000912,src:000003,op:arith8,pos:102,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000913,src:000003,op:arith8,pos:103,val:-9,+cov b/src/exchange/afl-tests/id:000913,src:000003,op:arith8,pos:103,val:-9,+cov
index 9afe3a253..9afe3a253 100644
--- a/src/mint/afl-tests/id:000913,src:000003,op:arith8,pos:103,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000913,src:000003,op:arith8,pos:103,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000914,src:000003,op:arith8,pos:103,val:+12 b/src/exchange/afl-tests/id:000914,src:000003,op:arith8,pos:103,val:+12
index 72a270322..72a270322 100644
--- a/src/mint/afl-tests/id:000914,src:000003,op:arith8,pos:103,val:+12
+++ b/src/exchange/afl-tests/id:000914,src:000003,op:arith8,pos:103,val:+12
diff --git a/src/mint/afl-tests/id:000915,src:000003,op:arith8,pos:103,val:+20,+cov b/src/exchange/afl-tests/id:000915,src:000003,op:arith8,pos:103,val:+20,+cov
index 6377fb486..6377fb486 100644
--- a/src/mint/afl-tests/id:000915,src:000003,op:arith8,pos:103,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000915,src:000003,op:arith8,pos:103,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000916,src:000003,op:arith8,pos:103,val:+22,+cov b/src/exchange/afl-tests/id:000916,src:000003,op:arith8,pos:103,val:+22,+cov
index 1991d1942..1991d1942 100644
--- a/src/mint/afl-tests/id:000916,src:000003,op:arith8,pos:103,val:+22,+cov
+++ b/src/exchange/afl-tests/id:000916,src:000003,op:arith8,pos:103,val:+22,+cov
diff --git a/src/mint/afl-tests/id:000917,src:000003,op:arith8,pos:103,val:+29,+cov b/src/exchange/afl-tests/id:000917,src:000003,op:arith8,pos:103,val:+29,+cov
index 12842c912..12842c912 100644
--- a/src/mint/afl-tests/id:000917,src:000003,op:arith8,pos:103,val:+29,+cov
+++ b/src/exchange/afl-tests/id:000917,src:000003,op:arith8,pos:103,val:+29,+cov
diff --git a/src/mint/afl-tests/id:000918,src:000003,op:arith8,pos:103,val:+33,+cov b/src/exchange/afl-tests/id:000918,src:000003,op:arith8,pos:103,val:+33,+cov
index 8c2a9ac21..8c2a9ac21 100644
--- a/src/mint/afl-tests/id:000918,src:000003,op:arith8,pos:103,val:+33,+cov
+++ b/src/exchange/afl-tests/id:000918,src:000003,op:arith8,pos:103,val:+33,+cov
diff --git a/src/mint/afl-tests/id:000919,src:000003,op:arith8,pos:104,val:-10,+cov b/src/exchange/afl-tests/id:000919,src:000003,op:arith8,pos:104,val:-10,+cov
index 252570d4c..252570d4c 100644
--- a/src/mint/afl-tests/id:000919,src:000003,op:arith8,pos:104,val:-10,+cov
+++ b/src/exchange/afl-tests/id:000919,src:000003,op:arith8,pos:104,val:-10,+cov
diff --git a/src/mint/afl-tests/id:000920,src:000003,op:arith8,pos:104,val:-12,+cov b/src/exchange/afl-tests/id:000920,src:000003,op:arith8,pos:104,val:-12,+cov
index 49d6946a6..49d6946a6 100644
--- a/src/mint/afl-tests/id:000920,src:000003,op:arith8,pos:104,val:-12,+cov
+++ b/src/exchange/afl-tests/id:000920,src:000003,op:arith8,pos:104,val:-12,+cov
diff --git a/src/mint/afl-tests/id:000921,src:000003,op:arith8,pos:104,val:+34,+cov b/src/exchange/afl-tests/id:000921,src:000003,op:arith8,pos:104,val:+34,+cov
index 193b82567..193b82567 100644
--- a/src/mint/afl-tests/id:000921,src:000003,op:arith8,pos:104,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000921,src:000003,op:arith8,pos:104,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000922,src:000003,op:arith8,pos:106,val:+5,+cov b/src/exchange/afl-tests/id:000922,src:000003,op:arith8,pos:106,val:+5,+cov
index 3a0ed74ac..3a0ed74ac 100644
--- a/src/mint/afl-tests/id:000922,src:000003,op:arith8,pos:106,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000922,src:000003,op:arith8,pos:106,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000923,src:000003,op:arith8,pos:106,val:-13,+cov b/src/exchange/afl-tests/id:000923,src:000003,op:arith8,pos:106,val:-13,+cov
index c4e20580e..c4e20580e 100644
--- a/src/mint/afl-tests/id:000923,src:000003,op:arith8,pos:106,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000923,src:000003,op:arith8,pos:106,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000924,src:000003,op:arith8,pos:110,val:+15,+cov b/src/exchange/afl-tests/id:000924,src:000003,op:arith8,pos:110,val:+15,+cov
index 61eb8b650..61eb8b650 100644
--- a/src/mint/afl-tests/id:000924,src:000003,op:arith8,pos:110,val:+15,+cov
+++ b/src/exchange/afl-tests/id:000924,src:000003,op:arith8,pos:110,val:+15,+cov
diff --git a/src/mint/afl-tests/id:000925,src:000003,op:arith8,pos:112,val:-13,+cov b/src/exchange/afl-tests/id:000925,src:000003,op:arith8,pos:112,val:-13,+cov
index 9333ce8e0..9333ce8e0 100644
--- a/src/mint/afl-tests/id:000925,src:000003,op:arith8,pos:112,val:-13,+cov
+++ b/src/exchange/afl-tests/id:000925,src:000003,op:arith8,pos:112,val:-13,+cov
diff --git a/src/mint/afl-tests/id:000926,src:000003,op:arith8,pos:113,val:+34,+cov b/src/exchange/afl-tests/id:000926,src:000003,op:arith8,pos:113,val:+34,+cov
index 6221fe08f..6221fe08f 100644
--- a/src/mint/afl-tests/id:000926,src:000003,op:arith8,pos:113,val:+34,+cov
+++ b/src/exchange/afl-tests/id:000926,src:000003,op:arith8,pos:113,val:+34,+cov
diff --git a/src/mint/afl-tests/id:000927,src:000003,op:arith8,pos:114,val:+5,+cov b/src/exchange/afl-tests/id:000927,src:000003,op:arith8,pos:114,val:+5,+cov
index 80c1d1621..80c1d1621 100644
--- a/src/mint/afl-tests/id:000927,src:000003,op:arith8,pos:114,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000927,src:000003,op:arith8,pos:114,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000928,src:000003,op:arith8,pos:114,val:+26,+cov b/src/exchange/afl-tests/id:000928,src:000003,op:arith8,pos:114,val:+26,+cov
index b40bbdd99..b40bbdd99 100644
--- a/src/mint/afl-tests/id:000928,src:000003,op:arith8,pos:114,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000928,src:000003,op:arith8,pos:114,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000929,src:000003,op:arith8,pos:114,val:-27,+cov b/src/exchange/afl-tests/id:000929,src:000003,op:arith8,pos:114,val:-27,+cov
index c4e1e34b3..c4e1e34b3 100644
--- a/src/mint/afl-tests/id:000929,src:000003,op:arith8,pos:114,val:-27,+cov
+++ b/src/exchange/afl-tests/id:000929,src:000003,op:arith8,pos:114,val:-27,+cov
diff --git a/src/mint/afl-tests/id:000930,src:000003,op:arith8,pos:118,val:-28,+cov b/src/exchange/afl-tests/id:000930,src:000003,op:arith8,pos:118,val:-28,+cov
index e6c25bc9b..e6c25bc9b 100644
--- a/src/mint/afl-tests/id:000930,src:000003,op:arith8,pos:118,val:-28,+cov
+++ b/src/exchange/afl-tests/id:000930,src:000003,op:arith8,pos:118,val:-28,+cov
diff --git a/src/mint/afl-tests/id:000931,src:000003,op:arith8,pos:119,val:+12,+cov b/src/exchange/afl-tests/id:000931,src:000003,op:arith8,pos:119,val:+12,+cov
index 1f154fd0d..1f154fd0d 100644
--- a/src/mint/afl-tests/id:000931,src:000003,op:arith8,pos:119,val:+12,+cov
+++ b/src/exchange/afl-tests/id:000931,src:000003,op:arith8,pos:119,val:+12,+cov
diff --git a/src/mint/afl-tests/id:000932,src:000003,op:arith8,pos:119,val:+27,+cov b/src/exchange/afl-tests/id:000932,src:000003,op:arith8,pos:119,val:+27,+cov
index c08f57d0b..c08f57d0b 100644
--- a/src/mint/afl-tests/id:000932,src:000003,op:arith8,pos:119,val:+27,+cov
+++ b/src/exchange/afl-tests/id:000932,src:000003,op:arith8,pos:119,val:+27,+cov
diff --git a/src/mint/afl-tests/id:000933,src:000003,op:arith8,pos:122,val:-4,+cov b/src/exchange/afl-tests/id:000933,src:000003,op:arith8,pos:122,val:-4,+cov
index fd1fe2a23..fd1fe2a23 100644
--- a/src/mint/afl-tests/id:000933,src:000003,op:arith8,pos:122,val:-4,+cov
+++ b/src/exchange/afl-tests/id:000933,src:000003,op:arith8,pos:122,val:-4,+cov
diff --git a/src/mint/afl-tests/id:000934,src:000003,op:arith8,pos:122,val:-26,+cov b/src/exchange/afl-tests/id:000934,src:000003,op:arith8,pos:122,val:-26,+cov
index a52e79133..a52e79133 100644
--- a/src/mint/afl-tests/id:000934,src:000003,op:arith8,pos:122,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000934,src:000003,op:arith8,pos:122,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000935,src:000003,op:arith8,pos:122,val:+35,+cov b/src/exchange/afl-tests/id:000935,src:000003,op:arith8,pos:122,val:+35,+cov
index cb64996e0..cb64996e0 100644
--- a/src/mint/afl-tests/id:000935,src:000003,op:arith8,pos:122,val:+35,+cov
+++ b/src/exchange/afl-tests/id:000935,src:000003,op:arith8,pos:122,val:+35,+cov
diff --git a/src/mint/afl-tests/id:000936,src:000003,op:arith8,pos:123,val:-11,+cov b/src/exchange/afl-tests/id:000936,src:000003,op:arith8,pos:123,val:-11,+cov
index 979faa6ce..979faa6ce 100644
--- a/src/mint/afl-tests/id:000936,src:000003,op:arith8,pos:123,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000936,src:000003,op:arith8,pos:123,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000937,src:000003,op:arith8,pos:124,val:-14,+cov b/src/exchange/afl-tests/id:000937,src:000003,op:arith8,pos:124,val:-14,+cov
index 5aff0b9e5..5aff0b9e5 100644
--- a/src/mint/afl-tests/id:000937,src:000003,op:arith8,pos:124,val:-14,+cov
+++ b/src/exchange/afl-tests/id:000937,src:000003,op:arith8,pos:124,val:-14,+cov
diff --git a/src/mint/afl-tests/id:000938,src:000003,op:arith8,pos:128,val:+5,+cov b/src/exchange/afl-tests/id:000938,src:000003,op:arith8,pos:128,val:+5,+cov
index c1cbf35e3..c1cbf35e3 100644
--- a/src/mint/afl-tests/id:000938,src:000003,op:arith8,pos:128,val:+5,+cov
+++ b/src/exchange/afl-tests/id:000938,src:000003,op:arith8,pos:128,val:+5,+cov
diff --git a/src/mint/afl-tests/id:000939,src:000003,op:arith8,pos:129,val:+21,+cov b/src/exchange/afl-tests/id:000939,src:000003,op:arith8,pos:129,val:+21,+cov
index 30446f009..30446f009 100644
--- a/src/mint/afl-tests/id:000939,src:000003,op:arith8,pos:129,val:+21,+cov
+++ b/src/exchange/afl-tests/id:000939,src:000003,op:arith8,pos:129,val:+21,+cov
diff --git a/src/mint/afl-tests/id:000940,src:000003,op:arith8,pos:133,val:-7,+cov b/src/exchange/afl-tests/id:000940,src:000003,op:arith8,pos:133,val:-7,+cov
index b91dd1aa3..b91dd1aa3 100644
--- a/src/mint/afl-tests/id:000940,src:000003,op:arith8,pos:133,val:-7,+cov
+++ b/src/exchange/afl-tests/id:000940,src:000003,op:arith8,pos:133,val:-7,+cov
diff --git a/src/mint/afl-tests/id:000941,src:000003,op:arith8,pos:133,val:+20,+cov b/src/exchange/afl-tests/id:000941,src:000003,op:arith8,pos:133,val:+20,+cov
index 4f05b4bfb..4f05b4bfb 100644
--- a/src/mint/afl-tests/id:000941,src:000003,op:arith8,pos:133,val:+20,+cov
+++ b/src/exchange/afl-tests/id:000941,src:000003,op:arith8,pos:133,val:+20,+cov
diff --git a/src/mint/afl-tests/id:000942,src:000003,op:arith8,pos:135,val:-26,+cov b/src/exchange/afl-tests/id:000942,src:000003,op:arith8,pos:135,val:-26,+cov
index 435feabbf..435feabbf 100644
--- a/src/mint/afl-tests/id:000942,src:000003,op:arith8,pos:135,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000942,src:000003,op:arith8,pos:135,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000943,src:000003,op:arith8,pos:141,val:+1,+cov b/src/exchange/afl-tests/id:000943,src:000003,op:arith8,pos:141,val:+1,+cov
index acf781914..acf781914 100644
--- a/src/mint/afl-tests/id:000943,src:000003,op:arith8,pos:141,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000943,src:000003,op:arith8,pos:141,val:+1,+cov
diff --git a/src/mint/afl-tests/id:000944,src:000003,op:arith8,pos:143,val:-5,+cov b/src/exchange/afl-tests/id:000944,src:000003,op:arith8,pos:143,val:-5,+cov
index f90df0388..f90df0388 100644
--- a/src/mint/afl-tests/id:000944,src:000003,op:arith8,pos:143,val:-5,+cov
+++ b/src/exchange/afl-tests/id:000944,src:000003,op:arith8,pos:143,val:-5,+cov
diff --git a/src/mint/afl-tests/id:000945,src:000003,op:arith8,pos:145,val:+21,+cov b/src/exchange/afl-tests/id:000945,src:000003,op:arith8,pos:145,val:+21,+cov
index b109313e0..b109313e0 100644
--- a/src/mint/afl-tests/id:000945,src:000003,op:arith8,pos:145,val:+21,+cov
+++ b/src/exchange/afl-tests/id:000945,src:000003,op:arith8,pos:145,val:+21,+cov
diff --git a/src/mint/afl-tests/id:000946,src:000003,op:arith8,pos:147,val:-9,+cov b/src/exchange/afl-tests/id:000946,src:000003,op:arith8,pos:147,val:-9,+cov
index 65dee0ea2..65dee0ea2 100644
--- a/src/mint/afl-tests/id:000946,src:000003,op:arith8,pos:147,val:-9,+cov
+++ b/src/exchange/afl-tests/id:000946,src:000003,op:arith8,pos:147,val:-9,+cov
diff --git a/src/mint/afl-tests/id:000947,src:000003,op:arith8,pos:147,val:+31,+cov b/src/exchange/afl-tests/id:000947,src:000003,op:arith8,pos:147,val:+31,+cov
index 1043610ff..1043610ff 100644
--- a/src/mint/afl-tests/id:000947,src:000003,op:arith8,pos:147,val:+31,+cov
+++ b/src/exchange/afl-tests/id:000947,src:000003,op:arith8,pos:147,val:+31,+cov
diff --git a/src/mint/afl-tests/id:000948,src:000003,op:arith8,pos:148,val:+3,+cov b/src/exchange/afl-tests/id:000948,src:000003,op:arith8,pos:148,val:+3,+cov
index dabe160c0..dabe160c0 100644
--- a/src/mint/afl-tests/id:000948,src:000003,op:arith8,pos:148,val:+3,+cov
+++ b/src/exchange/afl-tests/id:000948,src:000003,op:arith8,pos:148,val:+3,+cov
diff --git a/src/mint/afl-tests/id:000949,src:000003,op:arith8,pos:148,val:-11,+cov b/src/exchange/afl-tests/id:000949,src:000003,op:arith8,pos:148,val:-11,+cov
index d36334b62..d36334b62 100644
--- a/src/mint/afl-tests/id:000949,src:000003,op:arith8,pos:148,val:-11,+cov
+++ b/src/exchange/afl-tests/id:000949,src:000003,op:arith8,pos:148,val:-11,+cov
diff --git a/src/mint/afl-tests/id:000950,src:000003,op:arith8,pos:149,val:-18,+cov b/src/exchange/afl-tests/id:000950,src:000003,op:arith8,pos:149,val:-18,+cov
index e40bc63bd..e40bc63bd 100644
--- a/src/mint/afl-tests/id:000950,src:000003,op:arith8,pos:149,val:-18,+cov
+++ b/src/exchange/afl-tests/id:000950,src:000003,op:arith8,pos:149,val:-18,+cov
diff --git a/src/mint/afl-tests/id:000951,src:000003,op:arith8,pos:151,val:-21,+cov b/src/exchange/afl-tests/id:000951,src:000003,op:arith8,pos:151,val:-21,+cov
index 537af8de5..537af8de5 100644
--- a/src/mint/afl-tests/id:000951,src:000003,op:arith8,pos:151,val:-21,+cov
+++ b/src/exchange/afl-tests/id:000951,src:000003,op:arith8,pos:151,val:-21,+cov
diff --git a/src/mint/afl-tests/id:000952,src:000003,op:arith8,pos:151,val:+26,+cov b/src/exchange/afl-tests/id:000952,src:000003,op:arith8,pos:151,val:+26,+cov
index 9eac5215a..9eac5215a 100644
--- a/src/mint/afl-tests/id:000952,src:000003,op:arith8,pos:151,val:+26,+cov
+++ b/src/exchange/afl-tests/id:000952,src:000003,op:arith8,pos:151,val:+26,+cov
diff --git a/src/mint/afl-tests/id:000953,src:000003,op:arith8,pos:151,val:-30,+cov b/src/exchange/afl-tests/id:000953,src:000003,op:arith8,pos:151,val:-30,+cov
index d9c3ab03d..d9c3ab03d 100644
--- a/src/mint/afl-tests/id:000953,src:000003,op:arith8,pos:151,val:-30,+cov
+++ b/src/exchange/afl-tests/id:000953,src:000003,op:arith8,pos:151,val:-30,+cov
diff --git a/src/mint/afl-tests/id:000954,src:000003,op:arith16,pos:88,val:-16,+cov b/src/exchange/afl-tests/id:000954,src:000003,op:arith16,pos:88,val:-16,+cov
index 588d9d272..588d9d272 100644
--- a/src/mint/afl-tests/id:000954,src:000003,op:arith16,pos:88,val:-16,+cov
+++ b/src/exchange/afl-tests/id:000954,src:000003,op:arith16,pos:88,val:-16,+cov
diff --git a/src/mint/afl-tests/id:000955,src:000003,op:arith16,pos:109,val:-19,+cov b/src/exchange/afl-tests/id:000955,src:000003,op:arith16,pos:109,val:-19,+cov
index c669844df..c669844df 100644
--- a/src/mint/afl-tests/id:000955,src:000003,op:arith16,pos:109,val:-19,+cov
+++ b/src/exchange/afl-tests/id:000955,src:000003,op:arith16,pos:109,val:-19,+cov
diff --git a/src/mint/afl-tests/id:000956,src:000003,op:arith16,pos:109,val:-26,+cov b/src/exchange/afl-tests/id:000956,src:000003,op:arith16,pos:109,val:-26,+cov
index 46cb980b3..46cb980b3 100644
--- a/src/mint/afl-tests/id:000956,src:000003,op:arith16,pos:109,val:-26,+cov
+++ b/src/exchange/afl-tests/id:000956,src:000003,op:arith16,pos:109,val:-26,+cov
diff --git a/src/mint/afl-tests/id:000957,src:000003,op:arith16,pos:109,val:-33,+cov b/src/exchange/afl-tests/id:000957,src:000003,op:arith16,pos:109,val:-33,+cov
index 365ef3f8e..365ef3f8e 100644
--- a/src/mint/afl-tests/id:000957,src:000003,op:arith16,pos:109,val:-33,+cov
+++ b/src/exchange/afl-tests/id:000957,src:000003,op:arith16,pos:109,val:-33,+cov
diff --git a/src/mint/afl-tests/id:000958,src:000003,op:arith16,pos:121,val:-34,+cov b/src/exchange/afl-tests/id:000958,src:000003,op:arith16,pos:121,val:-34,+cov
index 883400b0c..883400b0c 100644
--- a/src/mint/afl-tests/id:000958,src:000003,op:arith16,pos:121,val:-34,+cov
+++ b/src/exchange/afl-tests/id:000958,src:000003,op:arith16,pos:121,val:-34,+cov
diff --git a/src/mint/afl-tests/id:000959,src:000003,op:int8,pos:80,val:+16,+cov b/src/exchange/afl-tests/id:000959,src:000003,op:int8,pos:80,val:+16,+cov
index 245a87782..245a87782 100644
--- a/src/mint/afl-tests/id:000959,src:000003,op:int8,pos:80,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000959,src:000003,op:int8,pos:80,val:+16,+cov
diff --git a/src/mint/afl-tests/id:000960,src:000003,op:int8,pos:83,val:+1,+cov b/src/exchange/afl-tests/id:000960,src:000003,op:int8,pos:83,val:+1,+cov
index 76311eddc..76311eddc 100644
--- a/src/mint/afl-tests/id:000960,src:000003,op:int8,pos:83,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000960,src:000003,op:int8,pos:83,val:+1,+cov
diff --git a/src/mint/afl-tests/id:000961,src:000003,op:int8,pos:101,val:+64,+cov b/src/exchange/afl-tests/id:000961,src:000003,op:int8,pos:101,val:+64,+cov
index 11503890f..11503890f 100644
--- a/src/mint/afl-tests/id:000961,src:000003,op:int8,pos:101,val:+64,+cov
+++ b/src/exchange/afl-tests/id:000961,src:000003,op:int8,pos:101,val:+64,+cov
diff --git a/src/mint/afl-tests/id:000962,src:000003,op:int8,pos:120,val:-128,+cov b/src/exchange/afl-tests/id:000962,src:000003,op:int8,pos:120,val:-128,+cov
index deb20dfc4..deb20dfc4 100644
--- a/src/mint/afl-tests/id:000962,src:000003,op:int8,pos:120,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000962,src:000003,op:int8,pos:120,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000963,src:000003,op:int8,pos:139,val:+16,+cov b/src/exchange/afl-tests/id:000963,src:000003,op:int8,pos:139,val:+16,+cov
index 295b45834..295b45834 100644
--- a/src/mint/afl-tests/id:000963,src:000003,op:int8,pos:139,val:+16,+cov
+++ b/src/exchange/afl-tests/id:000963,src:000003,op:int8,pos:139,val:+16,+cov
diff --git a/src/mint/afl-tests/id:000964,src:000003,op:int16,pos:81,val:+127,+cov b/src/exchange/afl-tests/id:000964,src:000003,op:int16,pos:81,val:+127,+cov
index f88675cf7..f88675cf7 100644
--- a/src/mint/afl-tests/id:000964,src:000003,op:int16,pos:81,val:+127,+cov
+++ b/src/exchange/afl-tests/id:000964,src:000003,op:int16,pos:81,val:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000965,src:000003,op:int16,pos:95,val:+1,+cov b/src/exchange/afl-tests/id:000965,src:000003,op:int16,pos:95,val:+1,+cov
index cf3c98fd9..cf3c98fd9 100644
--- a/src/mint/afl-tests/id:000965,src:000003,op:int16,pos:95,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000965,src:000003,op:int16,pos:95,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000966,src:000003,op:int16,pos:97,val:be:+127,+cov b/src/exchange/afl-tests/id:000966,src:000003,op:int16,pos:97,val:be:+127,+cov
index ebeff8ca4..ebeff8ca4 100644
--- a/src/mint/afl-tests/id:000966,src:000003,op:int16,pos:97,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000966,src:000003,op:int16,pos:97,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000967,src:000003,op:int16,pos:98,val:+1,+cov b/src/exchange/afl-tests/id:000967,src:000003,op:int16,pos:98,val:+1,+cov
index 0e5190281..0e5190281 100644
--- a/src/mint/afl-tests/id:000967,src:000003,op:int16,pos:98,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000967,src:000003,op:int16,pos:98,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000968,src:000003,op:int16,pos:100,val:-1,+cov b/src/exchange/afl-tests/id:000968,src:000003,op:int16,pos:100,val:-1,+cov
index 44cd6d9ac..44cd6d9ac 100644
--- a/src/mint/afl-tests/id:000968,src:000003,op:int16,pos:100,val:-1,+cov
+++ b/src/exchange/afl-tests/id:000968,src:000003,op:int16,pos:100,val:-1,+cov
diff --git a/src/mint/afl-tests/id:000969,src:000003,op:int16,pos:102,val:be:+127,+cov b/src/exchange/afl-tests/id:000969,src:000003,op:int16,pos:102,val:be:+127,+cov
index bc0b934e9..bc0b934e9 100644
--- a/src/mint/afl-tests/id:000969,src:000003,op:int16,pos:102,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000969,src:000003,op:int16,pos:102,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000970,src:000003,op:int16,pos:107,val:-128,+cov b/src/exchange/afl-tests/id:000970,src:000003,op:int16,pos:107,val:-128,+cov
index acf89f2d3..acf89f2d3 100644
--- a/src/mint/afl-tests/id:000970,src:000003,op:int16,pos:107,val:-128,+cov
+++ b/src/exchange/afl-tests/id:000970,src:000003,op:int16,pos:107,val:-128,+cov
diff --git a/src/mint/afl-tests/id:000971,src:000003,op:int16,pos:108,val:be:+127,+cov b/src/exchange/afl-tests/id:000971,src:000003,op:int16,pos:108,val:be:+127,+cov
index c7d9a2692..c7d9a2692 100644
--- a/src/mint/afl-tests/id:000971,src:000003,op:int16,pos:108,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000971,src:000003,op:int16,pos:108,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000972,src:000003,op:int16,pos:109,val:be:+100,+cov b/src/exchange/afl-tests/id:000972,src:000003,op:int16,pos:109,val:be:+100,+cov
index 6fddc5c97..6fddc5c97 100644
--- a/src/mint/afl-tests/id:000972,src:000003,op:int16,pos:109,val:be:+100,+cov
+++ b/src/exchange/afl-tests/id:000972,src:000003,op:int16,pos:109,val:be:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000973,src:000003,op:int16,pos:125,val:+1000,+cov b/src/exchange/afl-tests/id:000973,src:000003,op:int16,pos:125,val:+1000,+cov
index 28ac24ca1..28ac24ca1 100644
--- a/src/mint/afl-tests/id:000973,src:000003,op:int16,pos:125,val:+1000,+cov
+++ b/src/exchange/afl-tests/id:000973,src:000003,op:int16,pos:125,val:+1000,+cov
diff --git a/src/mint/afl-tests/id:000974,src:000003,op:int16,pos:137,val:be:+32,+cov b/src/exchange/afl-tests/id:000974,src:000003,op:int16,pos:137,val:be:+32,+cov
index 577590a16..577590a16 100644
--- a/src/mint/afl-tests/id:000974,src:000003,op:int16,pos:137,val:be:+32,+cov
+++ b/src/exchange/afl-tests/id:000974,src:000003,op:int16,pos:137,val:be:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000975,src:000003,op:int16,pos:150,val:be:+255,+cov b/src/exchange/afl-tests/id:000975,src:000003,op:int16,pos:150,val:be:+255,+cov
index ec5a1cd90..ec5a1cd90 100644
--- a/src/mint/afl-tests/id:000975,src:000003,op:int16,pos:150,val:be:+255,+cov
+++ b/src/exchange/afl-tests/id:000975,src:000003,op:int16,pos:150,val:be:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000976,src:000003,op:int32,pos:1,val:be:+65535 b/src/exchange/afl-tests/id:000976,src:000003,op:int32,pos:1,val:be:+65535
index 510fc61db..510fc61db 100644
--- a/src/mint/afl-tests/id:000976,src:000003,op:int32,pos:1,val:be:+65535
+++ b/src/exchange/afl-tests/id:000976,src:000003,op:int32,pos:1,val:be:+65535
Binary files differ
diff --git a/src/mint/afl-tests/id:000977,src:000003,op:int32,pos:54,val:+32768,+cov b/src/exchange/afl-tests/id:000977,src:000003,op:int32,pos:54,val:+32768,+cov
index b7636df4d..b7636df4d 100644
--- a/src/mint/afl-tests/id:000977,src:000003,op:int32,pos:54,val:+32768,+cov
+++ b/src/exchange/afl-tests/id:000977,src:000003,op:int32,pos:54,val:+32768,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000978,src:000003,op:int32,pos:80,val:be:+32767,+cov b/src/exchange/afl-tests/id:000978,src:000003,op:int32,pos:80,val:be:+32767,+cov
index 59b35346e..59b35346e 100644
--- a/src/mint/afl-tests/id:000978,src:000003,op:int32,pos:80,val:be:+32767,+cov
+++ b/src/exchange/afl-tests/id:000978,src:000003,op:int32,pos:80,val:be:+32767,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000979,src:000003,op:int32,pos:84,val:+2147483647 b/src/exchange/afl-tests/id:000979,src:000003,op:int32,pos:84,val:+2147483647
index 818508f9e..818508f9e 100644
--- a/src/mint/afl-tests/id:000979,src:000003,op:int32,pos:84,val:+2147483647
+++ b/src/exchange/afl-tests/id:000979,src:000003,op:int32,pos:84,val:+2147483647
diff --git a/src/mint/afl-tests/id:000980,src:000003,op:int32,pos:89,val:be:+4096,+cov b/src/exchange/afl-tests/id:000980,src:000003,op:int32,pos:89,val:be:+4096,+cov
index 661fbfb23..661fbfb23 100644
--- a/src/mint/afl-tests/id:000980,src:000003,op:int32,pos:89,val:be:+4096,+cov
+++ b/src/exchange/afl-tests/id:000980,src:000003,op:int32,pos:89,val:be:+4096,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000981,src:000003,op:int32,pos:98,val:-129,+cov b/src/exchange/afl-tests/id:000981,src:000003,op:int32,pos:98,val:-129,+cov
index 38a988472..38a988472 100644
--- a/src/mint/afl-tests/id:000981,src:000003,op:int32,pos:98,val:-129,+cov
+++ b/src/exchange/afl-tests/id:000981,src:000003,op:int32,pos:98,val:-129,+cov
diff --git a/src/mint/afl-tests/id:000982,src:000003,op:int32,pos:99,val:-32769,+cov b/src/exchange/afl-tests/id:000982,src:000003,op:int32,pos:99,val:-32769,+cov
index 0e9ee2bd1..0e9ee2bd1 100644
--- a/src/mint/afl-tests/id:000982,src:000003,op:int32,pos:99,val:-32769,+cov
+++ b/src/exchange/afl-tests/id:000982,src:000003,op:int32,pos:99,val:-32769,+cov
diff --git a/src/mint/afl-tests/id:000983,src:000003,op:int32,pos:99,val:+100663045,+cov b/src/exchange/afl-tests/id:000983,src:000003,op:int32,pos:99,val:+100663045,+cov
index 3b45040a1..3b45040a1 100644
--- a/src/mint/afl-tests/id:000983,src:000003,op:int32,pos:99,val:+100663045,+cov
+++ b/src/exchange/afl-tests/id:000983,src:000003,op:int32,pos:99,val:+100663045,+cov
diff --git a/src/mint/afl-tests/id:000984,src:000003,op:int32,pos:101,val:+64,+cov b/src/exchange/afl-tests/id:000984,src:000003,op:int32,pos:101,val:+64,+cov
index 3541a43dd..3541a43dd 100644
--- a/src/mint/afl-tests/id:000984,src:000003,op:int32,pos:101,val:+64,+cov
+++ b/src/exchange/afl-tests/id:000984,src:000003,op:int32,pos:101,val:+64,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000985,src:000003,op:int32,pos:102,val:be:+32,+cov b/src/exchange/afl-tests/id:000985,src:000003,op:int32,pos:102,val:be:+32,+cov
index 3bcb01144..3bcb01144 100644
--- a/src/mint/afl-tests/id:000985,src:000003,op:int32,pos:102,val:be:+32,+cov
+++ b/src/exchange/afl-tests/id:000985,src:000003,op:int32,pos:102,val:be:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000986,src:000003,op:int32,pos:105,val:be:+512,+cov b/src/exchange/afl-tests/id:000986,src:000003,op:int32,pos:105,val:be:+512,+cov
index f1143db78..f1143db78 100644
--- a/src/mint/afl-tests/id:000986,src:000003,op:int32,pos:105,val:be:+512,+cov
+++ b/src/exchange/afl-tests/id:000986,src:000003,op:int32,pos:105,val:be:+512,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000987,src:000003,op:int32,pos:106,val:+100,+cov b/src/exchange/afl-tests/id:000987,src:000003,op:int32,pos:106,val:+100,+cov
index 9da1d38d2..9da1d38d2 100644
--- a/src/mint/afl-tests/id:000987,src:000003,op:int32,pos:106,val:+100,+cov
+++ b/src/exchange/afl-tests/id:000987,src:000003,op:int32,pos:106,val:+100,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000988,src:000003,op:int32,pos:109,val:-100663046,+cov b/src/exchange/afl-tests/id:000988,src:000003,op:int32,pos:109,val:-100663046,+cov
index 8639e0fc9..8639e0fc9 100644
--- a/src/mint/afl-tests/id:000988,src:000003,op:int32,pos:109,val:-100663046,+cov
+++ b/src/exchange/afl-tests/id:000988,src:000003,op:int32,pos:109,val:-100663046,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000989,src:000003,op:int32,pos:120,val:+255,+cov b/src/exchange/afl-tests/id:000989,src:000003,op:int32,pos:120,val:+255,+cov
index 85eec95fc..85eec95fc 100644
--- a/src/mint/afl-tests/id:000989,src:000003,op:int32,pos:120,val:+255,+cov
+++ b/src/exchange/afl-tests/id:000989,src:000003,op:int32,pos:120,val:+255,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000990,src:000003,op:int32,pos:121,val:+1000,+cov b/src/exchange/afl-tests/id:000990,src:000003,op:int32,pos:121,val:+1000,+cov
index 341f2890d..341f2890d 100644
--- a/src/mint/afl-tests/id:000990,src:000003,op:int32,pos:121,val:+1000,+cov
+++ b/src/exchange/afl-tests/id:000990,src:000003,op:int32,pos:121,val:+1000,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000991,src:000003,op:int32,pos:121,val:-100663046,+cov b/src/exchange/afl-tests/id:000991,src:000003,op:int32,pos:121,val:-100663046,+cov
index a5daead54..a5daead54 100644
--- a/src/mint/afl-tests/id:000991,src:000003,op:int32,pos:121,val:-100663046,+cov
+++ b/src/exchange/afl-tests/id:000991,src:000003,op:int32,pos:121,val:-100663046,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000992,src:000003,op:int32,pos:121,val:be:+65535,+cov b/src/exchange/afl-tests/id:000992,src:000003,op:int32,pos:121,val:be:+65535,+cov
index 99b1c63af..99b1c63af 100644
--- a/src/mint/afl-tests/id:000992,src:000003,op:int32,pos:121,val:be:+65535,+cov
+++ b/src/exchange/afl-tests/id:000992,src:000003,op:int32,pos:121,val:be:+65535,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000993,src:000003,op:int32,pos:130,val:+100663045,+cov b/src/exchange/afl-tests/id:000993,src:000003,op:int32,pos:130,val:+100663045,+cov
index ed6c92dac..ed6c92dac 100644
--- a/src/mint/afl-tests/id:000993,src:000003,op:int32,pos:130,val:+100663045,+cov
+++ b/src/exchange/afl-tests/id:000993,src:000003,op:int32,pos:130,val:+100663045,+cov
diff --git a/src/mint/afl-tests/id:000994,src:000003,op:int32,pos:135,val:be:+32,+cov b/src/exchange/afl-tests/id:000994,src:000003,op:int32,pos:135,val:be:+32,+cov
index e84696596..e84696596 100644
--- a/src/mint/afl-tests/id:000994,src:000003,op:int32,pos:135,val:be:+32,+cov
+++ b/src/exchange/afl-tests/id:000994,src:000003,op:int32,pos:135,val:be:+32,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000995,src:000003,op:int32,pos:136,val:be:+127,+cov b/src/exchange/afl-tests/id:000995,src:000003,op:int32,pos:136,val:be:+127,+cov
index 2c4ed3cb2..2c4ed3cb2 100644
--- a/src/mint/afl-tests/id:000995,src:000003,op:int32,pos:136,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000995,src:000003,op:int32,pos:136,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000996,src:000003,op:int32,pos:138,val:+1,+cov b/src/exchange/afl-tests/id:000996,src:000003,op:int32,pos:138,val:+1,+cov
index 3e2e306d0..3e2e306d0 100644
--- a/src/mint/afl-tests/id:000996,src:000003,op:int32,pos:138,val:+1,+cov
+++ b/src/exchange/afl-tests/id:000996,src:000003,op:int32,pos:138,val:+1,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000997,src:000003,op:int32,pos:147,val:be:+127,+cov b/src/exchange/afl-tests/id:000997,src:000003,op:int32,pos:147,val:be:+127,+cov
index 767942d31..767942d31 100644
--- a/src/mint/afl-tests/id:000997,src:000003,op:int32,pos:147,val:be:+127,+cov
+++ b/src/exchange/afl-tests/id:000997,src:000003,op:int32,pos:147,val:be:+127,+cov
Binary files differ
diff --git a/src/mint/afl-tests/id:000998,src:000003,op:ext_AO,pos:29,+cov b/src/exchange/afl-tests/id:000998,src:000003,op:ext_AO,pos:29,+cov
index 3ace43bf2..3ace43bf2 100644
--- a/src/mint/afl-tests/id:000998,src:000003,op:ext_AO,pos:29,+cov
+++ b/src/exchange/afl-tests/id:000998,src:000003,op:ext_AO,pos:29,+cov
diff --git a/src/mint/afl-tests/id:000999,src:000003,op:ext_AO,pos:31,+cov b/src/exchange/afl-tests/id:000999,src:000003,op:ext_AO,pos:31,+cov
index fe0bec5b6..fe0bec5b6 100644
--- a/src/mint/afl-tests/id:000999,src:000003,op:ext_AO,pos:31,+cov
+++ b/src/exchange/afl-tests/id:000999,src:000003,op:ext_AO,pos:31,+cov
diff --git a/src/mint/afl-tests/id:001000,src:000003,op:ext_AO,pos:37,+cov b/src/exchange/afl-tests/id:001000,src:000003,op:ext_AO,pos:37,+cov
index 065858eae..065858eae 100644
--- a/src/mint/afl-tests/id:001000,src:000003,op:ext_AO,pos:37,+cov
+++ b/src/exchange/afl-tests/id:001000,src:000003,op:ext_AO,pos:37,+cov
diff --git a/src/mint/afl-tests/id:001001,src:000003,op:ext_AO,pos:40,+cov b/src/exchange/afl-tests/id:001001,src:000003,op:ext_AO,pos:40,+cov
index 5c117ee8f..5c117ee8f 100644
--- a/src/mint/afl-tests/id:001001,src:000003,op:ext_AO,pos:40,+cov
+++ b/src/exchange/afl-tests/id:001001,src:000003,op:ext_AO,pos:40,+cov
diff --git a/src/mint/afl-tests/id:001002,src:000003,op:ext_AO,pos:44,+cov b/src/exchange/afl-tests/id:001002,src:000003,op:ext_AO,pos:44,+cov
index 5e904b337..5e904b337 100644
--- a/src/mint/afl-tests/id:001002,src:000003,op:ext_AO,pos:44,+cov
+++ b/src/exchange/afl-tests/id:001002,src:000003,op:ext_AO,pos:44,+cov
diff --git a/src/mint/afl-tests/id:001003,src:000003,op:ext_AO,pos:44,+cov b/src/exchange/afl-tests/id:001003,src:000003,op:ext_AO,pos:44,+cov
index 3c8cc6250..3c8cc6250 100644
--- a/src/mint/afl-tests/id:001003,src:000003,op:ext_AO,pos:44,+cov
+++ b/src/exchange/afl-tests/id:001003,src:000003,op:ext_AO,pos:44,+cov
diff --git a/src/mint/afl-tests/id:001004,src:000003,op:ext_AO,pos:51,+cov b/src/exchange/afl-tests/id:001004,src:000003,op:ext_AO,pos:51,+cov
index 678c15b8a..678c15b8a 100644
--- a/src/mint/afl-tests/id:001004,src:000003,op:ext_AO,pos:51,+cov
+++ b/src/exchange/afl-tests/id:001004,src:000003,op:ext_AO,pos:51,+cov
diff --git a/src/mint/afl-tests/id:001005,src:000003,op:ext_AO,pos:54,+cov b/src/exchange/afl-tests/id:001005,src:000003,op:ext_AO,pos:54,+cov
index df74c6765..df74c6765 100644
--- a/src/mint/afl-tests/id:001005,src:000003,op:ext_AO,pos:54,+cov
+++ b/src/exchange/afl-tests/id:001005,src:000003,op:ext_AO,pos:54,+cov
diff --git a/src/mint/afl-tests/id:001006,src:000003,op:ext_AO,pos:55,+cov b/src/exchange/afl-tests/id:001006,src:000003,op:ext_AO,pos:55,+cov
index 3f0ed93f5..3f0ed93f5 100644
--- a/src/mint/afl-tests/id:001006,src:000003,op:ext_AO,pos:55,+cov
+++ b/src/exchange/afl-tests/id:001006,src:000003,op:ext_AO,pos:55,+cov
diff --git a/src/mint/afl-tests/id:001007,src:000003,op:ext_AO,pos:61,+cov b/src/exchange/afl-tests/id:001007,src:000003,op:ext_AO,pos:61,+cov
index 8e27ae726..8e27ae726 100644
--- a/src/mint/afl-tests/id:001007,src:000003,op:ext_AO,pos:61,+cov
+++ b/src/exchange/afl-tests/id:001007,src:000003,op:ext_AO,pos:61,+cov
diff --git a/src/mint/afl-tests/id:001008,src:000003,op:ext_AO,pos:64,+cov b/src/exchange/afl-tests/id:001008,src:000003,op:ext_AO,pos:64,+cov
index 504edca42..504edca42 100644
--- a/src/mint/afl-tests/id:001008,src:000003,op:ext_AO,pos:64,+cov
+++ b/src/exchange/afl-tests/id:001008,src:000003,op:ext_AO,pos:64,+cov
diff --git a/src/mint/afl-tests/id:001009,src:000003,op:ext_AO,pos:66,+cov b/src/exchange/afl-tests/id:001009,src:000003,op:ext_AO,pos:66,+cov
index 8abf5fe4f..8abf5fe4f 100644
--- a/src/mint/afl-tests/id:001009,src:000003,op:ext_AO,pos:66,+cov
+++ b/src/exchange/afl-tests/id:001009,src:000003,op:ext_AO,pos:66,+cov
diff --git a/src/mint/afl-tests/id:001010,src:000003,op:ext_AO,pos:67,+cov b/src/exchange/afl-tests/id:001010,src:000003,op:ext_AO,pos:67,+cov
index c2ea619da..c2ea619da 100644
--- a/src/mint/afl-tests/id:001010,src:000003,op:ext_AO,pos:67,+cov
+++ b/src/exchange/afl-tests/id:001010,src:000003,op:ext_AO,pos:67,+cov
diff --git a/src/mint/afl-tests/id:001011,src:000003,op:ext_AO,pos:71,+cov b/src/exchange/afl-tests/id:001011,src:000003,op:ext_AO,pos:71,+cov
index 832ec77cb..832ec77cb 100644
--- a/src/mint/afl-tests/id:001011,src:000003,op:ext_AO,pos:71,+cov
+++ b/src/exchange/afl-tests/id:001011,src:000003,op:ext_AO,pos:71,+cov
diff --git a/src/mint/afl-tests/id:001012,src:000003,op:ext_AO,pos:80,+cov b/src/exchange/afl-tests/id:001012,src:000003,op:ext_AO,pos:80,+cov
index 01001189b..01001189b 100644
--- a/src/mint/afl-tests/id:001012,src:000003,op:ext_AO,pos:80,+cov
+++ b/src/exchange/afl-tests/id:001012,src:000003,op:ext_AO,pos:80,+cov
diff --git a/src/mint/afl-tests/id:001013,src:000003,op:ext_AO,pos:84,+cov b/src/exchange/afl-tests/id:001013,src:000003,op:ext_AO,pos:84,+cov
index 55c55ba9a..55c55ba9a 100644
--- a/src/mint/afl-tests/id:001013,src:000003,op:ext_AO,pos:84,+cov
+++ b/src/exchange/afl-tests/id:001013,src:000003,op:ext_AO,pos:84,+cov
diff --git a/src/mint/afl-tests/id:001014,src:000003,op:ext_AO,pos:84,+cov b/src/exchange/afl-tests/id:001014,src:000003,op:ext_AO,pos:84,+cov
index 6fb46117d..6fb46117d 100644
--- a/src/mint/afl-tests/id:001014,src:000003,op:ext_AO,pos:84,+cov
+++ b/src/exchange/afl-tests/id:001014,src:000003,op:ext_AO,pos:84,+cov
diff --git a/src/mint/afl-tests/id:001015,src:000003,op:ext_AO,pos:85,+cov b/src/exchange/afl-tests/id:001015,src:000003,op:ext_AO,pos:85,+cov
index 012eddc23..012eddc23 100644
--- a/src/mint/afl-tests/id:001015,src:000003,op:ext_AO,pos:85,+cov
+++ b/src/exchange/afl-tests/id:001015,src:000003,op:ext_AO,pos:85,+cov
diff --git a/src/mint/afl-tests/id:001016,src:000003,op:ext_AO,pos:86,+cov b/src/exchange/afl-tests/id:001016,src:000003,op:ext_AO,pos:86,+cov
index 23d4bbfec..23d4bbfec 100644
--- a/src/mint/afl-tests/id:001016,src:000003,op:ext_AO,pos:86,+cov
+++ b/src/exchange/afl-tests/id:001016,src:000003,op:ext_AO,pos:86,+cov
diff --git a/src/mint/afl-tests/id:001017,src:000003,op:ext_AO,pos:89,+cov b/src/exchange/afl-tests/id:001017,src:000003,op:ext_AO,pos:89,+cov
index a6f919570..a6f919570 100644
--- a/src/mint/afl-tests/id:001017,src:000003,op:ext_AO,pos:89,+cov
+++ b/src/exchange/afl-tests/id:001017,src:000003,op:ext_AO,pos:89,+cov
diff --git a/src/mint/afl-tests/id:001018,src:000003,op:ext_AO,pos:90,+cov b/src/exchange/afl-tests/id:001018,src:000003,op:ext_AO,pos:90,+cov
index 6b812280b..6b812280b 100644
--- a/src/mint/afl-tests/id:001018,src:000003,op:ext_AO,pos:90,+cov
+++ b/src/exchange/afl-tests/id:001018,src:000003,op:ext_AO,pos:90,+cov
diff --git a/src/mint/afl-tests/id:001019,src:000003,op:ext_AO,pos:90,+cov b/src/exchange/afl-tests/id:001019,src:000003,op:ext_AO,pos:90,+cov
index eee284d03..eee284d03 100644
--- a/src/mint/afl-tests/id:001019,src:000003,op:ext_AO,pos:90,+cov
+++ b/src/exchange/afl-tests/id:001019,src:000003,op:ext_AO,pos:90,+cov
diff --git a/src/mint/afl-tests/id:001020,src:000003,op:ext_AO,pos:101,+cov b/src/exchange/afl-tests/id:001020,src:000003,op:ext_AO,pos:101,+cov
index 3db93cc4b..3db93cc4b 100644
--- a/src/mint/afl-tests/id:001020,src:000003,op:ext_AO,pos:101,+cov
+++ b/src/exchange/afl-tests/id:001020,src:000003,op:ext_AO,pos:101,+cov
diff --git a/src/mint/afl-tests/id:001021,src:000003,op:ext_AO,pos:102,+cov b/src/exchange/afl-tests/id:001021,src:000003,op:ext_AO,pos:102,+cov
index b1fc45065..b1fc45065 100644
--- a/src/mint/afl-tests/id:001021,src:000003,op:ext_AO,pos:102,+cov
+++ b/src/exchange/afl-tests/id:001021,src:000003,op:ext_AO,pos:102,+cov
diff --git a/src/mint/afl-tests/id:001022,src:000003,op:ext_AO,pos:103,+cov b/src/exchange/afl-tests/id:001022,src:000003,op:ext_AO,pos:103,+cov
index 352cf41a6..352cf41a6 100644
--- a/src/mint/afl-tests/id:001022,src:000003,op:ext_AO,pos:103,+cov
+++ b/src/exchange/afl-tests/id:001022,src:000003,op:ext_AO,pos:103,+cov
diff --git a/src/mint/afl-tests/id:001023,src:000003,op:ext_AO,pos:106,+cov b/src/exchange/afl-tests/id:001023,src:000003,op:ext_AO,pos:106,+cov
index fbb8a9c07..fbb8a9c07 100644
--- a/src/mint/afl-tests/id:001023,src:000003,op:ext_AO,pos:106,+cov
+++ b/src/exchange/afl-tests/id:001023,src:000003,op:ext_AO,pos:106,+cov
diff --git a/src/mint/afl-tests/id:001024,src:000003,op:ext_AO,pos:107,+cov b/src/exchange/afl-tests/id:001024,src:000003,op:ext_AO,pos:107,+cov
index d79674087..d79674087 100644
--- a/src/mint/afl-tests/id:001024,src:000003,op:ext_AO,pos:107,+cov
+++ b/src/exchange/afl-tests/id:001024,src:000003,op:ext_AO,pos:107,+cov
diff --git a/src/mint/afl-tests/id:001025,src:000003,op:ext_AO,pos:109,+cov b/src/exchange/afl-tests/id:001025,src:000003,op:ext_AO,pos:109,+cov
index b00805e0a..b00805e0a 100644
--- a/src/mint/afl-tests/id:001025,src:000003,op:ext_AO,pos:109,+cov
+++ b/src/exchange/afl-tests/id:001025,src:000003,op:ext_AO,pos:109,+cov
diff --git a/src/mint/afl-tests/id:001026,src:000003,op:ext_AO,pos:109,+cov b/src/exchange/afl-tests/id:001026,src:000003,op:ext_AO,pos:109,+cov
index 98f6e7364..98f6e7364 100644
--- a/src/mint/afl-tests/id:001026,src:000003,op:ext_AO,pos:109,+cov
+++ b/src/exchange/afl-tests/id:001026,src:000003,op:ext_AO,pos:109,+cov
diff --git a/src/mint/afl-tests/id:001027,src:000003,op:ext_AO,pos:113,+cov b/src/exchange/afl-tests/id:001027,src:000003,op:ext_AO,pos:113,+cov
index 47e9988bd..47e9988bd 100644
--- a/src/mint/afl-tests/id:001027,src:000003,op:ext_AO,pos:113,+cov
+++ b/src/exchange/afl-tests/id:001027,src:000003,op:ext_AO,pos:113,+cov
diff --git a/src/mint/afl-tests/id:001028,src:000003,op:ext_AO,pos:117,+cov b/src/exchange/afl-tests/id:001028,src:000003,op:ext_AO,pos:117,+cov
index 251c8c161..251c8c161 100644
--- a/src/mint/afl-tests/id:001028,src:000003,op:ext_AO,pos:117,+cov
+++ b/src/exchange/afl-tests/id:001028,src:000003,op:ext_AO,pos:117,+cov
diff --git a/src/mint/afl-tests/id:001029,src:000003,op:ext_AO,pos:122,+cov b/src/exchange/afl-tests/id:001029,src:000003,op:ext_AO,pos:122,+cov
index 8b94c6afb..8b94c6afb 100644
--- a/src/mint/afl-tests/id:001029,src:000003,op:ext_AO,pos:122,+cov
+++ b/src/exchange/afl-tests/id:001029,src:000003,op:ext_AO,pos:122,+cov
diff --git a/src/mint/afl-tests/id:001030,src:000003,op:ext_AO,pos:122,+cov b/src/exchange/afl-tests/id:001030,src:000003,op:ext_AO,pos:122,+cov
index ea6fe6803..ea6fe6803 100644
--- a/src/mint/afl-tests/id:001030,src:000003,op:ext_AO,pos:122,+cov
+++ b/src/exchange/afl-tests/id:001030,src:000003,op:ext_AO,pos:122,+cov
diff --git a/src/mint/afl-tests/id:001031,src:000003,op:ext_AO,pos:124,+cov b/src/exchange/afl-tests/id:001031,src:000003,op:ext_AO,pos:124,+cov
index ab94cd297..ab94cd297 100644
--- a/src/mint/afl-tests/id:001031,src:000003,op:ext_AO,pos:124,+cov
+++ b/src/exchange/afl-tests/id:001031,src:000003,op:ext_AO,pos:124,+cov
diff --git a/src/mint/afl-tests/id:001032,src:000003,op:ext_AO,pos:125,+cov b/src/exchange/afl-tests/id:001032,src:000003,op:ext_AO,pos:125,+cov
index a0ec1a313..a0ec1a313 100644
--- a/src/mint/afl-tests/id:001032,src:000003,op:ext_AO,pos:125,+cov
+++ b/src/exchange/afl-tests/id:001032,src:000003,op:ext_AO,pos:125,+cov
diff --git a/src/mint/afl-tests/id:001033,src:000003,op:ext_AO,pos:125,+cov b/src/exchange/afl-tests/id:001033,src:000003,op:ext_AO,pos:125,+cov
index 05c77316c..05c77316c 100644
--- a/src/mint/afl-tests/id:001033,src:000003,op:ext_AO,pos:125,+cov
+++ b/src/exchange/afl-tests/id:001033,src:000003,op:ext_AO,pos:125,+cov
diff --git a/src/mint/afl-tests/id:001034,src:000003,op:ext_AO,pos:126,+cov b/src/exchange/afl-tests/id:001034,src:000003,op:ext_AO,pos:126,+cov
index d04efabb1..d04efabb1 100644
--- a/src/mint/afl-tests/id:001034,src:000003,op:ext_AO,pos:126,+cov
+++ b/src/exchange/afl-tests/id:001034,src:000003,op:ext_AO,pos:126,+cov
diff --git a/src/mint/afl-tests/id:001035,src:000003,op:ext_AO,pos:126,+cov b/src/exchange/afl-tests/id:001035,src:000003,op:ext_AO,pos:126,+cov
index bded4fb2a..bded4fb2a 100644
--- a/src/mint/afl-tests/id:001035,src:000003,op:ext_AO,pos:126,+cov
+++ b/src/exchange/afl-tests/id:001035,src:000003,op:ext_AO,pos:126,+cov
diff --git a/src/mint/afl-tests/id:001036,src:000003,op:ext_AO,pos:129,+cov b/src/exchange/afl-tests/id:001036,src:000003,op:ext_AO,pos:129,+cov
index 92b517930..92b517930 100644
--- a/src/mint/afl-tests/id:001036,src:000003,op:ext_AO,pos:129,+cov
+++ b/src/exchange/afl-tests/id:001036,src:000003,op:ext_AO,pos:129,+cov
diff --git a/src/mint/afl-tests/id:001037,src:000003,op:ext_AO,pos:129,+cov b/src/exchange/afl-tests/id:001037,src:000003,op:ext_AO,pos:129,+cov
index 7c4b1d56d..7c4b1d56d 100644
--- a/src/mint/afl-tests/id:001037,src:000003,op:ext_AO,pos:129,+cov
+++ b/src/exchange/afl-tests/id:001037,src:000003,op:ext_AO,pos:129,+cov
diff --git a/src/mint/afl-tests/id:001038,src:000003,op:ext_AO,pos:130,+cov b/src/exchange/afl-tests/id:001038,src:000003,op:ext_AO,pos:130,+cov
index 7612033f2..7612033f2 100644
--- a/src/mint/afl-tests/id:001038,src:000003,op:ext_AO,pos:130,+cov
+++ b/src/exchange/afl-tests/id:001038,src:000003,op:ext_AO,pos:130,+cov
diff --git a/src/mint/afl-tests/id:001039,src:000003,op:ext_AO,pos:135,+cov b/src/exchange/afl-tests/id:001039,src:000003,op:ext_AO,pos:135,+cov
index 912ea4ccc..912ea4ccc 100644
--- a/src/mint/afl-tests/id:001039,src:000003,op:ext_AO,pos:135,+cov
+++ b/src/exchange/afl-tests/id:001039,src:000003,op:ext_AO,pos:135,+cov
diff --git a/src/mint/afl-tests/id:001040,src:000003,op:ext_AO,pos:136,+cov b/src/exchange/afl-tests/id:001040,src:000003,op:ext_AO,pos:136,+cov
index 158cb6c82..158cb6c82 100644
--- a/src/mint/afl-tests/id:001040,src:000003,op:ext_AO,pos:136,+cov
+++ b/src/exchange/afl-tests/id:001040,src:000003,op:ext_AO,pos:136,+cov
diff --git a/src/mint/afl-tests/id:001041,src:000003,op:ext_AO,pos:140,+cov b/src/exchange/afl-tests/id:001041,src:000003,op:ext_AO,pos:140,+cov
index 71eef086c..71eef086c 100644
--- a/src/mint/afl-tests/id:001041,src:000003,op:ext_AO,pos:140,+cov
+++ b/src/exchange/afl-tests/id:001041,src:000003,op:ext_AO,pos:140,+cov
diff --git a/src/mint/afl-tests/id:001042,src:000003,op:ext_AO,pos:142,+cov b/src/exchange/afl-tests/id:001042,src:000003,op:ext_AO,pos:142,+cov
index 09df64a4c..09df64a4c 100644
--- a/src/mint/afl-tests/id:001042,src:000003,op:ext_AO,pos:142,+cov
+++ b/src/exchange/afl-tests/id:001042,src:000003,op:ext_AO,pos:142,+cov
diff --git a/src/mint/afl-tests/id:001043,src:000003,op:ext_AO,pos:142,+cov b/src/exchange/afl-tests/id:001043,src:000003,op:ext_AO,pos:142,+cov
index 9b048859f..9b048859f 100644
--- a/src/mint/afl-tests/id:001043,src:000003,op:ext_AO,pos:142,+cov
+++ b/src/exchange/afl-tests/id:001043,src:000003,op:ext_AO,pos:142,+cov
diff --git a/src/mint/afl-tests/id:001044,src:000003,op:ext_AO,pos:145,+cov b/src/exchange/afl-tests/id:001044,src:000003,op:ext_AO,pos:145,+cov
index 0151fb911..0151fb911 100644
--- a/src/mint/afl-tests/id:001044,src:000003,op:ext_AO,pos:145,+cov
+++ b/src/exchange/afl-tests/id:001044,src:000003,op:ext_AO,pos:145,+cov
diff --git a/src/mint/afl-tests/id:001045,src:000003,op:ext_AO,pos:147,+cov b/src/exchange/afl-tests/id:001045,src:000003,op:ext_AO,pos:147,+cov
index 159de8226..159de8226 100644
--- a/src/mint/afl-tests/id:001045,src:000003,op:ext_AO,pos:147,+cov
+++ b/src/exchange/afl-tests/id:001045,src:000003,op:ext_AO,pos:147,+cov
diff --git a/src/mint/afl-tests/id:001046,src:000003,op:ext_AO,pos:149,+cov b/src/exchange/afl-tests/id:001046,src:000003,op:ext_AO,pos:149,+cov
index 2ffa1917a..2ffa1917a 100644
--- a/src/mint/afl-tests/id:001046,src:000003,op:ext_AO,pos:149,+cov
+++ b/src/exchange/afl-tests/id:001046,src:000003,op:ext_AO,pos:149,+cov
diff --git a/src/mint/afl-tests/id:001047,src:000004,op:flip1,pos:0,+cov b/src/exchange/afl-tests/id:001047,src:000004,op:flip1,pos:0,+cov
index d13a75cb5..d13a75cb5 100644
--- a/src/mint/afl-tests/id:001047,src:000004,op:flip1,pos:0,+cov
+++ b/src/exchange/afl-tests/id:001047,src:000004,op:flip1,pos:0,+cov
diff --git a/src/mint/afl-tests/id:001048,src:000004,op:flip1,pos:4,+cov b/src/exchange/afl-tests/id:001048,src:000004,op:flip1,pos:4,+cov
index fa5707b8c..fa5707b8c 100644
--- a/src/mint/afl-tests/id:001048,src:000004,op:flip1,pos:4,+cov
+++ b/src/exchange/afl-tests/id:001048,src:000004,op:flip1,pos:4,+cov
diff --git a/src/mint/afl-tests/id:001049,src:000004,op:flip1,pos:4 b/src/exchange/afl-tests/id:001049,src:000004,op:flip1,pos:4
index 596e43e39..596e43e39 100644
--- a/src/mint/afl-tests/id:001049,src:000004,op:flip1,pos:4
+++ b/src/exchange/afl-tests/id:001049,src:000004,op:flip1,pos:4
Binary files differ
diff --git a/src/mint/afl-tests/id:001050,src:000004,op:flip1,pos:18 b/src/exchange/afl-tests/id:001050,src:000004,op:flip1,pos:18
index 596f01e21..596f01e21 100644
--- a/src/mint/afl-tests/id:001050,src:000004,op:flip1,pos:18
+++ b/src/exchange/afl-tests/id:001050,src:000004,op:flip1,pos:18
Binary files differ
diff --git a/src/mint/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov b/src/exchange/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov
index 65cd9fc29..65cd9fc29 100644
--- a/src/mint/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov
+++ b/src/exchange/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov
diff --git a/src/mint/afl-tests/id:001052,src:000004,op:flip1,pos:59 b/src/exchange/afl-tests/id:001052,src:000004,op:flip1,pos:59
index 22f1df82e..22f1df82e 100644
--- a/src/mint/afl-tests/id:001052,src:000004,op:flip1,pos:59
+++ b/src/exchange/afl-tests/id:001052,src:000004,op:flip1,pos:59
diff --git a/src/mint/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov b/src/exchange/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov
index ce06ef765..ce06ef765 100644
--- a/src/mint/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov
+++ b/src/exchange/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov
diff --git a/src/mint/afl-tests/id:001054,src:000004,op:flip1,pos:89 b/src/exchange/afl-tests/id:001054,src:000004,op:flip1,pos:89
index b09891805..b09891805 100644
--- a/src/mint/afl-tests/id:001054,src:000004,op:flip1,pos:89
+++ b/src/exchange/afl-tests/id:001054,src:000004,op:flip1,pos:89
diff --git a/src/mint/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov b/src/exchange/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov
index 337ece077..337ece077 100644
--- a/src/mint/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov
+++ b/src/exchange/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov
diff --git a/src/mint/afl-tests/id:001056,src:000004,op:flip1,pos:108 b/src/exchange/afl-tests/id:001056,src:000004,op:flip1,pos:108
index 5b908c709..5b908c709 100644
--- a/src/mint/afl-tests/id:001056,src:000004,op:flip1,pos:108
+++ b/src/exchange/afl-tests/id:001056,src:000004,op:flip1,pos:108
diff --git a/src/mint/afl-tests/id:001057,src:000004,op:flip1,pos:108 b/src/exchange/afl-tests/id:001057,src:000004,op:flip1,pos:108
index 340414e5d..340414e5d 100644
--- a/src/mint/afl-tests/id:001057,src:000004,op:flip1,pos:108
+++ b/src/exchange/afl-tests/id:001057,src:000004,op:flip1,pos:108
diff --git a/src/mint/afl-tests/id:001058,src:000004,op:flip1,pos:110 b/src/exchange/afl-tests/id:001058,src:000004,op:flip1,pos:110
index 77f342a2d..77f342a2d 100644
--- a/src/mint/afl-tests/id:001058,src:000004,op:flip1,pos:110
+++ b/src/exchange/afl-tests/id:001058,src:000004,op:flip1,pos:110
diff --git a/src/mint/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov b/src/exchange/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov
index 1f1c1c903..1f1c1c903 100644
--- a/src/mint/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov
+++ b/src/exchange/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov
diff --git a/src/mint/afl-tests/id:001060,src:000004,op:flip1,pos:112 b/src/exchange/afl-tests/id:001060,src:000004,op:flip1,pos:112
index 877f3c6f2..877f3c6f2 100644
--- a/src/mint/afl-tests/id:001060,src:000004,op:flip1,pos:112
+++ b/src/exchange/afl-tests/id:001060,src:000004,op:flip1,pos:112
diff --git a/src/mint/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov b/src/exchange/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov
index 30c8d756e..30c8d756e 100644
--- a/src/mint/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov
+++ b/src/exchange/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov
diff --git a/src/mint/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov b/src/exchange/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov
index d70e2f137..d70e2f137 100644
--- a/src/mint/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov
+++ b/src/exchange/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov
diff --git a/src/mint/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov b/src/exchange/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov
index 05c492917..05c492917 100644
--- a/src/mint/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov
+++ b/src/exchange/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov
diff --git a/src/mint/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov b/src/exchange/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov
index 9a4afa514..9a4afa514 100644
--- a/src/mint/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov
+++ b/src/exchange/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov
diff --git a/src/mint/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov b/src/exchange/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov
index cf3ab362e..cf3ab362e 100644
--- a/src/mint/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov
+++ b/src/exchange/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov
diff --git a/src/mint/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov b/src/exchange/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov
index 3957890d9..3957890d9 100644
--- a/src/mint/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov
+++ b/src/exchange/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov
diff --git a/src/mint/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov b/src/exchange/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov
index 0fc87d10b..0fc87d10b 100644
--- a/src/mint/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov
+++ b/src/exchange/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov
diff --git a/src/mint/afl-tests/id:001068,src:000004,op:flip1,pos:1150 b/src/exchange/afl-tests/id:001068,src:000004,op:flip1,pos:1150
index 695b545cb..695b545cb 100644
--- a/src/mint/afl-tests/id:001068,src:000004,op:flip1,pos:1150
+++ b/src/exchange/afl-tests/id:001068,src:000004,op:flip1,pos:1150
diff --git a/src/mint/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov b/src/exchange/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov
index 38455bb28..38455bb28 100644
--- a/src/mint/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov
+++ b/src/exchange/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov
diff --git a/src/mint/afl-tests/id:001070,src:000004,op:flip1,pos:1649 b/src/exchange/afl-tests/id:001070,src:000004,op:flip1,pos:1649
index 310494eff..310494eff 100644
--- a/src/mint/afl-tests/id:001070,src:000004,op:flip1,pos:1649
+++ b/src/exchange/afl-tests/id:001070,src:000004,op:flip1,pos:1649
diff --git a/src/mint/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov b/src/exchange/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov
index 6bedb8dc7..6bedb8dc7 100644
--- a/src/mint/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov
+++ b/src/exchange/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov
diff --git a/src/mint/afl-tests/id:001072,src:000004,op:flip1,pos:2148 b/src/exchange/afl-tests/id:001072,src:000004,op:flip1,pos:2148
index b18620069..b18620069 100644
--- a/src/mint/afl-tests/id:001072,src:000004,op:flip1,pos:2148
+++ b/src/exchange/afl-tests/id:001072,src:000004,op:flip1,pos:2148
diff --git a/src/mint/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov b/src/exchange/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov
index d0b7b7bfe..d0b7b7bfe 100644
--- a/src/mint/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov
+++ b/src/exchange/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov
diff --git a/src/mint/afl-tests/id:001074,src:000004,op:flip1,pos:2647 b/src/exchange/afl-tests/id:001074,src:000004,op:flip1,pos:2647
index 1d9852284..1d9852284 100644
--- a/src/mint/afl-tests/id:001074,src:000004,op:flip1,pos:2647
+++ b/src/exchange/afl-tests/id:001074,src:000004,op:flip1,pos:2647
diff --git a/src/mint/afl-tests/id:001075,src:000004,op:flip1,pos:3146 b/src/exchange/afl-tests/id:001075,src:000004,op:flip1,pos:3146
index 1035c4053..1035c4053 100644
--- a/src/mint/afl-tests/id:001075,src:000004,op:flip1,pos:3146
+++ b/src/exchange/afl-tests/id:001075,src:000004,op:flip1,pos:3146
diff --git a/src/mint/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov b/src/exchange/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov
index 63edd3a7c..63edd3a7c 100644
--- a/src/mint/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov
+++ b/src/exchange/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov
diff --git a/src/mint/afl-tests/id:001077,src:000004,op:flip1,pos:3645 b/src/exchange/afl-tests/id:001077,src:000004,op:flip1,pos:3645
index d404fd872..d404fd872 100644
--- a/src/mint/afl-tests/id:001077,src:000004,op:flip1,pos:3645
+++ b/src/exchange/afl-tests/id:001077,src:000004,op:flip1,pos:3645
diff --git a/src/mint/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov b/src/exchange/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov
index e93f23838..e93f23838 100644
--- a/src/mint/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov
+++ b/src/exchange/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov
diff --git a/src/mint/afl-tests/id:001079,src:000004,op:flip1,pos:4144 b/src/exchange/afl-tests/id:001079,src:000004,op:flip1,pos:4144
index 7d1b205dc..7d1b205dc 100644
--- a/src/mint/afl-tests/id:001079,src:000004,op:flip1,pos:4144
+++ b/src/exchange/afl-tests/id:001079,src:000004,op:flip1,pos:4144
diff --git a/src/mint/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov b/src/exchange/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov
index 75827a87c..75827a87c 100644
--- a/src/mint/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov
+++ b/src/exchange/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov
diff --git a/src/mint/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov b/src/exchange/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov
index 1a7dcd0eb..1a7dcd0eb 100644
--- a/src/mint/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov
+++ b/src/exchange/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov
diff --git a/src/mint/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov b/src/exchange/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov
index 42705b2be..42705b2be 100644
--- a/src/mint/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov
+++ b/src/exchange/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov
diff --git a/src/mint/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov b/src/exchange/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov
index 1c7d16a8b..1c7d16a8b 100644
--- a/src/mint/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov
+++ b/src/exchange/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov
diff --git a/src/mint/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov b/src/exchange/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov
index 98e29de85..98e29de85 100644
--- a/src/mint/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov
+++ b/src/exchange/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov
diff --git a/src/mint/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov b/src/exchange/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov
index 1afbaeb36..1afbaeb36 100644
--- a/src/mint/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov
+++ b/src/exchange/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov
diff --git a/src/mint/afl-tests/id:001086,src:000004,op:flip1,pos:5362 b/src/exchange/afl-tests/id:001086,src:000004,op:flip1,pos:5362
index 853498b32..853498b32 100644
--- a/src/mint/afl-tests/id:001086,src:000004,op:flip1,pos:5362
+++ b/src/exchange/afl-tests/id:001086,src:000004,op:flip1,pos:5362
diff --git a/src/mint/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov b/src/exchange/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov
index 5b859f6a5..5b859f6a5 100644
--- a/src/mint/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov
+++ b/src/exchange/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov
diff --git a/src/mint/afl-tests/id:001088,src:000004,op:flip1,pos:6639 b/src/exchange/afl-tests/id:001088,src:000004,op:flip1,pos:6639
index c30ed6671..c30ed6671 100644
--- a/src/mint/afl-tests/id:001088,src:000004,op:flip1,pos:6639
+++ b/src/exchange/afl-tests/id:001088,src:000004,op:flip1,pos:6639
diff --git a/src/mint/afl-tests/id:001089,src:000004,op:flip1,pos:7138 b/src/exchange/afl-tests/id:001089,src:000004,op:flip1,pos:7138
index c05262a60..c05262a60 100644
--- a/src/mint/afl-tests/id:001089,src:000004,op:flip1,pos:7138
+++ b/src/exchange/afl-tests/id:001089,src:000004,op:flip1,pos:7138
diff --git a/src/mint/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov b/src/exchange/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov
index f5c311ccb..f5c311ccb 100644
--- a/src/mint/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov
+++ b/src/exchange/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov
diff --git a/src/mint/afl-tests/id:001091,src:000004,op:flip1,pos:8136 b/src/exchange/afl-tests/id:001091,src:000004,op:flip1,pos:8136
index 63c68a5b1..63c68a5b1 100644
--- a/src/mint/afl-tests/id:001091,src:000004,op:flip1,pos:8136
+++ b/src/exchange/afl-tests/id:001091,src:000004,op:flip1,pos:8136
diff --git a/src/mint/afl-tests/id:001092,src:000004,op:flip1,pos:8636 b/src/exchange/afl-tests/id:001092,src:000004,op:flip1,pos:8636
index ed3eb4a01..ed3eb4a01 100644
--- a/src/mint/afl-tests/id:001092,src:000004,op:flip1,pos:8636
+++ b/src/exchange/afl-tests/id:001092,src:000004,op:flip1,pos:8636
diff --git a/src/mint/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov b/src/exchange/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov
index 32cd75712..32cd75712 100644
--- a/src/mint/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov
+++ b/src/exchange/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov
diff --git a/src/mint/afl-tests/id:001094,src:000004,op:flip1,pos:8712 b/src/exchange/afl-tests/id:001094,src:000004,op:flip1,pos:8712
index dd97c6ac7..dd97c6ac7 100644
--- a/src/mint/afl-tests/id:001094,src:000004,op:flip1,pos:8712
+++ b/src/exchange/afl-tests/id:001094,src:000004,op:flip1,pos:8712
diff --git a/src/mint/afl-tests/id:001095,src:000004,op:flip1,pos:8768 b/src/exchange/afl-tests/id:001095,src:000004,op:flip1,pos:8768
index 7ef20f5f7..7ef20f5f7 100644
--- a/src/mint/afl-tests/id:001095,src:000004,op:flip1,pos:8768
+++ b/src/exchange/afl-tests/id:001095,src:000004,op:flip1,pos:8768
diff --git a/src/mint/afl-tests/id:001096,src:000004,op:flip1,pos:8825 b/src/exchange/afl-tests/id:001096,src:000004,op:flip1,pos:8825
index cd01f87b3..cd01f87b3 100644
--- a/src/mint/afl-tests/id:001096,src:000004,op:flip1,pos:8825
+++ b/src/exchange/afl-tests/id:001096,src:000004,op:flip1,pos:8825
diff --git a/src/mint/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov b/src/exchange/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov
index 2c1d2d546..2c1d2d546 100644
--- a/src/mint/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov
+++ b/src/exchange/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov
diff --git a/src/mint/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov b/src/exchange/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov
index 05c296667..05c296667 100644
--- a/src/mint/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov
+++ b/src/exchange/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov
diff --git a/src/mint/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov b/src/exchange/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov
index f01f684ee..f01f684ee 100644
--- a/src/mint/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov
+++ b/src/exchange/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov
diff --git a/src/mint/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov b/src/exchange/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov
index 0e7f71998..0e7f71998 100644
--- a/src/mint/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov
+++ b/src/exchange/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov
diff --git a/src/mint/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov b/src/exchange/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov
index 3caaafdad..3caaafdad 100644
--- a/src/mint/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov
+++ b/src/exchange/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov
diff --git a/src/mint/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov b/src/exchange/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov
index 8362c9819..8362c9819 100644
--- a/src/mint/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov
+++ b/src/exchange/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov
diff --git a/src/mint/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov b/src/exchange/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov
index fdd838ccf..fdd838ccf 100644
--- a/src/mint/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov
+++ b/src/exchange/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov
diff --git a/src/mint/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov b/src/exchange/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov
index 7c078ab2e..7c078ab2e 100644
--- a/src/mint/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov
+++ b/src/exchange/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov
diff --git a/src/mint/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov b/src/exchange/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov
index 6e5a956d3..6e5a956d3 100644
--- a/src/mint/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov
+++ b/src/exchange/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov
diff --git a/src/mint/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov b/src/exchange/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov
index d306d0041..d306d0041 100644
--- a/src/mint/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov
+++ b/src/exchange/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov
diff --git a/src/mint/afl-tests/id:001107,src:000004,op:flip1,pos:10417 b/src/exchange/afl-tests/id:001107,src:000004,op:flip1,pos:10417
index c0e323631..c0e323631 100644
--- a/src/mint/afl-tests/id:001107,src:000004,op:flip1,pos:10417
+++ b/src/exchange/afl-tests/id:001107,src:000004,op:flip1,pos:10417
diff --git a/src/mint/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov b/src/exchange/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov
index 026431f36..026431f36 100644
--- a/src/mint/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov
+++ b/src/exchange/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov
diff --git a/src/mint/afl-tests/id:001109,src:000004,op:flip1,pos:10639 b/src/exchange/afl-tests/id:001109,src:000004,op:flip1,pos:10639
index 73fd35c1b..73fd35c1b 100644
--- a/src/mint/afl-tests/id:001109,src:000004,op:flip1,pos:10639
+++ b/src/exchange/afl-tests/id:001109,src:000004,op:flip1,pos:10639
diff --git a/src/mint/afl-tests/id:001110,src:000004,op:flip1,pos:10846 b/src/exchange/afl-tests/id:001110,src:000004,op:flip1,pos:10846
index cf9c6fa7d..cf9c6fa7d 100644
--- a/src/mint/afl-tests/id:001110,src:000004,op:flip1,pos:10846
+++ b/src/exchange/afl-tests/id:001110,src:000004,op:flip1,pos:10846
diff --git a/src/mint/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov b/src/exchange/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov
index 720af50ab..720af50ab 100644
--- a/src/mint/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov
+++ b/src/exchange/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov
diff --git a/src/mint/afl-tests/id:001112,src:000004,op:flip1,pos:11055 b/src/exchange/afl-tests/id:001112,src:000004,op:flip1,pos:11055
index 8d61f7536..8d61f7536 100644
--- a/src/mint/afl-tests/id:001112,src:000004,op:flip1,pos:11055
+++ b/src/exchange/afl-tests/id:001112,src:000004,op:flip1,pos:11055
diff --git a/src/mint/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov b/src/exchange/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov
index a967cf97f..a967cf97f 100644
--- a/src/mint/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov
+++ b/src/exchange/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov
diff --git a/src/mint/afl-tests/id:001114,src:000004,op:flip1,pos:11262 b/src/exchange/afl-tests/id:001114,src:000004,op:flip1,pos:11262
index 96039612c..96039612c 100644
--- a/src/mint/afl-tests/id:001114,src:000004,op:flip1,pos:11262
+++ b/src/exchange/afl-tests/id:001114,src:000004,op:flip1,pos:11262
diff --git a/src/mint/afl-tests/id:001115,src:000004,op:flip1,pos:11471 b/src/exchange/afl-tests/id:001115,src:000004,op:flip1,pos:11471
index 1ff255bc3..1ff255bc3 100644
--- a/src/mint/afl-tests/id:001115,src:000004,op:flip1,pos:11471
+++ b/src/exchange/afl-tests/id:001115,src:000004,op:flip1,pos:11471
diff --git a/src/mint/afl-tests/id:001116,src:000004,op:flip1,pos:11887 b/src/exchange/afl-tests/id:001116,src:000004,op:flip1,pos:11887
index 050fb05fb..050fb05fb 100644
--- a/src/mint/afl-tests/id:001116,src:000004,op:flip1,pos:11887
+++ b/src/exchange/afl-tests/id:001116,src:000004,op:flip1,pos:11887
diff --git a/src/mint/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov b/src/exchange/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov
index e699099e4..e699099e4 100644
--- a/src/mint/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov
+++ b/src/exchange/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov
diff --git a/src/mint/afl-tests/id:001118,src:000004,op:flip1,pos:12094 b/src/exchange/afl-tests/id:001118,src:000004,op:flip1,pos:12094
index e0e030e9c..e0e030e9c 100644
--- a/src/mint/afl-tests/id:001118,src:000004,op:flip1,pos:12094
+++ b/src/exchange/afl-tests/id:001118,src:000004,op:flip1,pos:12094
diff --git a/src/mint/afl-tests/id:001119,src:000004,op:flip1,pos:12302 b/src/exchange/afl-tests/id:001119,src:000004,op:flip1,pos:12302
index 9f75ab625..9f75ab625 100644
--- a/src/mint/afl-tests/id:001119,src:000004,op:flip1,pos:12302
+++ b/src/exchange/afl-tests/id:001119,src:000004,op:flip1,pos:12302
diff --git a/src/mint/afl-tests/id:001120,src:000004,op:flip1,pos:12511 b/src/exchange/afl-tests/id:001120,src:000004,op:flip1,pos:12511
index ed4428acb..ed4428acb 100644
--- a/src/mint/afl-tests/id:001120,src:000004,op:flip1,pos:12511
+++ b/src/exchange/afl-tests/id:001120,src:000004,op:flip1,pos:12511
diff --git a/src/mint/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov b/src/exchange/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov
index 08f6634a0..08f6634a0 100644
--- a/src/mint/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov
+++ b/src/exchange/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov
diff --git a/src/mint/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov b/src/exchange/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov
index b312ac3db..b312ac3db 100644
--- a/src/mint/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov
+++ b/src/exchange/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov
diff --git a/src/mint/afl-tests/id:001123,src:000004,op:flip1,pos:13342 b/src/exchange/afl-tests/id:001123,src:000004,op:flip1,pos:13342
index 792fae008..792fae008 100644
--- a/src/mint/afl-tests/id:001123,src:000004,op:flip1,pos:13342
+++ b/src/exchange/afl-tests/id:001123,src:000004,op:flip1,pos:13342
diff --git a/src/mint/afl-tests/id:001124,src:000004,op:flip1,pos:13550 b/src/exchange/afl-tests/id:001124,src:000004,op:flip1,pos:13550
index 07f0ec7ad..07f0ec7ad 100644
--- a/src/mint/afl-tests/id:001124,src:000004,op:flip1,pos:13550
+++ b/src/exchange/afl-tests/id:001124,src:000004,op:flip1,pos:13550
diff --git a/src/mint/afl-tests/id:001125,src:000004,op:flip1,pos:13758 b/src/exchange/afl-tests/id:001125,src:000004,op:flip1,pos:13758
index ba1194e1b..ba1194e1b 100644
--- a/src/mint/afl-tests/id:001125,src:000004,op:flip1,pos:13758
+++ b/src/exchange/afl-tests/id:001125,src:000004,op:flip1,pos:13758
diff --git a/src/mint/afl-tests/id:001126,src:000004,op:flip1,pos:13968 b/src/exchange/afl-tests/id:001126,src:000004,op:flip1,pos:13968
index 59dba82f5..59dba82f5 100644
--- a/src/mint/afl-tests/id:001126,src:000004,op:flip1,pos:13968
+++ b/src/exchange/afl-tests/id:001126,src:000004,op:flip1,pos:13968
diff --git a/src/mint/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov b/src/exchange/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov
index a663f1e95..a663f1e95 100644
--- a/src/mint/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov
+++ b/src/exchange/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov
diff --git a/src/mint/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov b/src/exchange/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov
index 6b452af69..6b452af69 100644
--- a/src/mint/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov
+++ b/src/exchange/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov
diff --git a/src/mint/afl-tests/id:001129,src:000004,op:flip1,pos:14603 b/src/exchange/afl-tests/id:001129,src:000004,op:flip1,pos:14603
index e1b7165f9..e1b7165f9 100644
--- a/src/mint/afl-tests/id:001129,src:000004,op:flip1,pos:14603
+++ b/src/exchange/afl-tests/id:001129,src:000004,op:flip1,pos:14603
diff --git a/src/mint/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov b/src/exchange/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov
index e749065db..e749065db 100644
--- a/src/mint/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov
+++ b/src/exchange/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov
diff --git a/src/mint/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov b/src/exchange/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov
index 61150d582..61150d582 100644
--- a/src/mint/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov
+++ b/src/exchange/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov
diff --git a/src/mint/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov b/src/exchange/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov
index 41dd314c4..41dd314c4 100644
--- a/src/mint/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov
+++ b/src/exchange/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov
diff --git a/src/mint/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov b/src/exchange/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov
index 3dc90c6c2..3dc90c6c2 100644
--- a/src/mint/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov
+++ b/src/exchange/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov
diff --git a/src/mint/afl-tests/id:001134,src:000004,op:flip1,pos:17507 b/src/exchange/afl-tests/id:001134,src:000004,op:flip1,pos:17507
index d2edebbec..d2edebbec 100644
--- a/src/mint/afl-tests/id:001134,src:000004,op:flip1,pos:17507
+++ b/src/exchange/afl-tests/id:001134,src:000004,op:flip1,pos:17507
diff --git a/src/mint/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov b/src/exchange/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov
index b54170879..b54170879 100644
--- a/src/mint/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov
+++ b/src/exchange/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov
diff --git a/src/mint/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov b/src/exchange/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov
index 1dd885533..1dd885533 100644
--- a/src/mint/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov
+++ b/src/exchange/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov
diff --git a/src/mint/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov b/src/exchange/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov
index 75e95e32d..75e95e32d 100644
--- a/src/mint/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov
+++ b/src/exchange/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov
diff --git a/src/mint/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov b/src/exchange/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov
index 2890e6c10..2890e6c10 100644
--- a/src/mint/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov
+++ b/src/exchange/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov
diff --git a/src/mint/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov b/src/exchange/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov
index 48ad875c6..48ad875c6 100644
--- a/src/mint/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov
+++ b/src/exchange/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov
diff --git a/src/mint/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov b/src/exchange/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov
index 38c57fd06..38c57fd06 100644
--- a/src/mint/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov
+++ b/src/exchange/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov
diff --git a/src/mint/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov b/src/exchange/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov
index 8fba732a9..8fba732a9 100644
--- a/src/mint/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov
+++ b/src/exchange/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov
diff --git a/src/mint/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov b/src/exchange/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov
index 4f04fd011..4f04fd011 100644
--- a/src/mint/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov
+++ b/src/exchange/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov
diff --git a/src/mint/afl-tests/id:001143,src:000004,op:flip1,pos:21044 b/src/exchange/afl-tests/id:001143,src:000004,op:flip1,pos:21044
index fd82bee8f..fd82bee8f 100644
--- a/src/mint/afl-tests/id:001143,src:000004,op:flip1,pos:21044
+++ b/src/exchange/afl-tests/id:001143,src:000004,op:flip1,pos:21044
diff --git a/src/mint/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov b/src/exchange/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov
index 2f38588d1..2f38588d1 100644
--- a/src/mint/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov
+++ b/src/exchange/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov
diff --git a/src/mint/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov b/src/exchange/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov
index 188621bac..188621bac 100644
--- a/src/mint/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov
+++ b/src/exchange/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov
diff --git a/src/mint/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov b/src/exchange/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov
index 7494f020a..7494f020a 100644
--- a/src/mint/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov
+++ b/src/exchange/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov
diff --git a/src/mint/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov b/src/exchange/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov
index 0aa3df33d..0aa3df33d 100644
--- a/src/mint/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov
+++ b/src/exchange/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov
diff --git a/src/mint/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov b/src/exchange/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov
index 8592c8246..8592c8246 100644
--- a/src/mint/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov
+++ b/src/exchange/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov
diff --git a/src/mint/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov b/src/exchange/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov
index 7c25b2134..7c25b2134 100644
--- a/src/mint/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov
+++ b/src/exchange/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov
diff --git a/src/mint/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov b/src/exchange/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov
index e7ca1358b..e7ca1358b 100644
--- a/src/mint/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov
+++ b/src/exchange/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov
diff --git a/src/mint/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov b/src/exchange/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov
index e985cc465..e985cc465 100644
--- a/src/mint/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov
+++ b/src/exchange/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov
diff --git a/src/mint/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov b/src/exchange/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov
index 33d0a93a6..33d0a93a6 100644
--- a/src/mint/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov
+++ b/src/exchange/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov
diff --git a/src/mint/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov b/src/exchange/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov
index 2dbd09187..2dbd09187 100644
--- a/src/mint/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov
+++ b/src/exchange/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov
diff --git a/src/mint/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov b/src/exchange/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov
index 87d7c814c..87d7c814c 100644
--- a/src/mint/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov
+++ b/src/exchange/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov
diff --git a/src/mint/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov b/src/exchange/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov
index 4aae7452e..4aae7452e 100644
--- a/src/mint/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov
+++ b/src/exchange/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov
diff --git a/src/mint/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov b/src/exchange/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov
index 2a7aae7b3..2a7aae7b3 100644
--- a/src/mint/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov
+++ b/src/exchange/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov
diff --git a/src/mint/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov b/src/exchange/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov
index 6381e638c..6381e638c 100644
--- a/src/mint/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov
+++ b/src/exchange/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov
diff --git a/src/mint/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov b/src/exchange/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov
index e6d0f83ce..e6d0f83ce 100644
--- a/src/mint/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov
+++ b/src/exchange/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov
diff --git a/src/mint/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov b/src/exchange/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov
index d74dd910f..d74dd910f 100644
--- a/src/mint/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov
+++ b/src/exchange/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov
diff --git a/src/mint/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov b/src/exchange/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov
index c0ec2ba7d..c0ec2ba7d 100644
--- a/src/mint/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov
+++ b/src/exchange/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov
diff --git a/src/mint/afl-tests/id:001161,src:000004,op:flip2,pos:108 b/src/exchange/afl-tests/id:001161,src:000004,op:flip2,pos:108
index 08a344286..08a344286 100644
--- a/src/mint/afl-tests/id:001161,src:000004,op:flip2,pos:108
+++ b/src/exchange/afl-tests/id:001161,src:000004,op:flip2,pos:108
diff --git a/src/mint/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov b/src/exchange/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov
index e6ec6a90e..e6ec6a90e 100644
--- a/src/mint/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov
+++ b/src/exchange/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov
diff --git a/src/mint/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov b/src/exchange/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov
index 14ef8b87f..14ef8b87f 100644
--- a/src/mint/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov
+++ b/src/exchange/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov
diff --git a/src/mint/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov b/src/exchange/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov
index bd6df83eb..bd6df83eb 100644
--- a/src/mint/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov
+++ b/src/exchange/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov
diff --git a/src/mint/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov b/src/exchange/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov
index 22acc5fee..22acc5fee 100644
--- a/src/mint/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov
+++ b/src/exchange/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov
diff --git a/src/mint/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov b/src/exchange/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov
index 672547a3d..672547a3d 100644
--- a/src/mint/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov
+++ b/src/exchange/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov
diff --git a/src/mint/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov b/src/exchange/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov
index a0fb164be..a0fb164be 100644
--- a/src/mint/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov
+++ b/src/exchange/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov
diff --git a/src/mint/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov b/src/exchange/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov
index f6eec0890..f6eec0890 100644
--- a/src/mint/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov
+++ b/src/exchange/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov
diff --git a/src/mint/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov b/src/exchange/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov
index b3ab01d8e..b3ab01d8e 100644
--- a/src/mint/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov
+++ b/src/exchange/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov
diff --git a/src/mint/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov b/src/exchange/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov
index eaa82fafc..eaa82fafc 100644
--- a/src/mint/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov
+++ b/src/exchange/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov
diff --git a/src/mint/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov b/src/exchange/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov
index 36104fb8a..36104fb8a 100644
--- a/src/mint/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov
+++ b/src/exchange/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov
diff --git a/src/mint/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov b/src/exchange/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov
index b2ab18004..b2ab18004 100644
--- a/src/mint/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov
+++ b/src/exchange/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov
diff --git a/src/mint/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov b/src/exchange/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov
index 70e9b6959..70e9b6959 100644
--- a/src/mint/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov
+++ b/src/exchange/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov
diff --git a/src/mint/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov b/src/exchange/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov
index b194779d6..b194779d6 100644
--- a/src/mint/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov
+++ b/src/exchange/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov
diff --git a/src/mint/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov b/src/exchange/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov
index 80862b397..80862b397 100644
--- a/src/mint/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov
+++ b/src/exchange/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov
diff --git a/src/mint/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov b/src/exchange/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov
index e97fdf9e1..e97fdf9e1 100644
--- a/src/mint/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov
+++ b/src/exchange/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov
diff --git a/src/mint/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov b/src/exchange/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov
index dd9e8b6ad..dd9e8b6ad 100644
--- a/src/mint/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov
+++ b/src/exchange/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov
diff --git a/src/mint/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov b/src/exchange/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov
index 5cb583de8..5cb583de8 100644
--- a/src/mint/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov
+++ b/src/exchange/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov
diff --git a/src/mint/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov b/src/exchange/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov
index 50ce154eb..50ce154eb 100644
--- a/src/mint/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov
+++ b/src/exchange/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov
diff --git a/src/mint/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov b/src/exchange/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov
index 782604aea..782604aea 100644
--- a/src/mint/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov
+++ b/src/exchange/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov
diff --git a/src/mint/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov b/src/exchange/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov
index 98d26fbcf..98d26fbcf 100644
--- a/src/mint/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov
+++ b/src/exchange/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov
diff --git a/src/mint/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov b/src/exchange/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov
index 625521f0a..625521f0a 100644
--- a/src/mint/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov
+++ b/src/exchange/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov
diff --git a/src/mint/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov b/src/exchange/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov
index df4bd5be2..df4bd5be2 100644
--- a/src/mint/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov
+++ b/src/exchange/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov
diff --git a/src/mint/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov b/src/exchange/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov
index 731c6c4c9..731c6c4c9 100644
--- a/src/mint/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov
+++ b/src/exchange/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov
diff --git a/src/mint/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov b/src/exchange/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov
index 0c3c81b24..0c3c81b24 100644
--- a/src/mint/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov
+++ b/src/exchange/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov
diff --git a/src/mint/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov b/src/exchange/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov
index 65513a07f..65513a07f 100644
--- a/src/mint/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov
+++ b/src/exchange/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov
diff --git a/src/mint/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov b/src/exchange/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov
index d96e4d747..d96e4d747 100644
--- a/src/mint/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov
+++ b/src/exchange/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov
diff --git a/src/mint/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov b/src/exchange/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov
index 017d9644a..017d9644a 100644
--- a/src/mint/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov
+++ b/src/exchange/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov
diff --git a/src/mint/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov b/src/exchange/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov
index 216475300..216475300 100644
--- a/src/mint/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov
+++ b/src/exchange/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov
diff --git a/src/mint/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov b/src/exchange/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov
index 4ecbdcd52..4ecbdcd52 100644
--- a/src/mint/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov
+++ b/src/exchange/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov
diff --git a/src/mint/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov b/src/exchange/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov
index ae2ab029c..ae2ab029c 100644
--- a/src/mint/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov
+++ b/src/exchange/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov
diff --git a/src/mint/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov b/src/exchange/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov
index 6f5703478..6f5703478 100644
--- a/src/mint/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov
+++ b/src/exchange/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov
diff --git a/src/mint/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov b/src/exchange/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov
index ec03c6265..ec03c6265 100644
--- a/src/mint/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov
+++ b/src/exchange/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov
diff --git a/src/mint/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov b/src/exchange/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov
index b06de9308..b06de9308 100644
--- a/src/mint/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov
+++ b/src/exchange/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov
diff --git a/src/mint/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov b/src/exchange/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov
index b88986ca7..b88986ca7 100644
--- a/src/mint/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov
+++ b/src/exchange/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov
diff --git a/src/mint/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov b/src/exchange/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov
index 015f1b603..015f1b603 100644
--- a/src/mint/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov
+++ b/src/exchange/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov
diff --git a/src/mint/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov b/src/exchange/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov
index 361c69fd7..361c69fd7 100644
--- a/src/mint/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov
+++ b/src/exchange/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov
diff --git a/src/mint/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov b/src/exchange/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov
index a4a563eaf..a4a563eaf 100644
--- a/src/mint/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov
+++ b/src/exchange/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov
diff --git a/src/mint/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov b/src/exchange/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov
index a8996d176..a8996d176 100644
--- a/src/mint/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov
+++ b/src/exchange/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov
diff --git a/src/mint/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov b/src/exchange/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov
index 513c55c33..513c55c33 100644
--- a/src/mint/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov
+++ b/src/exchange/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov
diff --git a/src/mint/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov b/src/exchange/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov
index 9b9de1add..9b9de1add 100644
--- a/src/mint/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov
+++ b/src/exchange/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov
diff --git a/src/mint/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov b/src/exchange/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov
index 52d4e76cc..52d4e76cc 100644
--- a/src/mint/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov
+++ b/src/exchange/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov
diff --git a/src/mint/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov b/src/exchange/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov
index 26b452c41..26b452c41 100644
--- a/src/mint/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov
+++ b/src/exchange/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov
diff --git a/src/mint/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov b/src/exchange/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov
index 4cb6df571..4cb6df571 100644
--- a/src/mint/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov
+++ b/src/exchange/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov
diff --git a/src/mint/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov b/src/exchange/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov
index bc2e00325..bc2e00325 100644
--- a/src/mint/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov
+++ b/src/exchange/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov
diff --git a/src/mint/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov b/src/exchange/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov
index 5f2516cd4..5f2516cd4 100644
--- a/src/mint/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov
+++ b/src/exchange/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov
diff --git a/src/mint/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov b/src/exchange/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov
index 3ce4d373e..3ce4d373e 100644
--- a/src/mint/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov
+++ b/src/exchange/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov
diff --git a/src/mint/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov b/src/exchange/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov
index 23825d180..23825d180 100644
--- a/src/mint/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov
+++ b/src/exchange/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov
diff --git a/src/mint/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov b/src/exchange/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov
index 5d902fd15..5d902fd15 100644
--- a/src/mint/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov
+++ b/src/exchange/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov
diff --git a/src/mint/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov b/src/exchange/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov
index 5b9b2bf3a..5b9b2bf3a 100644
--- a/src/mint/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov
+++ b/src/exchange/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov
diff --git a/src/mint/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov b/src/exchange/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov
index a00c97a9d..a00c97a9d 100644
--- a/src/mint/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov
+++ b/src/exchange/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov
diff --git a/src/mint/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov b/src/exchange/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov
index 7607e8165..7607e8165 100644
--- a/src/mint/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov
+++ b/src/exchange/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov
diff --git a/src/mint/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov b/src/exchange/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov
index 73f228a96..73f228a96 100644
--- a/src/mint/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov
+++ b/src/exchange/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov
diff --git a/src/mint/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov b/src/exchange/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov
index 94de8dcbe..94de8dcbe 100644
--- a/src/mint/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov
+++ b/src/exchange/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov
diff --git a/src/mint/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov b/src/exchange/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov
index c98df919a..c98df919a 100644
--- a/src/mint/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov
+++ b/src/exchange/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov
diff --git a/src/mint/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov b/src/exchange/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov
index 8c764fce7..8c764fce7 100644
--- a/src/mint/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov
+++ b/src/exchange/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov
diff --git a/src/mint/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov b/src/exchange/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov
index 2d65f69c7..2d65f69c7 100644
--- a/src/mint/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov
+++ b/src/exchange/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov
diff --git a/src/mint/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov b/src/exchange/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov
index 03b777caf..03b777caf 100644
--- a/src/mint/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov
+++ b/src/exchange/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov
diff --git a/src/mint/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov b/src/exchange/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov
index 889eb7e03..889eb7e03 100644
--- a/src/mint/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov
+++ b/src/exchange/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov
diff --git a/src/mint/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov b/src/exchange/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov
index 92e0834e8..92e0834e8 100644
--- a/src/mint/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov
+++ b/src/exchange/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov
diff --git a/src/mint/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov b/src/exchange/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov
index 6d40e15c5..6d40e15c5 100644
--- a/src/mint/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov
+++ b/src/exchange/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov
diff --git a/src/mint/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov b/src/exchange/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov
index d625ba258..d625ba258 100644
--- a/src/mint/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov
+++ b/src/exchange/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov
diff --git a/src/mint/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov b/src/exchange/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov
index ff5c27c4e..ff5c27c4e 100644
--- a/src/mint/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov
+++ b/src/exchange/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov
diff --git a/src/mint/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov b/src/exchange/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov
index 045286f69..045286f69 100644
--- a/src/mint/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov
+++ b/src/exchange/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov
diff --git a/src/mint/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov b/src/exchange/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov
index c396ea742..c396ea742 100644
--- a/src/mint/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov
+++ b/src/exchange/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov
diff --git a/src/mint/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov b/src/exchange/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov
index f67390f3e..f67390f3e 100644
--- a/src/mint/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov
+++ b/src/exchange/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov
diff --git a/src/mint/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov b/src/exchange/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov
index eeb4d1dd2..eeb4d1dd2 100644
--- a/src/mint/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov
+++ b/src/exchange/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov
diff --git a/src/mint/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov b/src/exchange/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov
index b2ae1fa9b..b2ae1fa9b 100644
--- a/src/mint/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov
+++ b/src/exchange/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov
diff --git a/src/mint/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov b/src/exchange/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov
index 7593747d4..7593747d4 100644
--- a/src/mint/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov
+++ b/src/exchange/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov
diff --git a/src/mint/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov b/src/exchange/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov
index b55c57fcf..b55c57fcf 100644
--- a/src/mint/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov
+++ b/src/exchange/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov
diff --git a/src/mint/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov b/src/exchange/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov
index f6da540e8..f6da540e8 100644
--- a/src/mint/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov
+++ b/src/exchange/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov
diff --git a/src/mint/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov b/src/exchange/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov
index 020367553..020367553 100644
--- a/src/mint/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov
+++ b/src/exchange/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov
diff --git a/src/mint/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov b/src/exchange/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov
index a0a5cbdc5..a0a5cbdc5 100644
--- a/src/mint/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov
+++ b/src/exchange/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov
diff --git a/src/mint/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov b/src/exchange/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov
index 19f230d0c..19f230d0c 100644
--- a/src/mint/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov
+++ b/src/exchange/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov
diff --git a/src/mint/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov b/src/exchange/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov
index 8d4aeaa25..8d4aeaa25 100644
--- a/src/mint/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov
+++ b/src/exchange/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov
diff --git a/src/mint/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov b/src/exchange/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov
index a8531a72d..a8531a72d 100644
--- a/src/mint/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov
+++ b/src/exchange/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov
diff --git a/src/mint/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov b/src/exchange/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov
index 12ffe2886..12ffe2886 100644
--- a/src/mint/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov
+++ b/src/exchange/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov
diff --git a/src/mint/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov b/src/exchange/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov
index 46c9cb5d0..46c9cb5d0 100644
--- a/src/mint/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov
+++ b/src/exchange/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov
diff --git a/src/mint/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov b/src/exchange/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov
index 23f6d573b..23f6d573b 100644
--- a/src/mint/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov
+++ b/src/exchange/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov
diff --git a/src/mint/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov b/src/exchange/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov
index d15412a4d..d15412a4d 100644
--- a/src/mint/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov
+++ b/src/exchange/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov
diff --git a/src/mint/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov b/src/exchange/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov
index a6c94b3c9..a6c94b3c9 100644
--- a/src/mint/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov
+++ b/src/exchange/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov
diff --git a/src/mint/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov b/src/exchange/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov
index c883d866c..c883d866c 100644
--- a/src/mint/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov
+++ b/src/exchange/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov
diff --git a/src/mint/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov b/src/exchange/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov
index 76b9110ec..76b9110ec 100644
--- a/src/mint/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov
+++ b/src/exchange/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov
diff --git a/src/mint/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov b/src/exchange/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov
index ddad3915e..ddad3915e 100644
--- a/src/mint/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov
+++ b/src/exchange/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov
diff --git a/src/mint/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov b/src/exchange/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov
index ee4227257..ee4227257 100644
--- a/src/mint/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov
+++ b/src/exchange/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov
diff --git a/src/mint/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov b/src/exchange/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov
index cb37e5bbe..cb37e5bbe 100644
--- a/src/mint/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov
+++ b/src/exchange/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
new file mode 100644
index 000000000..3ffce1d3f
--- /dev/null
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -0,0 +1,914 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-aggregator.c
+ * @brief Process that aggregates outgoing transactions and executes them
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - simplify global_ret: make it a global!
+ * - handle shutdown more nicely (call 'cancel' method on wire transfers)
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <pthread.h>
+#include "taler_exchangedb_lib.h"
+#include "taler_exchangedb_plugin.h"
+#include "taler_wire_lib.h"
+
+/**
+ * Which currency is used by this exchange?
+ */
+static char *exchange_currency_string;
+
+/**
+ * Which wireformat should be supported by this aggregator?
+ */
+static char *exchange_wireformat;
+
+/**
+ * Base directory of the exchange (global)
+ */
+static char *exchange_directory;
+
+/**
+ * The exchange's configuration (global)
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Our DB plugin.
+ */
+static struct TALER_EXCHANGEDB_Plugin *db_plugin;
+
+/**
+ * Our wire plugin.
+ */
+static struct TALER_WIRE_Plugin *wire_plugin;
+
+/**
+ * Task for the main #run() function.
+ */
+static struct GNUNET_SCHEDULER_Task *task;
+
+/**
+ * Limit on the number of transactions we aggregate at once. Note
+ * that the limit must be big enough to ensure that when transactions
+ * of the smallest possible unit are aggregated, they do surpass the
+ * "tiny" threshold beyond which we never trigger a wire transaction!
+ *
+ * TODO: make configurable (via config file or command line option)
+ */
+static unsigned int aggregation_limit = 10000;
+
+
+/**
+ * Load configuration parameters for the exchange
+ * server into the corresponding global variables.
+ *
+ * @param exchange_directory the exchange's directory
+ * @return #GNUNET_OK on success
+ */
+static int
+exchange_serve_process_config (const char *exchange_directory)
+{
+ char *type;
+
+ cfg = TALER_config_load (exchange_directory);
+ if (NULL == cfg)
+ {
+ fprintf (stderr,
+ "Failed to load exchange configuration\n");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "currency",
+ &exchange_currency_string))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "currency");
+ return GNUNET_SYSERR;
+ }
+ if (strlen (exchange_currency_string) >= TALER_CURRENCY_LEN)
+ {
+ fprintf (stderr,
+ "Currency `%s' longer than the allowed limit of %u characters.",
+ exchange_currency_string,
+ (unsigned int) TALER_CURRENCY_LEN);
+ return GNUNET_SYSERR;
+ }
+ if (NULL != exchange_wireformat)
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "exchange",
+ "wireformat",
+ exchange_wireformat);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "wireformat",
+ &type))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "wireformat");
+ return GNUNET_SYSERR;
+ }
+
+ if (NULL ==
+ (db_plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
+ {
+ fprintf (stderr,
+ "Failed to initialize DB subsystem\n");
+ GNUNET_free (type);
+ return GNUNET_SYSERR;
+ }
+
+ if (NULL ==
+ (wire_plugin = TALER_WIRE_plugin_load (cfg,
+ type)))
+ {
+ fprintf (stderr,
+ "Failed to load wire plugin for `%s'\n",
+ type);
+ GNUNET_free (type);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (type);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Information about one aggregation process to
+ * be executed.
+ */
+struct AggregationUnit
+{
+ /**
+ * Public key of the merchant.
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * Total amount to be transferred.
+ */
+ struct TALER_Amount total_amount;
+
+ /**
+ * Hash of @e wire.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Wire transfer identifier we use.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /**
+ * Row ID of the transaction that started it all.
+ */
+ unsigned long long row_id;
+
+ /**
+ * The current time.
+ */
+ struct GNUNET_TIME_Absolute execution_time;
+
+ /**
+ * Wire details of the merchant.
+ */
+ json_t *wire;
+
+ /**
+ * Database session for all of our transactions.
+ */
+ struct TALER_EXCHANGEDB_Session *session;
+
+ /**
+ * Wire preparation handle.
+ */
+ struct TALER_WIRE_PrepareHandle *ph;
+
+ /**
+ * Array of #aggregation_limit row_ids from the
+ * aggregation.
+ */
+ unsigned long long *additional_rows;
+
+ /**
+ * Pointer to global return value. Closure for #run().
+ */
+ int *global_ret;
+
+ /**
+ * Offset specifying how many #additional_rows are in use.
+ */
+ unsigned int rows_offset;
+
+ /**
+ * Set to #GNUNET_YES if we have to abort due to failure.
+ */
+ int failed;
+
+};
+
+
+/**
+ * Function called with details about deposits that have been made,
+ * with the goal of executing the corresponding wire transaction.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param row_id identifies database entry
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param deposit_fee amount the exchange gets to keep as transaction fees
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param wire wire details for the merchant
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static int
+deposit_cb (void *cls,
+ unsigned long long row_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ uint64_t transaction_id,
+ const struct GNUNET_HashCode *h_contract,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ const json_t *wire)
+{
+ struct AggregationUnit *au = cls;
+
+ au->merchant_pub = *merchant_pub;
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&au->total_amount,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fatally malformed record at %llu\n",
+ row_id);
+ return GNUNET_SYSERR;
+ }
+ au->row_id = row_id;
+ au->wire = (json_t *) wire;
+ au->execution_time = GNUNET_TIME_absolute_get ();
+ TALER_hash_json (au->wire,
+ &au->h_wire);
+ json_incref (au->wire);
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &au->wtid,
+ sizeof (au->wtid));
+ if (GNUNET_OK !=
+ db_plugin->insert_aggregation_tracking (db_plugin->cls,
+ au->session,
+ &au->wtid,
+ merchant_pub,
+ &au->h_wire,
+ h_contract,
+ transaction_id,
+ au->execution_time,
+ coin_pub,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_done (db_plugin->cls,
+ au->session,
+ row_id))
+ {
+ GNUNET_break (0);
+ au->failed = GNUNET_YES;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Function called with details about another deposit we
+ * can aggregate into an existing aggregation unit.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param row_id identifies database entry
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param deposit_fee amount the exchange gets to keep as transaction fees
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param wire wire details for the merchant
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static int
+aggregate_cb (void *cls,
+ unsigned long long row_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ uint64_t transaction_id,
+ const struct GNUNET_HashCode *h_contract,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ const json_t *wire)
+{
+ struct AggregationUnit *au = cls;
+ struct TALER_Amount delta;
+
+ GNUNET_break (0 ==
+ memcmp (&au->merchant_pub,
+ merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP)));
+ /* compute contribution of this coin after fees */
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&delta,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fatally malformed record at %llu\n",
+ row_id);
+ return GNUNET_SYSERR;
+ }
+ /* add to total */
+ if (GNUNET_OK !=
+ TALER_amount_add (&au->total_amount,
+ &au->total_amount,
+ &delta))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Overflow or currency incompatibility during aggregation at %llu\n",
+ row_id);
+ /* Skip this one, but keep going! */
+ return GNUNET_OK;
+ }
+ if (au->rows_offset >= aggregation_limit)
+ {
+ /* Bug: we asked for at most #aggregation_limit results! */
+ GNUNET_break (0);
+ /* Skip this one, but keep going. */
+ return GNUNET_OK;
+ }
+ if (NULL == au->additional_rows)
+ au->additional_rows = GNUNET_new_array (aggregation_limit,
+ unsigned long long);
+ /* "append" to our list of rows */
+ au->additional_rows[au->rows_offset++] = row_id;
+ /* insert into aggregation tracking table */
+ if (GNUNET_OK !=
+ db_plugin->insert_aggregation_tracking (db_plugin->cls,
+ au->session,
+ &au->wtid,
+ merchant_pub,
+ &au->h_wire,
+ h_contract,
+ transaction_id,
+ au->execution_time,
+ coin_pub,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_done (db_plugin->cls,
+ au->session,
+ row_id))
+ {
+ GNUNET_break (0);
+ au->failed = GNUNET_YES;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function to be called with the prepared transfer data.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param buf transaction data to persist, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+static void
+prepare_cb (void *cls,
+ const char *buf,
+ size_t buf_size);
+
+
+/**
+ * Main work function that queries the DB and aggregates transactions
+ * into larger wire transfers.
+ *
+ * @param cls pointer to an `int` which we will return from main()
+ * @param tc scheduler context
+ */
+static void
+run_aggregation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ int *global_ret = cls;
+ struct TALER_EXCHANGEDB_Session *session;
+ struct AggregationUnit *au;
+ unsigned int i;
+ int ret;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ if (NULL == (session = db_plugin->get_session (db_plugin->cls,
+ GNUNET_NO)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to obtain database session!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ db_plugin->start (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to start database transaction!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ au = GNUNET_new (struct AggregationUnit);
+ au->session = session;
+ ret = db_plugin->get_ready_deposit (db_plugin->cls,
+ session,
+ &deposit_cb,
+ au);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_free (au);
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ if (0 != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to execute deposit iteration!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ /* nothing to do, sleep for a minute and try again */
+ task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &run_aggregation,
+ global_ret);
+ return;
+ }
+ /* Now try to find other deposits to aggregate */
+ ret = db_plugin->iterate_matching_deposits (db_plugin->cls,
+ session,
+ &au->h_wire,
+ &au->merchant_pub,
+ &aggregate_cb,
+ au,
+ aggregation_limit);
+ if ( (GNUNET_SYSERR == ret) ||
+ (GNUNET_YES == au->failed) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to execute deposit iteration!\n");
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ /* Round to the unit supported by the wire transfer method */
+ GNUNET_assert (GNUNET_SYSERR !=
+ wire_plugin->amount_round (wire_plugin->cls,
+ &au->total_amount));
+ /* Check if after rounding down, we still have an amount to transfer */
+ if ( (0 == au->total_amount.value) &&
+ (0 == au->total_amount.fraction) )
+ {
+ /* Rollback ongoing transaction, as we will not use the respective
+ WTID and thus need to remove the tracking data */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ /* Start another transaction to mark all* of the selected deposits
+ *as minor! */
+ if (GNUNET_OK !=
+ db_plugin->start (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to start database transaction!\n");
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ return;
+ }
+ /* Mark transactions by row_id as minor */
+ ret = GNUNET_OK;
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_tiny (db_plugin->cls,
+ session,
+ au->row_id))
+ ret = GNUNET_SYSERR;
+ else
+ for (i=0;i<au->rows_offset;i++)
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_tiny (db_plugin->cls,
+ session,
+ au->additional_rows[i]))
+ ret = GNUNET_SYSERR;
+ /* commit */
+ if (GNUNET_OK !=
+ db_plugin->commit (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to commit database transaction!\n");
+ }
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+ au->global_ret = global_ret;
+ au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls,
+ au->wire,
+ &au->total_amount,
+ &au->wtid,
+ &prepare_cb,
+ au);
+ /* FIXME: currently we have no clean-up plan on
+ shutdown to call prepare_wire_transfer_cancel!
+ Maybe make 'au' global? */
+ if (NULL == au->ph)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+ /* otherwise we continue with #prepare_cb(), see below */
+}
+
+
+/**
+ * Execute the wire transfers that we have committed to
+ * do.
+ *
+ * @param cls pointer to an `int` which we will return from main()
+ * @param tc scheduler context
+ */
+static void
+run_transfers (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Function to be called with the prepared transfer data.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param buf transaction data to persist, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+static void
+prepare_cb (void *cls,
+ const char *buf,
+ size_t buf_size)
+{
+ struct AggregationUnit *au = cls;
+ int *global_ret = au->global_ret;
+ struct TALER_EXCHANGEDB_Session *session = au->session;
+
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ if (NULL == buf)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+
+ /* Commit our intention to execute the wire transfer! */
+ if (GNUNET_OK !=
+ db_plugin->wire_prepare_data_insert (db_plugin->cls,
+ session,
+ exchange_wireformat,
+ buf,
+ buf_size))
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+
+ /* Now we can finally commit the overall transaction, as we are
+ again consistent if all of this passes. */
+ if (GNUNET_OK !=
+ db_plugin->commit (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Failed to commit database transaction!\n");
+ /* try again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+
+ /* run alternative task: actually do wire transfer! */
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ &global_ret);
+}
+
+
+/**
+ * Data we keep to #run_transfers().
+ */
+struct WirePrepareData
+{
+
+ /**
+ * Database session for all of our transactions.
+ */
+ struct TALER_EXCHANGEDB_Session *session;
+
+ /**
+ * Wire execution handle.
+ */
+ struct TALER_WIRE_ExecuteHandle *eh;
+
+ /**
+ * Pointer to global return value. Closure for #run().
+ */
+ int *global_ret;
+
+
+ /**
+ * Row ID of the transfer.
+ */
+ unsigned long long row_id;
+
+};
+
+
+/**
+ * Function called with the result from the execute step.
+ *
+ * @param cls closure with the `struct WirePrepareData`
+ * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ * @param emsg NULL on success, otherwise an error message
+ */
+static void
+wire_confirm_cb (void *cls,
+ int success,
+ const char *emsg)
+{
+ struct WirePrepareData *wpd = cls;
+ int *global_ret = wpd->global_ret;
+ struct TALER_EXCHANGEDB_Session *session = wpd->session;
+
+ wpd->eh = NULL;
+ if (GNUNET_SYSERR == success)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire transaction failed: %s\n",
+ emsg);
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+ if (GNUNET_OK !=
+ db_plugin->wire_prepare_data_mark_finished (db_plugin->cls,
+ session,
+ wpd->row_id))
+ {
+ GNUNET_break (0); /* why!? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+ GNUNET_free (wpd);
+ if (GNUNET_OK !=
+ db_plugin->commit (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Failed to commit database transaction!\n");
+ /* try again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+ /* continue with #run_transfers(), just to guard
+ against the unlikely case that there are more. */
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ &global_ret);
+
+}
+
+
+/**
+ * Callback with data about a prepared transaction.
+ *
+ * @param cls closure with the `struct WirePrepareData`
+ * @param rowid row identifier used to mark prepared transaction as done
+ * @param buf transaction data that was persisted, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+static void
+wire_prepare_cb (void *cls,
+ unsigned long long rowid,
+ const char *buf,
+ size_t buf_size)
+{
+ struct WirePrepareData *wpd = cls;
+ int *global_ret = wpd->global_ret;
+
+ wpd->row_id = rowid;
+ wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls,
+ buf,
+ buf_size,
+ &wire_confirm_cb,
+ wpd);
+ /* FIXME: currently we have no clean-up plan on
+ shutdown to call execute_wire_transfer_cancel!
+ Maybe make 'wpd' global? */
+ if (NULL == wpd->eh)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ wpd->session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+}
+
+
+/**
+ * Execute the wire transfers that we have committed to
+ * do.
+ *
+ * @param cls pointer to an `int` which we will return from main()
+ * @param tc scheduler context
+ */
+static void
+run_transfers (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ int *global_ret = cls;
+ int ret;
+ struct WirePrepareData *wpd;
+ struct TALER_EXCHANGEDB_Session *session;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ if (NULL == (session = db_plugin->get_session (db_plugin->cls,
+ GNUNET_NO)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to obtain database session!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ db_plugin->start (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to start database transaction!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ wpd = GNUNET_new (struct WirePrepareData);
+ wpd->session = session;
+ wpd->global_ret = global_ret;
+ ret = db_plugin->wire_prepare_data_get (db_plugin->cls,
+ session,
+ exchange_wireformat,
+ &wire_prepare_cb,
+ wpd);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+ if (GNUNET_NO == ret)
+ {
+ /* no more prepared wire transfers, go back to aggregation! */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ GNUNET_free (wpd);
+ return;
+ }
+ /* otherwise, continues in #wire_prepare_cb() */
+}
+
+
+/**
+ * The main function of the taler-exchange-httpd server ("the exchange").
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'d', "exchange-dir", "DIR",
+ "exchange directory with configuration and keys for operating the exchange", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_directory},
+ {'f', "format", "WIREFORMAT",
+ "wireformat to use, overrides WIREFORMAT option in [exchange] section", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_wireformat},
+ TALER_GETOPT_OPTION_HELP ("background process that aggregates and executes wire transfers to merchants"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret = GNUNET_OK;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-aggregator",
+ "INFO",
+ NULL));
+ if (0 >=
+ GNUNET_GETOPT_run ("taler-exchange-aggregator",
+ options,
+ argc, argv))
+ return 1;
+ if (NULL == exchange_directory)
+ {
+ fprintf (stderr,
+ "Exchange directory not specified\n");
+ return 1;
+ }
+ if (GNUNET_OK !=
+ exchange_serve_process_config (exchange_directory))
+ {
+ return 1;
+ }
+
+ GNUNET_SCHEDULER_run (&run_transfers, &ret);
+
+ TALER_EXCHANGEDB_plugin_unload (db_plugin);
+ TALER_WIRE_plugin_unload (wire_plugin);
+ return (GNUNET_SYSERR == ret) ? 1 : 0;
+}
+
+/* end of taler-exchange-aggregator.c */
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
new file mode 100644
index 000000000..c16e26409
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd.c
@@ -0,0 +1,749 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd.c
+ * @brief Serve the HTTP interface of the exchange
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_mhd.h"
+#include "taler-exchange-httpd_admin.h"
+#include "taler-exchange-httpd_deposit.h"
+#include "taler-exchange-httpd_reserve.h"
+#include "taler-exchange-httpd_wire.h"
+#include "taler-exchange-httpd_refresh.h"
+#include "taler-exchange-httpd_tracking.h"
+#include "taler-exchange-httpd_keystate.h"
+#if HAVE_DEVELOPER
+#include "taler-exchange-httpd_test.h"
+#endif
+#include "taler_exchangedb_plugin.h"
+#include "taler-exchange-httpd_validation.h"
+
+/**
+ * Which currency is used by this exchange?
+ */
+char *TMH_exchange_currency_string;
+
+/**
+ * Should we return "Connection: close" in each response?
+ */
+int TMH_exchange_connection_close;
+
+/**
+ * Base directory of the exchange (global)
+ */
+char *TMH_exchange_directory;
+
+/**
+ * The exchange's configuration (global)
+ */
+struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Master public key (according to the
+ * configuration in the exchange directory).
+ */
+struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
+
+/**
+ * Our DB plugin.
+ */
+struct TALER_EXCHANGEDB_Plugin *TMH_plugin;
+
+/**
+ * Are we running in test mode?
+ */
+int TMH_test_mode;
+
+/**
+ * Default timeout in seconds for HTTP requests.
+ */
+static unsigned int connection_timeout = 30;
+
+/**
+ * The HTTP Daemon.
+ */
+static struct MHD_Daemon *mydaemon;
+
+/**
+ * Port to run the daemon on.
+ */
+static uint16_t serve_port;
+
+
+/**
+ * Function called whenever MHD is done with a request. If the
+ * request was a POST, we may have stored a `struct Buffer *` in the
+ * @a con_cls that might still need to be cleaned up. Call the
+ * respective function to free the memory.
+ *
+ * @param cls client-defined closure
+ * @param connection connection handle
+ * @param con_cls value as set by the last call to
+ * the #MHD_AccessHandlerCallback
+ * @param toe reason for request termination
+ * @see #MHD_OPTION_NOTIFY_COMPLETED
+ * @ingroup request
+ */
+static void
+handle_mhd_completion_callback (void *cls,
+ struct MHD_Connection *connection,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+ if (NULL == *con_cls)
+ return;
+ TMH_PARSE_post_cleanup_callback (*con_cls);
+ *con_cls = NULL;
+}
+
+
+/**
+ * Handle a request coming from libmicrohttpd.
+ *
+ * @param cls closure for MHD daemon (unused)
+ * @param connection the connection
+ * @param url the requested url
+ * @param method the method (POST, GET, ...)
+ * @param version HTTP version (ignored)
+ * @param upload_data request data
+ * @param upload_data_size size of @a upload_data in bytes
+ * @param con_cls closure for request (a `struct Buffer *`)
+ * @return MHD result code
+ */
+static int
+handle_mhd_request (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **con_cls)
+{
+ static struct TMH_RequestHandler handlers[] =
+ {
+ /* Landing page, tell humans to go away. */
+ { "/", MHD_HTTP_METHOD_GET, "text/plain",
+ "Hello, I'm the Taler exchange. This HTTP server is not for humans.\n", 0,
+ &TMH_MHD_handler_static_response, MHD_HTTP_OK },
+ /* /robots.txt: disallow everything */
+ { "/robots.txt", MHD_HTTP_METHOD_GET, "text/plain",
+ "User-agent: *\nDisallow: /\n", 0,
+ &TMH_MHD_handler_static_response, MHD_HTTP_OK },
+ /* AGPL licensing page, redirect to source. As per the AGPL-license,
+ every deployment is required to offer the user a download of the
+ source. We make this easy by including a redirect to the source
+ here. */
+ { "/agpl", MHD_HTTP_METHOD_GET, "text/plain",
+ NULL, 0,
+ &TMH_MHD_handler_agpl_redirect, MHD_HTTP_FOUND },
+
+ /* Return key material and fundamental properties for this exchange */
+ { "/keys", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_KS_handler_keys, MHD_HTTP_OK },
+ { "/keys", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ /* Requests for wiring information */
+ { "/wire", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_WIRE_handler_wire, MHD_HTTP_OK },
+ { "/wire", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/wire/test", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_WIRE_handler_wire_test, MHD_HTTP_FOUND },
+ { "/wire/test", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/wire/sepa", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_WIRE_handler_wire_sepa, MHD_HTTP_OK },
+ { "/wire/sepa", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ /* Withdrawing coins / interaction with reserves */
+ { "/reserve/status", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_RESERVE_handler_reserve_status, MHD_HTTP_OK },
+ { "/reserve/status", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/reserve/withdraw", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_RESERVE_handler_reserve_withdraw, MHD_HTTP_OK },
+ { "/reserve/withdraw", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ /* Depositing coins */
+ { "/deposit", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_DEPOSIT_handler_deposit, MHD_HTTP_OK },
+ { "/deposit", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ /* Dealing with change */
+ { "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_REFRESH_handler_refresh_melt, MHD_HTTP_OK },
+ { "/refresh/melt", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK },
+ { "/refresh/reveal", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK },
+ { "/refresh/reveal", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/refresh/link", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_REFRESH_handler_refresh_link, MHD_HTTP_OK },
+ { "/refresh/link", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ /* FIXME: maybe conditionally compile these? */
+ { "/admin/add/incoming", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_ADMIN_handler_admin_add_incoming, MHD_HTTP_OK },
+ { "/admin/add/incoming", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/wire/deposits", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_TRACKING_handler_wire_deposits, MHD_HTTP_OK },
+ { "/wire/deposits", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+ { "/deposit/wtid", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TRACKING_handler_deposit_wtid, MHD_HTTP_OK },
+ { "/deposit/wtid", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+#if HAVE_DEVELOPER
+ /* Client crypto-interoperability test functions */
+ { "/test", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test, MHD_HTTP_OK },
+ { "/test", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/base32", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_base32, MHD_HTTP_OK },
+ { "/test/base32", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/encrypt", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_encrypt, MHD_HTTP_OK },
+ { "/test/encrypt", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/hkdf", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_hkdf, MHD_HTTP_OK },
+ { "/test/hkdf", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/ecdhe", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_ecdhe, MHD_HTTP_OK },
+ { "/test/ecdhe", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/eddsa", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_eddsa, MHD_HTTP_OK },
+ { "/test/eddsa", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/rsa/get", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_rsa_get, MHD_HTTP_OK },
+ { "/test/rsa/get", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/rsa/sign", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_rsa_sign, MHD_HTTP_OK },
+ { "/test/rsa/sign", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+
+ { "/test/transfer", MHD_HTTP_METHOD_POST, "application/json",
+ NULL, 0,
+ &TMH_TEST_handler_test_transfer, MHD_HTTP_OK },
+ { "/test/transfer", NULL, "text/plain",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+#endif
+
+ { NULL, NULL, NULL, NULL, 0, 0 }
+ };
+ static struct TMH_RequestHandler h404 =
+ {
+ "", NULL, "text/html",
+ "<html><title>404: not found</title></html>", 0,
+ &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND
+ };
+ struct TMH_RequestHandler *rh;
+ unsigned int i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Handling request for URL '%s'\n",
+ url);
+ for (i=0;NULL != handlers[i].url;i++)
+ {
+ rh = &handlers[i];
+ if ( (0 == strcasecmp (url,
+ rh->url)) &&
+ ( (NULL == rh->method) ||
+ (0 == strcasecmp (method,
+ rh->method)) ) )
+ return rh->handler (rh,
+ connection,
+ con_cls,
+ upload_data,
+ upload_data_size);
+ }
+ return TMH_MHD_handler_static_response (&h404,
+ connection,
+ con_cls,
+ upload_data,
+ upload_data_size);
+}
+
+
+/**
+ * Load configuration parameters for the exchange
+ * server into the corresponding global variables.
+ *
+ * @param exchange_directory the exchange's directory
+ * @return #GNUNET_OK on success
+ */
+static int
+exchange_serve_process_config (const char *exchange_directory)
+{
+ unsigned long long port;
+ char *TMH_master_public_key_str;
+
+ cfg = TALER_config_load (exchange_directory);
+ if (NULL == cfg)
+ {
+ fprintf (stderr,
+ "Failed to load exchange configuration\n");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "currency",
+ &TMH_exchange_currency_string))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "currency");
+ return GNUNET_SYSERR;
+ }
+ if (strlen (TMH_exchange_currency_string) >= TALER_CURRENCY_LEN)
+ {
+ fprintf (stderr,
+ "Currency `%s' longer than the allowed limit of %u characters.",
+ TMH_exchange_currency_string,
+ (unsigned int) TALER_CURRENCY_LEN);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TMH_VALIDATION_init (cfg))
+ return GNUNET_SYSERR;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "master_public_key",
+ &TMH_master_public_key_str))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "master_public_key");
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (TMH_master_public_key_str,
+ strlen (TMH_master_public_key_str),
+ &TMH_master_public_key))
+ {
+ fprintf (stderr,
+ "Invalid master public key given in exchange configuration.");
+ GNUNET_free (TMH_master_public_key_str);
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (TMH_master_public_key_str);
+
+ if (NULL ==
+ (TMH_plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
+ {
+ fprintf (stderr,
+ "Failed to initialize DB subsystem\n");
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ "exchange",
+ "TESTRUN"))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Running in TEST mode! Database contents will not persist!\n");
+ TMH_test_mode = GNUNET_YES;
+ TMH_plugin->create_tables (TMH_plugin->cls,
+ GNUNET_YES);
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "exchange",
+ "port",
+ &port))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "port",
+ "port number required");
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+
+ if ( (0 == port) ||
+ (port > UINT16_MAX) )
+ {
+ fprintf (stderr,
+ "Invalid configuration (value out of range): %llu is not a valid port\n",
+ port);
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ serve_port = (uint16_t) port;
+
+ return GNUNET_OK;
+}
+
+
+/* Developer logic for supporting the `-f' option. */
+#if HAVE_DEVELOPER
+
+/**
+ * Option `-f' (specifies an input file to give to the HTTP server).
+ */
+static char *input_filename;
+
+
+/**
+ * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename
+ * as the input for the request. If launching the client worked,
+ * run the #TMH_KS_loop() event loop as usual.
+ *
+ * @return #GNUNET_OK
+ */
+static int
+run_fake_client ()
+{
+ pid_t cld;
+ char ports[6];
+ int fd;
+ int ret;
+ int status;
+
+ fd = open (input_filename, O_RDONLY);
+ if (-1 == fd)
+ {
+ fprintf (stderr,
+ "Failed to open `%s': %s\n",
+ input_filename,
+ strerror (errno));
+ return GNUNET_SYSERR;
+ }
+ /* Fake HTTP client request with #input_filename as input.
+ We do this using the nc tool. */
+ GNUNET_snprintf (ports,
+ sizeof (ports),
+ "%u",
+ serve_port);
+ if (0 == (cld = fork()))
+ {
+ GNUNET_break (0 == close (0));
+ GNUNET_break (0 == dup2 (fd, 0));
+ GNUNET_break (0 == close (fd));
+ if ( (0 != execlp ("nc",
+ "nc",
+ "localhost",
+ ports,
+ "-w", "30",
+ NULL)) &&
+ (0 != execlp ("ncat",
+ "ncat",
+ "localhost",
+ ports,
+ "-i", "30",
+ NULL)) )
+ {
+ fprintf (stderr,
+ "Failed to run both `nc' and `ncat': %s\n",
+ strerror (errno));
+ }
+ _exit (1);
+ }
+ /* parent process */
+ GNUNET_break (0 == close (fd));
+ ret = TMH_KS_loop ();
+ if (cld != waitpid (cld, &status, 0))
+ fprintf (stderr,
+ "Waiting for `nc' child failed: %s\n",
+ strerror (errno));
+ return ret;
+}
+
+
+/**
+ * Signature of the callback used by MHD to notify the application
+ * about completed connections. If we are running in test-mode with
+ * an #input_filename, this function is used to terminate the HTTPD
+ * after the first request has been processed.
+ *
+ * @param cls client-defined closure, NULL
+ * @param connection connection handle (ignored)
+ * @param socket_context socket-specific pointer (ignored)
+ * @param toe reason for connection notification
+ */
+static void
+connection_done (void *cls,
+ struct MHD_Connection *connection,
+ void **socket_context,
+ enum MHD_ConnectionNotificationCode toe)
+{
+ /* We only act if the connection is closed. */
+ if (MHD_CONNECTION_NOTIFY_CLOSED != toe)
+ return;
+ /* This callback is also present if the option wasn't, so
+ make sure the option was actually set. */
+ if (NULL == input_filename)
+ return;
+ /* We signal ourselves to terminate. */
+ if (0 != kill (getpid(),
+ SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "kill");
+}
+
+/* end of HAVE_DEVELOPER */
+#endif
+
+
+/**
+ * Function called for logging by MHD.
+ *
+ * @param cls closure, NULL
+ * @param fm format string (`printf()`-style)
+ * @param ap arguments to @a fm
+ */
+static void
+handle_mhd_logs (void *cls,
+ const char *fm,
+ va_list ap)
+{
+ char buf[2048];
+
+ vsnprintf (buf,
+ sizeof (buf),
+ fm,
+ ap);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+ "libmicrohttpd",
+ "%s",
+ buf);
+}
+
+
+/**
+ * The main function of the taler-exchange-httpd server ("the exchange").
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'C', "connection-close", NULL,
+ "force HTTP connections to be closed after each request", 0,
+ &GNUNET_GETOPT_set_one, &TMH_exchange_connection_close},
+ {'d', "exchange-dir", "DIR",
+ "exchange directory with configuration and keys for operating the exchange", 1,
+ &GNUNET_GETOPT_set_filename, &TMH_exchange_directory},
+ {'t', "timeout", "SECONDS",
+ "after how long do connections timeout by default (in seconds)", 1,
+ &GNUNET_GETOPT_set_uint, &connection_timeout},
+#if HAVE_DEVELOPER
+ {'f', "file-input", "FILENAME",
+ "run in test-mode using FILENAME as the HTTP request to process", 1,
+ &GNUNET_GETOPT_set_filename, &input_filename},
+#endif
+ TALER_GETOPT_OPTION_HELP ("HTTP server providing a RESTful API to access a Taler exchange"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-httpd",
+ "INFO",
+ NULL));
+ if (0 >=
+ GNUNET_GETOPT_run ("taler-exchange-httpd",
+ options,
+ argc, argv))
+ return 1;
+ if (NULL == TMH_exchange_directory)
+ {
+ fprintf (stderr,
+ "Exchange directory not specified\n");
+ return 1;
+ }
+
+ if (GNUNET_OK !=
+ exchange_serve_process_config (TMH_exchange_directory))
+ return 1;
+
+ mydaemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ serve_port,
+ NULL, NULL,
+ &handle_mhd_request, NULL,
+ MHD_OPTION_EXTERNAL_LOGGER, &handle_mhd_logs, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL,
+ MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
+#if HAVE_DEVELOPER
+ MHD_OPTION_NOTIFY_CONNECTION, &connection_done, NULL,
+#endif
+ MHD_OPTION_END);
+
+ if (NULL == mydaemon)
+ {
+ fprintf (stderr,
+ "Failed to start HTTP server.\n");
+ return 1;
+ }
+#if HAVE_DEVELOPER
+ if (NULL != input_filename)
+ {
+ /* run only the testfile input, then terminate */
+ ret = run_fake_client ();
+ }
+ else
+ {
+ /* normal behavior */
+ ret = TMH_KS_loop ();
+ }
+#else
+ /* normal behavior */
+ ret = TMH_KS_loop ();
+#endif
+
+ switch (ret)
+ {
+ case GNUNET_OK:
+ case GNUNET_SYSERR:
+ MHD_stop_daemon (mydaemon);
+ break;
+ case GNUNET_NO:
+ {
+ MHD_socket sock = MHD_quiesce_daemon (mydaemon);
+
+ /* FIXME #3474: fork another MHD, passing on the listen socket! */
+ while (0 != MHD_get_daemon_info (mydaemon,
+ MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections)
+ sleep (1);
+ MHD_stop_daemon (mydaemon);
+
+ close (sock); /* FIXME: done like this because #3474 is open */
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ MHD_stop_daemon (mydaemon);
+ break;
+ }
+
+ if (GNUNET_YES == TMH_test_mode)
+ {
+ struct TALER_EXCHANGEDB_Session *session;
+
+ session = TMH_plugin->get_session (TMH_plugin->cls,
+ GNUNET_YES);
+ if (NULL == session)
+ GNUNET_break (0);
+ else
+ TMH_plugin->drop_temporary (TMH_plugin->cls,
+ session);
+ }
+ TALER_EXCHANGEDB_plugin_unload (TMH_plugin);
+ TMH_VALIDATION_done ();
+ return (GNUNET_SYSERR == ret) ? 1 : 0;
+}
+
+/* end of taler-exchange-httpd.c */
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
new file mode 100644
index 000000000..5f17eac5b
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd.h
@@ -0,0 +1,128 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd.h
+ * @brief Global declarations for the exchange
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ *
+ * FIXME: Consider which of these need to really be globals...
+ */
+#ifndef TALER_EXCHANGE_HTTPD_H
+#define TALER_EXCHANGE_HTTPD_H
+
+#include <microhttpd.h>
+
+
+/**
+ * Which currency is used by this exchange?
+ */
+extern char *TMH_exchange_currency_string;
+
+/**
+ * Should we return "Connection: close" in each response?
+ */
+extern int TMH_exchange_connection_close;
+
+/**
+ * The exchange's configuration.
+ */
+extern struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Are we running in test mode?
+ */
+extern int TMH_test_mode;
+
+/**
+ * Main directory with exchange data.
+ */
+extern char *TMH_exchange_directory;
+
+/**
+ * Master public key (according to the
+ * configuration in the exchange directory).
+ */
+extern struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
+
+/**
+ * Private key of the exchange we use to sign messages.
+ */
+extern struct GNUNET_CRYPTO_EddsaPrivateKey TMH_exchange_private_signing_key;
+
+/**
+ * Our DB plugin.
+ */
+extern struct TALER_EXCHANGEDB_Plugin *TMH_plugin;
+
+
+/**
+ * @brief Struct describing an URL and the handler for it.
+ */
+struct TMH_RequestHandler
+{
+
+ /**
+ * URL the handler is for.
+ */
+ const char *url;
+
+ /**
+ * Method the handler is for, NULL for "all".
+ */
+ const char *method;
+
+ /**
+ * Mime type to use in reply (hint, can be NULL).
+ */
+ const char *mime_type;
+
+ /**
+ * Raw data for the @e handler
+ */
+ const void *data;
+
+ /**
+ * Number of bytes in @e data, 0 for 0-terminated.
+ */
+ size_t data_size;
+
+ /**
+ * Function to call to handle the request.
+ *
+ * @param rh this struct
+ * @param mime_type the @e mime_type for the reply (hint, can be NULL)
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+ int (*handler)(struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+ /**
+ * Default response code.
+ */
+ int response_code;
+};
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_admin.c b/src/exchange/taler-exchange-httpd_admin.c
new file mode 100644
index 000000000..575df7bb0
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_admin.c
@@ -0,0 +1,164 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_admin.c
+ * @brief Handle /admin/ requests
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include "taler-exchange-httpd_admin.h"
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_validation.h"
+
+
+/**
+ * Check permissions (we only allow access to /admin/ from loopback).
+ *
+ * @param connection connection to perform access check for
+ * @return #GNUNET_OK if permitted,
+ * #GNUNET_NO if denied and error was queued,
+ * #GNUNET_SYSERR if denied and we failed to report
+ */
+static int
+check_permissions (struct MHD_Connection *connection)
+{
+ const union MHD_ConnectionInfo *ci;
+ const struct sockaddr *addr;
+ int res;
+
+ ci = MHD_get_connection_info (connection,
+ MHD_CONNECTION_INFO_CLIENT_ADDRESS);
+ if (NULL == ci)
+ {
+ GNUNET_break (0);
+ res = TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to verify client address");
+ return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ addr = ci->client_addr;
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ {
+ const struct sockaddr_in *sin = (const struct sockaddr_in *) addr;
+
+ if (INADDR_LOOPBACK != ntohl (sin->sin_addr.s_addr))
+ {
+ res = TMH_RESPONSE_reply_permission_denied (connection,
+ "/admin/ only allowed via loopback");
+ return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ break;
+ }
+ case AF_INET6:
+ {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr;
+
+ if (! IN6_IS_ADDR_LOOPBACK (&sin6->sin6_addr))
+ {
+ res = TMH_RESPONSE_reply_permission_denied (connection,
+ "/admin/ only allowed via loopback");
+ return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ break;
+ }
+ default:
+ GNUNET_break (0);
+ res = TMH_RESPONSE_reply_internal_error (connection,
+ "Unsupported AF");
+ return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Handle a "/admin/add/incoming" request. Parses the
+ * given "reserve_pub", "amount", "transaction" and "h_wire"
+ * details and adds the respective transaction to the database.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_Amount amount;
+ struct GNUNET_TIME_Absolute at;
+ json_t *wire;
+ json_t *root;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("reserve_pub", &reserve_pub),
+ TMH_PARSE_member_amount ("amount", &amount),
+ TMH_PARSE_member_time_abs ("execution_date", &at),
+ TMH_PARSE_member_object ("wire", &wire),
+ TMH_PARSE_MEMBER_END
+ };
+ int res;
+
+ res = check_permissions (connection);
+ if (GNUNET_OK != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == root) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ json_decref (root);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ json_decref (root);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ if (GNUNET_YES !=
+ TMH_json_validate_wireformat (wire))
+ {
+ GNUNET_break_op (0);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "wire");
+ }
+ res = TMH_DB_execute_admin_add_incoming (connection,
+ &reserve_pub,
+ &amount,
+ at,
+ wire);
+ TMH_PARSE_release_data (spec);
+ return res;
+}
+
+/* end of taler-exchange-httpd_admin.c */
diff --git a/src/exchange/taler-exchange-httpd_admin.h b/src/exchange/taler-exchange-httpd_admin.h
new file mode 100644
index 000000000..d720d61d3
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_admin.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_admin.h
+ * @brief Handle /admin/ requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_ADMIN_H
+#define TALER_EXCHANGE_HTTPD_ADMIN_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+/**
+ * Handle a "/admin/add/incoming" request. Parses the
+ * given "reserve_pub", "amount", "transaction" and "h_wire"
+ * details and adds the respective transaction to the database.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
new file mode 100644
index 000000000..9d04efa9b
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -0,0 +1,1900 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_db.c
+ * @brief High-level (transactional-layer) database operations for the exchange.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <pthread.h>
+#include <jansson.h>
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_keystate.h"
+
+/**
+ * How often should we retry a transaction before giving up
+ * (for transactions resulting in serialization/dead locks only).
+ */
+#define MAX_TRANSACTION_COMMIT_RETRIES 3
+
+/**
+ * Code to begin a transaction, must be inline as we define a block
+ * that ends with #COMMIT_TRANSACTION() within which we perform a number
+ * of retries. Note that this code may call "return" internally, so
+ * it must be called within a function where any cleanup will be done
+ * by the caller. Furthermore, the function's return value must
+ * match that of a #TMH_RESPONSE_reply_internal_db_error() status code.
+ *
+ * @param session session handle
+ * @param connection connection handle
+ */
+#define START_TRANSACTION(session,connection) \
+{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\
+ unsigned int transaction_retries = 0; \
+ int transaction_commit_result; \
+transaction_start_label: /* we will use goto for retries */ \
+ if (GNUNET_OK != \
+ TMH_plugin->start (TMH_plugin->cls, \
+ session)) \
+ { \
+ GNUNET_break (0); \
+ return TMH_RESPONSE_reply_internal_db_error (connection); \
+ }
+
+/**
+ * Code to conclude a transaction, dual to #START_TRANSACTION(). Note
+ * that this code may call "return" internally, so it must be called
+ * within a function where any cleanup will be done by the caller.
+ * Furthermore, the function's return value must match that of a
+ * #TMH_RESPONSE_reply_internal_db_error() status code.
+ *
+ * @param session session handle
+ * @param connection connection handle
+ */
+#define COMMIT_TRANSACTION(session,connection) \
+ transaction_commit_result = \
+ TMH_plugin->commit (TMH_plugin->cls, \
+ session); \
+ if (GNUNET_SYSERR == transaction_commit_result) \
+ { \
+ TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
+ return TMH_RESPONSE_reply_commit_error (connection); \
+ } \
+ if (GNUNET_NO == transaction_commit_result) \
+ { \
+ TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
+ if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \
+ goto transaction_start_label; \
+ TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \
+ transaction_retries, \
+ __FUNCTION__); \
+ return TMH_RESPONSE_reply_commit_error (connection); \
+ } \
+} /* end of scope opened by BEGIN_TRANSACTION */
+
+
+/**
+ * Calculate the total value of all transactions performed.
+ * Stores @a off plus the cost of all transactions in @a tl
+ * in @a ret.
+ *
+ * @param tl transaction list to process
+ * @param off offset to use as the starting value
+ * @param ret where the resulting total is to be stored
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
+ */
+static int
+calculate_transaction_list_totals (struct TALER_EXCHANGEDB_TransactionList *tl,
+ const struct TALER_Amount *off,
+ struct TALER_Amount *ret)
+{
+ struct TALER_Amount spent = *off;
+ struct TALER_EXCHANGEDB_TransactionList *pos;
+
+ for (pos = tl; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_EXCHANGEDB_TT_DEPOSIT:
+ if (GNUNET_OK !=
+ TALER_amount_add (&spent,
+ &spent,
+ &pos->details.deposit->amount_with_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ case TALER_EXCHANGEDB_TT_REFRESH_MELT:
+ if (GNUNET_OK !=
+ TALER_amount_add (&spent,
+ &spent,
+ &pos->details.melt->amount_with_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ }
+ }
+ *ret = spent;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Execute a deposit. The validity of the coin and signature
+ * have already been checked. The database must now check that
+ * the coin is not (double or over) spent, and execute the
+ * transaction (record details, generate success or failure response).
+ *
+ * @param connection the MHD connection to handle
+ * @param deposit information about the deposit
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_deposit (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_Deposit *deposit)
+{
+ struct TALER_EXCHANGEDB_Session *session;
+ struct TALER_EXCHANGEDB_TransactionList *tl;
+ struct TALER_Amount spent;
+ struct TALER_Amount value;
+ struct TALER_Amount amount_without_fee;
+ struct TMH_KS_StateHandle *mks;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ int ret;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (GNUNET_YES ==
+ TMH_plugin->have_deposit (TMH_plugin->cls,
+ session,
+ deposit))
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_subtract (&amount_without_fee,
+ &deposit->amount_with_fee,
+ &deposit->deposit_fee));
+ return TMH_RESPONSE_reply_deposit_success (connection,
+ &deposit->coin.coin_pub,
+ &deposit->h_wire,
+ &deposit->h_contract,
+ deposit->transaction_id,
+ deposit->timestamp,
+ deposit->refund_deadline,
+ &deposit->merchant_pub,
+ &amount_without_fee);
+ }
+ mks = TMH_KS_acquire ();
+ dki = TMH_KS_denomination_key_lookup (mks,
+ &deposit->coin.denom_pub,
+ TMH_KS_DKU_DEPOSIT);
+ if (NULL == dki)
+ {
+ TMH_KS_release (mks);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "denom_pub");
+ }
+ TALER_amount_ntoh (&value,
+ &dki->issue.properties.value);
+ TMH_KS_release (mks);
+
+ START_TRANSACTION (session, connection);
+
+ /* fee for THIS transaction */
+ spent = deposit->amount_with_fee;
+ /* add cost of all previous transactions */
+ tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls,
+ session,
+ &deposit->coin.coin_pub);
+ if (GNUNET_OK !=
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
+ {
+ TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
+ tl);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ /* Check that cost of all transactions is smaller than
+ the value of the coin. */
+ if (0 < TALER_amount_cmp (&spent,
+ &value))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ ret = TMH_RESPONSE_reply_deposit_insufficient_funds (connection,
+ tl);
+ TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
+ tl);
+ return ret;
+ }
+ TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
+ tl);
+
+ if (GNUNET_OK !=
+ TMH_plugin->insert_deposit (TMH_plugin->cls,
+ session,
+ deposit))
+ {
+ TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ COMMIT_TRANSACTION(session, connection);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_subtract (&amount_without_fee,
+ &deposit->amount_with_fee,
+ &deposit->deposit_fee));
+ return TMH_RESPONSE_reply_deposit_success (connection,
+ &deposit->coin.coin_pub,
+ &deposit->h_wire,
+ &deposit->h_contract,
+ deposit->transaction_id,
+ deposit->timestamp,
+ deposit->refund_deadline,
+ &deposit->merchant_pub,
+ &amount_without_fee);
+}
+
+
+/**
+ * Execute a /reserve/status. Given the public key of a reserve,
+ * return the associated transaction history.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve_pub public key of the reserve to check
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_reserve_status (struct MHD_Connection *connection,
+ const struct TALER_ReservePublicKeyP *reserve_pub)
+{
+ struct TALER_EXCHANGEDB_Session *session;
+ struct TALER_EXCHANGEDB_ReserveHistory *rh;
+ int res;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ rh = TMH_plugin->get_reserve_history (TMH_plugin->cls,
+ session,
+ reserve_pub);
+ if (NULL == rh)
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s, s:s}",
+ "error", "Reserve not found",
+ "parameter", "withdraw_pub");
+ res = TMH_RESPONSE_reply_reserve_status_success (connection,
+ rh);
+ TMH_plugin->free_reserve_history (TMH_plugin->cls,
+ rh);
+ return res;
+}
+
+
+/**
+ * Try to execute /reserve/withdraw transaction.
+ *
+ * @param connection request we are handling
+ * @param session database session we are using
+ * @param key_state key state to lookup denomination pubs
+ * @param reserve reserve to withdraw from
+ * @param denomination_pub public key of the denomination requested
+ * @param dki denomination to withdraw
+ * @param blinded_msg blinded message to be signed
+ * @param blinded_msg_len number of bytes in @a blinded_msg
+ * @param h_blind hash of @a blinded_msg
+ * @param signature signature over the withdraw request, to be stored in DB
+ * @param denom_sig[out] where to write the resulting signature
+ * (used to release memory in case of transaction failure
+ * @return MHD result code
+ */
+static int
+execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ struct TMH_KS_StateHandle *key_state,
+ const struct TALER_ReservePublicKeyP *reserve,
+ const struct TALER_DenominationPublicKey *denomination_pub,
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ const char *blinded_msg,
+ size_t blinded_msg_len,
+ const struct GNUNET_HashCode *h_blind,
+ const struct TALER_ReserveSignatureP *signature,
+ struct TALER_DenominationSignature *denom_sig)
+{
+ struct TALER_EXCHANGEDB_ReserveHistory *rh;
+ const struct TALER_EXCHANGEDB_ReserveHistory *pos;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *tdki;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
+ struct TALER_Amount amount_required;
+ struct TALER_Amount deposit_total;
+ struct TALER_Amount withdraw_total;
+ struct TALER_Amount balance;
+ struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
+ int res;
+
+ /* Check if balance is sufficient */
+ START_TRANSACTION (session, connection);
+ rh = TMH_plugin->get_reserve_history (TMH_plugin->cls,
+ session,
+ reserve);
+ if (NULL == rh)
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "reserve_pub");
+ }
+
+ /* calculate amount required including fees */
+ TALER_amount_ntoh (&value,
+ &dki->issue.properties.value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->issue.properties.fee_withdraw);
+
+ if (GNUNET_OK !=
+ TALER_amount_add (&amount_required,
+ &value,
+ &fee_withdraw))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ /* calculate balance of the reserve */
+ res = 0;
+ for (pos = rh; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
+ if (0 == (res & 1))
+ deposit_total = pos->details.bank->amount;
+ else
+ if (GNUNET_OK !=
+ TALER_amount_add (&deposit_total,
+ &deposit_total,
+ &pos->details.bank->amount))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ res |= 1;
+ break;
+ case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
+ tdki = TMH_KS_denomination_key_lookup (key_state,
+ &pos->details.withdraw->denom_pub,
+ TMH_KS_DKU_WITHDRAW);
+ if (NULL == tdki)
+ {
+ GNUNET_break (0);
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ TALER_amount_ntoh (&value,
+ &tdki->issue.properties.value);
+ if (0 == (res & 2))
+ withdraw_total = value;
+ else
+ if (GNUNET_OK !=
+ TALER_amount_add (&withdraw_total,
+ &withdraw_total,
+ &value))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ res |= 2;
+ break;
+ }
+ }
+ if (0 == (res & 1))
+ {
+ /* did not encounter any deposit operations, how can we have a reserve? */
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (0 == (res & 2))
+ {
+ /* did not encounter any withdraw operations, set to zero */
+ TALER_amount_get_zero (deposit_total.currency,
+ &withdraw_total);
+ }
+ /* All reserve balances should be non-negative */
+ GNUNET_assert (GNUNET_SYSERR !=
+ TALER_amount_subtract (&balance,
+ &deposit_total,
+ &withdraw_total));
+ if (0 < TALER_amount_cmp (&amount_required,
+ &balance))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ res = TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (connection,
+ rh);
+ TMH_plugin->free_reserve_history (TMH_plugin->cls,
+ rh);
+ return res;
+ }
+ TMH_plugin->free_reserve_history (TMH_plugin->cls,
+ rh);
+
+ /* Balance is good, sign the coin! */
+ denom_sig->rsa_signature
+ = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
+ blinded_msg,
+ blinded_msg_len);
+ if (NULL == denom_sig->rsa_signature)
+ {
+ GNUNET_break (0);
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Internal error");
+ }
+ collectable.sig = *denom_sig;
+ collectable.denom_pub = *denomination_pub;
+ collectable.amount_with_fee = amount_required;
+ collectable.withdraw_fee = fee_withdraw;
+ collectable.reserve_pub = *reserve;
+ collectable.h_coin_envelope = *h_blind;
+ collectable.reserve_sig = *signature;
+ if (GNUNET_OK !=
+ TMH_plugin->insert_withdraw_info (TMH_plugin->cls,
+ session,
+ &collectable))
+ {
+ GNUNET_break (0);
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ COMMIT_TRANSACTION (session, connection);
+
+ return TMH_RESPONSE_reply_reserve_withdraw_success (connection,
+ &collectable);
+}
+
+
+
+/**
+ * Execute a "/reserve/withdraw". Given a reserve and a properly signed
+ * request to withdraw a coin, check the balance of the reserve and
+ * if it is sufficient, store the request and return the signed
+ * blinded envelope.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve public key of the reserve
+ * @param denomination_pub public key of the denomination requested
+ * @param blinded_msg blinded message to be signed
+ * @param blinded_msg_len number of bytes in @a blinded_msg
+ * @param signature signature over the withdraw request, to be stored in DB
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
+ const struct TALER_ReservePublicKeyP *reserve,
+ const struct TALER_DenominationPublicKey *denomination_pub,
+ const char *blinded_msg,
+ size_t blinded_msg_len,
+ const struct TALER_ReserveSignatureP *signature)
+{
+ struct TALER_EXCHANGEDB_Session *session;
+ struct TMH_KS_StateHandle *key_state;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
+ struct TALER_DenominationSignature denom_sig;
+ struct GNUNET_HashCode h_blind;
+ int res;
+
+ GNUNET_CRYPTO_hash (blinded_msg,
+ blinded_msg_len,
+ &h_blind);
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ res = TMH_plugin->get_withdraw_info (TMH_plugin->cls,
+ session,
+ &h_blind,
+ &collectable);
+ if (GNUNET_SYSERR == res)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ /* Don't sign again if we have already signed the coin */
+ if (GNUNET_YES == res)
+ {
+ res = TMH_RESPONSE_reply_reserve_withdraw_success (connection,
+ &collectable);
+ GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key);
+ return res;
+ }
+ GNUNET_assert (GNUNET_NO == res);
+
+ key_state = TMH_KS_acquire ();
+ dki = TMH_KS_denomination_key_lookup (key_state,
+ denomination_pub,
+ TMH_KS_DKU_WITHDRAW);
+ if (NULL == dki)
+ {
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error",
+ "Denomination not found");
+ }
+ denom_sig.rsa_signature = NULL;
+ res = execute_reserve_withdraw_transaction (connection,
+ session,
+ key_state,
+ reserve,
+ denomination_pub,
+ dki,
+ blinded_msg,
+ blinded_msg_len,
+ &h_blind,
+ signature,
+ &denom_sig);
+ if (NULL != denom_sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature);
+ TMH_KS_release (key_state);
+ return res;
+}
+
+
+/**
+ * Parse coin melt requests from a JSON object and write them to
+ * the database.
+ *
+ * @param connection the connection to send errors to
+ * @param session the database connection
+ * @param key_state the exchange's key state
+ * @param session_hash hash identifying the refresh session
+ * @param coin_details details about the coin being melted
+ * @param oldcoin_index what is the number assigned to this coin
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if an error message was generated,
+ * #GNUNET_SYSERR on internal errors (no response generated)
+ */
+static int
+refresh_accept_melts (struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TMH_KS_StateHandle *key_state,
+ const struct GNUNET_HashCode *session_hash,
+ const struct TMH_DB_MeltDetails *coin_details,
+ uint16_t oldcoin_index)
+{
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk;
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki;
+ struct TALER_EXCHANGEDB_TransactionList *tl;
+ struct TALER_Amount coin_value;
+ struct TALER_Amount coin_residual;
+ struct TALER_Amount spent;
+ struct TALER_EXCHANGEDB_RefreshMelt melt;
+ int res;
+
+ dk = TMH_KS_denomination_key_lookup (key_state,
+ &coin_details->coin_info.denom_pub,
+ TMH_KS_DKU_DEPOSIT);
+ if (NULL == dk)
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_arg_unknown (connection,
+ "denom_pub"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ dki = &dk->issue;
+ TALER_amount_ntoh (&coin_value,
+ &dki->properties.value);
+ /* fee for THIS transaction; the melt amount includes the fee! */
+ spent = coin_details->melt_amount_with_fee;
+ /* add historic transaction costs of this coin */
+ tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls,
+ session,
+ &coin_details->coin_info.coin_pub);
+ if (GNUNET_OK !=
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
+ {
+ GNUNET_break (0);
+ TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
+ tl);
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ /* Refuse to refresh when the coin's value is insufficient
+ for the cost of all transactions. */
+ if (TALER_amount_cmp (&coin_value,
+ &spent) < 0)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_subtract (&coin_residual,
+ &spent,
+ &coin_details->melt_amount_with_fee));
+ res = (MHD_YES ==
+ TMH_RESPONSE_reply_refresh_melt_insufficient_funds (connection,
+ &coin_details->coin_info.coin_pub,
+ coin_value,
+ tl,
+ coin_details->melt_amount_with_fee,
+ coin_residual))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
+ tl);
+ return res;
+ }
+ TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
+ tl);
+
+ melt.coin = coin_details->coin_info;
+ melt.coin_sig = coin_details->melt_sig;
+ melt.session_hash = *session_hash;
+ melt.amount_with_fee = coin_details->melt_amount_with_fee;
+ melt.melt_fee = coin_details->melt_fee;
+ if (GNUNET_OK !=
+ TMH_plugin->insert_refresh_melt (TMH_plugin->cls,
+ session,
+ oldcoin_index,
+ &melt))
+ {
+ GNUNET_break (0);
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Execute a "/refresh/melt". We have been given a list of valid
+ * coins and a request to melt them into the given
+ * @a refresh_session_pub. Check that the coins all have the
+ * required value left and if so, store that they have been
+ * melted and confirm the melting operation to the client.
+ *
+ * @param connection the MHD connection to handle
+ * @param session_hash hash code of the session the coins are melted into
+ * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array
+ * @param denom_pubs public keys of the coins we want to withdraw in the end
+ * @param coin_count number of entries in @a coin_melt_details, size of y-dimension of @a commit_link array
+ * @param coin_melt_details signatures and (residual) value of the respective coin should be melted
+ * @param commit_coin 2d array of coin commitments (what the exchange is to sign
+ * once the "/refres/reveal" of cut and choose is done),
+ * x-dimension must be #TALER_CNC_KAPPA
+ * @param commit_link 2d array of coin link commitments (what the exchange is
+ * to return via "/refresh/link" to enable linkage in the
+ * future)
+ * x-dimension must be #TALER_CNC_KAPPA
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int num_new_denoms,
+ const struct TALER_DenominationPublicKey *denom_pubs,
+ unsigned int coin_count,
+ const struct TMH_DB_MeltDetails *coin_melt_details,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin,
+ struct TALER_RefreshCommitLinkP *const* commit_link)
+{
+ struct TMH_KS_StateHandle *key_state;
+ struct TALER_EXCHANGEDB_RefreshSession refresh_session;
+ struct TALER_EXCHANGEDB_Session *session;
+ int res;
+ unsigned int i;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ START_TRANSACTION (session, connection);
+ res = TMH_plugin->get_refresh_session (TMH_plugin->cls,
+ session,
+ session_hash,
+ &refresh_session);
+ if (GNUNET_YES == res)
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ res = TMH_RESPONSE_reply_refresh_melt_success (connection,
+ session_hash,
+ refresh_session.noreveal_index);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ if (GNUNET_SYSERR == res)
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ /* store 'global' session data */
+ refresh_session.num_oldcoins = coin_count;
+ refresh_session.num_newcoins = num_new_denoms;
+ refresh_session.noreveal_index
+ = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
+ TALER_CNC_KAPPA);
+ if (GNUNET_OK !=
+ (res = TMH_plugin->create_refresh_session (TMH_plugin->cls,
+ session,
+ session_hash,
+ &refresh_session)))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ /* Melt old coins and check that they had enough residual value */
+ key_state = TMH_KS_acquire ();
+ for (i=0;i<coin_count;i++)
+ {
+ if (GNUNET_OK !=
+ (res = refresh_accept_melts (connection,
+ session,
+ key_state,
+ session_hash,
+ &coin_melt_details[i],
+ i)))
+ {
+ TMH_KS_release (key_state);
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ }
+ TMH_KS_release (key_state);
+
+ /* store requested new denominations */
+ if (GNUNET_OK !=
+ TMH_plugin->insert_refresh_order (TMH_plugin->cls,
+ session,
+ session_hash,
+ num_new_denoms,
+ denom_pubs))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ for (i = 0; i < TALER_CNC_KAPPA; i++)
+ {
+ if (GNUNET_OK !=
+ TMH_plugin->insert_refresh_commit_coins (TMH_plugin->cls,
+ session,
+ session_hash,
+ i,
+ num_new_denoms,
+ commit_coin[i]))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ }
+ for (i = 0; i < TALER_CNC_KAPPA; i++)
+ {
+ if (GNUNET_OK !=
+ TMH_plugin->insert_refresh_commit_links (TMH_plugin->cls,
+ session,
+ session_hash,
+ i,
+ coin_count,
+ commit_link[i]))
+ {
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ }
+
+ COMMIT_TRANSACTION (session, connection);
+ return TMH_RESPONSE_reply_refresh_melt_success (connection,
+ session_hash,
+ refresh_session.noreveal_index);
+}
+
+
+/**
+ * Send an error response with the details of the original melt
+ * commitment and the location of the mismatch.
+ *
+ * @param connection the MHD connection to handle
+ * @param session database connection to use
+ * @param session_hash hash of session to query
+ * @param off commitment offset to check
+ * @param index index of the mismatch
+ * @param object_name name of the object with the problem
+ * @return #GNUNET_NO if we generated the error message
+ * #GNUNET_SYSERR if we could not even generate an error message
+ */
+static int
+send_melt_commitment_error (struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int off,
+ unsigned int index,
+ const char *object_name)
+{
+ struct TALER_EXCHANGEDB_MeltCommitment *mc;
+ int ret;
+
+ mc = TMH_plugin->get_melt_commitment (TMH_plugin->cls,
+ session,
+ session_hash);
+ if (NULL == mc)
+ {
+ GNUNET_break (0);
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_internal_error (connection,
+ "Melt commitment assembly"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_refresh_reveal_missmatch (connection,
+ mc,
+ off,
+ index,
+ object_name))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ TMH_plugin->free_melt_commitment (TMH_plugin->cls,
+ mc);
+ return ret;
+}
+
+
+/**
+ * Check if the given @a transfer_privs correspond to an honest
+ * commitment for the given session.
+ * Checks that the transfer private keys match their commitments.
+ * Then derives the shared secret for each #TALER_CNC_KAPPA, and check that they match.
+ *
+ * @param connection the MHD connection to handle
+ * @param session database connection to use
+ * @param session_hash hash of session to query
+ * @param off commitment offset to check
+ * @param num_oldcoins size of the @a transfer_privs and @a melts arrays
+ * @param transfer_privs private transfer keys
+ * @param melts array of melted coins
+ * @param num_newcoins number of newcoins being generated
+ * @param denom_pubs array of @a num_newcoins keys for the new coins
+ * @return #GNUNET_OK if the committment was honest,
+ * #GNUNET_NO if there was a problem and we generated an error message
+ * #GNUNET_SYSERR if we could not even generate an error message
+ */
+static int
+check_commitment (struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int off,
+ unsigned int num_oldcoins,
+ const struct TALER_TransferPrivateKeyP *transfer_privs,
+ const struct TALER_EXCHANGEDB_RefreshMelt *melts,
+ unsigned int num_newcoins,
+ const struct TALER_DenominationPublicKey *denom_pubs)
+{
+ unsigned int j;
+ struct TALER_LinkSecretP last_shared_secret;
+ int secret_initialized = GNUNET_NO;
+ struct TALER_RefreshCommitLinkP *commit_links;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
+
+ commit_links = GNUNET_malloc (num_oldcoins *
+ sizeof (struct TALER_RefreshCommitLinkP));
+ if (GNUNET_OK !=
+ TMH_plugin->get_refresh_commit_links (TMH_plugin->cls,
+ session,
+ session_hash,
+ off,
+ num_oldcoins,
+ commit_links))
+ {
+ GNUNET_break (0);
+ GNUNET_free (commit_links);
+ return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
+ for (j = 0; j < num_oldcoins; j++)
+ {
+ struct TALER_LinkSecretP shared_secret;
+ struct TALER_TransferPublicKeyP transfer_pub_check;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[j].ecdhe_priv,
+ &transfer_pub_check.ecdhe_pub);
+ if (0 !=
+ memcmp (&transfer_pub_check,
+ &commit_links[j].transfer_pub,
+ sizeof (struct TALER_TransferPublicKeyP)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "transfer keys do not match\n");
+ GNUNET_free (commit_links);
+ return send_melt_commitment_error (connection,
+ session,
+ session_hash,
+ off,
+ j,
+ "transfer key");
+ }
+
+ if (GNUNET_OK !=
+ TALER_link_decrypt_secret (&commit_links[j].shared_secret_enc,
+ &transfer_privs[j],
+ &melts[j].coin.coin_pub,
+ &shared_secret))
+ {
+ GNUNET_free (commit_links);
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_internal_error (connection,
+ "Transfer secret decryption error"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ if (GNUNET_NO == secret_initialized)
+ {
+ secret_initialized = GNUNET_YES;
+ last_shared_secret = shared_secret;
+ }
+ else if (0 != memcmp (&shared_secret,
+ &last_shared_secret,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "shared secrets do not match\n");
+ GNUNET_free (commit_links);
+ return send_melt_commitment_error (connection,
+ session,
+ session_hash,
+ off,
+ j,
+ "transfer secret");
+ }
+ }
+ GNUNET_break (GNUNET_YES == secret_initialized);
+ GNUNET_free (commit_links);
+
+ /* Check that the commitments for all new coins were correct */
+ commit_coins = GNUNET_malloc (num_newcoins *
+ sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin));
+
+ if (GNUNET_OK !=
+ TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls,
+ session,
+ session_hash,
+ off,
+ num_newcoins,
+ commit_coins))
+ {
+ GNUNET_break (0);
+ GNUNET_free (commit_coins);
+ return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
+ for (j = 0; j < num_newcoins; j++)
+ {
+ struct TALER_RefreshLinkDecrypted *link_data;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode h_msg;
+ char *buf;
+ size_t buf_len;
+
+ link_data = TALER_refresh_decrypt (commit_coins[j].refresh_link,
+ &last_shared_secret);
+ if (NULL == link_data)
+ {
+ GNUNET_break (0);
+ GNUNET_free (commit_coins);
+ return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection,
+ "Decryption error"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&link_data->coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash (&coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP),
+ &h_msg);
+ if (0 == (buf_len =
+ GNUNET_CRYPTO_rsa_blind (&h_msg,
+ link_data->blinding_key.rsa_blinding_key,
+ denom_pubs[j].rsa_public_key,
+ &buf)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "blind failed\n");
+ GNUNET_free (commit_coins);
+ return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection,
+ "Blinding error"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
+ if ( (buf_len != commit_coins[j].coin_ev_size) ||
+ (0 != memcmp (buf,
+ commit_coins[j].coin_ev,
+ buf_len)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "blind envelope does not match for k=%u, old=%d\n",
+ off,
+ (int) j);
+ GNUNET_free (commit_coins);
+ return send_melt_commitment_error (connection,
+ session,
+ session_hash,
+ off,
+ j,
+ "envelope");
+ }
+ GNUNET_free (buf);
+ }
+ GNUNET_free (commit_coins);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Exchange a coin as part of a refresh operation. Obtains the
+ * envelope from the database and performs the signing operation.
+ *
+ * @param connection the MHD connection to handle
+ * @param session database connection to use
+ * @param session_hash hash of session to query
+ * @param key_state key state to lookup denomination pubs
+ * @param denom_pub denomination key for the coin to create
+ * @param commit_coin the coin that was committed
+ * @param coin_off number of the coin
+ * @return NULL on error, otherwise signature over the coin
+ */
+static struct TALER_DenominationSignature
+refresh_exchange_coin (struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ struct TMH_KS_StateHandle *key_state,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin,
+ unsigned int coin_off)
+{
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TALER_DenominationSignature ev_sig;
+
+ dki = TMH_KS_denomination_key_lookup (key_state,
+ denom_pub,
+ TMH_KS_DKU_WITHDRAW);
+ if (NULL == dki)
+ {
+ GNUNET_break (0);
+ ev_sig.rsa_signature = NULL;
+ return ev_sig;
+ }
+ ev_sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
+ commit_coin->coin_ev,
+ commit_coin->coin_ev_size);
+ if (NULL == ev_sig.rsa_signature)
+ {
+ GNUNET_break (0);
+ return ev_sig;
+ }
+ if (GNUNET_OK !=
+ TMH_plugin->insert_refresh_out (TMH_plugin->cls,
+ session,
+ session_hash,
+ coin_off,
+ &ev_sig))
+ {
+ GNUNET_break (0);
+ GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature);
+ ev_sig.rsa_signature = NULL;
+ }
+ return ev_sig;
+}
+
+
+/**
+ * The client request was well-formed, now execute the DB transaction
+ * of a "/refresh/reveal" operation. We use the @a ev_sigs and
+ * @a commit_coins to clean up resources after this function returns
+ * as we might experience retries of the database transaction.
+ *
+ * @param connection the MHD connection to handle
+ * @param session database session
+ * @param session_hash hash identifying the refresh session
+ * @param refresh_session information about the refresh operation we are doing
+ * @param melts array of "num_oldcoins" with information about melted coins
+ * @param denom_pubs array of "num_newcoins" denomination keys for the new coins
+ * @param[out] ev_sigs where to store generated signatures for the new coins,
+ * array of length "num_newcoins", memory released by the
+ * caller
+ * @param[out] commit_coins array of length "num_newcoins" to be used for
+ * information about the new coins from the commitment.
+ * @return MHD result code
+ */
+static int
+execute_refresh_reveal_transaction (struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ const struct TALER_EXCHANGEDB_RefreshSession *refresh_session,
+ const struct TALER_EXCHANGEDB_RefreshMelt *melts,
+ const struct TALER_DenominationPublicKey *denom_pubs,
+ struct TALER_DenominationSignature *ev_sigs,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins)
+{
+ unsigned int j;
+ struct TMH_KS_StateHandle *key_state;
+
+ START_TRANSACTION (session, connection);
+ if (GNUNET_OK !=
+ TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls,
+ session,
+ session_hash,
+ refresh_session->noreveal_index,
+ refresh_session->num_newcoins,
+ commit_coins))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ key_state = TMH_KS_acquire ();
+ for (j=0;j<refresh_session->num_newcoins;j++)
+ {
+ if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries */
+ ev_sigs[j] = refresh_exchange_coin (connection,
+ session,
+ session_hash,
+ key_state,
+ &denom_pubs[j],
+ &commit_coins[j],
+ j);
+ if (NULL == ev_sigs[j].rsa_signature)
+ {
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ }
+ TMH_KS_release (key_state);
+ COMMIT_TRANSACTION (session, connection);
+ return TMH_RESPONSE_reply_refresh_reveal_success (connection,
+ refresh_session->num_newcoins,
+ ev_sigs);
+}
+
+
+/**
+ * Execute a "/refresh/reveal". The client is revealing to us the
+ * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins. Verify that the
+ * revealed transfer keys would allow linkage to the blinded coins,
+ * and if so, return the signed coins for corresponding to the set of
+ * coins that was not chosen.
+ *
+ * @param connection the MHD connection to handle
+ * @param session_hash hash identifying the refresh session
+ * @param num_oldcoins size of y-dimension of @a transfer_privs array
+ * @param transfer_privs array with the revealed transfer keys,
+ * x-dimension must be #TALER_CNC_KAPPA - 1
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int num_oldcoins,
+ struct TALER_TransferPrivateKeyP **transfer_privs)
+{
+ int res;
+ struct TALER_EXCHANGEDB_Session *session;
+ struct TALER_EXCHANGEDB_RefreshSession refresh_session;
+ struct TALER_EXCHANGEDB_RefreshMelt *melts;
+ struct TALER_DenominationPublicKey *denom_pubs;
+ struct TALER_DenominationSignature *ev_sigs;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
+ unsigned int i;
+ unsigned int j;
+ unsigned int off;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ res = TMH_plugin->get_refresh_session (TMH_plugin->cls,
+ session,
+ session_hash,
+ &refresh_session);
+ if (GNUNET_NO == res)
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "session_hash");
+ if (GNUNET_SYSERR == res)
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ if (0 == refresh_session.num_oldcoins)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+
+ melts = GNUNET_malloc (refresh_session.num_oldcoins *
+ sizeof (struct TALER_EXCHANGEDB_RefreshMelt));
+ for (j=0;j<refresh_session.num_oldcoins;j++)
+ {
+ if (GNUNET_OK !=
+ TMH_plugin->get_refresh_melt (TMH_plugin->cls,
+ session,
+ session_hash,
+ j,
+ &melts[j]))
+ {
+ GNUNET_break (0);
+ for (i=0;i<j;i++)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
+ }
+ GNUNET_free (melts);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ }
+ denom_pubs = GNUNET_malloc (refresh_session.num_newcoins *
+ sizeof (struct TALER_DenominationPublicKey));
+ if (GNUNET_OK !=
+ TMH_plugin->get_refresh_order (TMH_plugin->cls,
+ session,
+ session_hash,
+ refresh_session.num_newcoins,
+ denom_pubs))
+ {
+ GNUNET_break (0);
+ GNUNET_free (denom_pubs);
+ for (i=0;i<refresh_session.num_oldcoins;i++)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
+ }
+ GNUNET_free (melts);
+ return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
+
+ off = 0;
+ for (i=0;i<TALER_CNC_KAPPA - 1;i++)
+ {
+ if (i == refresh_session.noreveal_index)
+ off = 1;
+ if (GNUNET_OK !=
+ (res = check_commitment (connection,
+ session,
+ session_hash,
+ i + off,
+ refresh_session.num_oldcoins,
+ transfer_privs[i],
+ melts,
+ refresh_session.num_newcoins,
+ denom_pubs)))
+ {
+ for (j=0;j<refresh_session.num_newcoins;j++)
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
+ GNUNET_free (denom_pubs);
+ for (i=0;i<refresh_session.num_oldcoins;i++)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
+ }
+ GNUNET_free (melts);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+ }
+ for (i=0;i<refresh_session.num_oldcoins;i++)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
+ }
+ GNUNET_free (melts);
+
+ /* Client request OK, start transaction */
+ commit_coins = GNUNET_malloc (refresh_session.num_newcoins *
+ sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin));
+ ev_sigs = GNUNET_malloc (refresh_session.num_newcoins *
+ sizeof (struct TALER_DenominationSignature));
+ res = execute_refresh_reveal_transaction (connection,
+ session,
+ session_hash,
+ &refresh_session,
+ melts,
+ denom_pubs,
+ ev_sigs,
+ commit_coins);
+ for (i=0;i<refresh_session.num_newcoins;i++)
+ if (NULL != ev_sigs[i].rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature);
+ for (j=0;j<refresh_session.num_newcoins;j++)
+ if (NULL != denom_pubs[j].rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
+ GNUNET_free (ev_sigs);
+ GNUNET_free (denom_pubs);
+ GNUNET_free (commit_coins);
+ return res;
+}
+
+
+/**
+ * Closure for #handle_transfer_data().
+ */
+struct HTD_Context
+{
+
+ /**
+ * Session link data we collect.
+ */
+ struct TMH_RESPONSE_LinkSessionInfo *sessions;
+
+ /**
+ * Database session. Nothing to do with @a sessions.
+ */
+ struct TALER_EXCHANGEDB_Session *session;
+
+ /**
+ * MHD connection, for queueing replies.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * Number of sessions the coin was melted into.
+ */
+ unsigned int num_sessions;
+
+ /**
+ * How are we expected to proceed. #GNUNET_SYSERR if we
+ * failed to return an error (should return #MHD_NO).
+ * #GNUNET_NO if we succeeded in queueing an MHD error
+ * (should return #MHD_YES from #TMH_execute_refresh_link),
+ * #GNUNET_OK if we should call #TMH_RESPONSE_reply_refresh_link_success().
+ */
+ int status;
+};
+
+
+/**
+ * Function called with the session hashes and transfer secret
+ * information for a given coin. Gets the linkage data and
+ * builds the reply for the client.
+ *
+ *
+ * @param cls closure, a `struct HTD_Context`
+ * @param session_hash a session the coin was melted in
+ * @param transfer_pub public transfer key for the session
+ * @param shared_secret_enc set to shared secret for the session
+ */
+static void
+handle_transfer_data (void *cls,
+ const struct GNUNET_HashCode *session_hash,
+ const struct TALER_TransferPublicKeyP *transfer_pub,
+ const struct TALER_EncryptedLinkSecretP *shared_secret_enc)
+{
+ struct HTD_Context *ctx = cls;
+ struct TALER_EXCHANGEDB_LinkDataList *ldl;
+ struct TMH_RESPONSE_LinkSessionInfo *lsi;
+
+ if (GNUNET_OK != ctx->status)
+ return;
+ ldl = TMH_plugin->get_link_data_list (TMH_plugin->cls,
+ ctx->session,
+ session_hash);
+ if (NULL == ldl)
+ {
+ ctx->status = GNUNET_NO;
+ if (MHD_NO ==
+ TMH_RESPONSE_reply_json_pack (ctx->connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error",
+ "link data not found (link)"))
+ ctx->status = GNUNET_SYSERR;
+ return;
+ }
+ GNUNET_array_grow (ctx->sessions,
+ ctx->num_sessions,
+ ctx->num_sessions + 1);
+ lsi = &ctx->sessions[ctx->num_sessions - 1];
+ lsi->transfer_pub = *transfer_pub;
+ lsi->shared_secret_enc = *shared_secret_enc;
+ lsi->ldl = ldl;
+}
+
+
+/**
+ * Execute a "/refresh/link". Returns the linkage information that
+ * will allow the owner of a coin to follow the refresh trail to
+ * the refreshed coin.
+ *
+ * @param connection the MHD connection to handle
+ * @param coin_pub public key of the coin to link
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_refresh_link (struct MHD_Connection *connection,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub)
+{
+ struct HTD_Context ctx;
+ int res;
+ unsigned int i;
+
+ if (NULL == (ctx.session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ ctx.connection = connection;
+ ctx.num_sessions = 0;
+ ctx.sessions = NULL;
+ ctx.status = GNUNET_OK;
+ res = TMH_plugin->get_transfer (TMH_plugin->cls,
+ ctx.session,
+ coin_pub,
+ &handle_transfer_data,
+ &ctx);
+ if (GNUNET_SYSERR == ctx.status)
+ {
+ res = MHD_NO;
+ goto cleanup;
+ }
+ if (GNUNET_NO == ctx.status)
+ {
+ res = MHD_YES;
+ goto cleanup;
+ }
+ GNUNET_assert (GNUNET_OK == ctx.status);
+ if (0 == ctx.num_sessions)
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "coin_pub");
+ res = TMH_RESPONSE_reply_refresh_link_success (connection,
+ ctx.num_sessions,
+ ctx.sessions);
+ cleanup:
+ for (i=0;i<ctx.num_sessions;i++)
+ TMH_plugin->free_link_data_list (TMH_plugin->cls,
+ ctx.sessions[i].ldl);
+ GNUNET_free_non_null (ctx.sessions);
+ return res;
+}
+
+
+/**
+ * Add an incoming transaction to the database. Checks if the
+ * transaction is fresh (not a duplicate) and if so adds it to
+ * the database.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve_pub public key of the reserve
+ * @param amount amount to add to the reserve
+ * @param execution_time when did we receive the wire transfer
+ * @param wire details about the wire transfer
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute execution_time,
+ json_t *wire)
+{
+ struct TALER_EXCHANGEDB_Session *session;
+ int ret;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ ret = TMH_plugin->reserves_in_insert (TMH_plugin->cls,
+ session,
+ reserve_pub,
+ amount,
+ execution_time,
+ wire);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:s}",
+ "status",
+ (GNUNET_OK == ret)
+ ? "NEW"
+ : "DUP");
+}
+
+
+/**
+ * Closure for #handle_transaction_data.
+ */
+struct WtidTransactionContext
+{
+
+ /**
+ * Total amount of the wire transfer, as calculated by
+ * summing up the individual amounts. To be rounded down
+ * to calculate the real transfer amount at the end.
+ * Only valid if @e is_valid is #GNUNET_YES.
+ */
+ struct TALER_Amount total;
+
+ /**
+ * Public key of the merchant, only valid if @e is_valid
+ * is #GNUNET_YES.
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * Hash of the wire details of the merchant (identical for all
+ * deposits), only valid if @e is_valid is #GNUNET_YES.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * JSON array with details about the individual deposits.
+ */
+ json_t *deposits;
+
+ /**
+ * Initially #GNUNET_NO, if we found no deposits so far. Set to
+ * #GNUNET_YES if we got transaction data, and the database replies
+ * remained consistent with respect to @e merchant_pub and @e h_wire
+ * (as they should). Set to #GNUNET_SYSERR if we encountered an
+ * internal error.
+ */
+ int is_valid;
+
+};
+
+
+/**
+ * Function called with the results of the lookup of the
+ * transaction data for the given wire transfer identifier.
+ *
+ * @param cls our context for transmission
+ * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_contract which contract was this payment about
+ * @param transaction_id merchant's transaction ID for the payment
+ * @param coin_pub which public key was this payment about
+ * @param deposit_value amount contributed by this coin in total
+ * @param deposit_fee deposit fee charged by exchange for this coin
+ */
+static void
+handle_transaction_data (void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *deposit_value,
+ const struct TALER_Amount *deposit_fee)
+{
+ struct WtidTransactionContext *ctx = cls;
+ struct TALER_Amount delta;
+
+ if (GNUNET_SYSERR == ctx->is_valid)
+ return;
+ if (GNUNET_NO == ctx->is_valid)
+ {
+ ctx->merchant_pub = *merchant_pub;
+ ctx->h_wire = *h_wire;
+ ctx->is_valid = GNUNET_YES;
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&ctx->total,
+ deposit_value,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ }
+ else
+ {
+ if ( (0 != memcmp (&ctx->merchant_pub,
+ merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP))) ||
+ (0 != memcmp (&ctx->h_wire,
+ h_wire,
+ sizeof (struct GNUNET_HashCode))) )
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&delta,
+ deposit_value,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_add (&ctx->total,
+ &ctx->total,
+ &delta))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ }
+ /* NOTE: We usually keep JSON stuff out of the _DB file, and this
+ is also ugly if we ever add signatures over this data. (#4135) */
+ json_array_append (ctx->deposits,
+ json_pack ("{s:o, s:o, s:o, s:I, s:o}",
+ "deposit_value", TALER_json_from_amount (deposit_value),
+ "deposit_fee", TALER_json_from_amount (deposit_fee),
+ "H_contract", TALER_json_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "transaction_id", (json_int_t) transaction_id,
+ "coin_pub", TALER_json_from_data (coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP))));
+}
+
+
+/**
+ * Execute a "/wire/deposits". Returns the transaction information
+ * associated with the given wire transfer identifier.
+ *
+ * @param connection the MHD connection to handle
+ * @param wtid wire transfer identifier to resolve
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
+ const struct TALER_WireTransferIdentifierRawP *wtid)
+{
+ int ret;
+ struct WtidTransactionContext ctx;
+ struct TALER_EXCHANGEDB_Session *session;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ ctx.is_valid = GNUNET_NO;
+ ctx.deposits = json_array ();
+ ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls,
+ session,
+ wtid,
+ &handle_transaction_data,
+ &ctx);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ json_decref (ctx.deposits);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (GNUNET_SYSERR == ctx.is_valid)
+ {
+ GNUNET_break (0);
+ json_decref (ctx.deposits);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (GNUNET_NO == ctx.is_valid)
+ {
+ json_decref (ctx.deposits);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "wtid");
+ }
+ return TMH_RESPONSE_reply_wire_deposit_details (connection,
+ &ctx.total,
+ &ctx.merchant_pub,
+ &ctx.h_wire,
+ ctx.deposits);
+}
+
+
+/**
+ * Closure for #handle_wtid_data.
+ */
+struct DepositWtidContext
+{
+
+ /**
+ * Where should we send the reply?
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * Hash of the contract we are looking up.
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Hash of the wire transfer details we are looking up.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Public key we are looking up.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Transaction ID we are looking up.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * MHD result code to return.
+ */
+ int res;
+};
+
+
+/**
+ * Function called with the results of the lookup of the
+ * wire transfer identifier information.
+ *
+ * @param cls our context for transmission
+ * @param wtid raw wire transfer identifier, NULL
+ * if the transaction was not yet done
+ * @param coin_contribution how much did the coin we asked about
+ * contribute to the total transfer value? (deposit value including fee)
+ * @param coin_fee how much did the exchange charge for the deposit fee
+ * @param execution_time when was the transaction done, or
+ * when we expect it to be done (if @a wtid was NULL);
+ * #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
+ * to the exchange
+ */
+static void
+handle_wtid_data (void *cls,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
+ struct GNUNET_TIME_Absolute execution_time)
+{
+ struct DepositWtidContext *ctx = cls;
+ struct TALER_Amount coin_delta;
+
+ if (NULL == wtid)
+ {
+ ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
+ execution_time);
+ }
+ else
+ {
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&coin_delta,
+ coin_contribution,
+ coin_fee))
+ {
+ GNUNET_break (0);
+ ctx->res = TMH_RESPONSE_reply_internal_db_error (ctx->connection);
+ }
+ else
+ {
+ ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection,
+ &ctx->h_contract,
+ &ctx->h_wire,
+ &ctx->coin_pub,
+ &coin_delta,
+ ctx->transaction_id,
+ wtid,
+ execution_time);
+ }
+ }
+}
+
+
+/**
+ * Execute a "/deposit/wtid". Returns the transfer information
+ * associated with the given deposit.
+ *
+ * @param connection the MHD connection to handle
+ * @param h_contract hash of the contract
+ * @param h_wire hash of the wire details
+ * @param coin_pub public key of the coin to link
+ * @param merchant_pub public key of the merchant
+ * @param transaction_id transaction ID of the merchant
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ uint64_t transaction_id)
+{
+ int ret;
+ struct DepositWtidContext ctx;
+ struct TALER_EXCHANGEDB_Session *session;
+
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ ctx.connection = connection;
+ ctx.h_contract = *h_contract;
+ ctx.h_wire = *h_wire;
+ ctx.coin_pub = *coin_pub;
+ ctx.transaction_id = transaction_id;
+ ctx.res = GNUNET_SYSERR;
+ ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls,
+ session,
+ h_contract,
+ h_wire,
+ coin_pub,
+ merchant_pub,
+ transaction_id,
+ &handle_wtid_data,
+ &ctx);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ GNUNET_break (GNUNET_SYSERR == ctx.res);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (GNUNET_NO == ret)
+ {
+ GNUNET_break (GNUNET_SYSERR == ctx.res);
+ return TMH_RESPONSE_reply_deposit_unknown (connection);
+ }
+ if (GNUNET_SYSERR == ctx.res)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "bug resolving deposit wtid");
+ }
+ return ctx.res;
+}
+
+
+/* end of taler-exchange-httpd_db.c */
diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h
new file mode 100644
index 000000000..d6245a702
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_db.h
@@ -0,0 +1,230 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange/taler-exchange-httpd_db.h
+ * @brief High-level (transactional-layer) database operations for the exchange
+ * @author Chrisitan Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_DB_H
+#define TALER_EXCHANGE_HTTPD_DB_H
+
+#include <microhttpd.h>
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Execute a "/deposit". The validity of the coin and signature
+ * have already been checked. The database must now check that
+ * the coin is not (double or over) spent, and execute the
+ * transaction (record details, generate success or failure response).
+ *
+ * @param connection the MHD connection to handle
+ * @param deposit information about the deposit
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_deposit (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_Deposit *deposit);
+
+
+/**
+ * Execute a "/reserve/status". Given the public key of a reserve,
+ * return the associated transaction history.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve_pub public key of the reserve to check
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_reserve_status (struct MHD_Connection *connection,
+ const struct TALER_ReservePublicKeyP *reserve_pub);
+
+
+/**
+ * Execute a "/reserve/withdraw". Given a reserve and a properly signed
+ * request to withdraw a coin, check the balance of the reserve and
+ * if it is sufficient, store the request and return the signed
+ * blinded envelope.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve public key of the reserve
+ * @param denomination_pub public key of the denomination requested
+ * @param blinded_msg blinded message to be signed
+ * @param blinded_msg_len number of bytes in @a blinded_msg
+ * @param signature signature over the withdraw request, to be stored in DB
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
+ const struct TALER_ReservePublicKeyP *reserve,
+ const struct TALER_DenominationPublicKey *denomination_pub,
+ const char *blinded_msg,
+ size_t blinded_msg_len,
+ const struct TALER_ReserveSignatureP *signature);
+
+
+/**
+ * @brief Details about a melt operation of an individual coin.
+ */
+struct TMH_DB_MeltDetails
+{
+
+ /**
+ * Information about the coin being melted.
+ */
+ struct TALER_CoinPublicInfo coin_info;
+
+ /**
+ * Signature allowing the melt (using
+ * a `struct TALER_EXCHANGEDB_RefreshMeltConfirmSignRequestBody`) to sign over.
+ */
+ struct TALER_CoinSpendSignatureP melt_sig;
+
+ /**
+ * How much of the coin's value did the client allow to be melted?
+ * This amount includes the fees, so the final amount contributed
+ * to the melt is this value minus the fee for melting the coin.
+ */
+ struct TALER_Amount melt_amount_with_fee;
+
+ /**
+ * What fee is earned by the exchange? Set delayed during
+ * #verify_coin_public_info().
+ */
+ struct TALER_Amount melt_fee;
+};
+
+
+/**
+ * Execute a "/refresh/melt". We have been given a list of valid
+ * coins and a request to melt them into the given
+ * @a refresh_session_pub. Check that the coins all have the
+ * required value left and if so, store that they have been
+ * melted and confirm the melting operation to the client.
+ *
+ * @param connection the MHD connection to handle
+ * @param session_hash hash code of the session the coins are melted into
+ * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array
+ * @param denom_pubs array of public denomination keys for the refresh (?)
+ * @param coin_count number of entries in @ a coin_melt_details, size of y-dimension of @a commit_link array
+ * @param coin_melt_details signatures and (residual) value of and information about the respective coin to be melted
+ * @param commit_coin 2d array of coin commitments (what the exchange is to sign
+ * once the "/refres/reveal" of cut and choose is done)
+ * @param commit_link 2d array of coin link commitments (what the exchange is
+ * to return via "/refresh/link" to enable linkage in the
+ * future)
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int num_new_denoms,
+ const struct TALER_DenominationPublicKey *denom_pubs,
+ unsigned int coin_count,
+ const struct TMH_DB_MeltDetails *coin_melt_details,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin,
+ struct TALER_RefreshCommitLinkP *const* commit_link);
+
+
+/**
+ * Execute a "/refresh/reveal". The client is revealing to us the
+ * transfer keys for #TALER_CNC_KAPPA-1 sets of coins. Verify that the
+ * revealed transfer keys would allow linkage to the blinded coins,
+ * and if so, return the signed coins for corresponding to the set of
+ * coins that was not chosen.
+ *
+ * @param connection the MHD connection to handle
+ * @param session_hash hash over the refresh session
+ * @param num_oldcoins size of y-dimension of @a transfer_privs array
+ * @param transfer_privs array with the revealed transfer keys, #TALER_CNC_KAPPA is 1st-dimension
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int num_oldcoins,
+ struct TALER_TransferPrivateKeyP **transfer_privs);
+
+
+/**
+ * Execute a "/refresh/link". Returns the linkage information that
+ * will allow the owner of a coin to follow the refresh trail to the
+ * refreshed coin.
+ *
+ * @param connection the MHD connection to handle
+ * @param coin_pub public key of the coin to link
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_refresh_link (struct MHD_Connection *connection,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub);
+
+
+
+/**
+ * Add an incoming transaction to the database.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve_pub public key of the reserve
+ * @param amount amount to add to the reserve
+ * @param execution_time when did we receive the wire transfer
+ * @param wire details about the wire transfer
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute execution_time,
+ json_t *wire);
+
+
+/**
+ * Execute a "/wire/deposits". Returns the transaction information
+ * associated with the given wire transfer identifier.
+ *
+ * @param connection the MHD connection to handle
+ * @param wtid wire transfer identifier to resolve
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
+ const struct TALER_WireTransferIdentifierRawP *wtid);
+
+
+/**
+ * Execute a "/deposit/wtid". Returns the transfer information
+ * associated with the given deposit.
+ *
+ * @param connection the MHD connection to handle
+ * @param h_contract hash of the contract
+ * @param h_wire hash of the wire details
+ * @param coin_pub public key of the coin to link
+ * @param merchant_pub public key of the merchant
+ * @param transaction_id transaction ID of the merchant
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ uint64_t transaction_id);
+
+
+#endif
+/* TALER_EXCHANGE_HTTPD_DB_H */
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
new file mode 100644
index 000000000..629d6f8b5
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -0,0 +1,281 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_deposit.c
+ * @brief Handle /deposit requests; parses the POST and JSON and
+ * verifies the coin signature before handing things off
+ * to the database.
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - ugly if-construction for deposit type
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_deposit.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_validation.h"
+
+
+/**
+ * We have parsed the JSON information about the deposit, do some
+ * basic sanity checks (especially that the signature on the coin is
+ * valid, and that this type of coin exists) and then execute the
+ * deposit.
+ *
+ * @param connection the MHD connection to handle
+ * @param deposit information about the deposit
+ * @return MHD result code
+ */
+static int
+verify_and_execute_deposit (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_Deposit *deposit)
+{
+ struct TMH_KS_StateHandle *key_state;
+ struct TALER_DepositRequestPS dr;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TALER_Amount fee_deposit;
+
+ dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
+ dr.h_contract = deposit->h_contract;
+ dr.h_wire = deposit->h_wire;
+ dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp);
+ dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline);
+ dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &deposit->amount_with_fee);
+ TALER_amount_hton (&dr.deposit_fee,
+ &deposit->deposit_fee);
+ dr.merchant = deposit->merchant_pub;
+ dr.coin_pub = deposit->coin.coin_pub;
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
+ &dr.purpose,
+ &deposit->csig.eddsa_signature,
+ &deposit->coin.coin_pub.eddsa_pub))
+ {
+ TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
+ return TMH_RESPONSE_reply_signature_invalid (connection,
+ "coin_sig");
+ }
+ /* check denomination exists and is valid */
+ key_state = TMH_KS_acquire ();
+ dki = TMH_KS_denomination_key_lookup (key_state,
+ &deposit->coin.denom_pub,
+ TMH_KS_DKU_DEPOSIT);
+ if (NULL == dki)
+ {
+ TMH_KS_release (key_state);
+ TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n");
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "denom_pub");
+ }
+ /* check coin signature */
+ if (GNUNET_YES !=
+ TALER_test_coin_valid (&deposit->coin))
+ {
+ TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_signature_invalid (connection,
+ "ub_sig");
+ }
+ TALER_amount_ntoh (&fee_deposit,
+ &dki->issue.properties.fee_deposit);
+ if (0 < TALER_amount_cmp (&fee_deposit,
+ &deposit->amount_with_fee))
+ {
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_external_error (connection,
+ "deposited amount smaller than depositing fee");
+ }
+ TMH_KS_release (key_state);
+
+ return TMH_DB_execute_deposit (connection,
+ deposit);
+}
+
+
+/**
+ * Handle a "/deposit" request. This function parses the
+ * JSON information and then calls #verify_and_execute_deposit()
+ * to verify the signatures and execute the deposit.
+ *
+ * @param connection the MHD connection to handle
+ * @param root root of the posted JSON
+ * @param amount how much should be deposited
+ * @param wire json describing the wire details (?)
+ * @return MHD result code
+ */
+static int
+parse_and_handle_deposit_request (struct MHD_Connection *connection,
+ const json_t *root,
+ const struct TALER_Amount *amount,
+ json_t *wire)
+{
+ int res;
+ struct TALER_EXCHANGEDB_Deposit deposit;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TMH_KS_StateHandle *ks;
+ struct GNUNET_HashCode my_h_wire;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_denomination_public_key ("denom_pub", &deposit.coin.denom_pub),
+ TMH_PARSE_member_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
+ TMH_PARSE_member_fixed ("coin_pub", &deposit.coin.coin_pub),
+ TMH_PARSE_member_fixed ("merchant_pub", &deposit.merchant_pub),
+ TMH_PARSE_member_fixed ("H_contract", &deposit.h_contract),
+ TMH_PARSE_member_fixed ("H_wire", &deposit.h_wire),
+ TMH_PARSE_member_fixed ("coin_sig", &deposit.csig),
+ TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id),
+ TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp),
+ TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline),
+ TMH_PARSE_member_time_abs ("edate", &deposit.wire_deadline),
+ TMH_PARSE_MEMBER_END
+ };
+
+ memset (&deposit, 0, sizeof (deposit));
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO; /* hard failure */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* failure */
+
+ if (GNUNET_YES !=
+ TMH_json_validate_wireformat (wire))
+ {
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "wire");
+ }
+ if (GNUNET_OK !=
+ TALER_hash_json (wire,
+ &my_h_wire))
+ {
+ TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "wire");
+ }
+ if (0 != memcmp (&deposit.h_wire,
+ &my_h_wire,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ /* Client hashed contract differently than we did, reject */
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "H_wire");
+ }
+ ks = TMH_KS_acquire ();
+ dki = TMH_KS_denomination_key_lookup (ks,
+ &deposit.coin.denom_pub,
+ TMH_KS_DKU_DEPOSIT);
+ if (NULL == dki)
+ {
+ TMH_KS_release (ks);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "denom_pub");
+ }
+ TALER_amount_ntoh (&deposit.deposit_fee,
+ &dki->issue.properties.fee_deposit);
+ TMH_KS_release (ks);
+ deposit.wire = wire;
+ deposit.amount_with_fee = *amount;
+ if (-1 == TALER_amount_cmp (&deposit.amount_with_fee,
+ &deposit.deposit_fee))
+ {
+ /* Total amount smaller than fee, invalid */
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "f");
+ }
+ res = verify_and_execute_deposit (connection,
+ &deposit);
+ TMH_PARSE_release_data (spec);
+ return res;
+}
+
+
+/**
+ * Handle a "/deposit" request. Parses the JSON in the post to find
+ * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if
+ * successful, passes the JSON data to
+ * #parse_and_handle_deposit_request() to further check the details
+ * of the operation specified in the "wire" field of the JSON data.
+ * If everything checks out, this will ultimately lead to the
+ * "/deposit" being executed, or rejected.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ json_t *wire;
+ int res;
+ struct TALER_Amount amount;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_object ("wire", &wire),
+ TMH_PARSE_member_amount ("f", &amount),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ if (GNUNET_OK != res)
+ {
+ json_decref (json);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+ res = parse_and_handle_deposit_request (connection,
+ json,
+ &amount,
+ wire);
+ TMH_PARSE_release_data (spec);
+ json_decref (json);
+ return res;
+}
+
+
+/* end of taler-exchange-httpd_deposit.c */
diff --git a/src/exchange/taler-exchange-httpd_deposit.h b/src/exchange/taler-exchange-httpd_deposit.h
new file mode 100644
index 000000000..6e84573e5
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_deposit.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_deposit.h
+ * @brief Handle /deposit requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_DEPOSIT_H
+#define TALER_EXCHANGE_HTTPD_DEPOSIT_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/deposit" request. Parses the JSON in the post to find
+ * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if
+ * successful, passes the JSON data to
+ * #parse_and_handle_deposit_request() to further check the details
+ * of the operation specified in the "wire" field of the JSON data.
+ * If everything checks out, this will ultimately lead to the
+ * "/deposit" being executed, or rejected.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
new file mode 100644
index 000000000..e278882fe
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -0,0 +1,1011 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_keystate.c
+ * @brief management of our coin signing keys
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <pthread.h>
+#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Snapshot of the (coin and signing) keys (including private keys) of
+ * the exchange. There can be multiple instances of this struct, as it is
+ * reference counted and only destroyed once the last user is done
+ * with it. The current instance is acquired using
+ * #TMH_KS_acquire(). Using this function increases the
+ * reference count. The contents of this structure (except for the
+ * reference counter) should be considered READ-ONLY until it is
+ * ultimately destroyed (as there can be many concurrent users).
+ */
+struct TMH_KS_StateHandle
+{
+ /**
+ * JSON array with denomination keys. (Currently not really used
+ * after initialization.)
+ */
+ json_t *denom_keys_array;
+
+ /**
+ * JSON array with signing keys. (Currently not really used
+ * after initialization.)
+ */
+ json_t *sign_keys_array;
+
+ /**
+ * JSON array with auditor information. (Currently not really used
+ * after initialization.)
+ */
+ json_t *auditors_array;
+
+ /**
+ * Cached JSON text that the exchange will send for a "/keys" request.
+ * Includes our @e TMH_master_public_key public key, the signing and
+ * denomination keys as well as the @e reload_time.
+ */
+ char *keys_json;
+
+ /**
+ * Mapping from denomination keys to denomination key issue struct.
+ * Used to lookup the key by hash.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
+
+ /**
+ * Hash context we used to combine the hashes of all denomination
+ * keys into one big hash.
+ */
+ struct GNUNET_HashContext *hash_context;
+
+ /**
+ * When did we initiate the key reloading?
+ */
+ struct GNUNET_TIME_Absolute reload_time;
+
+ /**
+ * When is the next key invalid and we have to reload? (We also
+ * reload on SIGUSR1.)
+ */
+ struct GNUNET_TIME_Absolute next_reload;
+
+ /**
+ * Exchange signing key that should be used currently.
+ */
+ struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP current_sign_key_issue;
+
+ /**
+ * Reference count. The struct is released when the RC hits zero.
+ */
+ unsigned int refcnt;
+};
+
+
+/**
+ * Exchange key state. Never use directly, instead access via
+ * #TMH_KS_acquire() and #TMH_KS_release().
+ */
+static struct TMH_KS_StateHandle *internal_key_state;
+
+/**
+ * Mutex protecting access to #internal_key_state.
+ */
+static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Pipe used for signaling reloading of our key state.
+ */
+static int reload_pipe[2];
+
+
+/**
+ * Convert the public part of a denomination key issue to a JSON
+ * object.
+ *
+ * @param pk public key of the denomination key
+ * @param dki the denomination key issue
+ * @return a JSON object describing the denomination key isue (public part)
+ */
+static json_t *
+denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk,
+ const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki)
+{
+ struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_Amount fee_deposit;
+ struct TALER_Amount fee_refresh;
+
+ TALER_amount_ntoh (&value,
+ &dki->properties.value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->properties.fee_withdraw);
+ TALER_amount_ntoh (&fee_deposit,
+ &dki->properties.fee_deposit);
+ TALER_amount_ntoh (&fee_refresh,
+ &dki->properties.fee_refresh);
+ return
+ json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
+ "master_sig",
+ TALER_json_from_data (&dki->signature,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature)),
+ "stamp_start",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)),
+ "stamp_expire_withdraw",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)),
+ "stamp_expire_deposit",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_spend)),
+ "stamp_expire_legal",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)),
+ "denom_pub",
+ TALER_json_from_rsa_public_key (pk->rsa_public_key),
+ "value",
+ TALER_json_from_amount (&value),
+ "fee_withdraw",
+ TALER_json_from_amount (&fee_withdraw),
+ "fee_deposit",
+ TALER_json_from_amount (&fee_deposit),
+ "fee_refresh",
+ TALER_json_from_amount (&fee_refresh));
+}
+
+
+/**
+ * Get the relative time value that describes how
+ * far in the future do we want to provide coin keys.
+ *
+ * @return the provide duration
+ */
+static struct GNUNET_TIME_Relative
+TALER_EXCHANGE_conf_duration_provide ()
+{
+ struct GNUNET_TIME_Relative rel;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ "exchange_keys",
+ "lookahead_provide",
+ &rel))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange_keys",
+ "lookahead_provide",
+ "time value required");
+ GNUNET_assert (0);
+ }
+ return rel;
+}
+
+
+/**
+ * Iterator for (re)loading/initializing denomination keys.
+ *
+ * @param cls closure
+ * @param dki the denomination key issue
+ * @param alias coin alias
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+reload_keys_denom_iter (void *cls,
+ const char *alias,
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ struct TMH_KS_StateHandle *ctx = cls;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute horizon;
+ struct GNUNET_HashCode denom_key_hash;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *d2;
+ struct TALER_EXCHANGEDB_Session *session;
+ int res;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Loading denomination key `%s'\n",
+ alias);
+ horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ());
+ if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us >
+ horizon.abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping future denomination key `%s'\n",
+ alias);
+ return GNUNET_OK;
+ }
+ now = GNUNET_TIME_absolute_get ();
+ if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us <
+ now.abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping expired denomination key `%s'\n",
+ alias);
+ return GNUNET_OK;
+ }
+
+ GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+ &denom_key_hash);
+ GNUNET_CRYPTO_hash_context_read (ctx->hash_context,
+ &denom_key_hash,
+ sizeof (struct GNUNET_HashCode));
+ session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode);
+ if (NULL == session)
+ return GNUNET_SYSERR;
+ /* Try to insert DKI into DB until we succeed; note that if the DB
+ failure is persistent, this code may loop forever (as there is no
+ sane alternative, we cannot continue without the DKI being in the
+ DB). */
+ res = GNUNET_SYSERR;
+ while (GNUNET_OK != res)
+ {
+ res = TMH_plugin->start (TMH_plugin->cls,
+ session);
+ if (GNUNET_OK != res)
+ {
+ /* Transaction start failed!? Very bad error, log and retry */
+ GNUNET_break (0);
+ continue;
+ }
+ res = TMH_plugin->get_denomination_info (TMH_plugin->cls,
+ session,
+ &dki->denom_pub,
+ NULL);
+ if (GNUNET_SYSERR == res)
+ {
+ /* Fetch failed!? Very bad error, log and retry */
+ GNUNET_break (0);
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ continue;
+ }
+ if (GNUNET_OK == res)
+ {
+ /* Record exists, we're good, just exit */
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ break;
+ }
+ res = TMH_plugin->insert_denomination_info (TMH_plugin->cls,
+ session,
+ &dki->denom_pub,
+ &dki->issue);
+ if (GNUNET_OK != res)
+ {
+ /* Insert failed!? Very bad error, log and retry */
+ GNUNET_break (0);
+ TMH_plugin->rollback (TMH_plugin->cls,
+ session);
+ continue;
+ }
+ res = TMH_plugin->commit (TMH_plugin->cls,
+ session);
+ /* If commit succeeded, we're done, otherwise we retry; this
+ time without logging, as theroetically commits can fail
+ in a transactional DB due to concurrent activities that
+ cannot be reconciled. This should be rare for DKIs, but
+ as it is possible we just retry until we succeed. */
+ }
+
+ d2 = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation);
+ d2->issue = dki->issue;
+ d2->denom_priv.rsa_private_key
+ = GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key);
+ d2->denom_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
+ res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map,
+ &denom_key_hash,
+ d2,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Duplicate denomination key `%s'\n",
+ alias);
+ GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key);
+ GNUNET_free (d2);
+ return GNUNET_OK;
+ }
+ json_array_append_new (ctx->denom_keys_array,
+ denom_key_issue_to_json (&dki->denom_pub,
+ &dki->issue));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Convert the public part of a sign key issue to a JSON object.
+ *
+ * @param ski the sign key issue
+ * @return a JSON object describing the sign key issue (public part)
+ */
+static json_t *
+sign_key_issue_to_json (const struct TALER_ExchangeSigningKeyValidityPS *ski)
+{
+ return
+ json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}",
+ "stamp_start",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)),
+ "stamp_expire",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)),
+ "stamp_end",
+ TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->end)),
+ "master_pub",
+ TALER_json_from_data (&ski->master_public_key,
+ sizeof (struct TALER_MasterPublicKeyP)),
+ "master_sig",
+ TALER_json_from_data (&ski->signature,
+ sizeof (struct TALER_MasterSignatureP)),
+ "key",
+ TALER_json_from_data (&ski->signkey_pub,
+ sizeof (struct TALER_ExchangePublicKeyP)));
+}
+
+
+/**
+ * Iterator for sign keys.
+ *
+ * @param cls closure with the `struct TMH_KS_StateHandle *`
+ * @param filename name of the file the key came from
+ * @param ski the sign key issue
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+reload_keys_sign_iter (void *cls,
+ const char *filename,
+ const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski)
+{
+ struct TMH_KS_StateHandle *ctx = cls;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute horizon;
+
+ horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ());
+ if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us >
+ horizon.abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping future signing key `%s'\n",
+ filename);
+ return GNUNET_OK;
+ }
+ now = GNUNET_TIME_absolute_get ();
+ if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us <
+ now.abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping expired signing key `%s'\n",
+ filename);
+ return GNUNET_OK;
+ }
+
+ /* The signkey is valid at this time, check if it's more recent than
+ what we have so far! */
+ if ( (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us <
+ GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) &&
+ (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us <
+ now.abs_value_us) )
+ {
+ /* We use the most recent one, if it is valid now (not just in the near future) */
+ ctx->current_sign_key_issue = *ski;
+ }
+ json_array_append_new (ctx->sign_keys_array,
+ sign_key_issue_to_json (&ski->issue));
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Convert information from an auditor to a JSON object.
+ *
+ * @param apub the auditor's public key
+ * @param dki_len length of @a dki and @a asigs arrays
+ * @param asigs the auditor's signatures
+ * @param dki array of denomination coin data signed by the auditor
+ * @return a JSON object describing the auditor information and signature
+ */
+static json_t *
+auditor_to_json (const struct TALER_AuditorPublicKeyP *apub,
+ unsigned int dki_len,
+ const struct TALER_AuditorSignatureP **asigs,
+ const struct TALER_DenominationKeyValidityPS **dki)
+{
+ unsigned int i;
+ json_t *ja;
+
+ ja = json_array ();
+ for (i=0;i<dki_len;i++)
+ json_array_append_new (ja,
+ json_pack ("{s:o, s:o}",
+ "denom_pub_h",
+ TALER_json_from_data (&dki[i]->denom_hash,
+ sizeof (struct GNUNET_HashCode)),
+ "auditor_sig",
+ TALER_json_from_data (asigs[i],
+ sizeof (struct TALER_AuditorSignatureP))));
+ return
+ json_pack ("{s:o, s:o}",
+ "denomination_keys", ja,
+ "auditor_pub",
+ TALER_json_from_data (apub,
+ sizeof (struct TALER_AuditorPublicKeyP)));
+}
+
+
+/**
+ * @brief Iterator called with auditor information.
+ * Check that the @a mpub actually matches this exchange, and then
+ * add the auditor information to our /keys response (if it is
+ * (still) applicable).
+ *
+ * @param cls closure with the `struct TMH_KS_StateHandle *`
+ * @param apub the auditor's public key
+ * @param mpub the exchange's public key (as expected by the auditor)
+ * @param dki_len length of @a dki and @a asigs
+ * @param asigs array with the auditor's signatures, of length @a dki_len
+ * @param dki array of denomination coin data signed by the auditor
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+reload_auditor_iter (void *cls,
+ const struct TALER_AuditorPublicKeyP *apub,
+ const struct TALER_MasterPublicKeyP *mpub,
+ unsigned int dki_len,
+ const struct TALER_AuditorSignatureP *asigs,
+ const struct TALER_DenominationKeyValidityPS *dki)
+{
+ struct TMH_KS_StateHandle *ctx = cls;
+ unsigned int i;
+ unsigned int keep;
+ const struct TALER_AuditorSignatureP *kept_asigs[dki_len];
+ const struct TALER_DenominationKeyValidityPS *kept_dkis[dki_len];
+
+ /* Check if the signature is at least for this exchange. */
+ if (0 != memcmp (&mpub->eddsa_pub,
+ &TMH_master_public_key,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Auditing information provided for a different exchange, ignored\n");
+ return GNUNET_OK;
+ }
+ /* Filter the auditor information for those for which the
+ keys actually match the denomination keys that are active right now */
+ keep = 0;
+ for (i=0;i<dki_len;i++)
+ {
+ if (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_contains (ctx->denomkey_map,
+ &dki[i].denom_hash))
+ {
+ kept_asigs[keep] = &asigs[i];
+ kept_dkis[keep] = &dki[i];
+ keep++;
+ }
+ }
+ /* add auditor information to our /keys response */
+ json_array_append_new (ctx->auditors_array,
+ auditor_to_json (apub,
+ keep,
+ kept_asigs,
+ kept_dkis));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Iterator for freeing denomination keys.
+ *
+ * @param cls closure with the `struct TMH_KS_StateHandle`
+ * @param key key for the denomination key
+ * @param value coin details
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+free_denom_key (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki = value;
+
+ GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key);
+ GNUNET_free (dki);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Release key state, free if necessary (if reference count gets to zero).
+ * Internal method used when the mutex is already held.
+ *
+ * @param key_state the key state to release
+ */
+static void
+ks_release_ (struct TMH_KS_StateHandle *key_state)
+{
+ GNUNET_assert (0 < key_state->refcnt);
+ key_state->refcnt--;
+ if (0 == key_state->refcnt)
+ {
+ if (NULL != key_state->denom_keys_array)
+ {
+ json_decref (key_state->denom_keys_array);
+ key_state->denom_keys_array = NULL;
+ }
+ if (NULL != key_state->sign_keys_array)
+ {
+ json_decref (key_state->sign_keys_array);
+ key_state->sign_keys_array = NULL;
+ }
+ if (NULL != key_state->denomkey_map)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map,
+ &free_denom_key,
+ key_state);
+ GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map);
+ key_state->denomkey_map = NULL;
+ }
+ GNUNET_free_non_null (key_state->keys_json);
+ GNUNET_free (key_state);
+ }
+}
+
+
+/**
+ * Release key state, free if necessary (if reference count gets to zero).
+ *
+ * @param location name of the function in which the lock is acquired
+ * @param key_state the key state to release
+ */
+void
+TMH_KS_release_ (const char *location,
+ struct TMH_KS_StateHandle *key_state)
+{
+ GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
+ ks_release_ (key_state);
+ GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
+}
+
+
+/**
+ * Acquire the key state of the exchange. Updates keys if necessary.
+ * For every call to #TMH_KS_acquire(), a matching call
+ * to #TMH_KS_release() must be made.
+ *
+ * @param location name of the function in which the lock is acquired
+ * @return the key state
+ */
+struct TMH_KS_StateHandle *
+TMH_KS_acquire_ (const char *location)
+{
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct TMH_KS_StateHandle *key_state;
+ json_t *keys;
+ struct TALER_ExchangeKeySetPS ks;
+ struct TALER_ExchangeSignatureP sig;
+
+ GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
+ if ( (NULL != internal_key_state) &&
+ (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) )
+ {
+ ks_release_ (internal_key_state);
+ internal_key_state = NULL;
+ }
+ if (NULL == internal_key_state)
+ {
+ key_state = GNUNET_new (struct TMH_KS_StateHandle);
+ key_state->hash_context = GNUNET_CRYPTO_hash_context_start ();
+
+
+ key_state->denom_keys_array = json_array ();
+ GNUNET_assert (NULL != key_state->denom_keys_array);
+
+ key_state->sign_keys_array = json_array ();
+ GNUNET_assert (NULL != key_state->sign_keys_array);
+
+ key_state->auditors_array = json_array ();
+ GNUNET_assert (NULL != key_state->auditors_array);
+
+ key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32,
+ GNUNET_NO);
+ key_state->reload_time = GNUNET_TIME_absolute_get ();
+ TALER_round_abs_time (&key_state->reload_time);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Loading keys from `%s'\n",
+ TMH_exchange_directory);
+ TALER_EXCHANGEDB_denomination_keys_iterate (TMH_exchange_directory,
+ &reload_keys_denom_iter,
+ key_state);
+ TALER_EXCHANGEDB_signing_keys_iterate (TMH_exchange_directory,
+ &reload_keys_sign_iter,
+ key_state);
+ TALER_EXCHANGEDB_auditor_iterate (TMH_exchange_directory,
+ &reload_auditor_iter,
+ key_state);
+ ks.purpose.size = htonl (sizeof (ks));
+ ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
+ ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time);
+ GNUNET_CRYPTO_hash_context_finish (key_state->hash_context,
+ &ks.hc);
+ key_state->hash_context = NULL;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
+ &ks.purpose,
+ &sig.eddsa_signature));
+ key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire);
+ if (0 == key_state->next_reload.abs_value_us)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No valid signing key found!\n");
+
+ keys = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
+ "master_public_key",
+ TALER_json_from_data (&TMH_master_public_key,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)),
+ "signkeys", key_state->sign_keys_array,
+ "denoms", key_state->denom_keys_array,
+ "auditors", key_state->auditors_array,
+ "list_issue_date", TALER_json_from_abs (key_state->reload_time),
+ "eddsa_pub", TALER_json_from_data (&key_state->current_sign_key_issue.issue.signkey_pub,
+ sizeof (struct TALER_ExchangePublicKeyP)),
+ "eddsa_sig", TALER_json_from_data (&sig,
+ sizeof (struct TALER_ExchangeSignatureP)));
+ key_state->auditors_array = NULL;
+ key_state->sign_keys_array = NULL;
+ key_state->denom_keys_array = NULL;
+ key_state->keys_json = json_dumps (keys,
+ JSON_INDENT (2));
+ json_decref (keys);
+ internal_key_state = key_state;
+ }
+ key_state = internal_key_state;
+ key_state->refcnt++;
+ GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
+
+ return key_state;
+}
+
+
+/**
+ * Look up the issue for a denom public key.
+ *
+ * @param key_state state to look in
+ * @param denom_pub denomination public key
+ * @param use purpose for which the key is being located
+ * @return the denomination key issue,
+ * or NULL if denom_pub could not be found
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
+TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ enum TMH_KS_DenominationKeyUse use)
+{
+ struct GNUNET_HashCode hc;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct GNUNET_TIME_Absolute now;
+
+ GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
+ &hc);
+ dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map,
+ &hc);
+ if (NULL == dki)
+ return NULL;
+ now = GNUNET_TIME_absolute_get ();
+ if (now.abs_value_us <
+ GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Not returning DKI for %s, as start time is in the future\n",
+ GNUNET_h2s (&hc));
+ return NULL;
+ }
+ now = GNUNET_TIME_absolute_get ();
+ switch (use)
+ {
+ case TMH_KS_DKU_WITHDRAW:
+ if (now.abs_value_us >
+ GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Not returning DKI for %s, as time to create coins has passed\n",
+ GNUNET_h2s (&hc));
+ return NULL;
+ }
+ break;
+ case TMH_KS_DKU_DEPOSIT:
+ if (now.abs_value_us >
+ GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Not returning DKI for %s, as time to spend coin has passed\n",
+ GNUNET_h2s (&hc));
+ return NULL;
+ }
+ break;
+ }
+ return dki;
+}
+
+
+/**
+ * Handle a signal, writing relevant signal numbers to the pipe.
+ *
+ * @param signal_number the signal number
+ */
+static void
+handle_signal (int signal_number)
+{
+ ssize_t res;
+ char c = signal_number;
+
+ res = write (reload_pipe[1],
+ &c,
+ 1);
+ if ( (res < 0) &&
+ (EINTR != errno) )
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (0 == res)
+ {
+ GNUNET_break (0);
+ return;
+ }
+}
+
+
+/**
+ * Call #handle_signal() to pass the received signal via
+ * the control pipe.
+ */
+static void
+handle_sigusr1 ()
+{
+ handle_signal (SIGUSR1);
+}
+
+
+/**
+ * Call #handle_signal() to pass the received signal via
+ * the control pipe.
+ */
+static void
+handle_sigint ()
+{
+ handle_signal (SIGINT);
+}
+
+
+/**
+ * Call #handle_signal() to pass the received signal via
+ * the control pipe.
+ */
+static void
+handle_sigterm ()
+{
+ handle_signal (SIGTERM);
+}
+
+
+/**
+ * Call #handle_signal() to pass the received signal via
+ * the control pipe.
+ */
+static void
+handle_sighup ()
+{
+ handle_signal (SIGHUP);
+}
+
+
+/**
+ * Call #handle_signal() to pass the received signal via
+ * the control pipe.
+ */
+static void
+handle_sigchld ()
+{
+ handle_signal (SIGCHLD);
+}
+
+
+/**
+ * Read signals from a pipe in a loop, and reload keys from disk if
+ * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and
+ * restart if SIGHUP is received.
+ *
+ * @return #GNUNET_SYSERR on errors,
+ * #GNUNET_OK to terminate normally
+ * #GNUNET_NO to restart an update version of the binary
+ */
+int
+TMH_KS_loop (void)
+{
+ struct GNUNET_SIGNAL_Context *sigusr1;
+ struct GNUNET_SIGNAL_Context *sigterm;
+ struct GNUNET_SIGNAL_Context *sigint;
+ struct GNUNET_SIGNAL_Context *sighup;
+ struct GNUNET_SIGNAL_Context *sigchld;
+ int ret;
+
+ if (0 != pipe (reload_pipe))
+ {
+ fprintf (stderr,
+ "Failed to create pipe.\n");
+ return GNUNET_SYSERR;
+ }
+ sigusr1 = GNUNET_SIGNAL_handler_install (SIGUSR1,
+ &handle_sigusr1);
+ sigterm = GNUNET_SIGNAL_handler_install (SIGTERM,
+ &handle_sigterm);
+ sigint = GNUNET_SIGNAL_handler_install (SIGINT,
+ &handle_sigint);
+ sighup = GNUNET_SIGNAL_handler_install (SIGHUP,
+ &handle_sighup);
+ sigchld = GNUNET_SIGNAL_handler_install (SIGCHLD,
+ &handle_sigchld);
+
+ ret = 0;
+ while (0 == ret)
+ {
+ char c;
+ ssize_t res;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "(re-)loading keys\n");
+ if (NULL != internal_key_state)
+ {
+ TMH_KS_release (internal_key_state);
+ internal_key_state = NULL;
+ }
+ /* This will re-initialize 'internal_key_state' with
+ an initial refcnt of 1 */
+ (void) TMH_KS_acquire ();
+
+read_again:
+ errno = 0;
+ res = read (reload_pipe[0],
+ &c,
+ 1);
+ if ((res < 0) && (EINTR != errno))
+ {
+ GNUNET_break (0);
+ ret = GNUNET_SYSERR;
+ break;
+ }
+ if (EINTR == errno)
+ goto read_again;
+ switch (c)
+ {
+ case SIGUSR1:
+ /* reload internal key state, we do this in the loop */
+ break;
+ case SIGTERM:
+ case SIGINT:
+ /* terminate */
+ ret = GNUNET_OK;
+ break;
+ case SIGHUP:
+ /* restart updated binary */
+ ret = GNUNET_NO;
+ break;
+#if HAVE_DEVELOPER
+ case SIGCHLD:
+ /* running in test-mode, test finished, terminate */
+ ret = GNUNET_OK;
+ break;
+#endif
+ default:
+ /* unexpected character */
+ GNUNET_break (0);
+ break;
+ }
+ }
+ if (NULL != internal_key_state)
+ {
+ TMH_KS_release (internal_key_state);
+ internal_key_state = NULL;
+ }
+ GNUNET_SIGNAL_handler_uninstall (sigusr1);
+ GNUNET_SIGNAL_handler_uninstall (sigterm);
+ GNUNET_SIGNAL_handler_uninstall (sigint);
+ GNUNET_SIGNAL_handler_uninstall (sighup);
+ GNUNET_SIGNAL_handler_uninstall (sigchld);
+ return ret;
+}
+
+
+/**
+ * Sign the message in @a purpose with the exchange's signing key.
+ *
+ * @param purpose the message to sign
+ * @param[out] pub set to the current public signing key of the exchange
+ * @param[out] sig signature over purpose using current signing key
+ */
+void
+TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct TALER_ExchangePublicKeyP *pub,
+ struct TALER_ExchangeSignatureP *sig)
+
+{
+ struct TMH_KS_StateHandle *key_state;
+
+ key_state = TMH_KS_acquire ();
+ *pub = key_state->current_sign_key_issue.issue.signkey_pub;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
+ purpose,
+ &sig->eddsa_signature));
+ TMH_KS_release (key_state);
+}
+
+
+/**
+ * Function to call to handle the request by sending
+ * back static data from the @a rh.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_KS_handler_keys (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct TMH_KS_StateHandle *key_state;
+ struct MHD_Response *response;
+ int ret;
+
+ key_state = TMH_KS_acquire ();
+ response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
+ key_state->keys_json,
+ MHD_RESPMEM_MUST_COPY);
+ TMH_KS_release (key_state);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (response);
+ (void) MHD_add_response_header (response,
+ "Content-Type",
+ rh->mime_type);
+ ret = MHD_queue_response (connection,
+ rh->response_code,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+/* end of taler-exchange-httpd_keystate.c */
diff --git a/src/exchange/taler-exchange-httpd_keystate.h b/src/exchange/taler-exchange-httpd_keystate.h
new file mode 100644
index 000000000..56151a878
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_keystate.h
@@ -0,0 +1,163 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange/taler-exchange-httpd_keystate.h
+ * @brief management of our private signing keys (denomination keys)
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_KEYSTATE_H
+#define TALER_EXCHANGE_HTTPD_KEYSTATE_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+#include "taler_exchangedb_lib.h"
+
+
+/**
+ * Snapshot of the (coin and signing)
+ * keys (including private keys) of the exchange.
+ */
+struct TMH_KS_StateHandle;
+
+
+/**
+ * Acquire the key state of the exchange. Updates keys if necessary.
+ * For every call to #TMH_KS_acquire(), a matching call
+ * to #TMH_KS_release() must be made.
+ *
+ * @param location name of the function in which the lock is acquired
+ * @return the key state
+ */
+struct TMH_KS_StateHandle *
+TMH_KS_acquire_ (const char *location);
+
+
+/**
+ * Release key state, free if necessary (if reference count gets to zero).
+ *
+ * @param location name of the function in which the lock is acquired
+ * @param key_state the key state to release
+ */
+void
+TMH_KS_release_ (const char *location,
+ struct TMH_KS_StateHandle *key_state);
+
+
+/**
+ * Acquire the key state of the exchange. Updates keys if necessary.
+ * For every call to #TMH_KS_acquire(), a matching call
+ * to #TMH_KS_release() must be made.
+ *
+ * @return the key state
+ */
+#define TMH_KS_acquire(void) TMH_KS_acquire_(__FUNCTION__)
+
+
+/**
+ * Release key state, free if necessary (if reference count gets to zero).
+ *
+ * @param key_state the key state to release
+ */
+#define TMH_KS_release(key_state) TMH_KS_release_ (__FUNCTION__, key_state)
+
+
+/**
+ * Denomination key lookups can be for signing of fresh coins
+ * or to validate signatures on existing coins. As the validity
+ * periods for a key differ, the caller must specify which
+ * use is relevant for the current operation.
+ */
+enum TMH_KS_DenominationKeyUse {
+
+ /**
+ * The key is to be used for a /reserve/withdraw or /refresh (exchange)
+ * operation.
+ */
+ TMH_KS_DKU_WITHDRAW,
+
+ /**
+ * The key is to be usd for a /deposit or /refresh (melt) operation.
+ */
+ TMH_KS_DKU_DEPOSIT
+
+};
+
+
+/**
+ * Look up the issue for a denom public key. Note that the result
+ * is only valid while the @a key_state is not released!
+ *
+ * @param key_state state to look in
+ * @param denom_pub denomination public key
+ * @param use purpose for which the key is being located
+ * @return the denomination key issue,
+ * or NULL if denom_pub could not be found (or is not valid at this time for the given @a use)
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
+TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ enum TMH_KS_DenominationKeyUse use);
+
+
+/**
+ * Read signals from a pipe in a loop, and reload keys from disk if
+ * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and
+ * restart if SIGHUP is received.
+ *
+ * @return #GNUNET_SYSERR on errors,
+ * #GNUNET_OK to terminate normally
+ * #GNUNET_NO to restart an update version of the binary
+ */
+int
+TMH_KS_loop (void);
+
+
+/**
+ * Sign the message in @a purpose with the exchange's signing
+ * key.
+ *
+ * @param purpose the message to sign
+ * @param[out] pub set to the current public signing key of the exchange
+ * @param[out] sig signature over purpose using current signing key
+ */
+void
+TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct TALER_ExchangePublicKeyP *pub,
+ struct TALER_ExchangeSignatureP *sig);
+
+
+/**
+ * Handle a "/keys" request
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_KS_handler_keys (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_mhd.c b/src/exchange/taler-exchange-httpd_mhd.c
new file mode 100644
index 000000000..b7ad437aa
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_mhd.c
@@ -0,0 +1,152 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd_mhd.c
+ * @brief helpers for MHD interaction; these are TALER_EXCHANGE_handler_ functions
+ * that generate simple MHD replies that do not require any real operations
+ * to be performed (error handling, static pages, etc.)
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd.h"
+#include "taler-exchange-httpd_mhd.h"
+
+/**
+ * Function to call to handle the request by sending
+ * back static data from the @a rh.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 == rh->data_size)
+ rh->data_size = strlen ((const char *) rh->data);
+ response = MHD_create_response_from_buffer (rh->data_size,
+ (void *) rh->data,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (response);
+ if (NULL != rh->mime_type)
+ (void) MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ rh->mime_type);
+ ret = MHD_queue_response (connection,
+ rh->response_code,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+/**
+ * Function to call to handle the request by sending
+ * back a redirect to the AGPL source code.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ const char *agpl =
+ "This server is licensed under the Affero GPL. You will now be redirected to the source code.";
+ struct MHD_Response *response;
+ int ret;
+
+ response = MHD_create_response_from_buffer (strlen (agpl),
+ (void *) agpl,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (response);
+ if (NULL != rh->mime_type)
+ (void) MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ rh->mime_type);
+ MHD_add_response_header (response,
+ MHD_HTTP_HEADER_LOCATION,
+ "http://www.git.taler.net/?p=exchange.git");
+ ret = MHD_queue_response (connection,
+ rh->response_code,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+/**
+ * Function to call to handle the request by building a JSON
+ * reply with an error message from @a rh.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ rh->response_code,
+ "{s:s}",
+ "error",
+ rh->data);
+}
+
+
+/* end of taler-exchange-httpd_mhd.c */
diff --git a/src/exchange/taler-exchange-httpd_mhd.h b/src/exchange/taler-exchange-httpd_mhd.h
new file mode 100644
index 000000000..3e825c559
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_mhd.h
@@ -0,0 +1,111 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd_mhd.h
+ * @brief helpers for MHD interaction, used to generate simple responses
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_MHD_H
+#define TALER_EXCHANGE_HTTPD_MHD_H
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Function to call to handle the request by sending
+ * back static data from the @a rh.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Function to call to handle the request by sending
+ * back a redirect to the AGPL source code.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Function to call to handle the request by building a JSON
+ * reply from varargs.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param response_code HTTP response code to use
+ * @param do_cache can the response be cached? (0: no, 1: yes)
+ * @param fmt format string for pack
+ * @param ... varargs
+ * @return MHD result code
+ */
+int
+TMH_MHD_helper_send_json_pack (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void *connection_cls,
+ int response_code,
+ int do_cache,
+ const char *fmt,
+ ...);
+
+
+/**
+ * Function to call to handle the request by building a JSON
+ * reply with an error message from @a rh.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_parsing.c b/src/exchange/taler-exchange-httpd_parsing.c
new file mode 100644
index 000000000..25539aeb7
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_parsing.c
@@ -0,0 +1,1137 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd_parsing.c
+ * @brief functions to parse incoming requests (MHD arguments and JSON snippets)
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Initial size for POST request buffer.
+ */
+#define REQUEST_BUFFER_INITIAL (2*1024)
+
+/**
+ * Maximum POST request size.
+ */
+#define REQUEST_BUFFER_MAX (1024*1024)
+
+
+/**
+ * Buffer for POST requests.
+ */
+struct Buffer
+{
+ /**
+ * Allocated memory
+ */
+ char *data;
+
+ /**
+ * Number of valid bytes in buffer.
+ */
+ size_t fill;
+
+ /**
+ * Number of allocated bytes in buffer.
+ */
+ size_t alloc;
+};
+
+
+/**
+ * Initialize a buffer.
+ *
+ * @param buf the buffer to initialize
+ * @param data the initial data
+ * @param data_size size of the initial data
+ * @param alloc_size size of the buffer
+ * @param max_size maximum size that the buffer can grow to
+ * @return a GNUnet result code
+ */
+static int
+buffer_init (struct Buffer *buf,
+ const void *data,
+ size_t data_size,
+ size_t alloc_size,
+ size_t max_size)
+{
+ if (data_size > max_size || alloc_size > max_size)
+ return GNUNET_SYSERR;
+ if (data_size > alloc_size)
+ alloc_size = data_size;
+ buf->data = GNUNET_malloc (alloc_size);
+ memcpy (buf->data, data, data_size);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Free the data in a buffer. Does *not* free
+ * the buffer object itself.
+ *
+ * @param buf buffer to de-initialize
+ */
+static void
+buffer_deinit (struct Buffer *buf)
+{
+ GNUNET_free (buf->data);
+ buf->data = NULL;
+}
+
+
+/**
+ * Append data to a buffer, growing the buffer if necessary.
+ *
+ * @param buf the buffer to append to
+ * @param data the data to append
+ * @param data_size the size of @a data
+ * @param max_size maximum size that the buffer can grow to
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if the buffer can't accomodate for the new data
+ */
+static int
+buffer_append (struct Buffer *buf,
+ const void *data,
+ size_t data_size,
+ size_t max_size)
+{
+ if (buf->fill + data_size > max_size)
+ return GNUNET_NO;
+ if (data_size + buf->fill > buf->alloc)
+ {
+ char *new_buf;
+ size_t new_size = buf->alloc;
+ while (new_size < buf->fill + data_size)
+ new_size += 2;
+ if (new_size > max_size)
+ return GNUNET_NO;
+ new_buf = GNUNET_malloc (new_size);
+ memcpy (new_buf, buf->data, buf->fill);
+ GNUNET_free (buf->data);
+ buf->data = new_buf;
+ buf->alloc = new_size;
+ }
+ memcpy (buf->data + buf->fill, data, data_size);
+ buf->fill += data_size;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Release all memory allocated for the variable-size fields in
+ * the parser specification.
+ *
+ * @param spec specification to free
+ * @param spec_len number of items in @a spec to look at
+ */
+static void
+release_data (struct TMH_PARSE_FieldSpecification *spec,
+ unsigned int spec_len)
+{
+ unsigned int i;
+
+ for (i=0; i < spec_len; i++)
+ {
+ switch (spec[i].command)
+ {
+ case TMH_PARSE_JNC_FIELD:
+ GNUNET_break (0);
+ return;
+ case TMH_PARSE_JNC_INDEX:
+ GNUNET_break (0);
+ return;
+ case TMH_PARSE_JNC_RET_DATA:
+ break;
+ case TMH_PARSE_JNC_RET_DATA_VAR:
+ if (NULL != spec[i].destination)
+ {
+ GNUNET_free (* (void**) spec[i].destination);
+ *(void**) spec[i].destination = NULL;
+ *spec[i].destination_size_out = 0;
+ }
+ break;
+ case TMH_PARSE_JNC_RET_TYPED_JSON:
+ {
+ json_t *json;
+
+ json = *(json_t **) spec[i].destination;
+ if (NULL != json)
+ {
+ json_decref (json);
+ *(json_t**) spec[i].destination = NULL;
+ }
+ }
+ break;
+ case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
+ {
+ struct TALER_DenominationPublicKey *pk;
+
+ pk = spec[i].destination;
+ if (NULL != pk->rsa_public_key)
+ {
+ GNUNET_CRYPTO_rsa_public_key_free (pk->rsa_public_key);
+ pk->rsa_public_key = NULL;
+ }
+ }
+ break;
+ case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
+ {
+ struct TALER_DenominationSignature *sig;
+
+ sig = spec[i].destination;
+ if (NULL != sig->rsa_signature)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (sig->rsa_signature);
+ sig->rsa_signature = NULL;
+ }
+ }
+ break;
+ case TMH_PARSE_JNC_RET_AMOUNT:
+ memset (spec[i].destination,
+ 0,
+ sizeof (struct TALER_Amount));
+ break;
+ case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
+ break;
+ case TMH_PARSE_JNC_RET_UINT64:
+ break;
+ }
+ }
+}
+
+
+/**
+ * Process a POST request containing a JSON object. This function
+ * realizes an MHD POST processor that will (incrementally) process
+ * JSON data uploaded to the HTTP server. It will store the required
+ * state in the @a con_cls, which must be cleaned up using
+ * #TMH_PARSE_post_cleanup_callback().
+ *
+ * @param connection the MHD connection
+ * @param con_cls the closure (points to a `struct Buffer *`)
+ * @param upload_data the POST data
+ * @param upload_data_size number of bytes in @a upload_data
+ * @param json the JSON object for a completed request
+ * @return
+ * #GNUNET_YES if json object was parsed or at least
+ * may be parsed in the future (call again);
+ * `*json` will be NULL if we need to be called again,
+ * and non-NULL if we are done.
+ * #GNUNET_NO is request incomplete or invalid
+ * (error message was generated)
+ * #GNUNET_SYSERR on internal error
+ * (we could not even queue an error message,
+ * close HTTP session with MHD_NO)
+ */
+int
+TMH_PARSE_post_json (struct MHD_Connection *connection,
+ void **con_cls,
+ const char *upload_data,
+ size_t *upload_data_size,
+ json_t **json)
+{
+ struct Buffer *r = *con_cls;
+
+ *json = NULL;
+ if (NULL == *con_cls)
+ {
+ /* We are seeing a fresh POST request. */
+ r = GNUNET_new (struct Buffer);
+ if (GNUNET_OK !=
+ buffer_init (r,
+ upload_data,
+ *upload_data_size,
+ REQUEST_BUFFER_INITIAL,
+ REQUEST_BUFFER_MAX))
+ {
+ *con_cls = NULL;
+ buffer_deinit (r);
+ GNUNET_free (r);
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_internal_error (connection,
+ "out of memory"))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ }
+ /* everything OK, wait for more POST data */
+ *upload_data_size = 0;
+ *con_cls = r;
+ return GNUNET_YES;
+ }
+ if (0 != *upload_data_size)
+ {
+ /* We are seeing an old request with more data available. */
+
+ if (GNUNET_OK !=
+ buffer_append (r,
+ upload_data,
+ *upload_data_size,
+ REQUEST_BUFFER_MAX))
+ {
+ /* Request too long */
+ *con_cls = NULL;
+ buffer_deinit (r);
+ GNUNET_free (r);
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_request_too_large (connection))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ }
+ /* everything OK, wait for more POST data */
+ *upload_data_size = 0;
+ return GNUNET_YES;
+ }
+
+ /* We have seen the whole request. */
+
+ *json = json_loadb (r->data,
+ r->fill,
+ 0,
+ NULL);
+ if (NULL == *json)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse JSON request body\n");
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_invalid_json (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ buffer_deinit (r);
+ GNUNET_free (r);
+ *con_cls = NULL;
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function called whenever we are done with a request
+ * to clean up our state.
+ *
+ * @param con_cls value as it was left by
+ * #TMH_PARSE_post_json(), to be cleaned up
+ */
+void
+TMH_PARSE_post_cleanup_callback (void *con_cls)
+{
+ struct Buffer *r = con_cls;
+
+ if (NULL != r)
+ {
+ buffer_deinit (r);
+ GNUNET_free (r);
+ }
+}
+
+
+/**
+ * Extract base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is missing or
+ * invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to store the result
+ * @param out_size expected size of data
+ * @return
+ * #GNUNET_YES if the the argument is present
+ * #GNUNET_NO if the argument is absent or malformed
+ * #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
+ const char *param_name,
+ void *out_data,
+ size_t out_size)
+{
+ const char *str;
+
+ str = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ param_name);
+ if (NULL == str)
+ {
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_arg_missing (connection, param_name))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ }
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ out_data,
+ out_size))
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_arg_invalid (connection, param_name))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Extraxt variable-size base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is missing
+ * or the encoding is invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to allocate buffer and store the result
+ * @param[out] out_size set to the size of the buffer allocated in @a out_data
+ * @return
+ * #GNUNET_YES if the the argument is present
+ * #GNUNET_NO if the argument is absent or malformed
+ * #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
+ const char *param_name,
+ void **out_data,
+ size_t *out_size)
+{
+ const char *str;
+ size_t slen;
+ size_t olen;
+ void *out;
+
+ str = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ param_name);
+ if (NULL == str)
+ {
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_arg_missing (connection, param_name))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ }
+ slen = strlen (str);
+ olen = (slen * 5) / 8;
+ out = GNUNET_malloc (olen);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ out,
+ olen))
+ {
+ GNUNET_free (out);
+ *out_size = 0;
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_arg_invalid (connection, param_name))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ }
+ *out_data = out;
+ *out_size = olen;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Navigate through a JSON tree.
+ *
+ * Sends an error response if navigation is impossible (i.e.
+ * the JSON object is invalid)
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
+ * @return
+ * #GNUNET_YES if navigation was successful
+ * #GNUNET_NO if json is malformed, error response was generated
+ * #GNUNET_SYSERR on internal error (no response was generated,
+ * connection must be closed)
+ */
+int
+TMH_PARSE_navigate_json (struct MHD_Connection *connection,
+ const json_t *root,
+ ...)
+{
+ va_list argp;
+ int ret;
+ json_t *path; /* what's our current path from 'root'? */
+
+ path = json_array ();
+ va_start (argp, root);
+ ret = 2; /* just not any of the valid return values */
+ while (2 == ret)
+ {
+ enum TMH_PARSE_JsonNavigationCommand command
+ = va_arg (argp,
+ enum TMH_PARSE_JsonNavigationCommand);
+
+ switch (command)
+ {
+ case TMH_PARSE_JNC_FIELD:
+ {
+ const char *fname = va_arg(argp, const char *);
+
+ json_array_append_new (path,
+ json_string (fname));
+ root = json_object_get (root,
+ fname);
+ if (NULL == root)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s, s:O}",
+ "error", "missing field in JSON",
+ "field", fname,
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ }
+ break;
+
+ case TMH_PARSE_JNC_INDEX:
+ {
+ int fnum = va_arg(argp, int);
+
+ json_array_append_new (path,
+ json_integer (fnum));
+ root = json_array_get (root,
+ fnum);
+ if (NULL == root)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "missing index in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ }
+ break;
+
+ case TMH_PARSE_JNC_RET_DATA:
+ {
+ void *where = va_arg (argp, void *);
+ size_t len = va_arg (argp, size_t);
+ const char *str;
+ int res;
+
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "string expected",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ res = GNUNET_STRINGS_string_to_data (str, strlen (str),
+ where, len);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "malformed binary data in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ ret = GNUNET_OK;
+ }
+ break;
+
+ case TMH_PARSE_JNC_RET_DATA_VAR:
+ {
+ void **where = va_arg (argp, void **);
+ size_t *len = va_arg (argp, size_t *);
+ const char *str;
+ int res;
+
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_internal_error (connection,
+ "json_string_value() failed"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ *len = (strlen (str) * 5) / 8;
+ if (NULL != where)
+ {
+ *where = GNUNET_malloc (*len);
+ res = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ *where,
+ *len);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (*where);
+ *where = NULL;
+ *len = 0;
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "malformed binary data in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ }
+ ret = GNUNET_OK;
+ }
+ break;
+
+ case TMH_PARSE_JNC_RET_TYPED_JSON:
+ {
+ int typ = va_arg (argp, int);
+ const json_t **r_json = va_arg (argp, const json_t **);
+
+ if ( (NULL == root) ||
+ ( (-1 != typ) &&
+ (json_typeof (root) != typ)) )
+ {
+ GNUNET_break_op (0);
+ *r_json = NULL;
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:i, s:i, s:O}",
+ "error", "wrong JSON field type",
+ "type_expected", typ,
+ "type_actual", json_typeof (root),
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ *r_json = root;
+ json_incref ((json_t *) root);
+ ret = GNUNET_OK;
+ }
+ break;
+
+ case TMH_PARSE_JNC_RET_UINT64:
+ {
+ uint64_t *r_u64 = va_arg (argp, uint64_t *);
+
+ if (json_typeof (root) != JSON_INTEGER)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s, s:i, s:O}",
+ "error", "wrong JSON field type",
+ "type_expected", "integer",
+ "type_actual", json_typeof (root),
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ *r_u64 = (uint64_t) json_integer_value (root);
+ ret = GNUNET_OK;
+ }
+ break;
+
+ case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
+ {
+ struct TALER_DenominationPublicKey *where;
+ size_t len;
+ const char *str;
+ int res;
+ void *buf;
+
+ where = va_arg (argp,
+ struct TALER_DenominationPublicKey *);
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "string expected",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ len = (strlen (str) * 5) / 8;
+ buf = GNUNET_malloc (len);
+ res = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ buf,
+ len);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (buf);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "malformed binary data in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf,
+ len);
+ GNUNET_free (buf);
+ if (NULL == where->rsa_public_key)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "malformed RSA public key in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ ret = GNUNET_OK;
+ break;
+ }
+
+ case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
+ {
+ struct TALER_DenominationSignature *where;
+ size_t len;
+ const char *str;
+ int res;
+ void *buf;
+
+ where = va_arg (argp,
+ struct TALER_DenominationSignature *);
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "string expected",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ len = (strlen (str) * 5) / 8;
+ buf = GNUNET_malloc (len);
+ res = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ buf,
+ len);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (buf);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "malformed binary data in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf,
+ len);
+ GNUNET_free (buf);
+ if (NULL == where->rsa_signature)
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "malformed RSA signature in JSON",
+ "path", path))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ ret = GNUNET_OK;
+ break;
+ }
+
+ case TMH_PARSE_JNC_RET_AMOUNT:
+ {
+ struct TALER_Amount *where = va_arg (argp, void *);
+
+ if (GNUNET_OK !=
+ TALER_json_to_amount ((json_t *) root,
+ where))
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES !=
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O}",
+ "error", "Bad format",
+ "path", path))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ break;
+ }
+ if (0 != strcmp (where->currency,
+ TMH_exchange_currency_string))
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES !=
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:O, s:s}",
+ "error", "Currency not supported",
+ "path", path,
+ "currency", where->currency))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ memset (where, 0, sizeof (struct TALER_Amount));
+ break;
+ }
+ ret = GNUNET_OK;
+ break;
+ }
+
+ case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
+ {
+ struct GNUNET_TIME_Absolute *where = va_arg (argp, void *);
+
+ if (GNUNET_OK !=
+ TALER_json_to_abs ((json_t *) root,
+ where))
+ {
+ GNUNET_break_op (0);
+ ret = (MHD_YES !=
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s, s:O}",
+ "error", "Bad format",
+ "hint", "expected absolute time",
+ "path", path))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ break;
+ }
+ ret = GNUNET_OK;
+ break;
+ }
+
+ default:
+ GNUNET_break (0);
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_internal_error (connection,
+ "unhandled value in switch"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ break;
+ }
+ }
+ va_end (argp);
+ json_decref (path);
+ return ret;
+}
+
+
+/**
+ * Parse JSON object into components based on the given field
+ * specification.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param spec field specification for the parser
+ * @return
+ * #GNUNET_YES if navigation was successful (caller is responsible
+ * for freeing allocated variable-size data using
+ * #TMH_PARSE_release_data() when done)
+ * #GNUNET_NO if json is malformed, error response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+int
+TMH_PARSE_json_data (struct MHD_Connection *connection,
+ const json_t *root,
+ struct TMH_PARSE_FieldSpecification *spec)
+{
+ unsigned int i;
+ int ret;
+
+ ret = GNUNET_YES;
+ for (i=0; NULL != spec[i].field_name; i++)
+ {
+ if (GNUNET_YES != ret)
+ break;
+ switch (spec[i].command)
+ {
+ case TMH_PARSE_JNC_FIELD:
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ case TMH_PARSE_JNC_INDEX:
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ case TMH_PARSE_JNC_RET_DATA:
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_DATA,
+ spec[i].destination,
+ spec[i].destination_size_in);
+ break;
+ case TMH_PARSE_JNC_RET_DATA_VAR:
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_DATA_VAR,
+ (void **) spec[i].destination,
+ spec[i].destination_size_out);
+ break;
+ case TMH_PARSE_JNC_RET_TYPED_JSON:
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_TYPED_JSON,
+ spec[i].type,
+ spec[i].destination);
+ break;
+ case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
+ spec[i].destination);
+ break;
+ case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_RSA_SIGNATURE,
+ spec[i].destination);
+ break;
+ case TMH_PARSE_JNC_RET_AMOUNT:
+ GNUNET_assert (sizeof (struct TALER_Amount) ==
+ spec[i].destination_size_in);
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_AMOUNT,
+ spec[i].destination);
+ break;
+ case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
+ GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) ==
+ spec[i].destination_size_in);
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
+ spec[i].destination);
+ break;
+ case TMH_PARSE_JNC_RET_UINT64:
+ GNUNET_assert (sizeof (uint64_t) ==
+ spec[i].destination_size_in);
+ ret = TMH_PARSE_navigate_json (connection,
+ root,
+ TMH_PARSE_JNC_FIELD,
+ spec[i].field_name,
+ TMH_PARSE_JNC_RET_UINT64,
+ spec[i].destination);
+ break;
+ }
+ }
+ if (GNUNET_YES != ret)
+ release_data (spec,
+ i - 1);
+ return ret;
+}
+
+
+/**
+ * Release all memory allocated for the variable-size fields in
+ * the parser specification.
+ *
+ * @param spec specification to free
+ */
+void
+TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec)
+{
+ unsigned int i;
+
+ for (i=0; NULL != spec[i].field_name; i++) ;
+ release_data (spec, i);
+}
+
+
+/**
+ * Generate line in parser specification for 64-bit integer
+ * given as an integer in JSON.
+ *
+ * @param field name of the field
+ * @param[out] u64 integer to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_uint64 (const char *field,
+ uint64_t *u64)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, (void *) u64, sizeof (uint64_t), NULL, TMH_PARSE_JNC_RET_UINT64, 0 };
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for JSON object value.
+ *
+ * @param field name of the field
+ * @param[out] jsonp address of pointer to JSON to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_object (const char *field,
+ json_t **jsonp)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT };
+ *jsonp = NULL;
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for JSON array value.
+ *
+ * @param field name of the field
+ * @param[out] jsonp address of JSON pointer to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_array (const char *field,
+ json_t **jsonp)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY };
+ *jsonp = NULL;
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for an absolute time.
+ *
+ * @param field name of the field
+ * @param[out] atime time to initialize
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_time_abs (const char *field,
+ struct GNUNET_TIME_Absolute *atime)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, atime, sizeof(struct GNUNET_TIME_Absolute), NULL, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, 0 };
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for RSA public key.
+ *
+ * @param field name of the field
+ * @param[out] pk key to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_denomination_public_key (const char *field,
+ struct TALER_DenominationPublicKey *pk)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 };
+ pk->rsa_public_key = NULL;
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for RSA public key.
+ *
+ * @param field name of the field
+ * @param sig the signature to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_denomination_signature (const char *field,
+ struct TALER_DenominationSignature *sig)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 };
+ sig->rsa_signature = NULL;
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for an amount.
+ *
+ * @param field name of the field
+ * @param amount a `struct TALER_Amount *` to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_amount (const char *field,
+ struct TALER_Amount *amount)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 };
+ memset (amount, 0, sizeof (struct TALER_Amount));
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for variable-size value.
+ *
+ * @param field name of the field
+ * @param[out] ptr pointer to initialize
+ * @param[out] ptr_size size to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_variable (const char *field,
+ void **ptr,
+ size_t *ptr_size)
+{
+ struct TMH_PARSE_FieldSpecification ret =
+ { field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 };
+ *ptr = NULL;
+ return ret;
+}
+
+/* end of taler-exchange-httpd_parsing.c */
diff --git a/src/exchange/taler-exchange-httpd_parsing.h b/src/exchange/taler-exchange-httpd_parsing.h
new file mode 100644
index 000000000..a39235685
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_parsing.h
@@ -0,0 +1,408 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_parsing.h
+ * @brief functions to parse incoming requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_PARSING_H
+#define TALER_EXCHANGE_HTTPD_PARSING_H
+
+#include <microhttpd.h>
+#include <jansson.h>
+#include "taler_util.h"
+
+
+/**
+ * Process a POST request containing a JSON object. This
+ * function realizes an MHD POST processor that will
+ * (incrementally) process JSON data uploaded to the HTTP
+ * server. It will store the required state in the
+ * "connection_cls", which must be cleaned up using
+ * #TMH_PARSE_post_cleanup_callback().
+ *
+ * @param connection the MHD connection
+ * @param con_cls the closure (points to a `struct Buffer *`)
+ * @param upload_data the POST data
+ * @param upload_data_size number of bytes in @a upload_data
+ * @param json the JSON object for a completed request
+ * @return
+ * #GNUNET_YES if json object was parsed or at least
+ * may be parsed in the future (call again);
+ * `*json` will be NULL if we need to be called again,
+ * and non-NULL if we are done.
+ * #GNUNET_NO is request incomplete or invalid
+ * (error message was generated)
+ * #GNUNET_SYSERR on internal error
+ * (we could not even queue an error message,
+ * close HTTP session with MHD_NO)
+ */
+int
+TMH_PARSE_post_json (struct MHD_Connection *connection,
+ void **con_cls,
+ const char *upload_data,
+ size_t *upload_data_size,
+ json_t **json);
+
+
+/**
+ * Function called whenever we are done with a request
+ * to clean up our state.
+ *
+ * @param con_cls value as it was left by
+ * #TMH_PARSE_post_json(), to be cleaned up
+ */
+void
+TMH_PARSE_post_cleanup_callback (void *con_cls);
+
+
+/**
+ * Constants for JSON navigation description.
+ */
+enum TMH_PARSE_JsonNavigationCommand
+{
+ /**
+ * Access a field.
+ * Param: const char *
+ */
+ TMH_PARSE_JNC_FIELD,
+
+ /**
+ * Access an array index.
+ * Param: int
+ */
+ TMH_PARSE_JNC_INDEX,
+
+ /**
+ * Return base32crockford encoded data of
+ * constant size.
+ * Params: (void *, size_t)
+ */
+ TMH_PARSE_JNC_RET_DATA,
+
+ /**
+ * Return base32crockford encoded data of
+ * variable size.
+ * Params: (void **, size_t *)
+ */
+ TMH_PARSE_JNC_RET_DATA_VAR,
+
+ /**
+ * Return a json object, which must be
+ * of the given type (JSON_* type constants,
+ * or -1 for any type).
+ * Params: (int, json_t **)
+ */
+ TMH_PARSE_JNC_RET_TYPED_JSON,
+
+ /**
+ * Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was
+ * encoded as variable-size base32crockford encoded data.
+ */
+ TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
+
+ /**
+ * Return a `struct GNUNET_CRYPTO_rsa_Signature` which was
+ * encoded as variable-size base32crockford encoded data.
+ */
+ TMH_PARSE_JNC_RET_RSA_SIGNATURE,
+
+ /**
+ * Return a `struct TALER_Amount` which was
+ * encoded within its own json object.
+ */
+ TMH_PARSE_JNC_RET_AMOUNT,
+
+ /**
+ * Return a `struct GNUNET_TIME_Absolute` which was
+ * encoded within its own json object.
+ * Param: struct GNUNET_TIME_Absolute *
+ */
+ TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
+
+ /**
+ * Return a `uint64_t` which was
+ * encoded as a JSON integer.
+ * Param: uint64_t *
+ */
+ TMH_PARSE_JNC_RET_UINT64
+
+};
+
+
+/**
+ * Navigate through a JSON tree.
+ *
+ * Sends an error response if navigation is impossible (i.e.
+ * the JSON object is invalid)
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
+ * @return
+ * #GNUNET_YES if navigation was successful
+ * #GNUNET_NO if json is malformed, error response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+int
+TMH_PARSE_navigate_json (struct MHD_Connection *connection,
+ const json_t *root,
+ ...);
+
+
+/**
+ * @brief Specification for how to parse a JSON field.
+ */
+struct TMH_PARSE_FieldSpecification
+{
+ /**
+ * Name of the field. NULL only to terminate array.
+ */
+ const char *field_name;
+
+ /**
+ * Where to store the result. Must have exactly
+ * @e destination_size bytes, except if @e destination_size is zero.
+ * NULL to skip assignment (but check presence of the value).
+ */
+ void *destination;
+
+ /**
+ * How big should the result be, 0 for variable size. In
+ * this case, @e destination must be a "void **", pointing
+ * to a location that is currently NULL and is to be allocated.
+ */
+ size_t destination_size_in;
+
+ /**
+ * @e destination_size_out will then be set to the size of the
+ * value that was stored in @e destination (useful for
+ * variable-size allocations).
+ */
+ size_t *destination_size_out;
+
+ /**
+ * Navigation command to use to extract the value. Note that
+ * #TMH_PARSE_JNC_RET_DATA or #TMH_PARSE_JNC_RET_DATA_VAR must be used for @e
+ * destination_size_in and @e destination_size_out to have a
+ * meaning. #TMH_PARSE_JNC_FIELD and #TMH_PARSE_JNC_INDEX must not be used here!
+ */
+ enum TMH_PARSE_JsonNavigationCommand command;
+
+ /**
+ * JSON type to use, only meaningful in connection with a @e command
+ * value of #TMH_PARSE_JNC_RET_TYPED_JSON. Typical values are
+ * #JSON_ARRAY and #JSON_OBJECT.
+ */
+ int type;
+
+};
+
+
+/**
+ * Parse JSON object into components based on the given field
+ * specification.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param spec field specification for the parser
+ * @return
+ * #GNUNET_YES if navigation was successful (caller is responsible
+ * for freeing allocated variable-size data using
+ * #TMH_PARSE_release_data() when done)
+ * #GNUNET_NO if json is malformed, error response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+int
+TMH_PARSE_json_data (struct MHD_Connection *connection,
+ const json_t *root,
+ struct TMH_PARSE_FieldSpecification *spec);
+
+
+/**
+ * Release all memory allocated for the variable-size fields in
+ * the parser specification.
+ *
+ * @param spec specification to free
+ */
+void
+TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec);
+
+
+/**
+ * Generate line in parser specification for fixed-size value.
+ *
+ * @param field name of the field
+ * @param value where to store the value
+ */
+#define TMH_PARSE_member_fixed(field,value) { field, value, sizeof (*value), NULL, TMH_PARSE_JNC_RET_DATA, 0 }
+
+
+/**
+ * Generate line in parser specification for variable-size value.
+ *
+ * @param field name of the field
+ * @param[out] ptr pointer to initialize
+ * @param[out] ptr_size size to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_variable (const char *field,
+ void **ptr,
+ size_t *ptr_size);
+
+
+/**
+ * Generate line in parser specification for 64-bit integer
+ * given as an integer in JSON.
+ *
+ * @param field name of the field
+ * @param[out] u64 integer to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_uint64 (const char *field,
+ uint64_t *u64);
+
+
+/**
+ * Generate line in parser specification for JSON array value.
+ *
+ * @param field name of the field
+ * @param[out] jsonp address of JSON pointer to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_array (const char *field,
+ json_t **jsonp);
+
+
+/**
+ * Generate line in parser specification for JSON object value.
+ *
+ * @param field name of the field
+ * @param[out] jsonp address of pointer to JSON to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_object (const char *field,
+ json_t **jsonp);
+
+
+/**
+ * Generate line in parser specification for RSA public key.
+ *
+ * @param field name of the field
+ * @param[out] pk key to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_denomination_public_key (const char *field,
+ struct TALER_DenominationPublicKey *pk);
+
+
+/**
+ * Generate line in parser specification for RSA public key.
+ *
+ * @param field name of the field
+ * @param sig the signature to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_denomination_signature (const char *field,
+ struct TALER_DenominationSignature *sig);
+
+
+/**
+ * Generate line in parser specification for an amount.
+ *
+ * @param field name of the field
+ * @param[out] amount a `struct TALER_Amount *` to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_amount (const char *field,
+ struct TALER_Amount *amount);
+
+
+/**
+ * Generate line in parser specification for an absolute time.
+ *
+ * @param field name of the field
+ * @param[out] atime time to initialize
+ * @return corresponding field spec
+ */
+struct TMH_PARSE_FieldSpecification
+TMH_PARSE_member_time_abs (const char *field,
+ struct GNUNET_TIME_Absolute *atime);
+
+
+
+/**
+ * Generate line in parser specification indicating the end of the spec.
+ */
+#define TMH_PARSE_MEMBER_END { NULL, NULL, 0, NULL, TMH_PARSE_JNC_FIELD, 0 }
+
+
+/**
+ * Extraxt fixed-size base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is missing or
+ * invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to store the result
+ * @param out_size expected size of @a out_data
+ * @return
+ * #GNUNET_YES if the the argument is present
+ * #GNUNET_NO if the argument is absent or malformed
+ * #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
+ const char *param_name,
+ void *out_data,
+ size_t out_size);
+
+
+/**
+ * Extraxt variable-size base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is missing
+ * or the encoding is invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to allocate buffer and store the result
+ * @param[out] out_size set to the size of the buffer allocated in @a out_data
+ * @return
+ * #GNUNET_YES if the the argument is present
+ * #GNUNET_NO if the argument is absent or malformed
+ * #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
+ const char *param_name,
+ void **out_data,
+ size_t *out_size);
+
+
+
+
+#endif /* TALER_EXCHANGE_HTTPD_PARSING_H */
diff --git a/src/exchange/taler-exchange-httpd_refresh.c b/src/exchange/taler-exchange-httpd_refresh.c
new file mode 100644
index 000000000..45bbf3d4d
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_refresh.c
@@ -0,0 +1,911 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_refresh.c
+ * @brief Handle /refresh/ requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_mhd.h"
+#include "taler-exchange-httpd_refresh.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_keystate.h"
+
+
+/**
+ * Handle a "/refresh/melt" request after the main JSON parsing has happened.
+ * We now need to validate the coins being melted and the session signature
+ * and then hand things of to execute the melt operation.
+ *
+ * @param connection the MHD connection to handle
+ * @param num_new_denoms number of coins to be created, size of y-dimension of @a commit_link array
+ * @param denom_pubs array of @a num_new_denoms keys
+ * @param coin_count number of coins to be melted, size of y-dimension of @a commit_coin array
+ * @param coin_melt_details array with @a coin_count entries with melting details
+ * @param session_hash hash over the data that the client commits to
+ * @param commit_coin 2d array of coin commitments (what the exchange is to sign
+ * once the "/refres/reveal" of cut and choose is done)
+ * @param commit_link 2d array of coin link commitments (what the exchange is
+ * to return via "/refresh/link" to enable linkage in the
+ * future)
+ * @return MHD result code
+ */
+static int
+handle_refresh_melt_binary (struct MHD_Connection *connection,
+ unsigned int num_new_denoms,
+ const struct TALER_DenominationPublicKey *denom_pubs,
+ unsigned int coin_count,
+ const struct TMH_DB_MeltDetails *coin_melt_details,
+ const struct GNUNET_HashCode *session_hash,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin,
+ struct TALER_RefreshCommitLinkP *const* commit_link)
+{
+ unsigned int i;
+ struct TMH_KS_StateHandle *key_state;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk;
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki;
+ struct TALER_Amount cost;
+ struct TALER_Amount total_cost;
+ struct TALER_Amount melt;
+ struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_Amount fee_melt;
+ struct TALER_Amount total_melt;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (TMH_exchange_currency_string,
+ &total_cost));
+ key_state = TMH_KS_acquire ();
+ for (i=0;i<num_new_denoms;i++)
+ {
+ dk = TMH_KS_denomination_key_lookup (key_state,
+ &denom_pubs[i],
+ TMH_KS_DKU_WITHDRAW);
+ if (NULL == dk)
+ {
+ GNUNET_break_op (0);
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "new_denoms");
+ }
+ dki = &dk->issue;
+ TALER_amount_ntoh (&value,
+ &dki->properties.value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->properties.fee_withdraw);
+ if ( (GNUNET_OK !=
+ TALER_amount_add (&cost,
+ &value,
+ &fee_withdraw)) ||
+ (GNUNET_OK !=
+ TALER_amount_add (&total_cost,
+ &cost,
+ &total_cost)) )
+ {
+ GNUNET_break_op (0);
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "cost calculation failure");
+ }
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (TMH_exchange_currency_string,
+ &total_melt));
+ for (i=0;i<coin_count;i++)
+ {
+ /* calculate contribution of the i-th melt by subtracting
+ the fee; add the rest to the total_melt value */
+ dk = TMH_KS_denomination_key_lookup (key_state,
+ &coin_melt_details[i].coin_info.denom_pub,
+ TMH_KS_DKU_DEPOSIT);
+ if (NULL == dk)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "denom_pub");
+ }
+ dki = &dk->issue;
+ TALER_amount_ntoh (&fee_melt,
+ &dki->properties.fee_refresh);
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&melt,
+ &coin_melt_details->melt_amount_with_fee,
+ &fee_melt))
+ {
+ GNUNET_break_op (0);
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_external_error (connection,
+ "Melt contribution below melting fee");
+ }
+ if (GNUNET_OK !=
+ TALER_amount_add (&total_melt,
+ &melt,
+ &total_melt))
+ {
+ GNUNET_break_op (0);
+ TMH_KS_release (key_state);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "balance calculation failure");
+ }
+ }
+ TMH_KS_release (key_state);
+ if (0 !=
+ TALER_amount_cmp (&total_cost,
+ &total_melt))
+ {
+ GNUNET_break_op (0);
+ /* We require total value of coins being melted and
+ total value of coins being generated to match! */
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s}",
+ "error", "value mismatch");
+ }
+ return TMH_DB_execute_refresh_melt (connection,
+ session_hash,
+ num_new_denoms,
+ denom_pubs,
+ coin_count,
+ coin_melt_details,
+ commit_coin,
+ commit_link);
+}
+
+
+/**
+ * Extract public coin information from a JSON object.
+ *
+ * @param connection the connection to send error responses to
+ * @param coin_info the JSON object to extract the coin info from
+ * @param[out] r_melt_detail set to details about the coin's melting permission (if valid)
+ * @return #GNUNET_YES if coin public info in JSON was valid
+ * #GNUNET_NO JSON was invalid, response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+static int
+get_coin_public_info (struct MHD_Connection *connection,
+ json_t *coin_info,
+ struct TMH_DB_MeltDetails *r_melt_detail)
+{
+ int ret;
+ struct TALER_CoinSpendSignatureP melt_sig;
+ struct TALER_DenominationSignature sig;
+ struct TALER_DenominationPublicKey pk;
+ struct TALER_Amount amount;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("coin_pub", &r_melt_detail->coin_info.coin_pub),
+ TMH_PARSE_member_denomination_signature ("denom_sig", &sig),
+ TMH_PARSE_member_denomination_public_key ("denom_pub", &pk),
+ TMH_PARSE_member_fixed ("confirm_sig", &melt_sig),
+ TMH_PARSE_member_amount ("value_with_fee", &amount),
+ TMH_PARSE_MEMBER_END
+ };
+
+ ret = TMH_PARSE_json_data (connection,
+ coin_info,
+ spec);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break_op (0);
+ return ret;
+ }
+ /* check exchange signature on the coin */
+ r_melt_detail->coin_info.denom_sig = sig;
+ r_melt_detail->coin_info.denom_pub = pk;
+ if (GNUNET_OK !=
+ TALER_test_coin_valid (&r_melt_detail->coin_info))
+ {
+ GNUNET_break_op (0);
+ TMH_PARSE_release_data (spec);
+ r_melt_detail->coin_info.denom_sig.rsa_signature = NULL;
+ r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_signature_invalid (connection,
+ "denom_sig"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ r_melt_detail->melt_sig = melt_sig;
+ r_melt_detail->melt_amount_with_fee = amount;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify that the signature shows that this coin is to be melted into
+ * the given @a session_hash melting session, and that this is a valid
+ * coin (we know the denomination key and the signature on it is
+ * valid). Essentially, this does all of the per-coin checks that can
+ * be done before the transaction starts.
+ *
+ * @param connection the connection to send error responses to
+ * @param session_hash hash over refresh session the coin is melted into
+ * @param[in,out] melt_detail details about the coin's melting permission,
+ * the `melt_fee` is updated
+ * @return #GNUNET_YES if coin public info in JSON was valid
+ * #GNUNET_NO JSON was invalid, response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+static int
+verify_coin_public_info (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ struct TMH_DB_MeltDetails *melt_detail)
+{
+ struct TALER_RefreshMeltCoinAffirmationPS body;
+ struct TMH_KS_StateHandle *key_state;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TALER_Amount fee_refresh;
+
+ key_state = TMH_KS_acquire ();
+ dki = TMH_KS_denomination_key_lookup (key_state,
+ &melt_detail->coin_info.denom_pub,
+ TMH_KS_DKU_DEPOSIT);
+ if (NULL == dki)
+ {
+ TMH_KS_release (key_state);
+ TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "denom_pub");
+ }
+ TALER_amount_ntoh (&fee_refresh,
+ &dki->issue.properties.fee_refresh);
+ melt_detail->melt_fee = fee_refresh;
+ body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
+ body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
+ body.session_hash = *session_hash;
+ TALER_amount_hton (&body.amount_with_fee,
+ &melt_detail->melt_amount_with_fee);
+ TALER_amount_hton (&body.melt_fee,
+ &fee_refresh);
+ body.coin_pub = melt_detail->coin_info.coin_pub;
+ if (TALER_amount_cmp (&fee_refresh,
+ &melt_detail->melt_amount_with_fee) > 0)
+ {
+ GNUNET_break_op (0);
+ TMH_KS_release (key_state);
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_external_error (connection,
+ "melt amount smaller than melting fee"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
+ TMH_KS_release (key_state);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
+ &body.purpose,
+ &melt_detail->melt_sig.eddsa_signature,
+ &melt_detail->coin_info.coin_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ if (MHD_YES !=
+ TMH_RESPONSE_reply_signature_invalid (connection,
+ "confirm_sig"))
+ return GNUNET_SYSERR;
+ return GNUNET_NO;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Release memory from the @a commit_coin array.
+ *
+ * @param commit_coin array to release
+ * @param kappa size of 1st dimension
+ * @param num_new_coins size of 2nd dimension
+ */
+static void
+free_commit_coins (struct TALER_EXCHANGEDB_RefreshCommitCoin **commit_coin,
+ unsigned int kappa,
+ unsigned int num_new_coins)
+{
+ unsigned int i;
+ unsigned int j;
+
+ for (i=0;i<kappa;i++)
+ {
+ if (NULL == commit_coin[i])
+ break;
+ for (j=0;j<num_new_coins;j++)
+ {
+ GNUNET_free_non_null (commit_coin[i][j].coin_ev);
+ GNUNET_free_non_null (commit_coin[i][j].refresh_link);
+ }
+ GNUNET_free (commit_coin[i]);
+ }
+}
+
+
+/**
+ * Release memory from the @a commit_link array.
+ *
+ * @param commit_link array to release
+ * @param kappa size of 1st dimension
+ * @param num_old_coins size of 2nd dimension
+ */
+static void
+free_commit_links (struct TALER_RefreshCommitLinkP **commit_link,
+ unsigned int kappa,
+ unsigned int num_old_coins)
+{
+ unsigned int i;
+
+ for (i=0;i<kappa;i++)
+ {
+ if (NULL == commit_link[i])
+ break;
+ GNUNET_free (commit_link[i]);
+ }
+}
+
+
+/**
+ * Handle a "/refresh/melt" request after the first parsing has happened.
+ * We now need to validate the coins being melted and the session signature
+ * and then hand things of to execute the melt operation. This function
+ * parses the JSON arrays and then passes processing on to
+ * #handle_refresh_melt_binary().
+ *
+ * @param connection the MHD connection to handle
+ * @param new_denoms array of denomination keys
+ * @param melt_coins array of coins to melt
+ * @param num_oldcoins number of coins that are being melted
+ * @param transfer_pubs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins transfer keys
+ * @param secret_encs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins secrets
+ * @param num_newcoins number of coins that the refresh will generate
+ * @param coin_evs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins envelopes to sign
+ * @param link_encs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins encrypted links
+ * @return MHD result code
+ */
+static int
+handle_refresh_melt_json (struct MHD_Connection *connection,
+ const json_t *new_denoms,
+ const json_t *melt_coins,
+ unsigned int num_oldcoins,
+ const json_t *transfer_pubs,
+ const json_t *secret_encs,
+ unsigned int num_newcoins,
+ const json_t *coin_evs,
+ const json_t *link_encs)
+{
+ int res;
+ unsigned int i;
+ unsigned int j;
+ struct TALER_DenominationPublicKey *denom_pubs;
+ unsigned int num_new_denoms;
+ struct TMH_DB_MeltDetails *coin_melt_details;
+ unsigned int coin_count;
+ struct GNUNET_HashCode session_hash;
+ struct GNUNET_HashContext *hash_context;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA];
+ struct TALER_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA];
+
+ /* For the signature check, we hash most of the inputs together
+ (except for the signatures on the coins). */
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
+ num_new_denoms = json_array_size (new_denoms);
+ denom_pubs = GNUNET_malloc (num_new_denoms *
+ sizeof (struct TALER_DenominationPublicKey));
+ for (i=0;i<num_new_denoms;i++)
+ {
+ char *buf;
+ size_t buf_size;
+
+ res = TMH_PARSE_navigate_json (connection,
+ new_denoms,
+ TMH_PARSE_JNC_INDEX, (int) i,
+ TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
+ &denom_pubs[i].rsa_public_key);
+ if (GNUNET_OK != res)
+ {
+ res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ goto cleanup_denoms;
+ }
+ buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key,
+ &buf);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ buf,
+ buf_size);
+ GNUNET_free (buf);
+ }
+
+ coin_count = json_array_size (melt_coins);
+ coin_melt_details = GNUNET_new_array (coin_count,
+ struct TMH_DB_MeltDetails);
+ for (i=0;i<coin_count;i++)
+ {
+ /* decode JSON data on coin to melt */
+ struct TALER_AmountNBO melt_amount;
+
+ res = get_coin_public_info (connection,
+ json_array_get (melt_coins, i),
+ &coin_melt_details[i]);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ goto cleanup_melt_details;
+ }
+ /* Check that the client does not try to melt the same coin twice
+ into the same session! */
+ for (j=0;j<i;j++)
+ {
+ if (0 == memcmp (&coin_melt_details[i].coin_info.coin_pub,
+ &coin_melt_details[j].coin_info.coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP)))
+ {
+ GNUNET_break_op (0);
+ res = TMH_RESPONSE_reply_external_error (connection,
+ "melting same coin twice in same session is not allowed");
+ goto cleanup_melt_details;
+ }
+ }
+ TALER_amount_hton (&melt_amount,
+ &coin_melt_details[i].melt_amount_with_fee);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &coin_melt_details[i].coin_info.coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP));
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &melt_amount,
+ sizeof (struct TALER_AmountNBO));
+ }
+
+ /* parse JSON arrays into 2d binary arrays and hash everything
+ together for the signature check */
+ memset (commit_coin, 0, sizeof (commit_coin));
+ memset (commit_link, 0, sizeof (commit_link));
+ for (i = 0; i < TALER_CNC_KAPPA; i++)
+ {
+ commit_coin[i] = GNUNET_malloc (num_newcoins *
+ sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin));
+ for (j = 0; j < num_newcoins; j++)
+ {
+ char *link_enc;
+ size_t link_enc_size;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &commit_coin[i][j];
+
+ res = TMH_PARSE_navigate_json (connection,
+ coin_evs,
+ TMH_PARSE_JNC_INDEX, (int) i,
+ TMH_PARSE_JNC_INDEX, (int) j,
+ TMH_PARSE_JNC_RET_DATA_VAR,
+ &rcc->coin_ev,
+ &rcc->coin_ev_size);
+
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ goto cleanup;
+ }
+
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ rcc->coin_ev,
+ rcc->coin_ev_size);
+ res = TMH_PARSE_navigate_json (connection,
+ link_encs,
+ TMH_PARSE_JNC_INDEX, (int) i,
+ TMH_PARSE_JNC_INDEX, (int) j,
+ TMH_PARSE_JNC_RET_DATA_VAR,
+ &link_enc,
+ &link_enc_size);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ goto cleanup;
+ }
+ rcc->refresh_link
+ = TALER_refresh_link_encrypted_decode (link_enc,
+ link_enc_size);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ link_enc,
+ link_enc_size);
+ GNUNET_free (link_enc);
+ }
+ }
+
+ for (i = 0; i < TALER_CNC_KAPPA; i++)
+ {
+ commit_link[i] = GNUNET_malloc (num_oldcoins *
+ sizeof (struct TALER_RefreshCommitLinkP));
+ for (j = 0; j < num_oldcoins; j++)
+ {
+ struct TALER_RefreshCommitLinkP *rcl = &commit_link[i][j];
+
+ res = TMH_PARSE_navigate_json (connection,
+ transfer_pubs,
+ TMH_PARSE_JNC_INDEX, (int) i,
+ TMH_PARSE_JNC_INDEX, (int) j,
+ TMH_PARSE_JNC_RET_DATA,
+ &rcl->transfer_pub,
+ sizeof (struct TALER_TransferPublicKeyP));
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ goto cleanup;
+ }
+ res = TMH_PARSE_navigate_json (connection,
+ secret_encs,
+ TMH_PARSE_JNC_INDEX, (int) i,
+ TMH_PARSE_JNC_INDEX, (int) j,
+ TMH_PARSE_JNC_RET_DATA,
+ &rcl->shared_secret_enc,
+ sizeof (struct TALER_EncryptedLinkSecretP));
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ goto cleanup;
+ }
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ rcl,
+ sizeof (struct TALER_RefreshCommitLinkP));
+ }
+ }
+ GNUNET_CRYPTO_hash_context_finish (hash_context,
+ &session_hash);
+ hash_context = NULL;
+ for (i=0;i<coin_count;i++)
+ {
+ /* verify signatures on coins to melt */
+ res = verify_coin_public_info (connection,
+ &session_hash,
+ &coin_melt_details[i]);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ goto cleanup;
+ }
+ }
+
+ /* execute commit */
+ res = handle_refresh_melt_binary (connection,
+ num_new_denoms,
+ denom_pubs,
+ coin_count,
+ coin_melt_details,
+ &session_hash,
+ commit_coin,
+ commit_link);
+ cleanup:
+ free_commit_coins (commit_coin,
+ TALER_CNC_KAPPA,
+ num_newcoins);
+ free_commit_links (commit_link,
+ TALER_CNC_KAPPA,
+ num_oldcoins);
+ cleanup_melt_details:
+ for (j=0;j<coin_count;j++)
+ {
+ if (NULL != coin_melt_details[j].coin_info.denom_pub.rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key);
+ if (NULL != coin_melt_details[j].coin_info.denom_sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature);
+ }
+ GNUNET_free (coin_melt_details);
+ cleanup_denoms:
+ for (j=0;j<num_new_denoms;j++)
+ if (NULL != denom_pubs[j].rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
+ GNUNET_free (denom_pubs);
+ if (NULL != hash_context)
+ GNUNET_CRYPTO_hash_context_abort (hash_context);
+ return res;
+}
+
+
+/**
+ * Handle a "/refresh/melt" request. Parses the request into the JSON
+ * components and then hands things of to #handle_refresh_melt_json()
+ * to validate the melted coins, the signature and execute the melt
+ * using TMH_DB_execute_refresh_melt().
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *root;
+ json_t *new_denoms;
+ json_t *melt_coins;
+ json_t *coin_evs;
+ json_t *link_encs;
+ json_t *transfer_pubs;
+ json_t *secret_encs;
+ unsigned int num_oldcoins;
+ unsigned int num_newcoins;
+ json_t *coin_detail;
+ int res;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_array ("new_denoms", &new_denoms),
+ TMH_PARSE_member_array ("melt_coins", &melt_coins),
+ TMH_PARSE_member_array ("coin_evs", &coin_evs),
+ TMH_PARSE_member_array ("link_encs", &link_encs),
+ TMH_PARSE_member_array ("transfer_pubs", &transfer_pubs),
+ TMH_PARSE_member_array ("secret_encs", &secret_encs),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == root) )
+ return MHD_YES;
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ json_decref (root);
+ if (GNUNET_OK != res)
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+
+ /* Determine dimensionality of the request (kappa, #old and #new coins) */
+ if (TALER_CNC_KAPPA != json_array_size (coin_evs))
+ {
+ GNUNET_break_op (0);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "coin_evs");
+ }
+ if (TALER_CNC_KAPPA != json_array_size (transfer_pubs))
+ {
+ GNUNET_break_op (0);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "transfer_pubs");
+ }
+ res = TMH_PARSE_navigate_json (connection,
+ coin_evs,
+ TMH_PARSE_JNC_INDEX, (int) 0,
+ TMH_PARSE_JNC_RET_TYPED_JSON,
+ JSON_ARRAY, &coin_detail);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ TMH_PARSE_release_data (spec);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ num_newcoins = json_array_size (coin_detail);
+ json_decref (coin_detail);
+ res = TMH_PARSE_navigate_json (connection,
+ transfer_pubs,
+ TMH_PARSE_JNC_INDEX, (int) 0,
+ TMH_PARSE_JNC_RET_TYPED_JSON,
+ JSON_ARRAY, &coin_detail);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ TMH_PARSE_release_data (spec);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ num_oldcoins = json_array_size (coin_detail);
+ json_decref (coin_detail);
+ res = handle_refresh_melt_json (connection,
+ new_denoms,
+ melt_coins,
+ num_oldcoins,
+ transfer_pubs,
+ secret_encs,
+ num_newcoins,
+ coin_evs,
+ link_encs);
+ TMH_PARSE_release_data (spec);
+ return res;
+}
+
+
+/**
+ * Handle a "/refresh/reveal" request. Parses the given JSON
+ * transfer private keys and if successful, passes everything to
+ * #TMH_DB_execute_refresh_reveal() which will verify that the
+ * revealed information is valid then returns the signed refreshed
+ * coins.
+ *
+ * @param connection the MHD connection to handle
+ * @param session_hash hash identifying the melting session
+ * @param num_oldcoins length of the 2nd dimension of @a transfer_privs array
+ * @param tp_json private transfer keys in JSON format
+ * @return MHD result code
+ */
+static int
+handle_refresh_reveal_json (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int num_oldcoins,
+ const json_t *tp_json)
+{
+ struct TALER_TransferPrivateKeyP *transfer_privs[TALER_CNC_KAPPA - 1];
+ unsigned int i;
+ unsigned int j;
+ int res;
+
+ for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
+ transfer_privs[i] = GNUNET_malloc (num_oldcoins *
+ sizeof (struct TALER_TransferPrivateKeyP));
+ res = GNUNET_OK;
+ for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
+ {
+ if (GNUNET_OK != res)
+ break;
+ for (j = 0; j < num_oldcoins; j++)
+ {
+ if (GNUNET_OK != res)
+ break;
+ res = TMH_PARSE_navigate_json (connection,
+ tp_json,
+ TMH_PARSE_JNC_INDEX, (int) i,
+ TMH_PARSE_JNC_INDEX, (int) j,
+ TMH_PARSE_JNC_RET_DATA,
+ &transfer_privs[i][j],
+ sizeof (struct TALER_TransferPrivateKeyP));
+ GNUNET_break_op (GNUNET_OK == res);
+ }
+ }
+ if (GNUNET_OK != res)
+ res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ else
+ res = TMH_DB_execute_refresh_reveal (connection,
+ session_hash,
+ num_oldcoins,
+ transfer_privs);
+ for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
+ GNUNET_free (transfer_privs[i]);
+ return res;
+}
+
+
+/**
+ * Handle a "/refresh/reveal" request. This time, the client reveals
+ * the private transfer keys except for the cut-and-choose value
+ * returned from "/refresh/melt". This function parses the revealed
+ * keys and secrets and ultimately passes everything to
+ * #TMH_DB_execute_refresh_reveal() which will verify that the
+ * revealed information is valid then returns the signed refreshed
+ * coins.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct GNUNET_HashCode session_hash;
+ int res;
+ unsigned int num_oldcoins;
+ json_t *reveal_detail;
+ json_t *root;
+ json_t *transfer_privs;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("session_hash", &session_hash),
+ TMH_PARSE_member_array ("transfer_privs", &transfer_privs),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == root) )
+ return MHD_YES;
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ json_decref (root);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ /* Determine dimensionality of the request (kappa and #old coins) */
+ /* Note we do +1 as 1 row (cut-and-choose!) is missing! */
+ if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1)
+ {
+ TMH_PARSE_release_data (spec);
+ GNUNET_break_op (0);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "transfer_privs");
+ }
+ res = TMH_PARSE_navigate_json (connection,
+ transfer_privs,
+ TMH_PARSE_JNC_INDEX, 0,
+ TMH_PARSE_JNC_RET_TYPED_JSON,
+ JSON_ARRAY,
+ &reveal_detail);
+ if (GNUNET_OK != res)
+ {
+ TMH_PARSE_release_data (spec);
+ GNUNET_break_op (0);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ num_oldcoins = json_array_size (reveal_detail);
+ json_decref (reveal_detail);
+ res = handle_refresh_reveal_json (connection,
+ &session_hash,
+ num_oldcoins,
+ transfer_privs);
+ TMH_PARSE_release_data (spec);
+ return res;
+}
+
+
+/**
+ * Handle a "/refresh/link" request. Note that for "/refresh/link"
+ * we do use a simple HTTP GET, and a HTTP POST!
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ int res;
+
+ res = TMH_PARSE_mhd_request_arg_data (connection,
+ "coin_pub",
+ &coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP));
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if (GNUNET_OK != res)
+ return MHD_YES;
+ return TMH_DB_execute_refresh_link (connection,
+ &coin_pub);
+}
+
+
+/* end of taler-exchange-httpd_refresh.c */
diff --git a/src/exchange/taler-exchange-httpd_refresh.h b/src/exchange/taler-exchange-httpd_refresh.h
new file mode 100644
index 000000000..aae9c4c6c
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_refresh.h
@@ -0,0 +1,94 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_refresh.h
+ * @brief Handle /refresh/ requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_REFRESH_H
+#define TALER_EXCHANGE_HTTPD_REFRESH_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/refresh/melt" request. Parses the request into the JSON
+ * components and then hands things of to #handle_refresh_melt_json()
+ * to validate the melted coins, the signature and execute the melt
+ * using TMH_DB_execute_refresh_melt().
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/refresh/reveal" request. This time, the client reveals
+ * the private transfer keys except for the cut-and-choose value
+ * returned from "/refresh/commit". This function parses the revealed
+ * keys and secrets and ultimately passes everything to
+ * #TMH_DB_execute_refresh_reveal() which will verify that the
+ * revealed information is valid then returns the signed refreshed
+ * coins.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/refresh/link" request
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_reserve.c b/src/exchange/taler-exchange-httpd_reserve.c
new file mode 100644
index 000000000..45f073107
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_reserve.c
@@ -0,0 +1,186 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014,2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_reserve.c
+ * @brief Handle /reserve/ requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include "taler-exchange-httpd_reserve.h"
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_keystate.h"
+
+
+/**
+ * Handle a "/reserve/status" request. Parses the
+ * given "reserve_pub" argument (which should contain the
+ * EdDSA public key of a reserve) and then respond with the
+ * status of the reserve.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct TALER_ReservePublicKeyP reserve_pub;
+ int res;
+
+ res = TMH_PARSE_mhd_request_arg_data (connection,
+ "reserve_pub",
+ &reserve_pub,
+ sizeof (struct TALER_ReservePublicKeyP));
+ if (GNUNET_SYSERR == res)
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* parse error */
+ return TMH_DB_execute_reserve_status (connection,
+ &reserve_pub);
+}
+
+
+/**
+ * Handle a "/reserve/withdraw" request. Parses the "reserve_pub"
+ * EdDSA key of the reserve and the requested "denom_pub" which
+ * specifies the key/value of the coin to be withdrawn, and checks
+ * that the signature "reserve_sig" makes this a valid withdrawl
+ * request from the specified reserve. If so, the envelope
+ * with the blinded coin "coin_ev" is passed down to execute the
+ * withdrawl operation.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *root;
+ struct TALER_WithdrawRequestPS wsrd;
+ int res;
+ struct TALER_DenominationPublicKey denomination_pub;
+ char *blinded_msg;
+ size_t blinded_msg_len;
+ struct TALER_Amount amount;
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_ReserveSignatureP signature;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TMH_KS_StateHandle *ks;
+
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_variable ("coin_ev",
+ (void **) &blinded_msg,
+ &blinded_msg_len),
+ TMH_PARSE_member_fixed ("reserve_pub",
+ &wsrd.reserve_pub),
+ TMH_PARSE_member_fixed ("reserve_sig",
+ &signature),
+ TMH_PARSE_member_denomination_public_key ("denom_pub",
+ &denomination_pub),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == root) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ json_decref (root);
+ if (GNUNET_OK != res)
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ ks = TMH_KS_acquire ();
+ dki = TMH_KS_denomination_key_lookup (ks,
+ &denomination_pub,
+ TMH_KS_DKU_WITHDRAW);
+ if (NULL == dki)
+ {
+ TMH_PARSE_release_data (spec);
+ TMH_KS_release (ks);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "denom_pub");
+ }
+ TALER_amount_ntoh (&amount,
+ &dki->issue.properties.value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->issue.properties.fee_withdraw);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_add (&amount_with_fee,
+ &amount,
+ &fee_withdraw));
+ TALER_amount_hton (&wsrd.amount_with_fee,
+ &amount_with_fee);
+ TALER_amount_hton (&wsrd.withdraw_fee,
+ &fee_withdraw);
+ TMH_KS_release (ks);
+ /* verify signature! */
+ wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
+ wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
+
+ GNUNET_CRYPTO_rsa_public_key_hash (denomination_pub.rsa_public_key,
+ &wsrd.h_denomination_pub);
+ GNUNET_CRYPTO_hash (blinded_msg,
+ blinded_msg_len,
+ &wsrd.h_coin_envelope);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
+ &wsrd.purpose,
+ &signature.eddsa_signature,
+ &wsrd.reserve_pub.eddsa_pub))
+ {
+ TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n");
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_signature_invalid (connection,
+ "reserve_sig");
+ }
+ res = TMH_DB_execute_reserve_withdraw (connection,
+ &wsrd.reserve_pub,
+ &denomination_pub,
+ blinded_msg,
+ blinded_msg_len,
+ &signature);
+ TMH_PARSE_release_data (spec);
+ return res;
+}
+
+/* end of taler-exchange-httpd_reserve.c */
diff --git a/src/exchange/taler-exchange-httpd_reserve.h b/src/exchange/taler-exchange-httpd_reserve.h
new file mode 100644
index 000000000..9a4960066
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_reserve.h
@@ -0,0 +1,73 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_reserve.h
+ * @brief Handle /reserve/ requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_RESERVE_H
+#define TALER_EXCHANGE_HTTPD_RESERVE_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+/**
+ * Handle a "/reserve/status" request. Parses the
+ * given "reserve_pub" argument (which should contain the
+ * EdDSA public key of a reserve) and then respond with the
+ * status of the reserve.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/reserve/withdraw" request. Parses the "reserve_pub"
+ * EdDSA key of the reserve and the requested "denom_pub" which
+ * specifies the key/value of the coin to be withdrawn, and checks
+ * that the signature "reserve_sig" makes this a valid withdrawl
+ * request from the specified reserve. If so, the envelope
+ * with the blinded coin "coin_ev" is passed down to execute the
+ * withdrawl operation.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
new file mode 100644
index 000000000..d6cf81bb7
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -0,0 +1,1177 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_responses.c
+ * @brief API for generating the various replies of the exchange; these
+ * functions are called TMH_RESPONSE_reply_ and they generate
+ * and queue MHD response objects for a given connection.
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler_util.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler-exchange-httpd_keystate.h"
+
+
+/**
+ * Add headers we want to return in every response.
+ * Useful for testing, like if we want to always close
+ * connections.
+ *
+ * @param response response to modify
+ */
+void
+TMH_RESPONSE_add_global_headers (struct MHD_Response *response)
+{
+ if (TMH_exchange_connection_close)
+ (void) MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONNECTION,
+ "close");
+}
+
+
+/**
+ * Send JSON object as response.
+ *
+ * @param connection the MHD connection
+ * @param json the json object
+ * @param response_code the http response code
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
+ const json_t *json,
+ unsigned int response_code)
+{
+ struct MHD_Response *resp;
+ char *json_str;
+ int ret;
+
+ json_str = json_dumps (json, JSON_INDENT(2));
+ GNUNET_assert (NULL != json_str);
+ resp = MHD_create_response_from_buffer (strlen (json_str), json_str,
+ MHD_RESPMEM_MUST_FREE);
+ if (NULL == resp)
+ {
+ free (json_str);
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (resp);
+ (void) MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ "application/json");
+ ret = MHD_queue_response (connection,
+ response_code,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+}
+
+
+/**
+ * Function to call to handle the request by building a JSON
+ * reply from a format string and varargs.
+ *
+ * @param connection the MHD connection to handle
+ * @param response_code HTTP response code to use
+ * @param fmt format string for pack
+ * @param ... varargs
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
+ unsigned int response_code,
+ const char *fmt,
+ ...)
+{
+ json_t *json;
+ va_list argp;
+ int ret;
+ json_error_t jerror;
+
+ va_start (argp, fmt);
+ json = json_vpack_ex (&jerror, 0, fmt, argp);
+ va_end (argp);
+ if (NULL == json)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to pack JSON with format `%s': %s\n",
+ fmt,
+ jerror.text);
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ ret = TMH_RESPONSE_reply_json (connection,
+ json,
+ response_code);
+ json_decref (json);
+ return ret;
+}
+
+
+/**
+ * Send a response indicating an invalid argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
+ const char *param_name)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s}",
+ "error", "invalid parameter",
+ "parameter", param_name);
+}
+
+
+/**
+ * Send a response indicating an argument refering to a
+ * resource unknown to the exchange (i.e. unknown reserve or
+ * denomination key).
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
+ const char *param_name)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s, s:s}",
+ "error", "unknown entity referenced",
+ "parameter", param_name);
+}
+
+
+/**
+ * Send a response indicating an invalid signature.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
+ const char *param_name)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_UNAUTHORIZED,
+ "{s:s, s:s}",
+ "error", "invalid signature",
+ "parameter", param_name);
+}
+
+
+/**
+ * Send a response indicating a missing argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is missing
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
+ const char *param_name)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{ s:s, s:s}",
+ "error", "missing parameter",
+ "parameter", param_name);
+}
+
+
+/**
+ * Send a response indicating permission denied.
+ *
+ * @param connection the MHD connection to use
+ * @param hint hint about why access was denied
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
+ const char *hint)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_FORBIDDEN,
+ "{s:s, s:s}",
+ "error", "permission denied",
+ "hint", hint);
+}
+
+
+/**
+ * Send a response indicating an internal error.
+ *
+ * @param connection the MHD connection to use
+ * @param hint hint about the internal error's nature
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
+ const char *hint)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ "{s:s, s:s}",
+ "error", "internal error",
+ "hint", hint);
+}
+
+
+/**
+ * Send a response indicating an external error.
+ *
+ * @param connection the MHD connection to use
+ * @param hint hint about the error's nature
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
+ const char *hint)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s}",
+ "error", "client error",
+ "hint", hint);
+}
+
+
+/**
+ * Send a response indicating an error committing a
+ * transaction (concurrent interference).
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s}",
+ "error", "commit failure");
+}
+
+
+/**
+ * Send a response indicating a failure to talk to the Exchange's
+ * database.
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection)
+{
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to connect to database");
+}
+
+
+/**
+ * Send a response indicating that the request was too big.
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection)
+{
+ struct MHD_Response *resp;
+ int ret;
+
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == resp)
+ return MHD_NO;
+ TMH_RESPONSE_add_global_headers (resp);
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+}
+
+
+/**
+ * Send a response indicating that the JSON was malformed.
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s}",
+ "error",
+ "invalid json");
+}
+
+
+/**
+ * Send confirmation of deposit success to client. This function
+ * will create a signed message affirming the given information
+ * and return it to the client. By this, the exchange affirms that
+ * the coin had sufficient (residual) value for the specified
+ * transaction and that it will execute the requested deposit
+ * operation with the given wiring details.
+ *
+ * @param connection connection to the client
+ * @param coin_pub public key of the coin
+ * @param h_wire hash of wire details
+ * @param h_contract hash of contract details
+ * @param transaction_id transaction ID
+ * @param timestamp client's timestamp
+ * @param refund_deadline until when this deposit be refunded
+ * @param merchant merchant public key
+ * @param amount_without_fee fraction of coin value to deposit, without the fee
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ struct GNUNET_TIME_Absolute timestamp,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ const struct TALER_MerchantPublicKeyP *merchant,
+ const struct TALER_Amount *amount_without_fee)
+{
+ struct TALER_DepositConfirmationPS dc;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+
+ dc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
+ dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
+ dc.h_contract = *h_contract;
+ dc.h_wire = *h_wire;
+ dc.transaction_id = GNUNET_htonll (transaction_id);
+ dc.timestamp = GNUNET_TIME_absolute_hton (timestamp);
+ dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
+ TALER_amount_hton (&dc.amount_without_fee,
+ amount_without_fee);
+ dc.coin_pub = *coin_pub;
+ dc.merchant = *merchant;
+ TMH_KS_sign (&dc.purpose,
+ &pub,
+ &sig);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:s, s:o, s:o}",
+ "status", "DEPOSIT_OK",
+ "sig", TALER_json_from_data (&sig,
+ sizeof (sig)),
+ "pub", TALER_json_from_data (&pub,
+ sizeof (pub)));
+}
+
+
+/**
+ * Compile the transaction history of a coin into a JSON object.
+ *
+ * @param tl transaction history to JSON-ify
+ * @return json representation of the @a rh
+ */
+static json_t *
+compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
+{
+ json_t *details;
+ const char *type;
+ struct TALER_Amount value;
+ json_t *history;
+ const struct TALER_CoinSpendSignatureP *sig;
+ const struct TALER_EXCHANGEDB_TransactionList *pos;
+
+ history = json_array ();
+ for (pos = tl; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_EXCHANGEDB_TT_DEPOSIT:
+ {
+ struct TALER_DepositRequestPS dr;
+ const struct TALER_EXCHANGEDB_Deposit *deposit = pos->details.deposit;
+
+ type = "DEPOSIT";
+ value = deposit->amount_with_fee;
+ dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
+ dr.h_contract = deposit->h_contract;
+ dr.h_wire = deposit->h_wire;
+ dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp);
+ dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline);
+ dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &deposit->amount_with_fee);
+ TALER_amount_hton (&dr.deposit_fee,
+ &deposit->deposit_fee);
+ dr.merchant = deposit->merchant_pub;
+ dr.coin_pub = deposit->coin.coin_pub;
+ sig = &deposit->csig;
+ /* internal sanity check before we hand out a bogus sig... */
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
+ &dr.purpose,
+ &sig->eddsa_signature,
+ &deposit->coin.coin_pub.eddsa_pub))
+ {
+ GNUNET_break (0);
+ json_decref (history);
+ return NULL;
+ }
+
+ details = TALER_json_from_data (&dr.purpose,
+ sizeof (struct TALER_DepositRequestPS));
+ break;
+ }
+ case TALER_EXCHANGEDB_TT_REFRESH_MELT:
+ {
+ struct TALER_RefreshMeltCoinAffirmationPS ms;
+ const struct TALER_EXCHANGEDB_RefreshMelt *melt = pos->details.melt;
+
+ type = "MELT";
+ value = melt->amount_with_fee;
+ ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
+ ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
+ ms.session_hash = melt->session_hash;
+ TALER_amount_hton (&ms.amount_with_fee,
+ &melt->amount_with_fee);
+ TALER_amount_hton (&ms.melt_fee,
+ &melt->melt_fee);
+ ms.coin_pub = melt->coin.coin_pub;
+ sig = &melt->coin_sig;
+ /* internal sanity check before we hand out a bogus sig... */
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
+ &ms.purpose,
+ &sig->eddsa_signature,
+ &melt->coin.coin_pub.eddsa_pub))
+ {
+ GNUNET_break (0);
+ json_decref (history);
+ return NULL;
+ }
+
+ details = TALER_json_from_data (&ms.purpose,
+ sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ json_array_append_new (history,
+ json_pack ("{s:s, s:o, s:o, s:o}",
+ "type", type,
+ "amount", TALER_json_from_amount (&value),
+ "signature", TALER_json_from_data (sig,
+ sizeof (struct TALER_CoinSpendSignatureP)),
+ "details", details));
+ }
+ return history;
+}
+
+
+/**
+ * Send proof that a /deposit request is invalid to client. This
+ * function will create a message with all of the operations affecting
+ * the coin that demonstrate that the coin has insufficient value.
+ *
+ * @param connection connection to the client
+ * @param tl transaction list to use to build reply
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_TransactionList *tl)
+{
+ json_t *history;
+
+ history = compile_transaction_history (tl);
+ if (NULL == history)
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_FORBIDDEN,
+ "{s:s, s:o}",
+ "error", "insufficient funds",
+ "history", history);
+}
+
+
+/**
+ * Compile the history of a reserve into a JSON object
+ * and calculate the total balance.
+ *
+ * @param rh reserve history to JSON-ify
+ * @param[out] balance set to current reserve balance
+ * @return json representation of the @a rh, NULL on error
+ */
+static json_t *
+compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
+ struct TALER_Amount *balance)
+{
+ struct TALER_Amount deposit_total;
+ struct TALER_Amount withdraw_total;
+ struct TALER_Amount value;
+ json_t *json_history;
+ int ret;
+ const struct TALER_EXCHANGEDB_ReserveHistory *pos;
+ struct TALER_WithdrawRequestPS wr;
+
+ json_history = json_array ();
+ ret = 0;
+ for (pos = rh; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
+ if (0 == ret)
+ deposit_total = pos->details.bank->amount;
+ else
+ if (GNUNET_OK !=
+ TALER_amount_add (&deposit_total,
+ &deposit_total,
+ &pos->details.bank->amount))
+ {
+ json_decref (json_history);
+ return NULL;
+ }
+ ret = 1;
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:O, s:o}",
+ "type", "DEPOSIT",
+ "wire", pos->details.bank->wire,
+ "amount", TALER_json_from_amount (&pos->details.bank->amount)));
+ break;
+ case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
+ break;
+ }
+ }
+
+ ret = 0;
+ for (pos = rh; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
+ break;
+ case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
+ value = pos->details.withdraw->amount_with_fee;
+ if (0 == ret)
+ {
+ withdraw_total = value;
+ }
+ else
+ {
+ if (GNUNET_OK !=
+ TALER_amount_add (&withdraw_total,
+ &withdraw_total,
+ &value))
+ {
+ json_decref (json_history);
+ return NULL;
+ }
+ }
+ ret = 1;
+ wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
+ wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
+ wr.reserve_pub = pos->details.withdraw->reserve_pub;
+ TALER_amount_hton (&wr.amount_with_fee,
+ &value);
+ TALER_amount_hton (&wr.withdraw_fee,
+ &pos->details.withdraw->withdraw_fee);
+ GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key,
+ &wr.h_denomination_pub);
+ wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope;
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:o, s:o, s:o}",
+ "type", "WITHDRAW",
+ "signature", TALER_json_from_data (&pos->details.withdraw->reserve_sig,
+ sizeof (struct TALER_ReserveSignatureP)),
+ "details", TALER_json_from_data (&wr,
+ sizeof (wr)),
+ "amount", TALER_json_from_amount (&value)));
+ break;
+ }
+ }
+ if (0 == ret)
+ {
+ /* did not encounter any withdraw operations, set to zero */
+ TALER_amount_get_zero (deposit_total.currency,
+ &withdraw_total);
+ }
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (balance,
+ &deposit_total,
+ &withdraw_total))
+ {
+ GNUNET_break (0);
+ json_decref (json_history);
+ return NULL;
+ }
+
+ return json_history;
+}
+
+
+/**
+ * Send reserve status information to client.
+ *
+ * @param connection connection to the client
+ * @param rh reserve history to return
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh)
+{
+ json_t *json_balance;
+ json_t *json_history;
+ struct TALER_Amount balance;
+
+ json_history = compile_reserve_history (rh,
+ &balance);
+ if (NULL == json_history)
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "balance calculation failure");
+ json_balance = TALER_json_from_amount (&balance);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o}",
+ "balance", json_balance,
+ "history", json_history);
+}
+
+
+/**
+ * Send reserve status information to client with the
+ * message that we have insufficient funds for the
+ * requested /reserve/withdraw operation.
+ *
+ * @param connection connection to the client
+ * @param rh reserve history to return
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh)
+{
+ json_t *json_balance;
+ json_t *json_history;
+ struct TALER_Amount balance;
+
+ json_history = compile_reserve_history (rh,
+ &balance);
+ if (NULL == json_history)
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "balance calculation failure");
+ json_balance = TALER_json_from_amount (&balance);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_PAYMENT_REQUIRED,
+ "{s:s, s:o, s:o}",
+ "error", "Insufficient funds",
+ "balance", json_balance,
+ "history", json_history);
+}
+
+
+/**
+ * Send blinded coin information to client.
+ *
+ * @param connection connection to the client
+ * @param collectable blinded coin to return
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
+{
+ json_t *sig_json;
+
+ sig_json = TALER_json_from_rsa_signature (collectable->sig.rsa_signature);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "ev_sig", sig_json);
+}
+
+
+/**
+ * Send a response for a failed "/refresh/melt" request. The
+ * transaction history of the given coin demonstrates that the
+ * @a residual value of the coin is below the @a requested
+ * contribution of the coin for the melt. Thus, the exchange
+ * refuses the melt operation.
+ *
+ * @param connection the connection to send the response to
+ * @param coin_pub public key of the coin
+ * @param coin_value original value of the coin
+ * @param tl transaction history for the coin
+ * @param requested how much this coin was supposed to contribute, including fee
+ * @param residual remaining value of the coin (after subtracting @a tl)
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_Amount coin_value,
+ struct TALER_EXCHANGEDB_TransactionList *tl,
+ struct TALER_Amount requested,
+ struct TALER_Amount residual)
+{
+ json_t *history;
+
+ history = compile_transaction_history (tl);
+ if (NULL == history)
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_FORBIDDEN,
+ "{s:s, s:o, s:o, s:o, s:o, s:o}",
+ "error",
+ "insufficient funds",
+ "coin_pub",
+ TALER_json_from_data (coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP)),
+ "original_value",
+ TALER_json_from_amount (&coin_value),
+ "residual_value",
+ TALER_json_from_amount (&residual),
+ "requested_value",
+ TALER_json_from_amount (&requested),
+ "history",
+ history);
+}
+
+
+/**
+ * Send a response to a "/refresh/melt" request.
+ *
+ * @param connection the connection to send the response to
+ * @param session_hash hash of the refresh session
+ * @param noreveal_index which index will the client not have to reveal
+ * @return a MHD status code
+ */
+int
+TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t noreveal_index)
+{
+ struct TALER_RefreshMeltConfirmationPS body;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+ json_t *sig_json;
+
+ body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
+ body.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT);
+ body.session_hash = *session_hash;
+ body.noreveal_index = htons (noreveal_index);
+ body.reserved = htons (0);
+ TMH_KS_sign (&body.purpose,
+ &pub,
+ &sig);
+ sig_json = TALER_json_from_data (&sig,
+ sizeof (sig));
+ GNUNET_assert (NULL != sig_json);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:i, s:o, s:o}",
+ "noreveal_index", (int) noreveal_index,
+ "exchange_sig", sig_json,
+ "exchange_pub", TALER_json_from_data (&pub,
+ sizeof (pub)));
+}
+
+
+/**
+ * Send a response for "/refresh/reveal".
+ *
+ * @param connection the connection to send the response to
+ * @param num_newcoins number of new coins for which we reveal data
+ * @param sigs array of @a num_newcoins signatures revealed
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection,
+ unsigned int num_newcoins,
+ const struct TALER_DenominationSignature *sigs)
+{
+ int newcoin_index;
+ json_t *root;
+ json_t *obj;
+ json_t *list;
+ int ret;
+
+ list = json_array ();
+ for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++)
+ {
+ obj = json_object ();
+ json_object_set_new (obj,
+ "ev_sig",
+ TALER_json_from_rsa_signature (sigs[newcoin_index].rsa_signature));
+ json_array_append_new (list,
+ obj);
+ }
+ root = json_object ();
+ json_object_set_new (root,
+ "ev_sigs",
+ list);
+ ret = TMH_RESPONSE_reply_json (connection,
+ root,
+ MHD_HTTP_OK);
+ json_decref (root);
+ return ret;
+}
+
+
+/**
+ * Send a response for a failed "/refresh/reveal", where the
+ * revealed value(s) do not match the original commitment.
+ *
+ * @param connection the connection to send the response to
+ * @param mc all information about the original commitment
+ * @param off offset in the array of kappa-commitments where
+ * the missmatch was detected
+ * @param j index of the coin for which the missmatch was
+ * detected
+ * @param missmatch_object name of the object that was
+ * bogus (i.e. "transfer key").
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_MeltCommitment *mc,
+ unsigned int off,
+ unsigned int j,
+ const char *missmatch_object)
+{
+ json_t *info_old;
+ json_t *info_new;
+ json_t *info_commit;
+ json_t *info_links;
+ unsigned int i;
+ unsigned int k;
+
+ info_old = json_array ();
+ for (i=0;i<mc->num_oldcoins;i++)
+ {
+ const struct TALER_EXCHANGEDB_RefreshMelt *rm;
+ json_t *rm_json;
+
+ rm = &mc->melts[i];
+ rm_json = json_object ();
+ json_object_set_new (rm_json,
+ "coin_sig",
+ TALER_json_from_data (&rm->coin_sig,
+ sizeof (struct TALER_CoinSpendSignatureP)));
+ json_object_set_new (rm_json,
+ "coin_pub",
+ TALER_json_from_data (&rm->coin.coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP)));
+ json_object_set_new (rm_json,
+ "melt_amount_with_fee",
+ TALER_json_from_amount (&rm->amount_with_fee));
+ json_object_set_new (rm_json,
+ "melt_fee",
+ TALER_json_from_amount (&rm->melt_fee));
+ json_array_append_new (info_old,
+ rm_json);
+ }
+ info_new = json_array ();
+ for (i=0;i<mc->num_newcoins;i++)
+ {
+ const struct TALER_DenominationPublicKey *pk;
+
+ pk = &mc->denom_pubs[i];
+ json_array_append_new (info_new,
+ TALER_json_from_rsa_public_key (pk->rsa_public_key));
+
+ }
+ info_commit = json_array ();
+ info_links = json_array ();
+ for (k=0;k<TALER_CNC_KAPPA;k++)
+ {
+ json_t *info_commit_k;
+ json_t *info_link_k;
+
+ info_commit_k = json_array ();
+ for (i=0;i<mc->num_newcoins;i++)
+ {
+ const struct TALER_EXCHANGEDB_RefreshCommitCoin *cc;
+ json_t *cc_json;
+
+ cc = &mc->commit_coins[k][i];
+ cc_json = json_object ();
+ json_object_set_new (cc_json,
+ "coin_ev",
+ TALER_json_from_data (cc->coin_ev,
+ cc->coin_ev_size));
+ json_object_set_new (cc_json,
+ "coin_priv_enc",
+ TALER_json_from_data (cc->refresh_link->coin_priv_enc,
+ sizeof (struct TALER_CoinSpendPrivateKeyP)));
+ json_object_set_new (cc_json,
+ "blinding_key_enc",
+ TALER_json_from_data (cc->refresh_link->blinding_key_enc,
+ cc->refresh_link->blinding_key_enc_size));
+
+ json_array_append_new (info_commit_k,
+ cc_json);
+ }
+ json_array_append_new (info_commit,
+ info_commit_k);
+ info_link_k = json_array ();
+ for (i=0;i<mc->num_oldcoins;i++)
+ {
+ const struct TALER_RefreshCommitLinkP *cl;
+ json_t *cl_json;
+
+ cl = &mc->commit_links[k][i];
+ cl_json = json_object ();
+ json_object_set_new (cl_json,
+ "transfer_pub",
+ TALER_json_from_data (&cl->transfer_pub,
+ sizeof (struct TALER_TransferPublicKeyP)));
+ json_object_set_new (cl_json,
+ "shared_secret_enc",
+ TALER_json_from_data (&cl->shared_secret_enc,
+ sizeof (struct TALER_EncryptedLinkSecretP)));
+ json_array_append_new (info_link_k,
+ cl_json);
+ }
+ json_array_append_new (info_links,
+ info_link_k);
+ }
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_CONFLICT,
+ "{s:s, s:i, s:i, s:o, s:o, s:o, s:o, s:s}",
+ "error", "commitment violation",
+ "offset", (int) off,
+ "index", (int) j,
+ "oldcoin_infos", info_old,
+ "newcoin_infos", info_new,
+ "commit_infos", info_commit,
+ "link_infos", info_links,
+ "object", missmatch_object);
+}
+
+
+/**
+ * Send a response for "/refresh/link".
+ *
+ * @param connection the connection to send the response to
+ * @param num_sessions number of sessions the coin was used in
+ * @param sessions array of @a num_session entries with
+ * information for each session
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
+ unsigned int num_sessions,
+ const struct TMH_RESPONSE_LinkSessionInfo *sessions)
+{
+ json_t *root;
+ json_t *mlist;
+ int res;
+ unsigned int i;
+
+ mlist = json_array ();
+ for (i=0;i<num_sessions;i++)
+ {
+ const struct TALER_EXCHANGEDB_LinkDataList *pos;
+ json_t *list = json_array ();
+
+ for (pos = sessions[i].ldl; NULL != pos; pos = pos->next)
+ {
+ json_t *obj;
+
+ obj = json_object ();
+ json_object_set_new (obj,
+ "link_enc",
+ TALER_json_from_data (pos->link_data_enc->coin_priv_enc,
+ sizeof (struct TALER_CoinSpendPrivateKeyP) +
+ pos->link_data_enc->blinding_key_enc_size));
+ json_object_set_new (obj,
+ "denom_pub",
+ TALER_json_from_rsa_public_key (pos->denom_pub.rsa_public_key));
+ json_object_set_new (obj,
+ "ev_sig",
+ TALER_json_from_rsa_signature (pos->ev_sig.rsa_signature));
+ json_array_append_new (list,
+ obj);
+ }
+ root = json_object ();
+ json_object_set_new (root,
+ "new_coins",
+ list);
+ json_object_set_new (root,
+ "transfer_pub",
+ TALER_json_from_data (&sessions[i].transfer_pub,
+ sizeof (struct TALER_TransferPublicKeyP)));
+ json_object_set_new (root,
+ "secret_enc",
+ TALER_json_from_data (&sessions[i].shared_secret_enc,
+ sizeof (struct TALER_EncryptedLinkSecretP)));
+ json_array_append_new (mlist,
+ root);
+ }
+ res = TMH_RESPONSE_reply_json (connection,
+ mlist,
+ MHD_HTTP_OK);
+ json_decref (mlist);
+ return res;
+}
+
+
+/**
+ * A merchant asked for details about a deposit, but
+ * we do not know anything about the deposit. Generate the
+ * 404 reply.
+ *
+ * @param connection connection to the client
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error", "Deposit unknown");
+}
+
+
+/**
+ * A merchant asked for details about a deposit, but
+ * we did not execute the deposit yet. Generate a 202 reply.
+ *
+ * @param connection connection to the client
+ * @param planned_exec_time planned execution time
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
+ struct GNUNET_TIME_Absolute planned_exec_time)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_ACCEPTED,
+ "{s:o}",
+ "execution_time", TALER_json_from_abs (planned_exec_time));
+}
+
+
+/**
+ * A merchant asked for details about a deposit. Provide
+ * them. Generates the 200 reply.
+ *
+ * @param connection connection to the client
+ * @param h_contract hash of the contract
+ * @param h_wire hash of wire account details
+ * @param coin_pub public key of the coin
+ * @param coin_contribution how much did the coin we asked about
+ * contribute to the total transfer value? (deposit value minus fee)
+ * @param transaction_id merchant transaction identifier
+ * @param wtid raw wire transfer identifier
+ * @param exec_time execution time of the wire transfer
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_contribution,
+ uint64_t transaction_id,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute exec_time)
+{
+ struct TALER_ConfirmWirePS cw;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+
+ cw.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE);
+ cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
+ cw.h_wire = *h_wire;
+ cw.h_contract = *h_contract;
+ cw.wtid = *wtid;
+ cw.coin_pub = *coin_pub;
+ cw.transaction_id = GNUNET_htonll (transaction_id);
+ cw.execution_time = GNUNET_TIME_absolute_hton (exec_time);
+ TALER_amount_hton (&cw.coin_contribution,
+ coin_contribution);
+ TMH_KS_sign (&cw.purpose,
+ &pub,
+ &sig);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:o, s:o, s:o, s:o}",
+ "wtid", TALER_json_from_data (wtid,
+ sizeof (*wtid)),
+ "execution_time", TALER_json_from_abs (exec_time),
+ "coin_contribution", TALER_json_from_amount (coin_contribution),
+ "exchange_sig", TALER_json_from_data (&sig,
+ sizeof (sig)),
+ "exchange_pub", TALER_json_from_data (&pub,
+ sizeof (pub)));
+}
+
+
+/**
+ * A merchant asked for transaction details about a wire transfer.
+ * Provide them. Generates the 200 reply.
+ *
+ * @param connection connection to the client
+ * @param total total amount that was transferred
+ * @param merchant_pub public key of the merchant
+ * @param h_wire destination account
+ * @param deposits details about the combined deposits
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
+ const struct TALER_Amount *total,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ json_t *deposits)
+{
+ /* FIXME: #4135: signing not implemented here */
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:o, s:o}",
+ "total", TALER_json_from_amount (total),
+ "merchant_pub", TALER_json_from_data (merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP)),
+ "h_wire", TALER_json_from_data (h_wire,
+ sizeof (struct GNUNET_HashCode)),
+ "deposits", deposits);
+}
+
+
+/* end of taler-exchange-httpd_responses.c */
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
new file mode 100644
index 000000000..817273a58
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -0,0 +1,469 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd_responses.h
+ * @brief API for generating the various replies of the exchange; these
+ * functions are called TMH_RESPONSE_reply_ and they generate
+ * and queue MHD response objects for a given connection.
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_RESPONSES_H
+#define TALER_EXCHANGE_HTTPD_RESPONSES_H
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler-exchange-httpd.h"
+#include "taler-exchange-httpd_db.h"
+
+/**
+ * Add headers we want to return in every response.
+ * Useful for testing, like if we want to always close
+ * connections.
+ *
+ * @param response response to modify
+ */
+void
+TMH_RESPONSE_add_global_headers (struct MHD_Response *response);
+
+
+/**
+ * Send JSON object as response.
+ *
+ * @param connection the MHD connection
+ * @param json the json object
+ * @param response_code the http response code
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
+ const json_t *json,
+ unsigned int response_code);
+
+
+/**
+ * Function to call to handle the request by building a JSON
+ * reply from a format string and varargs.
+ *
+ * @param connection the MHD connection to handle
+ * @param response_code HTTP response code to use
+ * @param fmt format string for pack
+ * @param ... varargs
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
+ unsigned int response_code,
+ const char *fmt,
+ ...);
+
+
+/**
+ * Send a response indicating an invalid signature.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
+ const char *param_name);
+
+
+/**
+ * Send a response indicating an invalid argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
+ const char *param_name);
+
+
+/**
+ * Send a response indicating an argument refering to a
+ * resource unknown to the exchange (i.e. unknown reserve or
+ * denomination key).
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
+ const char *param_name);
+
+
+/**
+ * Send a response indicating a missing argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is missing
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
+ const char *param_name);
+
+
+/**
+ * Send a response indicating permission denied.
+ *
+ * @param connection the MHD connection to use
+ * @param hint hint about why access was denied
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
+ const char *hint);
+
+
+/**
+ * Send a response indicating an internal error.
+ *
+ * @param connection the MHD connection to use
+ * @param hint hint about the internal error's nature
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
+ const char *hint);
+
+
+/**
+ * Send a response indicating an external error.
+ *
+ * @param connection the MHD connection to use
+ * @param hint hint about the error's nature
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
+ const char *hint);
+
+
+/**
+ * Send a response indicating an error committing a
+ * transaction (concurrent interference).
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection);
+
+
+/**
+ * Send a response indicating a failure to talk to the Exchange's
+ * database.
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection);
+
+
+/**
+ * Send a response indicating that the request was too big.
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection);
+
+
+/**
+ * Send a response indicating that the JSON was malformed.
+ *
+ * @param connection the MHD connection to use
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection);
+
+
+/**
+ * Send confirmation of deposit success to client. This function
+ * will create a signed message affirming the given information
+ * and return it to the client. By this, the exchange affirms that
+ * the coin had sufficient (residual) value for the specified
+ * transaction and that it will execute the requested deposit
+ * operation with the given wiring details.
+ *
+ * @param connection connection to the client
+ * @param coin_pub public key of the coin
+ * @param h_wire hash of wire details
+ * @param h_contract hash of contract details
+ * @param transaction_id transaction ID
+ * @param timestamp client's timestamp
+ * @param refund_deadline until when this deposit be refunded
+ * @param merchant merchant public key
+ * @param amount_without_fee fraction of coin value to deposit (without fee)
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ struct GNUNET_TIME_Absolute timestamp,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ const struct TALER_MerchantPublicKeyP *merchant,
+ const struct TALER_Amount *amount_without_fee);
+
+
+/**
+ * Send proof that a /deposit request is invalid to client. This
+ * function will create a message with all of the operations affecting
+ * the coin that demonstrate that the coin has insufficient value.
+ *
+ * @param connection connection to the client
+ * @param tl transaction list to use to build reply
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_TransactionList *tl);
+
+
+/**
+ * A merchant asked for details about a deposit, but
+ * we do not know anything about the deposit. Generate the
+ * 404 reply.
+ *
+ * @param connection connection to the client
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection);
+
+
+/**
+ * A merchant asked for details about a deposit, but
+ * we did not execute the deposit yet. Generate a 202 reply.
+ *
+ * @param connection connection to the client
+ * @param planned_exec_time planned execution time
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
+ struct GNUNET_TIME_Absolute planned_exec_time);
+
+
+/**
+ * A merchant asked for details about a deposit. Provide
+ * them. Generates the 200 reply.
+ *
+ * @param connection connection to the client
+ * @param h_contract hash of the contract
+ * @param h_wire hash of wire account details
+ * @param coin_pub public key of the coin
+ * @param coin_contribution contribution of this coin to the total amount transferred
+ * @param transaction_id merchant transaction identifier
+ * @param wtid raw wire transfer identifier
+ * @param exec_time execution time of the wire transfer
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_contribution,
+ uint64_t transaction_id,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute exec_time);
+
+
+/**
+ * A merchant asked for transaction details about a wire transfer.
+ * Provide them. Generates the 200 reply.
+ *
+ * @param connection connection to the client
+ * @param total total amount that was transferred
+ * @param merchant_pub public key of the merchant
+ * @param h_wire destination account
+ * @param deposits details about the combined deposits
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
+ const struct TALER_Amount *total,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ json_t *deposits);
+
+
+/**
+ * Send reserve status information to client.
+ *
+ * @param connection connection to the client
+ * @param rh reserve history to return
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh);
+
+
+/**
+ * Send reserve status information to client with the
+ * message that we have insufficient funds for the
+ * requested /reserve/withdraw operation.
+ *
+ * @param connection connection to the client
+ * @param rh reserve history to return
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_ReserveHistory *rh);
+
+
+/**
+ * Send blinded coin information to client.
+ *
+ * @param connection connection to the client
+ * @param collectable blinded coin to return
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
+
+
+/**
+ * Send a confirmation response to a "/refresh/melt" request.
+ *
+ * @param connection the connection to send the response to
+ * @param session_hash hash of the refresh session
+ * @param noreveal_index which index will the client not have to reveal
+ * @return a MHD status code
+ */
+int
+TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t noreveal_index);
+
+
+/**
+ * Send a response for a failed "/refresh/melt" request. The
+ * transaction history of the given coin demonstrates that the
+ * @a residual value of the coin is below the @a requested
+ * contribution of the coin for the melt. Thus, the exchange
+ * refuses the melt operation.
+ *
+ * @param connection the connection to send the response to
+ * @param coin_pub public key of the coin
+ * @param coin_value original value of the coin
+ * @param tl transaction history for the coin
+ * @param requested how much this coin was supposed to contribute
+ * @param residual remaining value of the coin (after subtracting @a tl)
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_Amount coin_value,
+ struct TALER_EXCHANGEDB_TransactionList *tl,
+ struct TALER_Amount requested,
+ struct TALER_Amount residual);
+
+
+/**
+ * Send a response for "/refresh/reveal".
+ *
+ * @param connection the connection to send the response to
+ * @param num_newcoins number of new coins for which we reveal data
+ * @param sigs array of @a num_newcoins signatures revealed
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection,
+ unsigned int num_newcoins,
+ const struct TALER_DenominationSignature *sigs);
+
+
+/**
+ * Send a response for a failed "/refresh/reveal", where the
+ * revealed value(s) do not match the original commitment.
+ *
+ * @param connection the connection to send the response to
+ * @param mc all information about the original commitment
+ * @param off offset in the array of kappa-commitments where
+ * the missmatch was detected
+ * @param j index of the coin for which the missmatch was
+ * detected
+ * @param missmatch_object name of the object that was
+ * bogus (i.e. "transfer key").
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_MeltCommitment *mc,
+ unsigned int off,
+ unsigned int j,
+ const char *missmatch_object);
+
+
+/**
+ * @brief Information for each session a coin was melted into.
+ */
+struct TMH_RESPONSE_LinkSessionInfo
+{
+ /**
+ * Transfer public key of the coin.
+ */
+ struct TALER_TransferPublicKeyP transfer_pub;
+
+ /**
+ * Encrypted shared secret for decrypting the transfer secrets.
+ */
+ struct TALER_EncryptedLinkSecretP shared_secret_enc;
+
+ /**
+ * Linked data of coins being created in the session.
+ */
+ struct TALER_EXCHANGEDB_LinkDataList *ldl;
+
+};
+
+
+/**
+ * Send a response for "/refresh/link".
+ *
+ * @param connection the connection to send the response to
+ * @param num_sessions number of sessions the coin was used in
+ * @param sessions array of @a num_session entries with
+ * information for each session
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
+ unsigned int num_sessions,
+ const struct TMH_RESPONSE_LinkSessionInfo *sessions);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_test.c b/src/exchange/taler-exchange-httpd_test.c
new file mode 100644
index 000000000..876869d86
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_test.c
@@ -0,0 +1,621 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_test.c
+ * @brief Handle /test requests; parses the POST and JSON and
+ * checks that the client is binary-compatible
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include "taler_signatures.h"
+#include "taler-exchange-httpd_test.h"
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Private key the test module uses for signing.
+ */
+static struct GNUNET_CRYPTO_rsa_PrivateKey *rsa_pk;
+
+
+/**
+ * Handle a "/test/base32" request. Parses the JSON in the post, runs
+ * the Crockford Base32 decoder on the "input" field in the JSON,
+ * hashes the result and sends the hashed value back as a JSON
+ * string with in Base32 Crockford encoding. Thus, this API
+ * allows testing the hashing and Crockford encoding/decoding
+ * functions.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ void *in_ptr;
+ size_t in_ptr_size;
+ struct GNUNET_HashCode hc;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ GNUNET_CRYPTO_hash (in_ptr,
+ in_ptr_size,
+ &hc);
+ TMH_PARSE_release_data (spec);
+ json_decref (json);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "output",
+ TALER_json_from_data (&hc, sizeof (struct GNUNET_HashCode)));
+}
+
+
+/**
+ * Handle a "/test/encrypt" request. Parses the JSON in the post,
+ * runs the Crockford Base32 decoder on the "input" field in the JSON,
+ * and encrypts the result with a shared secret derived using the HKDF
+ * function with salt "skey" and IV derived with salt "iv" of the
+ * Crockford Base32-encoded "key_hash" field in the JSON. The
+ * symmetric encryption is the AES/Twofish double-encryption used in
+ * Taler/GNUnet. The resulting ciphertext is returned as a Crockford
+ * Base32 encoded JSON string.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ struct GNUNET_HashCode key;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+ void *in_ptr;
+ size_t in_ptr_size;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
+ TMH_PARSE_member_fixed ("key_hash", &key),
+ TMH_PARSE_MEMBER_END
+ };
+ char *out;
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ json_decref (json);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (&skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
+ "skey", strlen ("skey"),
+ &key, sizeof (key),
+ NULL, 0));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (&iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
+ "iv", strlen ("iv"),
+ &key, sizeof (key),
+ NULL, 0));
+ out = GNUNET_malloc (in_ptr_size);
+ GNUNET_break (in_ptr_size ==
+ GNUNET_CRYPTO_symmetric_encrypt (in_ptr,
+ in_ptr_size,
+ &skey,
+ &iv,
+ out));
+ json = TALER_json_from_data (out,
+ in_ptr_size);
+ GNUNET_free (out);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "output",
+ json);
+}
+
+
+/**
+ * Handle a "/test/hkdf" request. Parses the JSON in the post, runs
+ * the Crockford Base32 decoder on the "input" field in the JSON,
+ * computes `HKDF(input, "salty")` and sends the result back as a JSON
+ * string with in Base32 Crockford encoding. Thus, this API allows
+ * testing the use of the (H)KDF. Note that the test fixes the
+ * input and output sizes and the salt (and the hash functions used
+ * by the HKDF), so this is only useful to test the HKDF in the
+ * same way it will be used within Taler/GNUnet.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ struct GNUNET_HashCode hc;
+ void *in_ptr;
+ size_t in_ptr_size;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ json_decref (json);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
+ "salty", strlen ("salty"),
+ in_ptr,
+ in_ptr_size,
+ NULL, 0);
+ TMH_PARSE_release_data (spec);
+ json = TALER_json_from_data (&hc,
+ sizeof (struct GNUNET_HashCode));
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "output",
+ json);
+}
+
+
+/**
+ * Handle a "/test/ecdhe" request. Parses the JSON in the post, which
+ * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv"
+ * with a private key. The reply is the resulting JSON is an object
+ * with the field "ecdh_hash" containing a Crockford Base32-encoded
+ * string representing the hash derived via ECDH of the two keys.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ struct GNUNET_CRYPTO_EcdhePublicKey pub;
+ struct GNUNET_CRYPTO_EcdhePrivateKey priv;
+ struct GNUNET_HashCode hc;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("ecdhe_pub", &pub),
+ TMH_PARSE_member_fixed ("ecdhe_priv", &priv),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ json_decref (json);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_ecc_ecdh (&priv,
+ &pub,
+ &hc))
+ {
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to perform ECDH");
+ }
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "ecdh_hash",
+ TALER_json_from_data (&hc,
+ sizeof (hc)));
+}
+
+
+/**
+ * Handle a "/test/eddsa" request. Parses the JSON in the post,
+ * which must contain a "eddsa_pub" with a public key and an
+ *"eddsa_sig" with the corresponding signature for a purpose
+ * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is
+ * valid, a reply with a #TALER_SIGNATURE_EXCHANGE_TEST_EDDSA is
+ * returned using the same JSON format.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ struct GNUNET_CRYPTO_EddsaPublicKey pub;
+ struct GNUNET_CRYPTO_EddsaSignature sig;
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("eddsa_pub", &pub),
+ TMH_PARSE_member_fixed ("eddsa_sig", &sig),
+ TMH_PARSE_MEMBER_END
+ };
+ struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ json_decref (json);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
+ purpose.purpose = htonl (TALER_SIGNATURE_CLIENT_TEST_EDDSA);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_CLIENT_TEST_EDDSA,
+ &purpose,
+ &sig,
+ &pub))
+ {
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_signature_invalid (connection,
+ "eddsa_sig");
+ }
+ TMH_PARSE_release_data (spec);
+ pk = GNUNET_CRYPTO_eddsa_key_create ();
+ purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_TEST_EDDSA);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_sign (pk,
+ &purpose,
+ &sig))
+ {
+ GNUNET_free (pk);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to EdDSA-sign");
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (pk,
+ &pub);
+ GNUNET_free (pk);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o}",
+ "eddsa_pub",
+ TALER_json_from_data (&pub,
+ sizeof (pub)),
+ "eddsa_sig",
+ TALER_json_from_data (&sig,
+ sizeof (sig)));
+}
+
+
+/**
+ * Handle a "/test/rsa/get" request. Returns the RSA public key
+ * ("rsa_pub") which is used for signing in "/test/rsa/sign".
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ int res;
+ struct GNUNET_CRYPTO_rsa_PublicKey *pub;
+
+ if (NULL == rsa_pk)
+ rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024);
+ if (NULL == rsa_pk)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to create RSA key");
+ }
+ pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk);
+ if (NULL == pub)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to get public RSA key");
+ }
+ res = TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "rsa_pub",
+ TALER_json_from_rsa_public_key (pub));
+ GNUNET_CRYPTO_rsa_public_key_free (pub);
+ return res;
+}
+
+
+/**
+ * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which
+ * must contain an "blind_ev" blinded value. A a blinded signature
+ * ("rsa_blind_sig") is returned.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ struct GNUNET_CRYPTO_rsa_Signature *sig;
+ void *in_ptr;
+ size_t in_ptr_size;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_variable ("blind_ev", &in_ptr, &in_ptr_size),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ json_decref (json);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ if (NULL == rsa_pk)
+ rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024);
+ if (NULL == rsa_pk)
+ {
+ GNUNET_break (0);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to create RSA key");
+ }
+ sig = GNUNET_CRYPTO_rsa_sign (rsa_pk,
+ in_ptr,
+ in_ptr_size);
+ if (NULL == sig)
+ {
+ GNUNET_break (0);
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to RSA-sign");
+ }
+ TMH_PARSE_release_data (spec);
+ res = TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "rsa_blind_sig",
+ TALER_json_from_rsa_signature (sig));
+ GNUNET_CRYPTO_rsa_signature_free (sig);
+ return res;
+}
+
+
+/**
+ * Handle a "/test/transfer" request. Parses the JSON in the post,
+ * which must contain a "secret_enc" with the encrypted link secret,
+ * a "trans_priv" with the transfer private key, a "coin_pub" with
+ * a coin public key. A reply with the decrypted "secret" is
+ * returned.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+ struct TALER_EncryptedLinkSecretP secret_enc;
+ struct TALER_TransferPrivateKeyP trans_priv;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("secret_enc", &secret_enc),
+ TMH_PARSE_member_fixed ("trans_priv", &trans_priv),
+ TMH_PARSE_member_fixed ("coin_pub", &coin_pub),
+ TMH_PARSE_MEMBER_END
+ };
+ struct TALER_LinkSecretP secret;
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ json_decref (json);
+ if (GNUNET_YES != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ if (GNUNET_OK !=
+ TALER_link_decrypt_secret (&secret_enc,
+ &trans_priv,
+ &coin_pub,
+ &secret))
+ {
+ TMH_PARSE_release_data (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to decrypt secret");
+ }
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "secret",
+ TALER_json_from_data (&secret,
+ sizeof (secret)));
+}
+
+
+/**
+ * Handle a "/test" request. Parses the JSON in the post.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ json_t *json;
+ int res;
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+
+ json_decref (json);
+ return MHD_NO;
+}
+
+
+/* end of taler-exchange-httpd_test.c */
diff --git a/src/exchange/taler-exchange-httpd_test.h b/src/exchange/taler-exchange-httpd_test.h
new file mode 100644
index 000000000..30535f54f
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_test.h
@@ -0,0 +1,225 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_test.h
+ * @brief Handle /test requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_TEST_H
+#define TALER_EXCHANGE_HTTPD_TEST_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/test/base32" request. Parses the JSON in the post, runs
+ * the Crockford Base32 decoder on the "input" field in the JSON,
+ * hashes the result and sends the hashed value back as a JSON
+ * string with in Base32 Crockford encoding. Thus, this API
+ * allows testing the hashing and Crockford encoding/decoding
+ * functions.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/encrypt" request. Parses the JSON in the post,
+ * runs the Crockford Base32 decoder on the "input" field in the JSON,
+ * and encrypts the result with a shared secret derived using the HKDF
+ * function with salt "skey" and IV derived with salt "iv" of the
+ * Crockford Base32-encoded "key_hash" field in the JSON. The
+ * symmetric encryption is the AES/Twofish double-encryption used in
+ * Taler/GNUnet. The resulting ciphertext is returned as a Crockford
+ * Base32 encoded JSON string.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/hkdf" request. Parses the JSON in the post, runs
+ * the Crockford Base32 decoder on the "input" field in the JSON,
+ * computes `HKDF(input, "salty")` and sends the result back as a JSON
+ * string with in Base32 Crockford encoding. Thus, this API allows
+ * testing the use of the (H)KDF. Note that the test fixes the
+ * input and output sizes and the salt (and the hash functions used
+ * by the HKDF), so this is only useful to test the HKDF in the
+ * same way it will be used within Taler/GNUnet.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/ecdhe" request. Parses the JSON in the post, which
+ * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv"
+ * with a private key. The reply is the resulting JSON is an object
+ * with the field "ecdh_hash" containing a Crockford Base32-encoded
+ * string representing the hash derived via ECDH of the two keys.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/eddsa" request. Parses the JSON in the post,
+ * which must contain a "eddsa_pub" with a public key and an
+ *"ecdsa_sig" with the corresponding signature for a purpose
+ * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is
+ * valid, a reply with a #TALER_SIGNATURE_EXCHANGE_TEST_EDDSA is
+ * returned using the same JSON format.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/rsa/get" request. Returns the RSA public key
+ * ("rsa_pub") which is used for signing in "/test/rsa/sign".
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which
+ * must contain an "blind_ev" blinded value. A a blinded signature
+ * ("rsa_blind_sig") is returned.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test/transfer" request. Parses the JSON in the post,
+ * which must contain a "secret_enc" with the encrypted link secret,
+ * a "trans_priv" with the transfer private key, a "coin_pub" with
+ * a coin public key. A reply with the decrypted "secret" is
+ * returned.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/test" request. Parses the JSON in the post.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TEST_handler_test (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_tracking.c b/src/exchange/taler-exchange-httpd_tracking.c
new file mode 100644
index 000000000..afb821cb9
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_tracking.c
@@ -0,0 +1,165 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_tracking.c
+ * @brief Handle wire transfer tracking-related requests
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_signatures.h"
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_tracking.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Handle a "/wire/deposits" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct TALER_WireTransferIdentifierRawP wtid;
+ int res;
+
+ res = TMH_PARSE_mhd_request_arg_data (connection,
+ "wtid",
+ &wtid,
+ sizeof (struct TALER_WireTransferIdentifierRawP));
+ if (GNUNET_SYSERR == res)
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* parse error */
+ return TMH_DB_execute_wire_deposits (connection,
+ &wtid);
+}
+
+
+/**
+ * Check the merchant signature, and if it is valid,
+ * return the wire transfer identifier.
+ *
+ * @param connection the MHD connection to handle
+ * @param tps signed request to execute
+ * @param merchant_pub public key from the merchant
+ * @param merchant_sig signature from the merchant (to be checked)
+ * @param transaction_id transaction ID (in host byte order)
+ * @return MHD result code
+ */
+static int
+check_and_handle_deposit_wtid_request (struct MHD_Connection *connection,
+ const struct TALER_DepositTrackPS *tps,
+ struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct TALER_MerchantSignatureP *merchant_sig,
+ uint64_t transaction_id)
+{
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID,
+ &tps->purpose,
+ &merchant_sig->eddsa_sig,
+ &merchant_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return TMH_RESPONSE_reply_signature_invalid (connection,
+ "merchant_sig");
+ }
+ return TMH_DB_execute_deposit_wtid (connection,
+ &tps->h_contract,
+ &tps->h_wire,
+ &tps->coin_pub,
+ merchant_pub,
+ transaction_id);
+}
+
+
+/**
+ * Handle a "/deposit/wtid" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ int res;
+ json_t *json;
+ struct TALER_DepositTrackPS tps;
+ uint64_t transaction_id;
+ struct TALER_MerchantSignatureP merchant_sig;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_fixed ("H_wire", &tps.h_wire),
+ TMH_PARSE_member_fixed ("H_contract", &tps.h_contract),
+ TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub),
+ TMH_PARSE_member_uint64 ("transaction_id", &transaction_id),
+ TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant),
+ TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == json) )
+ return MHD_YES;
+ res = TMH_PARSE_json_data (connection,
+ json,
+ spec);
+ if (GNUNET_OK != res)
+ {
+ json_decref (json);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+ tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS));
+ tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID);
+ tps.transaction_id = GNUNET_htonll (transaction_id);
+ res = check_and_handle_deposit_wtid_request (connection,
+ &tps,
+ &tps.merchant,
+ &merchant_sig,
+ transaction_id);
+ TMH_PARSE_release_data (spec);
+ json_decref (json);
+ return res;
+}
+
+
+/* end of taler-exchange-httpd_tracking.c */
diff --git a/src/exchange/taler-exchange-httpd_tracking.h b/src/exchange/taler-exchange-httpd_tracking.h
new file mode 100644
index 000000000..d77de460a
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_tracking.h
@@ -0,0 +1,65 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_tracking.h
+ * @brief Handle wire transfer tracking-related requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_TRACKING_H
+#define TALER_EXCHANGE_HTTPD_TRACKING_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/wire/deposits" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/deposit/wtid" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_validation.c b/src/exchange/taler-exchange-httpd_validation.c
new file mode 100644
index 000000000..9132e3e02
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_validation.c
@@ -0,0 +1,231 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd_validation.c
+ * @brief helpers for calling the wire plugins to validate addresses
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler-exchange-httpd_validation.h"
+#include "taler_wire_plugin.h"
+
+
+/**
+ * Information we keep for each plugin.
+ */
+struct Plugin
+{
+
+ /**
+ * We keep plugins in a DLL.
+ */
+ struct Plugin *next;
+
+ /**
+ * We keep plugins in a DLL.
+ */
+ struct Plugin *prev;
+
+ /**
+ * Type of the wireformat.
+ */
+ char *type;
+
+ /**
+ * Pointer to the plugin.
+ */
+ struct TALER_WIRE_Plugin *plugin;
+
+};
+
+/**
+ * Head of DLL of wire plugins.
+ */
+static struct Plugin *wire_head;
+
+/**
+ * Tail of DLL of wire plugins.
+ */
+static struct Plugin *wire_tail;
+
+
+/**
+ * Initialize validation subsystem.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct Plugin *p;
+ char *wireformats;
+ char *lib_name;
+ const char *token;
+
+ /* Find out list of supported wire formats */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "wireformat",
+ &wireformats))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "wireformat");
+ return GNUNET_SYSERR;
+ }
+ for (token = strtok (wireformats,
+ " ");
+ NULL != token;
+ token = strtok (NULL,
+ " "))
+ {
+ (void) GNUNET_asprintf (&lib_name,
+ "libtaler_plugin_wire_%s",
+ token);
+ p = GNUNET_new (struct Plugin);
+ p->type = GNUNET_strdup (token);
+ p->plugin = GNUNET_PLUGIN_load (lib_name,
+ (void *) cfg);
+ if (NULL == p->plugin)
+ {
+ GNUNET_free (p);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to load plugin %s\n",
+ lib_name);
+ GNUNET_free (lib_name);
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ p->plugin->library_name = lib_name;
+ GNUNET_CONTAINER_DLL_insert (wire_head,
+ wire_tail,
+ p);
+ }
+ GNUNET_free (wireformats);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown validation subsystem.
+ */
+void
+TMH_VALIDATION_done ()
+{
+ struct Plugin *p;
+ char *lib_name;
+
+ while (NULL != (p = wire_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (wire_head,
+ wire_tail,
+ p);
+ lib_name = p->plugin->library_name;
+ GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
+ p->plugin));
+ GNUNET_free (lib_name);
+ GNUNET_free (p->type);
+ GNUNET_free (p);
+ }
+}
+
+
+/**
+ * Check if the given wire format JSON object is correctly formatted as
+ * a wire address.
+ *
+ * @param wire the JSON wire format object
+ * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
+ */
+int
+TMH_json_validate_wireformat (const json_t *wire)
+{
+ const char *stype;
+ json_error_t error;
+ struct Plugin *p;
+
+ if (0 != json_unpack_ex ((json_t *) wire,
+ &error, 0,
+ "{s:s}",
+ "type", &stype))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ for (p=wire_head; NULL != p; p = p->next)
+ if (0 == strcasecmp (p->type,
+ stype))
+ return p->plugin->wire_validate (wire);
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check if we support the given wire method.
+ *
+ * @param type type of wire method to check
+ * @return #GNUNET_YES if the method is supported
+ */
+int
+TMH_VALIDATION_test_method (const char *type)
+{
+ struct Plugin *p;
+
+ for (p=wire_head;NULL != p;p = p->next)
+ if (0 == strcasecmp (type,
+ p->type))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Obtain supported validation methods as a JSON array,
+ * and as a hash.
+ *
+ * @param[out] h set to the hash of the JSON methods
+ * @return JSON array with the supported validation methods
+ */
+json_t *
+TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h)
+{
+ json_t *methods;
+ struct GNUNET_HashContext *hc;
+ const char *wf;
+ struct Plugin *p;
+
+ methods = json_array ();
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ for (p=wire_head;NULL != p;p = p->next)
+ {
+ wf = p->type;
+ json_array_append_new (methods,
+ json_string (wf));
+ GNUNET_CRYPTO_hash_context_read (hc,
+ wf,
+ strlen (wf) + 1);
+ }
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ h);
+ return methods;
+}
+
+
+/* end of taler-exchange-httpd_validation.c */
diff --git a/src/exchange/taler-exchange-httpd_validation.h b/src/exchange/taler-exchange-httpd_validation.h
new file mode 100644
index 000000000..f41e2ee5f
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_validation.h
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-exchange-httpd_validation.h
+ * @brief helpers for calling the wire plugins to validate addresses
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_VALIDATION_H
+#define TALER_EXCHANGE_HTTPD_VALIDATION_H
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+
+
+/**
+ * Initialize validation subsystem.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Shutdown validation subsystem.
+ */
+void
+TMH_VALIDATION_done (void);
+
+
+/**
+ * Check if the given wire format JSON object is correctly formatted as
+ * a wire address.
+ *
+ * @param wire the JSON wire format object
+ * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
+ */
+int
+TMH_json_validate_wireformat (const json_t *wire);
+
+/**
+ * Check if we support the given wire method.
+ *
+ * @param type type of wire method to check
+ * @return #GNUNET_YES if the method is supported
+ */
+int
+TMH_VALIDATION_test_method (const char *type);
+
+
+/**
+ * Obtain supported validation methods as a JSON array,
+ * and as a hash.
+ *
+ * @param[out] h set to the hash of the JSON methods
+ * @return JSON array with the supported validation methods
+ */
+json_t *
+TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c
new file mode 100644
index 000000000..faf018b99
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_wire.c
@@ -0,0 +1,220 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_wire.c
+ * @brief Handle /wire requests
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_validation.h"
+#include "taler-exchange-httpd_wire.h"
+#include <jansson.h>
+
+/**
+ * Handle a "/wire" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct TALER_ExchangeWireSupportMethodsPS wsm;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+ json_t *methods;
+
+ wsm.purpose.size = htonl (sizeof (wsm));
+ wsm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_WIRE_TYPES);
+ methods = TMH_VALIDATION_get_methods (&wsm.h_wire_types);
+ TMH_KS_sign (&wsm.purpose,
+ &pub,
+ &sig);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:o}",
+ "methods", methods,
+ "sig", TALER_json_from_data (&sig,
+ sizeof (sig)),
+ "pub", TALER_json_from_data (&pub,
+ sizeof (pub)));
+}
+
+
+/**
+ * Handle a "/wire/test" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct MHD_Response *response;
+ int ret;
+ char *wire_test_redirect;
+
+ response = MHD_create_response_from_buffer (0, NULL,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (response);
+ if (GNUNET_NO == TMH_VALIDATION_test_method ("test"))
+ {
+ /* Return 501: not implemented */
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NOT_IMPLEMENTED,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "wire-test",
+ "REDIRECT_URL",
+ &wire_test_redirect))
+ {
+ /* oopsie, configuration error */
+ MHD_destroy_response (response);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "REDIRECT_URL not configured");
+ }
+ MHD_add_response_header (response,
+ MHD_HTTP_HEADER_LOCATION,
+ wire_test_redirect);
+ GNUNET_free (wire_test_redirect);
+ ret = MHD_queue_response (connection,
+ rh->response_code,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+/**
+ * Handle a "/wire/sepa" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct MHD_Response *response;
+ int ret;
+ char *sepa_wire_file;
+ int fd;
+ struct stat sbuf;
+
+ if (GNUNET_NO == TMH_VALIDATION_test_method ("sepa"))
+ {
+ /* Return 501: not implemented */
+ response = MHD_create_response_from_buffer (0, NULL,
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (response);
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NOT_IMPLEMENTED,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+ }
+ /* Fetch reply */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "wire-sepa",
+ "SEPA_RESPONSE_FILE",
+ &sepa_wire_file))
+ {
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "SEPA_RESPONSE_FILE not configured");
+ }
+ fd = open (sepa_wire_file,
+ O_RDONLY);
+ if (-1 == fd)
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "open",
+ sepa_wire_file);
+ GNUNET_free (sepa_wire_file);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to open SEPA_RESPONSE_FILE");
+ }
+ if (0 != fstat (fd, &sbuf))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "fstat",
+ sepa_wire_file);
+ (void) close (fd);
+ GNUNET_free (sepa_wire_file);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to open SEPA_RESPONSE_FILE");
+ }
+ response = MHD_create_response_from_fd ((size_t) sbuf.st_size,
+ fd);
+ GNUNET_free (sepa_wire_file);
+ if (NULL == response)
+ {
+ (void) close (fd);
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ TMH_RESPONSE_add_global_headers (response);
+ if (NULL != rh->mime_type)
+ (void) MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ rh->mime_type);
+ ret = MHD_queue_response (connection,
+ rh->response_code,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+/* end of taler-exchange-httpd_wire.c */
diff --git a/src/exchange/taler-exchange-httpd_wire.h b/src/exchange/taler-exchange-httpd_wire.h
new file mode 100644
index 000000000..dc6dcc0f4
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_wire.h
@@ -0,0 +1,82 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_wire.h
+ * @brief Handle /wire requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_WIRE_H
+#define TALER_EXCHANGE_HTTPD_WIRE_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/wire" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/wire/test" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Handle a "/wire/sepa" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/mint/test-mint-home/master.priv b/src/exchange/test-exchange-home/master.priv
index 394926938..394926938 100644
--- a/src/mint/test-mint-home/master.priv
+++ b/src/exchange/test-exchange-home/master.priv
diff --git a/src/exchange/test_taler_exchange_httpd.data b/src/exchange/test_taler_exchange_httpd.data
new file mode 100644
index 000000000..43aa4ff05
--- /dev/null
+++ b/src/exchange/test_taler_exchange_httpd.data
@@ -0,0 +1,48 @@
+# This file is part of TALER
+# Copyright (C) 2015 GNUnet e.V.
+#
+# TALER is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
+#
+# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License along with
+# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+#
+#
+# This is a resource file for test_taler_exchange_httpd.sh.
+# Lines starting with '#' (must be first character in line) are comments.
+#
+# Each non-comment line must contain two strings, the first being the
+# URL on the HTTP serve which a HTTP POST request should be made out
+# two, followed by the JSON data to POST to the server.
+#
+# Note that neither element may contain any spaces!
+#
+#
+# Bad amount:
+/admin/add/incoming {"reserve_pub":"7RZBZ86677QMASD2KAYGEPD246C7B7RC6P101FNTG6ZK8X61A620","amount":"1","execution_date":"\/Date(1435934428788)\/","wire":{"empty":"empty"}}
+#
+# Bad wire format:
+/admin/add/incoming {"reserve_pub":"6VRFYZRVHJ434BV3J018MS6H7Q1V5Q6YECNMEF9G4WKB8QJQCAX0","amount":{"currency":"EUR","value":10,"fraction":3},"execution_date":"\/Date(1436258333286)\/","wire":{"empty":"empty"}}
+#
+# Malformed JSON (ill-balanced quotes around 'amount')
+/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0",amount":{"currency":"EUR","value":5,"fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}}
+#
+# Bad amount (value not a string)
+/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":{"currency":"EUR","value":"5","fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}}
+#
+# Bad amount (overall amount is a string)
+/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":"{\"currency\":\"EUR\",\"value\":5,\"fraction\":3}","execution_date":"\/Date(1436271156447)\/","wire":{"type":"test"}}
+#
+# Bogus denomination key
+/deposit {"f":{"currency":"EUR","value":5,"fraction":0},"H_contract":"NRT9E07FYT147V4VCDG0102P0YX0FZ11ZRG90F4X1HDV95M0J64ZVE4XQGNN9MJ3B5K3JX6TJ181KNGRYSZSTYZ5PQHBM1F9QKQ5B50","wire":{"bank":"dest bank","type":"TEST","account":42},"timestamp":"/Date(1436823947)/","coin_pub":"2KCPBGZ77VGJT4DG99EZAY0GQ5TJ89DF53FWYR5RFRTK0CCXRMFG","denom_pub":"51B7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_sig":"W1TDFCSW5XQX9ZF4QPVP3JAJFYA7G4X6SY2B49KRNTDMA685M9YNFETV4610RFKZMSQ3RBRCYBJQH1ZQSMTDMW9W8X6C9SGPCA5ST0R","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26DSQ8913AC1S7513EC9G6914AE228H236HHR68VKCCSK650MAGSM6GV3GCHP6D330H1R8GVKJD9P68W46H9Q8GVK8HA6752M2CSN8N248DHJ8H346E9J8RS4CDA28D33ECJ38S33JC9R6MRM8D9G74WM8HA668T44H1N6RT44GHS8CSK8H1G6D346C9J6CS3EC1N8H2M4HA38CSK2D246CW4CD1P70VMAD1Q891K8H1M64TK6C258MRM6G9R88RM6E2488WK2CSQ6GW3GH9N64RKGH2375136GA66533GCSJ65344CHH84W38HHP75330DA58RSKJCJ364SK0C1R8GVK6DSP61134HA48GT4CE1J6MW36C9G891K2GT68GTMCCSQ890M8E1P88R44DA174VK4E135452081918G2J2G0","transaction_id":1,"merchant_pub":"4032W2ZXFW000KRJQDH3CZR00000000004000030P6YG1NR50000","refund_deadline":"/Date(0)/"}
+#
+# missing coin_ev argument
+/withdraw/sign {"denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","#oin_ev":"7DPN42W14BWWD2NWNDYP086276CFV0H8VEV43NFWQGZ3Y8WVR5R5HCN8THX43Z61TFN3CH9N6X5Q0P0T9NF2G8ZWBH8KXEQFQ973CMDDHF1FSE2G9289AB9ERHM8X222VB2WS733X36P8EMG4D3T1N2JHFP530C9RPEAPHDQXZABB6CJ63YD0581JVRY365HHF20RW3BNVKXP","reserve_sig":"VPKYWKGE6FB172XX222N1J0TAEXQE6VERN5X4ANJ0D9K1E7JAX01CPR1PT51SKK5JD72H1GRJ0S2ZQSKN22ZBEGKS77GMT6BF6DD030","reserve_pub":"FN7ARB2MJH2EDMMVT2985Y141YTCE503FS27BTNQ6JSCG3GMBJDG"}
+#
+# malformed coin_ev argument
+/withdraw/sign {"denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_ev":"'DPN42W14BWWD2NWNDYP086276CFV0H8VEV43NFWQGZ3Y8WVR5R5HCN8THX43Z61TFN3CH9N6X5Q0P0T9NF2G8ZWBH8KXEQFQ973CMDDHF1FSE2G9289AB9ERHM8X222VB2WS733X36P8EMG4D3T1N2JHFP530C9RPEAPHDQXZABB6CJ63YD0581JVRY365HHF20RW3BNVKXP","reserve_sig":"VPKYWKGE6FB172XX222N1J0TAEXQE6VERN5X4ANJ0D9K1E7JAX01CPR1PT51SKK5JD72H1GRJ0S2ZQSKN22ZBEGKS77GMT6BF6DD030","reserve_pub":"FN7ARB2MJH2EDMMVT2985Y141YTCE503FS27BTNQ6JSCG3GMBJDG"}
diff --git a/src/exchange/test_taler_exchange_httpd.sh b/src/exchange/test_taler_exchange_httpd.sh
new file mode 100755
index 000000000..209ee06fd
--- /dev/null
+++ b/src/exchange/test_taler_exchange_httpd.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# This file is part of TALER
+# Copyright (C) 2015 GNUnet e.V.
+#
+# TALER is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
+#
+# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License along with
+# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+#
+#
+# This script uses 'curl' to POST various ill-formed requests to the
+# taler-exchange-httpd. Basically, the goal is to make sure that the
+# HTTP server survives (and produces the 'correct' error code).
+#
+# We read the JSON snippets to POST from test_taler_exchange_httpd.data
+#
+# Setup keys.
+taler-exchange-keyup -d test-exchange-home -m test-exchange-home/master.priv
+# Run Exchange HTTPD (in background)
+taler-exchange-httpd -d test-exchange-home &
+# Give HTTP time to start
+sleep 5
+# Run test...
+cat test_taler_exchange_httpd.data | grep -v ^\# | awk '{ print "curl -d '\''" $2 "'\'' http://localhost:8081"$1 }' | bash
+# Stop HTTP server
+kill -TERM %%
+# FIXME: not sure this is the 'correct' return code...
+exit $?
diff --git a/src/exchange/test_taler_exchange_httpd_afl.sh b/src/exchange/test_taler_exchange_httpd_afl.sh
new file mode 100644
index 000000000..48beda722
--- /dev/null
+++ b/src/exchange/test_taler_exchange_httpd_afl.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# This file is part of TALER
+# Copyright (C) 2015 GNUnet e.V.
+#
+# TALER is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
+#
+# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License along with
+# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+#
+#
+# This script uses 'curl' to POST various ill-formed requests to the
+# taler-exchange-httpd. Basically, the goal is to make sure that the
+# HTTP server survives (and produces the 'correct' error code).
+#
+# We read the JSON snippets from afl-tests/
+#
+PREFIX=
+# Uncomment this line to run with valgrind...
+PREFIX="valgrind --leak-check=yes --log-file=valgrind.%p"
+# Setup keys.
+taler-exchange-keyup -d test-exchange-home -m test-exchange-home/master.priv
+# Setup database (just to be sure)
+taler-exchange-dbinit -d test-exchange-home &> /dev/null || true
+# Only log hard errors, we expect lots of warnings...
+export GNUNET_FORCE_LOG="taler-exchange-httpd;;;;ERROR/libmicrohttpd;;;;ERROR/util;;;;ERROR/"
+# Run test...
+for n in afl-tests/*
+do
+ echo -n "Test $n "
+ $PREFIX taler-exchange-httpd -d test-exchange-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; }
+# $PREFIX taler-exchange-httpd -d test-exchange-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; exit 1; }
+ echo "OK"
+done
+exit 0
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
new file mode 100644
index 000000000..d56d6676a
--- /dev/null
+++ b/src/exchangedb/Makefile.am
@@ -0,0 +1,110 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/pq/ $(POSTGRESQL_CPPFLAGS)
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+plugindir = $(libdir)/taler
+
+if HAVE_POSTGRESQL
+plugin_LTLIBRARIES = \
+ libtaler_plugin_exchangedb_postgres.la
+endif
+
+EXTRA_DIST = \
+ plugin_exchangedb_common.c \
+ test-exchange-db-postgres.conf
+
+libtaler_plugin_exchangedb_postgres_la_SOURCES = \
+ plugin_exchangedb_postgres.c
+libtaler_plugin_exchangedb_postgres_la_LIBADD = \
+ $(LTLIBINTL)
+libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \
+ $(TALER_PLUGIN_LDFLAGS) \
+ $(top_builddir)/src/pq/libtalerpq.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lpq \
+ -lgnunetpq \
+ -lgnunetutil $(XLIB)
+
+lib_LTLIBRARIES = \
+ libtalerexchangedb.la
+
+libtalerexchangedb_la_SOURCES = \
+ exchangedb_keyio.c \
+ exchangedb_plugin.c
+
+libtalerexchangedb_la_LIBADD = \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil $(XLIB)
+
+libtalerexchangedb_la_LDFLAGS = \
+ $(POSTGRESQL_LDFLAGS) \
+ -version-info 0:0:0 \
+ -no-undefined
+
+
+check_PROGRAMS = \
+ test-exchangedb-deposits \
+ test-exchangedb-keyio \
+ test-exchangedb-postgres \
+ test-perf-taler-exchangedb \
+ perf-exchangedb
+
+TESTS = \
+ test-exchangedb-postgres \
+ test-perf-taler-exchangedb
+
+test_exchangedb_deposits_SOURCES = \
+ test_exchangedb_deposits.c
+test_exchangedb_deposits_LDADD = \
+ libtalerexchangedb.la \
+ $(top_srcdir)/src/util/libtalerutil.la \
+ $(top_srcdir)/src/pq/libtalerpq.la \
+ -lgnunetutil \
+ -ljansson \
+ -lpq
+
+test_exchangedb_keyio_SOURCES = \
+ test_exchangedb_keyio.c
+test_exchangedb_keyio_LDADD = \
+ libtalerexchangedb.la \
+ $(top_srcdir)/src/util/libtalerutil.la \
+ $(top_srcdir)/src/pq/libtalerpq.la \
+ -lgnunetutil
+
+test_exchangedb_postgres_SOURCES = \
+ test_exchangedb.c
+test_exchangedb_postgres_LDADD = \
+ libtalerexchangedb.la \
+ $(top_srcdir)/src/util/libtalerutil.la \
+ $(top_srcdir)/src/pq/libtalerpq.la \
+ -lgnunetutil -ljansson
+
+test_perf_taler_exchangedb_SOURCES = \
+ test_perf_taler_exchangedb.c \
+ perf_taler_exchangedb_init.c \
+ perf_taler_exchangedb_interpreter.c
+test_perf_taler_exchangedb_LDADD = \
+ libtalerexchangedb.la \
+ $(top_srcdir)/src/util/libtalerutil.la \
+ $(top_srcdir)/src/pq/libtalerpq.la \
+ -ljansson \
+ -lgnunetutil
+
+perf_exchangedb_SOURCES = \
+ perf_taler_exchangedb.c \
+ perf_taler_exchangedb_init.c \
+ perf_taler_exchangedb_interpreter.c
+perf_exchangedb_LDADD = \
+ libtalerexchangedb.la \
+ $(top_srcdir)/src/util/libtalerutil.la \
+ $(top_srcdir)/src/pq/libtalerpq.la \
+ -ljansson \
+ -lgnunetutil
+
+
+EXTRA_test_exchangedb_postgres_DEPENDENCIES = \
+ libtaler_plugin_exchangedb_postgres.la
diff --git a/src/exchangedb/exchangedb_keyio.c b/src/exchangedb/exchangedb_keyio.c
new file mode 100644
index 000000000..6b8ca24e3
--- /dev/null
+++ b/src/exchangedb/exchangedb_keyio.c
@@ -0,0 +1,558 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchangedb/exchangedb_keyio.c
+ * @brief I/O operations for the Exchange's private keys
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Sree Harsha Totakura
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_exchangedb_lib.h"
+
+
+/**
+ * Closure for the #signkeys_iterate_dir_iter().
+ */
+struct SignkeysIterateContext
+{
+
+ /**
+ * Function to call on each signing key.
+ */
+ TALER_EXCHANGEDB_SigningKeyIterator it;
+
+ /**
+ * Closure for @e it.
+ */
+ void *it_cls;
+};
+
+
+/**
+ * Function called on each file in the directory with our signing
+ * keys. Parses the file and calls the iterator from @a cls.
+ *
+ * @param cls the `struct SignkeysIterateContext *`
+ * @param filename name of the file to parse
+ * @return #GNUNET_OK to continue,
+ * #GNUNET_NO to stop iteration without error,
+ * #GNUNET_SYSERR to stop iteration with error
+ */
+static int
+signkeys_iterate_dir_iter (void *cls,
+ const char *filename)
+{
+ struct SignkeysIterateContext *skc = cls;
+ ssize_t nread;
+ struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP issue;
+
+ nread = GNUNET_DISK_fn_read (filename,
+ &issue,
+ sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP));
+ if (nread != sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid signkey file `%s': wrong size (%d, expected %u)\n",
+ filename,
+ (int) nread,
+ sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP));
+ return GNUNET_OK;
+ }
+ return skc->it (skc->it_cls,
+ filename,
+ &issue);
+}
+
+
+/**
+ * Call @a it for each signing key found in the @a exchange_base_dir.
+ *
+ * @param exchange_base_dir base directory for the exchange,
+ * the signing keys must be in the #TALER_EXCHANGEDB_DIR_SIGNING_KEYS
+ * subdirectory
+ * @param it function to call on each signing key
+ * @param it_cls closure for @a it
+ * @return number of files found (may not match
+ * number of keys given to @a it as malformed
+ * files are simply skipped), -1 on error
+ */
+int
+TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir,
+ TALER_EXCHANGEDB_SigningKeyIterator it,
+ void *it_cls)
+{
+ char *signkey_dir;
+ struct SignkeysIterateContext skc;
+ int ret;
+
+ GNUNET_asprintf (&signkey_dir,
+ "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS,
+ exchange_base_dir);
+ skc.it = it;
+ skc.it_cls = it_cls;
+ ret = GNUNET_DISK_directory_scan (signkey_dir,
+ &signkeys_iterate_dir_iter,
+ &skc);
+ GNUNET_free (signkey_dir);
+ return ret;
+}
+
+
+/**
+ * Import a denomination key from the given file.
+ *
+ * @param filename the file to import the key from
+ * @param[out] dki set to the imported denomination key
+ * @return #GNUNET_OK upon success;
+ * #GNUNET_SYSERR upon failure
+ */
+int
+TALER_EXCHANGEDB_denomination_key_read (const char *filename,
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ uint64_t size;
+ size_t offset;
+ void *data;
+ struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
+
+ if (GNUNET_OK != GNUNET_DISK_file_size (filename,
+ &size,
+ GNUNET_YES,
+ GNUNET_YES))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping inaccessable denomination key file `%s'\n",
+ filename);
+ return GNUNET_SYSERR;
+ }
+ offset = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP);
+ if (size <= offset)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ data = GNUNET_malloc (size);
+ if (size !=
+ GNUNET_DISK_fn_read (filename,
+ data,
+ size))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "read",
+ filename);
+ GNUNET_free (data);
+ return GNUNET_SYSERR;
+ }
+ if (NULL ==
+ (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset,
+ size - offset)))
+ {
+ GNUNET_free (data);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (NULL == dki->denom_priv.rsa_private_key);
+ dki->denom_priv.rsa_private_key = priv;
+ dki->denom_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
+ memcpy (&dki->issue,
+ data,
+ offset);
+ GNUNET_free (data);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Exports a denomination key to the given file.
+ *
+ * @param filename the file where to write the denomination key
+ * @param dki the denomination key
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
+ */
+int
+TALER_EXCHANGEDB_denomination_key_write (const char *filename,
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ char *priv_enc;
+ size_t priv_enc_size;
+ struct GNUNET_DISK_FileHandle *fh;
+ ssize_t wrote;
+ size_t wsize;
+ int ret;
+
+ fh = NULL;
+ priv_enc_size
+ = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key,
+ &priv_enc);
+ ret = GNUNET_SYSERR;
+ if (NULL == (fh = GNUNET_DISK_file_open
+ (filename,
+ GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
+ GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
+ goto cleanup;
+ wsize = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP);
+ if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
+ &dki->issue,
+ wsize)))
+ goto cleanup;
+ if (wrote != wsize)
+ goto cleanup;
+ if (GNUNET_SYSERR ==
+ (wrote = GNUNET_DISK_file_write (fh,
+ priv_enc,
+ priv_enc_size)))
+ goto cleanup;
+ if (wrote != priv_enc_size)
+ goto cleanup;
+ ret = GNUNET_OK;
+ cleanup:
+ GNUNET_free_non_null (priv_enc);
+ if (NULL != fh)
+ (void) GNUNET_DISK_file_close (fh);
+ return ret;
+}
+
+
+/**
+ * Closure for #denomkeys_iterate_keydir_iter() and
+ * #denomkeys_iterate_topdir_iter().
+ */
+struct DenomkeysIterateContext
+{
+
+ /**
+ * Set to the name of the directory below the top-level directory
+ * during the call to #denomkeys_iterate_keydir_iter().
+ */
+ const char *alias;
+
+ /**
+ * Function to call on each denomination key.
+ */
+ TALER_EXCHANGEDB_DenominationKeyIterator it;
+
+ /**
+ * Closure for @e it.
+ */
+ void *it_cls;
+};
+
+
+/**
+ * Decode the denomination key in the given file @a filename and call
+ * the callback in @a cls with the information.
+ *
+ * @param cls the `struct DenomkeysIterateContext *`
+ * @param filename name of a file that should contain
+ * a denomination key
+ * @return #GNUNET_OK to continue to iterate
+ * #GNUNET_NO to abort iteration with success
+ * #GNUNET_SYSERR to abort iteration with failure
+ */
+static int
+denomkeys_iterate_keydir_iter (void *cls,
+ const char *filename)
+{
+ struct DenomkeysIterateContext *dic = cls;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue;
+ int ret;
+
+ memset (&issue, 0, sizeof (issue));
+ if (GNUNET_OK !=
+ TALER_EXCHANGEDB_denomination_key_read (filename,
+ &issue))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid denomkey file: '%s'\n",
+ filename);
+ return GNUNET_OK;
+ }
+ ret = dic->it (dic->it_cls,
+ dic->alias,
+ &issue);
+ GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key);
+ return ret;
+}
+
+
+/**
+ * Function called on each subdirectory in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS. Will
+ * call the #denomkeys_iterate_keydir_iter() on each file in the
+ * subdirectory.
+ *
+ * @param cls the `struct DenomkeysIterateContext *`
+ * @param filename name of the subdirectory to scan
+ * @return #GNUNET_OK on success,
+ * #GNUNET_SYSERR if we need to abort
+ */
+static int
+denomkeys_iterate_topdir_iter (void *cls,
+ const char *filename)
+{
+ struct DenomkeysIterateContext *dic = cls;
+
+ dic->alias = GNUNET_STRINGS_get_short_name (filename);
+ if (0 > GNUNET_DISK_directory_scan (filename,
+ &denomkeys_iterate_keydir_iter,
+ dic))
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Call @a it for each denomination key found in the @a exchange_base_dir.
+ *
+ * @param exchange_base_dir base directory for the exchange,
+ * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
+ * subdirectory
+ * @param it function to call on each denomination key found
+ * @param it_cls closure for @a it
+ * @return -1 on error, 0 if no files were found, otherwise
+ * a positive number (however, even with a positive
+ * number it is possible that @a it was never called
+ * as maybe none of the files were well-formed)
+ */
+int
+TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
+ TALER_EXCHANGEDB_DenominationKeyIterator it,
+ void *it_cls)
+{
+ char *dir;
+ struct DenomkeysIterateContext dic;
+ int ret;
+
+ GNUNET_asprintf (&dir,
+ "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS,
+ exchange_base_dir);
+ dic.it = it;
+ dic.it_cls = it_cls;
+ ret = GNUNET_DISK_directory_scan (dir,
+ &denomkeys_iterate_topdir_iter,
+ &dic);
+ GNUNET_free (dir);
+ return ret;
+}
+
+
+/**
+ * Closure for #auditor_iter() and
+ */
+struct AuditorIterateContext
+{
+
+ /**
+ * Function to call with the information for each auditor.
+ */
+ TALER_EXCHANGEDB_AuditorIterator it;
+
+ /**
+ * Closure for @e it.
+ */
+ void *it_cls;
+};
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Header of a file with auditing information.
+ */
+struct AuditorFileHeaderP
+{
+
+ /**
+ * Public key of the auditor.
+ */
+ struct TALER_AuditorPublicKeyP apub;
+
+ /**
+ * Master public key of the exchange the auditor is signing
+ * information for.
+ */
+ struct TALER_MasterPublicKeyP mpub;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * Load the auditor signature and the information signed by the
+ * auditor and call the callback in @a cls with the information.
+ *
+ * @param cls the `struct AuditorIterateContext *`
+ * @param filename name of a file that should contain
+ * a denomination key
+ * @return #GNUNET_OK to continue to iterate
+ * #GNUNET_NO to abort iteration with success
+ * #GNUNET_SYSERR to abort iteration with failure
+ */
+static int
+auditor_iter (void *cls,
+ const char *filename)
+{
+ struct AuditorIterateContext *aic = cls;
+ uint64_t size;
+ struct AuditorFileHeaderP *af;
+ const struct TALER_AuditorSignatureP *sigs;
+ const struct TALER_DenominationKeyValidityPS *dki;
+ unsigned int len;
+ int ret;
+
+ if (GNUNET_OK != GNUNET_DISK_file_size (filename,
+ &size,
+ GNUNET_YES,
+ GNUNET_YES))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping inaccessable auditor information file `%s'\n",
+ filename);
+ return GNUNET_SYSERR;
+ }
+ if ( (size < sizeof (struct AuditorFileHeaderP)) ||
+ (0 != (len = ((size - sizeof (struct AuditorFileHeaderP)) %
+ (sizeof (struct TALER_DenominationKeyValidityPS) +
+ sizeof (struct TALER_AuditorSignatureP))))) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ af = GNUNET_malloc (size);
+ if (size !=
+ GNUNET_DISK_fn_read (filename,
+ af,
+ size))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "read",
+ filename);
+ GNUNET_free (af);
+ return GNUNET_SYSERR;
+ }
+ sigs = (const struct TALER_AuditorSignatureP *) &af[1];
+ dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[len];
+ ret = aic->it (aic->it_cls,
+ &af->apub,
+ &af->mpub,
+ len,
+ sigs,
+ dki);
+ GNUNET_free (af);
+ return ret;
+}
+
+
+/**
+ * Call @a it with information for each auditor found in the @a exchange_base_dir.
+ *
+ * @param exchange_base_dir base directory for the exchange,
+ * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
+ * subdirectory
+ * @param it function to call with auditor information
+ * @param it_cls closure for @a it
+ * @return -1 on error, 0 if no files were found, otherwise
+ * a positive number (however, even with a positive
+ * number it is possible that @a it was never called
+ * as maybe none of the files were well-formed)
+ */
+int
+TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir,
+ TALER_EXCHANGEDB_AuditorIterator it,
+ void *it_cls)
+{
+ char *dir;
+ struct AuditorIterateContext aic;
+ int ret;
+
+ GNUNET_asprintf (&dir,
+ "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_AUDITORS,
+ exchange_base_dir);
+ aic.it = it;
+ aic.it_cls = it_cls;
+ ret = GNUNET_DISK_directory_scan (dir,
+ &auditor_iter,
+ &aic);
+ GNUNET_free (dir);
+ return ret;
+}
+
+
+/**
+ * Write auditor information to the given file.
+ *
+ * @param filename the file where to write the auditor information to
+ * @param apub the auditor's public key
+ * @param asigs the auditor's signatures, array of length @a dki_len
+ * @param mpub the exchange's public key (as expected by the auditor)
+ * @param dki_len length of @a dki
+ * @param dki array of denomination coin data signed by the auditor
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
+ */
+int
+TALER_EXCHANGEDB_auditor_write (const char *filename,
+ const struct TALER_AuditorPublicKeyP *apub,
+ const struct TALER_AuditorSignatureP *asigs,
+ const struct TALER_MasterPublicKeyP *mpub,
+ unsigned int dki_len,
+ const struct TALER_DenominationKeyValidityPS *dki)
+{
+ struct AuditorFileHeaderP af;
+ struct GNUNET_DISK_FileHandle *fh;
+ ssize_t wrote;
+ size_t wsize;
+ int ret;
+ int eno;
+
+ af.apub = *apub;
+ af.mpub = *mpub;
+ ret = GNUNET_SYSERR;
+ if (NULL == (fh = GNUNET_DISK_file_open
+ (filename,
+ GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
+ GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
+ goto cleanup;
+ wsize = sizeof (struct AuditorFileHeaderP);
+ if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
+ &af,
+ wsize)))
+ goto cleanup;
+ if (wrote != wsize)
+ goto cleanup;
+ wsize = dki_len * sizeof (struct TALER_AuditorSignatureP);
+ if (wsize ==
+ GNUNET_DISK_file_write (fh,
+ asigs,
+ wsize))
+ ret = GNUNET_OK;
+ wsize = dki_len * sizeof (struct TALER_DenominationKeyValidityPS);
+ if (wsize ==
+ GNUNET_DISK_file_write (fh,
+ dki,
+ wsize))
+ ret = GNUNET_OK;
+ cleanup:
+ eno = errno;
+ if (NULL != fh)
+ (void) GNUNET_DISK_file_close (fh);
+ errno = eno;
+ return ret;
+}
+
+
+/* end of exchangedb_keyio.c */
diff --git a/src/exchangedb/exchangedb_plugin.c b/src/exchangedb/exchangedb_plugin.c
new file mode 100644
index 000000000..ebaef9cc0
--- /dev/null
+++ b/src/exchangedb/exchangedb_plugin.c
@@ -0,0 +1,87 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchangedb/exchangedb_plugin.c
+ * @brief Logic to load database plugin
+ * @author Christian Grothoff
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "taler_exchangedb_plugin.h"
+#include <ltdl.h>
+
+
+/**
+ * Initialize the plugin.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+struct TALER_EXCHANGEDB_Plugin *
+TALER_EXCHANGEDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *plugin_name;
+ char *lib_name;
+ struct GNUNET_CONFIGURATION_Handle *cfg_dup;
+ struct TALER_EXCHANGEDB_Plugin *plugin;
+
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "db",
+ &plugin_name))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "db");
+ return NULL;
+ }
+ (void) GNUNET_asprintf (&lib_name,
+ "libtaler_plugin_exchangedb_%s",
+ plugin_name);
+ GNUNET_free (plugin_name);
+ cfg_dup = GNUNET_CONFIGURATION_dup (cfg);
+ plugin = GNUNET_PLUGIN_load (lib_name, cfg_dup);
+ if (NULL != plugin)
+ plugin->library_name = lib_name;
+ else
+ GNUNET_free (lib_name);
+ GNUNET_CONFIGURATION_destroy (cfg_dup);
+ return plugin;
+}
+
+
+/**
+ * Shutdown the plugin.
+ *
+ * @param plugin the plugin to unload
+ */
+void
+TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin)
+{
+ char *lib_name;
+
+ if (NULL == plugin)
+ return;
+ lib_name = plugin->library_name;
+ GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
+ plugin));
+ GNUNET_free (lib_name);
+}
+
+
+
+/* end of exchangedb_plugin.c */
diff --git a/src/exchangedb/perf_taler_exchangedb.c b/src/exchangedb/perf_taler_exchangedb.c
new file mode 100644
index 000000000..6ff7f5331
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb.c
@@ -0,0 +1,358 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/perf_taler_exchangedb.c
+ * @brief Exchange database performance analysis
+ * @author Nicolas Fournier
+ */
+#include "platform.h"
+#include "perf_taler_exchangedb_interpreter.h"
+
+
+#define NB_DENOMINATION_INIT 15
+#define NB_DENOMINATION_SAVE 15
+
+#define SMALL 1000
+#define BIG 10000
+#define BIGGER 100000
+
+#define NB_RESERVE_INIT BIGGER
+#define NB_RESERVE_SAVE BIG
+
+#define NB_DEPOSIT_INIT BIGGER
+#define NB_DEPOSIT_SAVE BIG
+
+#define NB_WITHDRAW_INIT BIGGER
+#define NB_WITHDRAW_SAVE BIG
+
+#define NB_REFRESH_INIT BIGGER
+#define NB_REFRESH_SAVE BIG
+
+#define NB_MELT_INIT BIG
+#define NB_MELT_SAVE SMALL
+
+/**
+ * Runs the performances tests for the exchange database
+ * and logs the results using Gauger
+ */
+int
+main (int argc, char ** argv)
+{
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Cmd benchmark[] =
+ {
+ /* Denomination used to create coins */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("Initializing database"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("01 - denomination loop",
+ NB_DENOMINATION_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert",
+ "01 - denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination",
+ "01 - denomination loop",
+ "01 - denomination",
+ NB_DENOMINATION_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("01 - end",
+ "01 - denomination loop"),
+ /* End of initialization */
+ /* Reserve initialization */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("02 - init reserve loop",
+ NB_RESERVE_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("02 - insert",
+ "02 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve",
+ "02 - init reserve loop",
+ "02 - reserve",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("02 - end",
+ "02 - init reserve loop"),
+ /* End reserve init */
+ /* Withdrawal initialization */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("03 - init withdraw loop",
+ NB_WITHDRAW_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load",
+ "03 - init withdraw loop",
+ "01 - save denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load",
+ "03 - init withdraw loop",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw",
+ "03 - denomination load",
+ "03 - reserve load"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert",
+ "03 - withdraw"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("03 - save coin",
+ "03 - init withdraw loop",
+ "03 - withdraw",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("03 - end",
+ "03 - init withdraw loop"),
+ /*End of withdrawal initialization */
+ /*Deposit initialization */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("04 - deposit init loop",
+ NB_DEPOSIT_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("04 - coin load",
+ "04 - deposit init loop",
+ "03 - save coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit",
+ "04 - coin load"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert",
+ "04 - deposit"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array",
+ "04 - deposit init loop",
+ "04 - deposit",
+ NB_DEPOSIT_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "04 - deposit init loop"),
+ /* End of deposit initialization */
+ /* Session initialization */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("05 - refresh session init loop",
+ NB_REFRESH_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION ("05 - refresh session"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("05 - session array",
+ "05 - refresh session init loop",
+ "05 - refresh session",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("05 - end",
+ "05 - refresh session init loop"),
+ /* End of refresh session initialization */
+ /* Refresh melt initialization */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("06 - refresh melt init loop",
+ NB_MELT_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ /* TODO: initialize using coins & sessions created localy
+ * in order to make sure the same coin are not melted twice*/
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("06 - session hash",
+ "06 - refresh melt init loop",
+ "05 - session array"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("06 - coin",
+ "06 - refresh melt init loop",
+ "03 - save coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_REFRESH_MELT ("06 - refresh melt",
+ "06 - session hash",
+ "06 - coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("06 - end",
+ "06 - refresh melt init loop"),
+ /* End of refresh melt initialization */
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of initialization"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("Start of performances measuring"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("21 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("21 - reserve insert measure",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("21 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("21 - insert",
+ "21 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "21 - reserve insert measure"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("21 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("21 - gauger",
+ "21 - start",
+ "21 - stop",
+ "POSTGRES",
+ "Number of reserve inserted per second",
+ "item/sec",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of reserve insertion"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("22 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("22 - reserve load measure",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("22 - reserve",
+ "22 - reserve load measure",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE ("22 - get",
+ "22 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "22 - reserve load measure"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("22 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "22 - start",
+ "22 - stop",
+ "POSTGRES",
+ "Number of reserve loaded per second",
+ "item/sec",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of reserve retreival"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("23 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("23 - reserve history measure",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("23 - reserve",
+ "23 - reserve history measure",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE_HISTORY ("",
+ "23 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "23 - reserve history measure"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("23 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "23 - start",
+ "23 - stop",
+ "POSTGRES",
+ "Number of reserve history loaded per second",
+ "item/sec",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of reserve history access"),
+
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("24 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("24 - withdraw insert measure",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("24 - reserve",
+ "24 - withdraw insert measure",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("24 - denomination",
+ "24 - withdraw insert measure",
+ "01 - save denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("24 - withdraw",
+ "24 - denomination",
+ "24 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("24 - insert",
+ "24 - withdraw"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "24 - withdraw insert measure"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("24 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "24 - start",
+ "24 - stop",
+ "POSTGRES",
+ "Number of withdraw insert per second",
+ "item/sec",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of withdraw insertion"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("25 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("25 - withdraw insert measure",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("25 - coin",
+ "25 - withdraw insert measure",
+ "03 - save coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_WITHDRAW ("",
+ "25 - coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "25 - withdraw insert measure"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("25 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "25 - start",
+ "25 - stop",
+ "POSTGRES",
+ "Number of withdraw loaded per second",
+ "item/sec",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of withdraw loading"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("26 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("26 - get coin transaction",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("26 - coin",
+ "26 - get coin transaction",
+ "03 - save coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_COIN_TRANSACTION("",
+ "26 - coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "26 - get coin transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("26 - end"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "26 - start",
+ "26 - end",
+ "POSTGRES",
+ "Number of coin transaction history loaded per second",
+ "item/sec",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of transaction loading"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("27 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("27 - /reserve/withdraw",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("27 - reserve",
+ "27 - /reserve/withdraw",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("27 - dki",
+ "27 - /reserve/withdraw",
+ "01 - save denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_WITHDRAW_SIGN ("",
+ "27 - dki",
+ "27 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "27 - /reserve/withdraw"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("27 - end"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "27 - start",
+ "27 - end",
+ "POSTGRES",
+ "Number of /reserve/withdraw per second",
+ "item/sec",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of /reserve/withdraw"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("28 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("28 - /deposit",
+ NB_DEPOSIT_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("28 - coin",
+ "28 - /deposit",
+ "03 - save coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEPOSIT ("28 - deposit",
+ "28 - coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "28 - /deposit"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("28 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "28 - start",
+ "28 - stop",
+ "POSTGRES",
+ "Number of /deposit per second",
+ "item/sec",
+ NB_DEPOSIT_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("29 - start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("29 - insert refresh session",
+ NB_REFRESH_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "29 - insert refresh session"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("29 - stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("",
+ "29 - start",
+ "29 - stop",
+ "POSTGRES",
+ "Number of refresh session inserted per second",
+ "item/sec",
+ NB_REFRESH_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END (""),
+ };
+
+ ret = PERF_TALER_EXCHANGEDB_run_benchmark (
+ "perf-taler-exchangedb",
+ "./test-exchange-db-postgres.conf",
+ (struct PERF_TALER_EXCHANGEDB_Cmd []) {PERF_TALER_EXCHANGEDB_INIT_CMD_END("")},
+ benchmark);
+ if (GNUNET_SYSERR == ret)
+ return 1;
+ return 0;
+}
diff --git a/src/exchangedb/perf_taler_exchangedb_init.c b/src/exchangedb/perf_taler_exchangedb_init.c
new file mode 100644
index 000000000..2e613b3cf
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_init.c
@@ -0,0 +1,622 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/perf_taler_exchangedb_init.c
+ * @brief Interpreter library for exchange database performance analysis
+ * @author Nicolas Fournier
+ */
+#include "platform.h"
+#include "perf_taler_exchangedb_init.h"
+#include <gnunet/gnunet_signatures.h>
+#include "taler_signatures.h"
+#include "taler_amount_lib.h"
+
+
+#define CURRENCY "EUR"
+#define PERF_TALER_EXCHANGEDB_RSA_SIZE 512
+
+
+/**
+ * Generate a dummy DenominationKeyInformation for testing purposes
+ * @return a dummy denomination key
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
+PERF_TALER_EXCHANGEDB_denomination_init ()
+{
+ struct GNUNET_CRYPTO_EddsaPrivateKey *master_prvt;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ struct TALER_DenominationPrivateKey denom_priv;
+ struct TALER_DenominationPublicKey denom_pub;
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
+
+ master_prvt = GNUNET_CRYPTO_eddsa_key_create();
+
+ dki = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation);
+ GNUNET_assert (NULL != dki);
+ denom_priv.rsa_private_key
+ = GNUNET_CRYPTO_rsa_private_key_create (PERF_TALER_EXCHANGEDB_RSA_SIZE);
+ GNUNET_assert (NULL != denom_priv.rsa_private_key);
+ denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv.rsa_private_key);
+ GNUNET_assert (NULL != denom_pub.rsa_public_key);
+ {/* issue */
+ struct TALER_MasterSignatureP signature;
+ struct TALER_DenominationKeyValidityPS properties;
+
+ {/* properties */
+ struct TALER_Amount amount;
+
+ properties.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
+ properties.purpose.size = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
+ GNUNET_CRYPTO_eddsa_key_get_public (master_prvt,
+ &properties.master.eddsa_pub);
+ properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get());
+ properties.expire_withdraw = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
+ properties.expire_spend = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
+ properties.expire_legal = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.1", &amount));
+ TALER_amount_hton (&properties.value, &amount);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.1", &amount));
+ TALER_amount_hton (&properties.fee_withdraw, &amount);
+ TALER_amount_hton (&properties.fee_deposit, &amount);
+ TALER_amount_hton (&properties.fee_refresh, &amount);
+ GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
+ &properties.denom_hash);
+ issue.properties = properties;
+ }
+ {/* signature */
+ GNUNET_CRYPTO_eddsa_sign (master_prvt,
+ &properties.purpose,
+ &signature.eddsa_signature);
+ issue.signature = signature;
+ }
+ }
+ dki->denom_priv = denom_priv;
+ dki->denom_pub = denom_pub;
+ dki->issue = issue;
+ GNUNET_free (master_prvt);
+ return dki;
+}
+
+
+/**
+ * Copies the given denomination
+ * @param reserve the deposit copy
+ * @return a copy of @a deposit; NULL if error
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
+PERF_TALER_EXCHANGEDB_denomination_copy (const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *copy;
+
+ GNUNET_assert (NULL !=
+ (copy = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation)));
+ {/* denom_priv */
+ copy->denom_priv.rsa_private_key =
+ GNUNET_CRYPTO_rsa_private_key_dup ( dki->denom_priv.rsa_private_key);
+ }
+ {/* denom_pub */
+ copy->denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
+ }
+ {/* issue */
+ copy->issue.properties = dki->issue.properties;
+ copy->issue.signature = dki->issue.signature;
+ }
+ return copy;
+}
+
+
+/**
+ * Free memory of a DenominationKeyIssueInformation
+ * @param dki pointer to the struct to free
+ */
+int
+PERF_TALER_EXCHANGEDB_denomination_free (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+{
+ if (NULL == dki)
+ return GNUNET_OK;
+ GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key);
+
+ GNUNET_free (dki);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Generate a dummy reserve for testing
+ * @return a reserve with 1000 EUR in it
+ */
+struct PERF_TALER_EXCHANGEDB_Reserve *
+PERF_TALER_EXCHANGEDB_reserve_init ()
+{
+ struct PERF_TALER_EXCHANGEDB_Reserve *reserve;
+
+ GNUNET_assert (NULL !=
+ (reserve = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Reserve)));
+ {/* private */
+ struct GNUNET_CRYPTO_EddsaPrivateKey *private;
+ private = GNUNET_CRYPTO_eddsa_key_create ();
+ GNUNET_assert (NULL != private);
+ reserve->private = *private;
+ GNUNET_free (private);
+ }
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&reserve->private,
+ &reserve->reserve.pub.eddsa_pub);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1000", &reserve->reserve.balance));
+ reserve->reserve.expiry = GNUNET_TIME_absolute_get_forever_ ();
+ return reserve;
+}
+
+
+/**
+ * Copies the given reserve
+ * @param reserve the reserve to copy
+ * @return a copy of @a reserve; NULL if error
+ */
+struct PERF_TALER_EXCHANGEDB_Reserve *
+PERF_TALER_EXCHANGEDB_reserve_copy (const struct PERF_TALER_EXCHANGEDB_Reserve *reserve)
+{
+ struct PERF_TALER_EXCHANGEDB_Reserve *copy;
+ GNUNET_assert (NULL !=
+ (copy = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Reserve)));
+ *copy = *reserve;
+ return copy;
+}
+
+
+/**
+ * Free memory of a reserve
+ * @param reserve pointer to the structure to be freed
+ */
+int
+PERF_TALER_EXCHANGEDB_reserve_free (struct PERF_TALER_EXCHANGEDB_Reserve *reserve)
+{
+ if (NULL == reserve)
+ return GNUNET_OK;
+ GNUNET_free (reserve);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Generate a dummy deposit for testing purposes
+ * @param dki the denomination key used to sign the key
+ */
+struct TALER_EXCHANGEDB_Deposit *
+PERF_TALER_EXCHANGEDB_deposit_init (const struct PERF_TALER_EXCHANGEDB_Coin *coin)
+{
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+ struct TALER_CoinSpendSignatureP csig;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct GNUNET_HashCode h_contract;
+ struct GNUNET_HashCode h_wire;
+ const char wire[] = "{"
+ "\"type\":\"SEPA\","
+ "\"IBAN\":\"DE67830654080004822650\","
+ "\"NAME\":\"GNUNET E.\","
+ "\"BIC\":\"GENODEF1SRL\""
+ "}";
+ static uint64_t transaction_id = 0;
+ struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_TIME_Absolute refund_deadline;
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
+
+ GNUNET_assert (NULL !=
+ (deposit = GNUNET_malloc (sizeof (struct TALER_EXCHANGEDB_Deposit) + sizeof (wire))));
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &h_contract);
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &h_wire);
+ { //csig
+ struct u32_presign
+ {
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_wire;
+ struct GNUNET_HashCode h_contract;
+ } unsigned_data;
+
+ unsigned_data.h_contract = h_contract;
+ unsigned_data.h_wire = h_wire;
+ unsigned_data.purpose.size = htonl (sizeof (struct u32_presign));
+ unsigned_data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&coin->priv,
+ &unsigned_data.purpose,
+ &csig.eddsa_signature));
+ }
+ { //merchant_pub
+ struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_prv;
+
+ eddsa_prv = GNUNET_CRYPTO_eddsa_key_create ();
+ GNUNET_assert(NULL != eddsa_prv);
+ GNUNET_CRYPTO_eddsa_key_get_public (
+ eddsa_prv,
+ &merchant_pub.eddsa_pub);
+ GNUNET_free (eddsa_prv);
+ }
+ timestamp = GNUNET_TIME_absolute_get ();
+ refund_deadline = GNUNET_TIME_absolute_get ();
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.1",
+ &amount_with_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.1",
+ &deposit_fee));
+ {
+ deposit->coin.coin_pub = coin->public_info.coin_pub;
+ deposit->coin.denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (
+ coin->public_info.denom_pub.rsa_public_key);
+ GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key);
+ deposit->coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (
+ coin->public_info.denom_sig.rsa_signature);
+ GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature);
+ }
+ deposit->csig = csig;
+ deposit->h_contract = h_contract;
+ deposit->h_wire = h_wire;
+ deposit->wire = json_loads (wire, 0, NULL);
+ deposit->transaction_id = transaction_id++;
+ deposit->timestamp = timestamp;
+ deposit->refund_deadline = refund_deadline;
+ deposit->amount_with_fee = amount_with_fee;
+ deposit->deposit_fee = deposit_fee;
+ return deposit;
+}
+
+
+/**
+ * Copies the given deposit
+ * @param reserve the deposit copy
+ * @return a copy of @a deposit; NULL if error
+ */
+struct TALER_EXCHANGEDB_Deposit *
+PERF_TALER_EXCHANGEDB_deposit_copy (const struct TALER_EXCHANGEDB_Deposit *deposit)
+{
+ struct TALER_EXCHANGEDB_Deposit *copy;
+
+ copy = GNUNET_new (struct TALER_EXCHANGEDB_Deposit);
+ *copy = *deposit;
+ json_incref (copy->wire);
+ copy->coin.denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (deposit->coin.denom_pub.rsa_public_key);
+ copy->coin.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_signature_dup (deposit->coin.denom_sig.rsa_signature);
+ return copy;
+}
+
+
+/**
+ * Free memory of a deposit
+ * @param deposit pointer to the structure to free
+ */
+int
+PERF_TALER_EXCHANGEDB_deposit_free (struct TALER_EXCHANGEDB_Deposit *deposit)
+{
+ if (NULL == deposit)
+ return GNUNET_OK;
+ GNUNET_CRYPTO_rsa_public_key_free (deposit->coin.denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (deposit->coin.denom_sig.rsa_signature);
+ json_decref (deposit->wire);
+ GNUNET_free (deposit);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Generate a CollectableBlindcoin for testing purpuses
+ * @param dki denomination key used to sign the coin
+ * @param reserve reserve providing the money for the coin
+ * @return a randomly generated CollectableBlindcoin
+ */
+struct PERF_TALER_EXCHANGEDB_Coin *
+PERF_TALER_EXCHANGEDB_coin_init (
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ const struct PERF_TALER_EXCHANGEDB_Reserve *reserve)
+{
+ struct PERF_TALER_EXCHANGEDB_Coin *coin;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+
+ coin = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Coin);
+ GNUNET_assert (NULL != coin);
+ /* priv */
+
+ priv = GNUNET_CRYPTO_eddsa_key_create();
+ GNUNET_assert (NULL != priv);
+ coin->priv = *priv;
+ GNUNET_free (priv);
+
+ /* public_info */
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin->priv,
+ &coin->public_info.coin_pub.eddsa_pub);
+ coin->public_info.denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
+ coin->public_info.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
+ &coin->public_info.coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP));
+ GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key);
+ GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature);
+
+ /* blind */
+ coin->blind.sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
+ coin->blind.denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
+ GNUNET_assert (NULL != coin->blind.sig.rsa_signature);
+ GNUNET_assert (NULL != coin->blind.denom_pub.rsa_public_key);
+ TALER_amount_ntoh (&coin->blind.amount_with_fee,
+ &dki->issue.properties.value);
+ TALER_amount_ntoh (&coin->blind.withdraw_fee,
+ &dki->issue.properties.fee_withdraw);
+ coin->blind.reserve_pub = reserve->reserve.pub;
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &coin->blind.h_coin_envelope);
+
+ return coin;
+}
+
+
+/**
+ * Copies the given coin
+ *
+ * @param coin the coin to copy
+ * @return a copy of coin; NULL if error
+ */
+struct PERF_TALER_EXCHANGEDB_Coin *
+PERF_TALER_EXCHANGEDB_coin_copy (const struct PERF_TALER_EXCHANGEDB_Coin *coin)
+{
+ struct PERF_TALER_EXCHANGEDB_Coin *copy;
+
+ copy = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Coin);
+ /* priv */
+ copy->priv = coin->priv;
+ /* public_info */
+ copy->public_info.coin_pub = coin->public_info.coin_pub;
+ copy->public_info.denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key);
+ copy->public_info.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
+
+ /* blind */
+ copy->blind.sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_signature_dup (coin->blind.sig.rsa_signature);
+ copy->blind.denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (coin->blind.denom_pub.rsa_public_key);
+ copy->blind.amount_with_fee = coin->blind.amount_with_fee;
+ copy->blind.withdraw_fee = coin->blind.withdraw_fee;
+ copy->blind.reserve_pub = coin->blind.reserve_pub;
+ copy->blind.h_coin_envelope = coin->blind.h_coin_envelope;
+ copy->blind.reserve_sig = coin->blind.reserve_sig;
+
+ return copy;
+}
+
+
+/**
+ * Free memory of @a coin
+ *
+ * @param coin pointer to the structure to free
+ */
+int
+PERF_TALER_EXCHANGEDB_coin_free (struct PERF_TALER_EXCHANGEDB_Coin *coin)
+{
+ if (NULL == coin)
+ return GNUNET_OK;
+ GNUNET_CRYPTO_rsa_public_key_free (coin->public_info.denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (coin->public_info.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_signature_free (coin->blind.sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (coin->blind.denom_pub.rsa_public_key);
+ GNUNET_free (coin);
+ return GNUNET_OK;
+}
+
+
+/**
+ * @return a randomly generated refresh session
+ */
+struct TALER_EXCHANGEDB_RefreshSession *
+PERF_TALER_EXCHANGEDB_refresh_session_init ()
+{
+ struct TALER_EXCHANGEDB_RefreshSession *refresh_session;
+
+ GNUNET_assert (NULL !=
+ (refresh_session = GNUNET_new (struct TALER_EXCHANGEDB_RefreshSession)));
+ refresh_session->noreveal_index = 1;
+ refresh_session->num_oldcoins = 1;
+ refresh_session->num_newcoins = 1;
+
+ return refresh_session;
+}
+
+
+/**
+ * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't
+ */
+int
+PERF_TALER_EXCHANGEDB_refresh_session_copy (struct TALER_EXCHANGEDB_RefreshSession *session,
+ struct TALER_EXCHANGEDB_RefreshSession *copy)
+{
+ *copy = *session;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Free a refresh session
+ */
+int
+PERF_TALER_EXCHANGEDB_refresh_session_free (struct TALER_EXCHANGEDB_RefreshSession *refresh_session)
+{
+ if (NULL == refresh_session)
+ return GNUNET_OK;
+ GNUNET_free (refresh_session);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Create a melt operation
+ *
+ * @param session the refresh session
+ * @param dki the denomination the melted coin uses
+ * @return a pointer to a #TALER_EXCHANGEDB_RefreshMelt
+ */
+struct TALER_EXCHANGEDB_RefreshMelt *
+PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session,
+ struct PERF_TALER_EXCHANGEDB_Coin *coin)
+{
+ struct TALER_EXCHANGEDB_RefreshMelt *melt;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct TALER_Amount amount;
+ struct TALER_Amount amount_with_fee;
+
+ {
+ struct
+ {
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode session;
+ } to_sign;
+
+ to_sign.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_TEST;
+ to_sign.purpose.size = htonl (sizeof (to_sign));
+ to_sign.session = *session;
+ GNUNET_CRYPTO_eddsa_sign (&coin->priv,
+ &to_sign.purpose,
+ &coin_sig.eddsa_signature);
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.1",
+ &amount));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.1",
+ &amount_with_fee));
+ melt = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt);
+ melt->coin.coin_pub = coin->public_info.coin_pub;
+ melt->coin.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
+ melt->coin.denom_pub.rsa_public_key =
+ GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key);
+ GNUNET_assert (NULL != melt->coin.denom_pub.rsa_public_key);
+ GNUNET_assert (NULL != melt->coin.denom_sig.rsa_signature);
+ melt->coin_sig = coin_sig;
+ melt->session_hash = *session;
+ melt->amount_with_fee = amount;
+ melt->melt_fee = amount_with_fee;
+ return melt;
+}
+
+
+/**
+ * Copies the internals of a #TALER_EXCHANGEDB_RefreshMelt
+ *
+ * @param melt the refresh melt to copy
+ * @return an copy of @ melt
+ */
+struct TALER_EXCHANGEDB_RefreshMelt *
+PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMelt *melt)
+{
+ struct TALER_EXCHANGEDB_RefreshMelt *copy;
+
+ copy = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt);
+ *copy = *melt;
+ copy->coin.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_signature_dup (melt->coin.denom_sig.rsa_signature);
+ GNUNET_assert (NULL != copy->coin.denom_sig.rsa_signature);
+
+ return copy;
+}
+
+
+/**
+ * Free the internal memory of a #TALER_EXCHANGEDB_RefreshMelt
+ *
+ * @param melt the #TALER_EXCHANGEDB_RefreshMelt to free
+ * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR
+ */
+int
+PERF_TALER_EXCHANGEDB_refresh_melt_free (struct TALER_EXCHANGEDB_RefreshMelt *melt)
+{
+ GNUNET_CRYPTO_rsa_signature_free (melt->coin.denom_sig.rsa_signature);
+ GNUNET_free (melt);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Create a #TALER_EXCHANGEDB_RefreshCommitCoin
+ */
+struct TALER_EXCHANGEDB_RefreshCommitCoin *
+PERF_TALER_EXCHANGEDB_refresh_commit_coin_init ()
+{
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin;
+ struct TALER_RefreshLinkEncrypted refresh_link;
+
+ commit_coin = GNUNET_new (struct TALER_EXCHANGEDB_RefreshCommitCoin);
+ GNUNET_assert (NULL != commit_coin);
+ {/* refresh_link */
+ refresh_link = (struct TALER_RefreshLinkEncrypted)
+ {
+ .blinding_key_enc = "blinding_key",
+ .blinding_key_enc_size = 13
+ };
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &refresh_link.coin_priv_enc,
+ sizeof(struct TALER_CoinSpendPrivateKeyP));
+ }
+ commit_coin->coin_ev = "coin_ev";
+ commit_coin->coin_ev_size = 8;
+ commit_coin->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted);
+ *commit_coin->refresh_link = refresh_link;
+ return commit_coin;
+}
+
+
+/**
+ * Copies a #TALER_EXCHANGEDB_RefreshCommitCoin
+ *
+ * @param commit_coin the commit to copy
+ * @return a copy of @a commit_coin
+ */
+struct TALER_EXCHANGEDB_RefreshCommitCoin *
+PERF_TALER_EXCHANGEDB_refresh_commit_coin_copy (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin)
+{
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *copy;
+
+ copy = GNUNET_new (struct TALER_EXCHANGEDB_RefreshCommitCoin);
+ copy->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted);
+ *copy->refresh_link = *commit_coin->refresh_link;
+ return copy;
+}
+
+
+/**
+ * Free a #TALER_EXCHANGEDB_RefreshCommitCoin
+ *
+ * @param commit_coin the coin to free
+ */
+void
+PERF_TALER_EXCHANGEDB_refresh_commit_coin_free (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin)
+{
+ GNUNET_free (commit_coin->refresh_link);
+ GNUNET_free (commit_coin);
+}
diff --git a/src/exchangedb/perf_taler_exchangedb_init.h b/src/exchangedb/perf_taler_exchangedb_init.h
new file mode 100644
index 000000000..0ff074108
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_init.h
@@ -0,0 +1,257 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/perf_taler_exchangedb_init.h
+ * @brief Heler function for creating dummy inputs for the exchange database
+ * @author Nicolas Fournier
+ */
+#ifndef __PERF_TALER_EXCHANGEDB_INIT_H___
+#define __PERF_TALER_EXCHANGEDB_INIT_H___
+
+#include "taler_exchangedb_plugin.h"
+
+
+#define CURRENCY "EUR"
+
+/**
+ * All information about a reserve
+ */
+struct PERF_TALER_EXCHANGEDB_Reserve
+{
+ /**
+ * Information about a rserve available to the Exchange
+ */
+ struct TALER_EXCHANGEDB_Reserve reserve;
+
+ /**
+ * Private key of a reserve
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey private;
+};
+
+
+/**
+ * All informations about a coin
+ */
+struct PERF_TALER_EXCHANGEDB_Coin
+{
+ /**
+ * Blinded coin, known by the exchange
+ */
+ struct TALER_EXCHANGEDB_CollectableBlindcoin blind;
+
+ /**
+ * Public key of the coin and othes informations
+ */
+ struct TALER_CoinPublicInfo public_info;
+
+ /**
+ * Private key of the coin
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey priv;
+};
+
+
+/**
+ * Generate a dummy DenominationKeyInformation for testing purposes
+ * @return a dummy denomination key
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
+PERF_TALER_EXCHANGEDB_denomination_init (void);
+
+
+/**
+ * Copies the given denomination
+ * @param reserve the deposit copy
+ * @return a copy of @a deposit; NULL if error
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
+PERF_TALER_EXCHANGEDB_denomination_copy (
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
+
+
+/**
+ * Free memory of a DenominationKeyIssueInformation
+ * @param dki pointer to the struct to free
+ */
+int
+PERF_TALER_EXCHANGEDB_denomination_free (
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
+
+
+/**
+ * Generate a dummy reserve for testing
+ * @return a reserve with 1000 EUR in it
+ */
+struct PERF_TALER_EXCHANGEDB_Reserve *
+PERF_TALER_EXCHANGEDB_reserve_init (void);
+
+
+/**
+ * Copies the given reserve
+ * @param reserve the reserve to copy
+ * @return a copy of @a reserve; NULL if error
+ */
+struct PERF_TALER_EXCHANGEDB_Reserve *
+PERF_TALER_EXCHANGEDB_reserve_copy (const struct PERF_TALER_EXCHANGEDB_Reserve *reserve);
+
+
+/**
+ * Free memory of a reserve
+ * @param reserve pointer to the structure to be freed
+ */
+int
+PERF_TALER_EXCHANGEDB_reserve_free (struct PERF_TALER_EXCHANGEDB_Reserve *reserve);
+
+
+/**
+ * Generate a dummy deposit for testing purposes
+ * @param dki the denomination key used to sign the key
+ */
+struct TALER_EXCHANGEDB_Deposit *
+PERF_TALER_EXCHANGEDB_deposit_init (
+ const struct PERF_TALER_EXCHANGEDB_Coin *coin);
+
+
+/**
+ * Copies the given deposit
+ * @param reserve the deposit copy
+ * @return a copy of @a deposit; NULL if error
+ */
+struct TALER_EXCHANGEDB_Deposit *
+PERF_TALER_EXCHANGEDB_deposit_copy (const struct TALER_EXCHANGEDB_Deposit *deposit);
+
+
+/**
+ * Free memory of a deposit
+ * @param deposit pointer to the structure to free
+ */
+int
+PERF_TALER_EXCHANGEDB_deposit_free (struct TALER_EXCHANGEDB_Deposit *deposit);
+
+
+/**
+ * Generate a coin for testing purpuses
+ * @param dki denomination key used to sign the coin
+ * @param reserve reserve providing the money for the coin
+ * @return a randomly generated CollectableBlindcoin
+ */
+struct PERF_TALER_EXCHANGEDB_Coin *
+PERF_TALER_EXCHANGEDB_coin_init (
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ const struct PERF_TALER_EXCHANGEDB_Reserve *reserve);
+
+
+/**
+ * Copies the given coin
+ * @param coin the coin to copy
+ * @return a copy of coin; NULL if error
+ */
+struct PERF_TALER_EXCHANGEDB_Coin *
+PERF_TALER_EXCHANGEDB_coin_copy (
+ const struct PERF_TALER_EXCHANGEDB_Coin *coin);
+
+
+/**
+ * Liberate memory of @a coin
+ * @param coin pointer to the structure to free
+ */
+int
+PERF_TALER_EXCHANGEDB_coin_free (
+ struct PERF_TALER_EXCHANGEDB_Coin *coin);
+
+
+/**
+ * @return a randomly generated refresh session
+ */
+struct TALER_EXCHANGEDB_RefreshSession *
+PERF_TALER_EXCHANGEDB_refresh_session_init (void);
+
+
+/**
+ * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't
+ */
+int
+PERF_TALER_EXCHANGEDB_refresh_session_copy (struct TALER_EXCHANGEDB_RefreshSession *session,
+ struct TALER_EXCHANGEDB_RefreshSession *copy);
+
+
+/**
+ * Frees memory of a refresh_session
+ */
+int
+PERF_TALER_EXCHANGEDB_refresh_session_free (
+ struct TALER_EXCHANGEDB_RefreshSession *refresh_session);
+
+
+/**
+ * Create a melt operation
+ *
+ * @param session the refresh session
+ * @param dki the denomination the melted coin uses
+ * @return a pointer to a #TALER_EXCHANGEDB_RefreshMelt
+ */
+struct TALER_EXCHANGEDB_RefreshMelt *
+PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session,
+ struct PERF_TALER_EXCHANGEDB_Coin *coin);
+
+
+/**
+ * Copies the internals of a #TALER_EXCHANGEDB_RefreshMelt
+ *
+ * @param melt the refresh melt to copy
+ * @return an copy of @ melt
+ */
+struct TALER_EXCHANGEDB_RefreshMelt *
+PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMelt *melt);
+
+
+/**
+ * Free the internal memory of a #TALER_EXCHANGEDB_RefreshMelt
+ *
+ * @param melt the #TALER_EXCHANGEDB_RefreshMelt to free
+ * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR
+ */
+int
+PERF_TALER_EXCHANGEDB_refresh_melt_free (struct TALER_EXCHANGEDB_RefreshMelt *melt);
+
+
+/**
+ * Create a #TALER_EXCHANGEDB_RefreshCommitCoin
+ */
+struct TALER_EXCHANGEDB_RefreshCommitCoin *
+PERF_TALER_EXCHANGEDB_refresh_commit_coin_init (void);
+
+
+/**
+ * Copies a #TALER_EXCHANGEDB_RefreshCommitCoin
+ *
+ * @param commit_coin the commit to copy
+ * @return a copy of @a commit_coin
+ */
+struct TALER_EXCHANGEDB_RefreshCommitCoin *
+PERF_TALER_EXCHANGEDB_refresh_commit_coin_copy (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin);
+
+
+/**
+ * Free a #TALER_EXCHANGEDB_RefreshCommitCoin
+ *
+ * @param commit_coin the coin to free
+ */
+void
+PERF_TALER_EXCHANGEDB_refresh_commit_coin_free (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin);
+
+#endif
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c
new file mode 100644
index 000000000..75b32cb60
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -0,0 +1,1998 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/perf_taler_exchangedb_interpreter.c
+ * @brief Interpreter library for exchange database performance analysis
+ * @author Nicolas Fournier
+ */
+#include "platform.h"
+#include "perf_taler_exchangedb_interpreter.h"
+#include "perf_taler_exchangedb_init.h"
+#include "gauger.h"
+
+
+/**
+ * Represents the state of the interpreter
+ */
+struct PERF_TALER_EXCHANGEDB_interpreter_state
+{
+ /**
+ * State of the commands
+ */
+ struct PERF_TALER_EXCHANGEDB_Cmd *cmd;
+
+ /**
+ * Database plugin
+ */
+ struct TALER_EXCHANGEDB_Plugin *plugin;
+
+ /**
+ * Current database session
+ */
+ struct TALER_EXCHANGEDB_Session *session;
+
+ /**
+ * The current index of the interpreter
+ */
+ unsigned int i;
+};
+
+
+/**
+ * Free the memory of @a data
+ */
+static void
+data_free (struct PERF_TALER_EXCHANGEDB_Data *data)
+{
+ switch (data->type)
+ {
+ case PERF_TALER_EXCHANGEDB_TIME:
+ if (NULL == data->data.time)
+ break;
+ GNUNET_free (data->data.time);
+ data->data.time = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_DEPOSIT:
+ if (NULL == data->data.deposit)
+ break;
+ PERF_TALER_EXCHANGEDB_deposit_free (data->data.deposit);
+ data->data.deposit = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_COIN:
+ if (NULL == data->data.coin)
+ break;
+ PERF_TALER_EXCHANGEDB_coin_free (data->data.coin);
+ data->data.coin = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_RESERVE:
+ if (NULL == data->data.reserve)
+ break;
+ PERF_TALER_EXCHANGEDB_reserve_free (data->data.reserve);
+ data->data.reserve = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_DENOMINATION_INFO:
+ if (NULL == data->data.dki)
+ break;
+ PERF_TALER_EXCHANGEDB_denomination_free (data->data.dki);
+ data->data.dki = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_REFRESH_HASH:
+ if (NULL == data->data.session_hash)
+ break;
+ GNUNET_free (data->data.session_hash);
+ data->data.session_hash = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_REFRESH_MELT:
+ if (NULL == data->data.refresh_melt)
+ break;
+ PERF_TALER_EXCHANGEDB_refresh_melt_free (data->data.refresh_melt);
+ data->data.refresh_melt = NULL;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_NONE:
+ break;
+ }
+}
+
+
+/**
+ * Copies @a data into @a copy
+ *
+ * @param data the data to be copied
+ * @param[out] copy the copy made
+ */
+static void
+data_copy (const struct PERF_TALER_EXCHANGEDB_Data *data,
+ struct PERF_TALER_EXCHANGEDB_Data *copy)
+{
+ copy->type = data->type;
+ switch (data->type)
+ {
+ case PERF_TALER_EXCHANGEDB_TIME:
+ copy->data.time = GNUNET_new (struct GNUNET_TIME_Absolute);
+ *copy->data.time = *data->data.time;
+ return;
+
+ case PERF_TALER_EXCHANGEDB_DEPOSIT:
+ copy->data.deposit
+ = PERF_TALER_EXCHANGEDB_deposit_copy (data->data.deposit);
+ return;
+
+ case PERF_TALER_EXCHANGEDB_COIN:
+ copy->data.coin
+ = PERF_TALER_EXCHANGEDB_coin_copy (data->data.coin);
+ return;
+
+ case PERF_TALER_EXCHANGEDB_RESERVE:
+ copy->data.reserve
+ = PERF_TALER_EXCHANGEDB_reserve_copy (data->data.reserve);
+ return;
+
+ case PERF_TALER_EXCHANGEDB_DENOMINATION_INFO:
+ copy->data.dki
+ = PERF_TALER_EXCHANGEDB_denomination_copy (data->data.dki);
+ return;
+
+ case PERF_TALER_EXCHANGEDB_REFRESH_HASH:
+ copy-> data.session_hash = GNUNET_new (struct GNUNET_HashCode);
+ *copy->data.session_hash
+ = *data->data.session_hash;
+ break;
+
+ case PERF_TALER_EXCHANGEDB_REFRESH_MELT:
+ copy->data.refresh_melt
+ = PERF_TALER_EXCHANGEDB_refresh_melt_copy (data->data.refresh_melt);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_NONE:
+ break;
+ }
+}
+
+
+/**
+ * Finds the first command in cmd with the name search
+ *
+ * @return the index of the first command with name search
+ * #GNUNET_SYSERR if none found
+ */
+static int
+cmd_find (const struct PERF_TALER_EXCHANGEDB_Cmd *cmd,
+ const char *search)
+{
+ unsigned int i;
+
+ for (i=0; PERF_TALER_EXCHANGEDB_CMD_END != cmd[i].command; i++)
+ if (0 == strcmp (cmd[i].label, search))
+ return i;
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Initialization of a command array
+ * and check for the type of the label
+ *
+ * @param cmd the comand array initialized
+ * @return #GNUNET_OK if the initialization was sucessful
+ * #GNUNET_SYSERR if there was a probleb. See the log for details
+ */
+static int
+cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
+{
+ unsigned int i;
+
+ for (i=0; PERF_TALER_EXCHANGEDB_CMD_END != cmd[i].command; i++)
+ {
+ switch (cmd[i].command)
+ {
+ case PERF_TALER_EXCHANGEDB_CMD_END_LOOP:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.end_loop.label_loop);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.end_loop.label_loop);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.end_loop.label_loop);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.end_loop.index_loop = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.save_array.label_save);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.save_array.label_save);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_NONE == cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.save_array.label_save);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.save_array.index_save = ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.save_array.label_loop);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.save_array.label_loop);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.save_array.label_loop);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.save_array.index_loop = ret;
+
+ GNUNET_assert (NULL == cmd[i].details.save_array.data_saved);
+ cmd[i].details.save_array.data_saved =
+ GNUNET_new_array (cmd[i].details.save_array.nb_saved,
+ struct PERF_TALER_EXCHANGEDB_Data);
+ cmd[i].details.save_array.type_saved =
+ cmd[cmd[i].details.save_array.index_save].exposed.type;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.load_array.label_save);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.load_array.label_save);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY != cmd[ret].command)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.load_array.label_save);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.load_array.index_save = ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.load_array.label_loop);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.load_array.label_loop);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.load_array.label_loop);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.load_array.index_loop = ret;
+
+ cmd[i].details.load_array.permutation =
+ GNUNET_CRYPTO_random_permute (
+ GNUNET_CRYPTO_QUALITY_WEAK,
+ cmd[cmd[i].details.load_array.index_save].details.save_array.nb_saved);
+ GNUNET_assert (NULL != cmd[i].details.load_array.permutation);
+
+ cmd[i].exposed.type = cmd[cmd[i].details.load_array.index_save].details.save_array.type_saved;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.load_random.label_save);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.load_random.label_save);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY != cmd[ret].command)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.load_random.label_save);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.load_random.index_save = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GAUGER:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.gauger.label_start);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.gauger.label_start);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_TIME != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.gauger.label_start);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.gauger.index_start = ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.gauger.label_stop);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.gauger.label_stop);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_TIME != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.gauger.label_stop);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.gauger.index_stop = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_denomination.label_denom);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_denomination.label_denom);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_denomination.label_denom);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_denomination.index_denom = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.get_denomination.label_denom);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_denomination.label_denom);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_denomination.label_denom);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_denomination.index_denom = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_reserve.label_reserve);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_reserve.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_reserve.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_reserve.index_reserve = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.get_reserve.label_reserve);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_reserve.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_reserve.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_reserve.index_reserve = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.get_reserve_history.label_reserve);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_reserve_history.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_reserve_history.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_reserve_history.index_reserve = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.create_withdraw.label_dki);
+ {
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.create_withdraw.label_dki);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.create_withdraw.label_dki);
+ return GNUNET_SYSERR;
+ }
+ }
+ cmd[i].details.create_withdraw.index_dki = ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.create_withdraw.label_reserve);
+ {
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.create_withdraw.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.create_withdraw.label_reserve);
+ return GNUNET_SYSERR;
+ }
+ }
+ cmd[i].details.create_withdraw.index_reserve = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_withdraw.label_coin);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_withdraw.label_coin);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_withdraw.label_coin);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_withdraw.index_coin = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.get_withdraw.label_coin);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_withdraw.label_coin);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_withdraw.label_coin);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_withdraw.index_coin = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_coin_transaction.label_coin);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_coin_transaction.label_coin);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_coin_transaction.label_coin);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_coin_transaction.index_coin = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.create_deposit.label_coin);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.create_deposit.label_coin);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.create_deposit.label_coin);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.create_deposit.index_coin = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT:
+ {
+ int ret;
+
+ ret = cmd_find( cmd,
+ cmd[i].details.insert_deposit.label_deposit);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_deposit.label_deposit);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_DEPOSIT != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_deposit.label_deposit);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_deposit.index_deposit = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.get_deposit.label_deposit);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_deposit.label_deposit);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_DEPOSIT != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_deposit.label_deposit);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_deposit.index_deposit = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.get_refresh_session.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_session.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_session.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_refresh_session.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT:
+ {
+ int ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_melt.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_melt.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_melt.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_melt.index_hash = ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_melt.label_coin);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_melt.label_coin);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_melt.label_coin);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_melt.index_coin = ret; }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_refresh_melt.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_melt.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_melt.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_refresh_melt.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_order.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_order.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_order.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_order.index_hash = ret;
+
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_order.label_denom);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_order.label_denom);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_order.label_denom);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_order.index_denom = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_refresh_order.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_order.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_order.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_refresh_order.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_commit_coin.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_commit_coin.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_commit_coin.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_commit_coin.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_refresh_commit_coin.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_commit_coin.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_commit_coin.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_refresh_commit_coin.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_commit_link.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_commit_link.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_commit_link.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_commit_link.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_refresh_commit_link.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_commit_link.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_refresh_commit_link.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_refresh_commit_link.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_melt_commitment.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_melt_commitment.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_melt_commitment.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_melt_commitment.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.insert_refresh_out.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_out.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.insert_refresh_out.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.insert_refresh_out.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_link_data_list.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_link_data_list.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_link_data_list.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_link_data_list.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER:
+ {
+ int ret;
+ ret = cmd_find (cmd,
+ cmd[i].details.get_transfer.label_hash);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Undefined reference to %s\n",
+ i,
+ cmd[i].details.get_transfer.label_hash);
+ return GNUNET_SYSERR;
+ }
+ if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%d:Wrong type reference to %s\n",
+ i,
+ cmd[i].details.get_transfer.label_hash);
+ return GNUNET_SYSERR;
+ }
+ cmd[i].details.get_transfer.index_hash = ret;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_END:
+ case PERF_TALER_EXCHANGEDB_CMD_DEBUG:
+ case PERF_TALER_EXCHANGEDB_CMD_LOOP:
+ case PERF_TALER_EXCHANGEDB_CMD_NEW_SESSION:
+ case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION:
+ case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION:
+ case PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION:
+ case PERF_TALER_EXCHANGEDB_CMD_GET_TIME:
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION:
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE:
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION:
+ break;
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Free the memory of the command chain
+ */
+static int
+cmd_clean (struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
+{
+ unsigned int i;
+
+ for (i=0; PERF_TALER_EXCHANGEDB_CMD_END != cmd[i].command; i++)
+ {
+ switch (cmd[i].command)
+ {
+ case PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY:
+ {
+ unsigned int j;
+
+ for (j = 0; j < cmd[i].details.save_array.nb_saved; j++)
+ {
+ data_free (&cmd[i].details.save_array.data_saved[j]);
+ }
+ GNUNET_free (cmd[i].details.save_array.data_saved);
+ cmd[i].details.save_array.data_saved = NULL;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY:
+ GNUNET_free (cmd[i].details.load_array.permutation);
+ cmd[i].details.load_array.permutation = NULL;
+ break;
+
+ default:
+ break;
+ }
+ data_free (&cmd[i].exposed);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handles the command #PERF_TALER_EXCHANGEDB_CMD_END_LOOP for the interpreter
+ * Cleans the memory at the end of the loop
+ */
+static void
+interpret_end_loop (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
+{
+ unsigned int i;
+ int jump;
+
+ jump = state->cmd[state->i].details.end_loop.index_loop;
+ // Cleaning up the memory in the loop
+ for (i = jump; i < state->i; i++)
+ data_free (&state->cmd[i].exposed);
+
+ state->cmd[jump].details.loop.curr_iteration++;
+ /* If the loop is not finished */
+ if (state->cmd[jump].details.loop.max_iterations >
+ state->cmd[jump].details.loop.curr_iteration)
+ {
+ /* jump back to the start */
+ state->i = jump;
+ }
+ else
+ {
+ /* Reset the loop counter and continue running */
+ state->cmd[jump].details.loop.curr_iteration = 0;
+ }
+}
+
+
+/**
+ * Part of the interpreter specific to
+ * #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY
+ * Saves the data exposed by another command into
+ * an array in the command specific struct.
+ */
+static void
+interpret_save_array (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
+{
+ struct PERF_TALER_EXCHANGEDB_Cmd *cmd = &state->cmd[state->i];
+ struct PERF_TALER_EXCHANGEDB_Cmd *save_ref;
+ struct PERF_TALER_EXCHANGEDB_Cmd *loop_ref;
+ int loop_index;
+ int save_index;
+ unsigned int selection_chance;
+
+ loop_index = cmd->details.save_array.index_loop;
+ save_index = cmd->details.save_array.index_save;
+ loop_ref = &state->cmd[loop_index];
+ save_ref = &state->cmd[save_index];
+ /* Array initialization on first loop iteration
+ Alows for nested loops */
+ if (0 == cmd->details.loop.curr_iteration)
+ {
+ cmd->details.save_array.index = 0;
+ }
+ /* The probability distribution of the saved items will be a little biased
+ against the few last items but it should not be a big problem. */
+ selection_chance = loop_ref->details.loop.max_iterations /
+ cmd->details.save_array.nb_saved;
+ /*
+ * If the remaining space is equal to the remaining number of
+ * iterations, the item is automaticly saved.
+ *
+ * Else it is saved only if the random numbre generated is 0
+ */
+ if ( (0 < (cmd->details.save_array.nb_saved -
+ cmd->details.save_array.index) ) &&
+ ( ((loop_ref->details.loop.max_iterations -
+ loop_ref->details.loop.curr_iteration) ==
+ (cmd->details.save_array.nb_saved -
+ cmd->details.save_array.index)) ||
+ (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ selection_chance)) ) )
+ {
+ struct PERF_TALER_EXCHANGEDB_Data *save_location;
+ struct PERF_TALER_EXCHANGEDB_Data *item_saved;
+
+ save_location = &cmd->details.save_array.data_saved[cmd->details.save_array.index];
+ item_saved = &save_ref->exposed;
+ data_copy (item_saved, save_location);
+ cmd->details.save_array.index++;
+ }
+}
+
+
+/**
+ * Part of the interpreter specific to
+ * #PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY
+ * Gets data from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY and exposes a copy
+ */
+static void
+interpret_load_array (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
+{
+ struct PERF_TALER_EXCHANGEDB_Cmd *cmd = &state->cmd[state->i];
+ unsigned int loop_iter;
+ int loop_index;
+ int save_index;
+ struct PERF_TALER_EXCHANGEDB_Data *loaded_data;
+
+ loop_index = cmd->details.load_array.index_loop;
+ save_index = cmd->details.load_array.index_save;
+ loop_iter = state->cmd[loop_index].details.loop.curr_iteration;
+ {
+ unsigned int i;
+ unsigned int quotient;
+
+ /* In case the iteration number is higher than the amount saved,
+ * the number is run several times in the permutation array */
+ quotient = loop_iter / state->cmd[save_index].details.save_array.nb_saved;
+ loop_iter = loop_iter % state->cmd[save_index].details.save_array.nb_saved;
+ for (i=0; i<=quotient; i++)
+ loop_iter = cmd->details.load_array.permutation[loop_iter];
+ }
+ /* Extracting the data from the loop_indexth indice in save_index
+ * array.
+ */
+ loaded_data = &state->cmd[save_index].details.save_array.data_saved[loop_iter];
+ data_copy (loaded_data,
+ &cmd->exposed);
+}
+
+
+/**
+ * Part of the interpreter specific to
+ * #PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM
+ * Get a random element from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY and exposes it
+ */
+static void
+interprete_load_random (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
+{
+ struct PERF_TALER_EXCHANGEDB_Cmd *cmd = &state->cmd[state->i];
+ unsigned int index;
+ int save_index;
+
+ save_index = cmd->details.load_random.index_save;
+ index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ state->cmd[save_index].details.save_array.nb_saved);
+ data_copy (&state->cmd[save_index].details.save_array.data_saved[index],
+ &cmd->exposed);
+}
+
+
+/**
+ * Iterate over the commands, acting accordingly at each step
+ *
+ * @param state the current state of the interpreter
+ */
+static int
+interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
+{
+ for (state->i=0; PERF_TALER_EXCHANGEDB_CMD_END != state->cmd[state->i].command; state->i++)
+ {
+ switch (state->cmd[state->i].command)
+ {
+ case PERF_TALER_EXCHANGEDB_CMD_END:
+ return GNUNET_YES;
+
+ case PERF_TALER_EXCHANGEDB_CMD_DEBUG:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "%s\n",
+ state->cmd[state->i].label);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_LOOP:
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_END_LOOP:
+ interpret_end_loop (state);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_TIME:
+ state->cmd[state->i].exposed.data.time =
+ GNUNET_new (struct GNUNET_TIME_Absolute);
+ *state->cmd[state->i].exposed.data.time =
+ GNUNET_TIME_absolute_get ();
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GAUGER:
+ {
+ unsigned int start_index;
+ unsigned int stop_index;
+ float ips;
+ struct GNUNET_TIME_Absolute start;
+ struct GNUNET_TIME_Absolute stop;
+ struct GNUNET_TIME_Relative elapsed;
+
+ start_index = state->cmd[state->i].details.gauger.index_start;
+ stop_index = state->cmd[state->i].details.gauger.index_stop;
+ start = *state->cmd[start_index].exposed.data.time;
+ stop = *state->cmd[stop_index].exposed.data.time;
+ elapsed = GNUNET_TIME_absolute_get_difference (start,
+ stop);
+ ips = (1.0 * state->cmd[state->i].details.gauger.divide) / (elapsed.rel_value_us/1000000.0);
+ GAUGER (state->cmd[state->i].details.gauger.category,
+ state->cmd[state->i].details.gauger.description,
+ ips,
+ state->cmd[state->i].details.gauger.unit);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_NEW_SESSION:
+ state->session = state->plugin->get_session (state->plugin->cls, GNUNET_YES);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION:
+ state->plugin->start (state->plugin->cls, state->session);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION:
+ state->plugin->commit (state->plugin->cls, state->session);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION:
+ state->plugin->rollback (state->plugin->cls,
+ state->session);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY:
+ interpret_save_array (state);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY:
+ interpret_load_array (state);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM:
+ interprete_load_random (state);
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT:
+ {
+ int coin_index;
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+
+ coin_index = state->cmd[state->i].details.create_deposit.index_coin;
+ deposit = PERF_TALER_EXCHANGEDB_deposit_init (state->cmd[coin_index].exposed.data.coin);
+ GNUNET_assert (NULL != deposit);
+ state->cmd[state->i].exposed.data.deposit = deposit;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT:
+ {
+ int deposit_index;
+ int ret;
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+
+ deposit_index = state->cmd[state->i].details.insert_deposit.index_deposit;
+ deposit = state->cmd[deposit_index].exposed.data.deposit;
+ ret = state->plugin->insert_deposit (state->plugin->cls,
+ state->session,
+ deposit);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ state->cmd[state->i].exposed.data.deposit = deposit;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT:
+ {
+ unsigned int source_index;
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Data *data;
+
+ source_index = state->cmd[state->i].details.get_deposit.index_deposit;
+ data = &state->cmd[source_index].exposed;
+ ret = state->plugin->have_deposit (state->plugin->cls,
+ state->session,
+ data->data.deposit);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE:
+ {
+ struct PERF_TALER_EXCHANGEDB_Reserve *reserve;
+
+ reserve = PERF_TALER_EXCHANGEDB_reserve_init ();
+ state->cmd[state->i].exposed.data.reserve = reserve;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE:
+ {
+ unsigned int reserve_index;
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Reserve *reserve;
+ json_t *details = NULL;
+
+ reserve_index = state->cmd[state->i].details.insert_reserve.index_reserve;
+ reserve = state->cmd[reserve_index].exposed.data.reserve;
+ details = json_pack ("{s:i}","justification",
+ GNUNET_CRYPTO_random_u32 (
+ GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX));
+ GNUNET_assert (NULL != details);
+ ret = state->plugin->reserves_in_insert (state->plugin->cls,
+ state->session,
+ &reserve->reserve.pub,
+ &reserve->reserve.balance,
+ GNUNET_TIME_absolute_get (),
+ details);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ json_decref (details);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE:
+ {
+ unsigned int reserve_index;
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Data *data;
+
+
+ reserve_index = state->cmd[state->i].details.get_reserve.index_reserve;
+ data = &state->cmd[reserve_index].exposed;
+ ret = state->plugin->reserve_get (state->plugin->cls,
+ state->session,
+ &data->data.reserve->reserve);
+ GNUNET_assert (GNUNET_OK == ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY:
+ {
+ unsigned int reserve_index;
+ struct TALER_EXCHANGEDB_ReserveHistory *history;
+ struct PERF_TALER_EXCHANGEDB_Data *data;
+
+ reserve_index = state->cmd[state->i].details.get_reserve_history.index_reserve;
+ data = &state->cmd[reserve_index].exposed;
+ history = state->plugin->get_reserve_history (state->plugin->cls,
+ state->session,
+ &data->data.reserve->reserve.pub);
+ GNUNET_assert (NULL != history);
+ state->plugin->free_reserve_history (state->plugin->cls,
+ history);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION:
+ {
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki =
+ PERF_TALER_EXCHANGEDB_denomination_init ();
+ GNUNET_assert (NULL != dki);
+ state->cmd[state->i].exposed.data.dki = dki;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION:
+ {
+ unsigned int denom_index;
+ int ret;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki ;
+
+ denom_index = state->cmd[state->i].details.insert_denomination.index_denom;
+ dki = state->cmd[denom_index].exposed.data.dki;
+ ret = state->plugin->insert_denomination_info (state->plugin->cls,
+ state->session,
+ &dki->denom_pub,
+ &dki->issue);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION:
+ {
+ unsigned int denom_index;
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Data *data;
+
+ denom_index = state->cmd[state->i].details.get_denomination.index_denom;
+ data = &state->cmd[denom_index].exposed;
+ ret = state->plugin->get_denomination_info (state->plugin->cls,
+ state->session,
+ &data->data.dki->denom_pub,
+ &data->data.dki->issue);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW:
+ {
+ unsigned int dki_index;
+ unsigned int reserve_index;
+ struct PERF_TALER_EXCHANGEDB_Coin *coin ;
+
+ dki_index = state->cmd[state->i].details.create_withdraw.index_dki;
+ reserve_index = state->cmd[state->i].details.create_withdraw.index_reserve;
+ coin = PERF_TALER_EXCHANGEDB_coin_init (state->cmd[dki_index].exposed.data.dki,
+ state->cmd[reserve_index].exposed.data.reserve);
+ GNUNET_assert (NULL != coin);
+ state->cmd[state->i].exposed.data.coin = coin;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW:
+ {
+ unsigned int coin_index;
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Coin *coin ;
+
+ coin_index = state->cmd[state->i].details.insert_withdraw.index_coin;
+ coin = state->cmd[coin_index].exposed.data.coin;
+ ret = state->plugin->insert_withdraw_info (state->plugin->cls,
+ state->session,
+ &coin->blind);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW:
+ {
+ unsigned int source_index;
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_Data *data;
+
+ source_index = state->cmd[state->i].details.get_denomination.index_denom;
+ data = &state->cmd[source_index].exposed;
+ ret = state->plugin->get_withdraw_info (state->plugin->cls,
+ state->session,
+ &data->data.coin->blind.h_coin_envelope,
+ &data->data.coin->blind);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION:
+ {
+ unsigned int coin_index;
+ struct PERF_TALER_EXCHANGEDB_Coin *coin;
+ struct TALER_EXCHANGEDB_TransactionList *transactions;
+
+ coin_index = state->cmd[state->i].details.get_coin_transaction.index_coin;
+ coin = state->cmd[coin_index].exposed.data.coin;
+ transactions = state->plugin->get_coin_transactions (state->plugin->cls,
+ state->session,
+ &coin->public_info.coin_pub);
+ GNUNET_assert (transactions != NULL);
+ state->plugin->free_coin_transaction_list (state->plugin->cls,
+ transactions);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION:
+ {
+ struct GNUNET_HashCode *hash;
+ struct TALER_EXCHANGEDB_RefreshSession *refresh_session;
+
+ hash = GNUNET_new (struct GNUNET_HashCode);
+ refresh_session = PERF_TALER_EXCHANGEDB_refresh_session_init ();
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ hash);
+ state->plugin->create_refresh_session (state->session,
+ state->session,
+ hash,
+ refresh_session);
+ state->cmd[state->i].exposed.data.session_hash = hash;
+ PERF_TALER_EXCHANGEDB_refresh_session_free (refresh_session);
+ GNUNET_free (refresh_session);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION:
+ {
+ unsigned int hash_index;
+ struct GNUNET_HashCode *hash;
+ struct TALER_EXCHANGEDB_RefreshSession refresh;
+
+ hash_index = state->cmd[state->i].details.get_refresh_session.index_hash;
+ hash = state->cmd[hash_index].exposed.data.session_hash;
+ state->plugin->get_refresh_session (state->session,
+ state->session,
+ hash,
+ &refresh);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT:
+ {
+ unsigned int hash_index;
+ unsigned int coin_index;
+ struct GNUNET_HashCode *hash;
+ struct TALER_EXCHANGEDB_RefreshMelt *melt;
+ struct PERF_TALER_EXCHANGEDB_Coin *coin;
+
+ hash_index = state->cmd[state->i].details.insert_refresh_melt.index_hash;
+ coin_index = state->cmd[state->i].details.insert_refresh_melt.index_coin;
+ hash = state->cmd[hash_index].exposed.data.session_hash;
+ coin = state->cmd[coin_index].exposed.data.coin;
+ melt = PERF_TALER_EXCHANGEDB_refresh_melt_init (hash,
+ coin);
+ state->plugin->insert_refresh_melt (state->plugin->cls,
+ state->session,
+ 1,
+ melt);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT:
+ {
+ int ret;
+ unsigned int hash_index;
+ struct GNUNET_HashCode *hash;
+ struct TALER_EXCHANGEDB_RefreshMelt melt;
+
+ hash_index = cmd_find (state->cmd,
+ state->cmd[state->i].details.get_refresh_melt.label_hash);
+ hash = state->cmd[hash_index].exposed.data.session_hash;
+ ret = state->plugin->get_refresh_melt (state->plugin->cls,
+ state->session,
+ hash,
+ 1,
+ &melt);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER:
+ {
+ unsigned int hash_index;
+ unsigned int denom_index;
+ struct GNUNET_HashCode *session_hash;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *denom;
+
+ hash_index = state->cmd[state->i].details.insert_refresh_order.index_hash;
+ denom_index = state->cmd[state->i].details.insert_refresh_order.index_denom;
+ session_hash = state->cmd[hash_index].exposed.data.session_hash;
+ denom = state->cmd[denom_index].exposed.data.dki;
+ state->plugin->insert_refresh_order (state->plugin->cls,
+ state->session,
+ session_hash,
+ 1,
+ &denom->denom_pub);
+
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER:
+ {
+ int hash_index;
+ struct GNUNET_HashCode *hash;
+ struct TALER_DenominationPublicKey denom_pub;
+
+ hash_index = state->cmd[state->i].details.get_refresh_order.index_hash;
+ hash = state->cmd[hash_index].exposed.data.session_hash;
+ state->plugin->get_refresh_order (state->plugin->cls,
+ state->session,
+ hash,
+ 1,
+ &denom_pub);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN:
+ {
+ int ret;
+ unsigned int hash_index;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *refresh_commit;
+
+ hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash;
+ refresh_commit = PERF_TALER_EXCHANGEDB_refresh_commit_coin_init ();
+ ret = state->plugin->insert_refresh_commit_coins (state->plugin->cls,
+ state->session,
+ state->cmd[hash_index].exposed.data.session_hash,
+ 1,
+ 1,
+ refresh_commit);
+ GNUNET_assert (GNUNET_OK == ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN:
+ {
+ unsigned int hash_index;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin refresh_commit;
+
+ hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash;
+ state->plugin->get_refresh_commit_coins (state->plugin->cls,
+ state->session,
+ state->cmd[hash_index].exposed.data.session_hash,
+ 1,
+ 1,
+ &refresh_commit);
+
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK:
+ {
+// unsigned int hash_index;
+//
+// hash_index = state->cmd[state->i].details.insert_refresh_commit_link.index_hash;
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK:
+ {
+ int ret;
+ unsigned int hash_index;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin commit_coin;
+
+ hash_index = state->cmd[state->i].details.get_refresh_commit_link.index_hash;
+ ret = state->plugin->get_refresh_commit_coins(state->plugin->cls,
+ state->session,
+ state->cmd[hash_index].exposed.data.session_hash,
+ 1,
+ 1,
+ &commit_coin);
+ GNUNET_assert (GNUNET_SYSERR != ret);
+ }
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT:
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT:
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST:
+ break;
+
+ case PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER:
+ break;
+
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Runs the commands given in @a cmd, working with
+ * the database referenced by @a db_plugin
+ *
+ * @param db_plugin the connection to the database
+ * @param cmd the commands to run
+ */
+int
+PERF_TALER_EXCHANGEDB_interpret (struct TALER_EXCHANGEDB_Plugin *db_plugin,
+ struct PERF_TALER_EXCHANGEDB_Cmd cmd[])
+{
+ int ret;
+ struct PERF_TALER_EXCHANGEDB_interpreter_state state =
+ {.i = 0, .cmd = cmd, .plugin = db_plugin};
+
+ ret = cmd_init (cmd);
+ if (GNUNET_SYSERR == ret)
+ return ret;
+ state.session = db_plugin->get_session (db_plugin->cls,
+ GNUNET_YES);
+ GNUNET_assert (NULL != state.session);
+ ret = interpret (&state);
+ cmd_clean (cmd);
+ return ret;
+}
+
+
+/**
+ * Initialize the database and run the benchmark
+ *
+ * @param benchmark_name the name of the benchmark, displayed in the logs
+ * @param configuration_file path to the taler configuration file to use
+ * @param init the commands to use for the database initialisation,
+ * if #NULL the standard initialization is used
+ * @param benchmark the commands for the benchmark
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+int
+PERF_TALER_EXCHANGEDB_run_benchmark (const char *benchmark_name,
+ const char *configuration_file,
+ struct PERF_TALER_EXCHANGEDB_Cmd *init,
+ struct PERF_TALER_EXCHANGEDB_Cmd *benchmark)
+{
+ struct TALER_EXCHANGEDB_Plugin *plugin;
+ struct GNUNET_CONFIGURATION_Handle *config;
+ int ret = 0;
+ struct PERF_TALER_EXCHANGEDB_Cmd init_def[] =
+ {
+ // Denomination used to create coins
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("00 - Start of interpreter"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("01 - denomination loop",
+ PERF_TALER_EXCHANGEDB_NB_DENOMINATION_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert",
+ "01 - denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination",
+ "01 - denomination loop",
+ "01 - denomination",
+ PERF_TALER_EXCHANGEDB_NB_DENOMINATION_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "01 - denomination loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("01 - init denomination complete"),
+ // End of initialization
+ // Reserve initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("02 - init reserve loop",
+ PERF_TALER_EXCHANGEDB_NB_RESERVE_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("02 - insert",
+ "02 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve",
+ "02 - init reserve loop",
+ "02 - reserve",
+ PERF_TALER_EXCHANGEDB_NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "02 - init reserve loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("02 - reserve init complete"),
+ // End reserve init
+ // Withdrawal initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("03 - init withdraw loop",
+ PERF_TALER_EXCHANGEDB_NB_WITHDRAW_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load",
+ "03 - init withdraw loop",
+ "01 - save denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load",
+ "03 - init withdraw loop",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw",
+ "03 - denomination load",
+ "03 - reserve load"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert",
+ "03 - withdraw"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("03 - save coin",
+ "03 - init withdraw loop",
+ "03 - withdraw",
+ PERF_TALER_EXCHANGEDB_NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("",
+ "03 - init withdraw loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("03 - withdraw init complete"),
+ //End of withdrawal initialization
+ //Deposit initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("04 - deposit init loop",
+ PERF_TALER_EXCHANGEDB_NB_DEPOSIT_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("04 - denomination load",
+ "04 - deposit init loop",
+ "03 - save coin"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT ("04 - deposit",
+ "04 - denomination load"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array",
+ "04 - deposit init loop",
+ "04 - deposit",
+ PERF_TALER_EXCHANGEDB_NB_DEPOSIT_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("04 - deposit init loop end",
+ "04 - deposit init loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("04 - deposit init complete"),
+ // End of deposit initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END ("end")
+ };
+
+ GNUNET_log_setup (benchmark_name,
+ "INFO",
+ NULL);
+ config = GNUNET_CONFIGURATION_create ();
+
+ ret = GNUNET_CONFIGURATION_load (config,
+ configuration_file);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error parsing configuration file\n");
+ return GNUNET_SYSERR;
+ }
+ plugin = TALER_EXCHANGEDB_plugin_load (config);
+ if (NULL == plugin)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error connectiong to the database\n");
+ return ret;
+ }
+ ret = plugin->create_tables (plugin->cls,
+ GNUNET_YES);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error while creating the database architecture\n");
+ return ret;
+ }
+ /*
+ * Running the initialization
+ */
+ if (NULL == init)
+ {
+ init = init_def;
+ }
+ ret = PERF_TALER_EXCHANGEDB_interpret (plugin,
+ init);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error during database initialization\n");
+ return ret;
+ }
+ /*
+ * Running the benchmark
+ */
+ ret = PERF_TALER_EXCHANGEDB_interpret (plugin,
+ benchmark);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error while runing the benchmark\n");
+ return ret;
+ }
+ /* Drop tables */
+ {
+ struct TALER_EXCHANGEDB_Session *session;
+
+ session = plugin->get_session (plugin->cls,
+ GNUNET_YES);
+ ret = plugin->drop_temporary (plugin->cls,
+ session);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error cleaning the database\n");
+ return ret;
+ }
+ }
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ GNUNET_CONFIGURATION_destroy (config);
+ return ret;
+}
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.h b/src/exchangedb/perf_taler_exchangedb_interpreter.h
new file mode 100644
index 000000000..a83251c60
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.h
@@ -0,0 +1,1319 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchangedb/perf_taler_exchangedb_interpreter.h
+ * @brief Library for performance analysis of the Taler database
+ * @author Nicolas Fournier
+ *
+ * This library contains functions and macro alowing Taler performance analysis
+ * to be written with ease.
+ * To do so, create a #PERF_TALER_EXCHANGEDB_Cmd array and fill it with the commands
+ * to execute in chronological order. Some command have an exposed variable wich
+ * can be reused in other commands.
+ * Macros are available to make the use much easier so feel free to use them
+ * to initialize your own command array.
+ */
+
+#ifndef __PERF_TALER_EXCHANGEDB_INTERPRETER_H__
+#define __PERF_TALER_EXCHANGEDB_INTERPRETER_H__
+
+#include <sys/time.h>
+#include "taler_exchangedb_plugin.h"
+
+
+#define PERF_TALER_EXCHANGEDB_NB_DENOMINATION_INIT 10
+#define PERF_TALER_EXCHANGEDB_NB_DENOMINATION_SAVE 10
+
+#define PERF_TALER_EXCHANGEDB_NB_RESERVE_INIT 100
+#define PERF_TALER_EXCHANGEDB_NB_RESERVE_SAVE 10
+
+#define PERF_TALER_EXCHANGEDB_NB_DEPOSIT_INIT 100
+#define PERF_TALER_EXCHANGEDB_NB_DEPOSIT_SAVE 10
+
+#define PERF_TALER_EXCHANGEDB_NB_WITHDRAW_INIT 100
+#define PERF_TALER_EXCHANGEDB_NB_WITHDRAW_SAVE 10
+
+
+/**
+ * Marks the end of the command chain
+ *
+ * @param _label The label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_END(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_END, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE \
+}
+
+
+/**
+ * Prints @ _label to stdout
+ *
+ * @param _label The label of the command,
+ * will be logged each time the command runs
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_DEBUG, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE \
+}
+
+/**
+ * The begining of a loop
+ *
+ * @param _label the label of the loop
+ * @param _iter the number of iterations of the loop
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP(_label, _iter) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_LOOP , \
+ .label = _label , \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE , \
+ .details.loop = { \
+ .max_iterations = _iter , \
+ .curr_iteration = 0 } \
+}
+
+/**
+ * Marks the end of the loop @_label_loop
+ *
+ * @param _label the label of the command
+ * @param _label_loop the label of the loop closed by this command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP(_label, _label_loop) \
+{\
+ .command = PERF_TALER_EXCHANGEDB_CMD_END_LOOP , \
+ .label = _label , \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE , \
+ .details.end_loop.label_loop = _label_loop \
+}
+
+/**
+ * Saves the time of execution to use for logging with Gauger
+ *
+ * @param _label the label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_TIME, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_TIME \
+}
+
+/**
+ * Commits the duration between @a _label_start and @a _label_stop
+ * to Gauger with @a _description explaining what was measured.
+ *
+ * @param _label the label of this command
+ * @param _label_start label of the start of the measurment
+ * @param _label_stop label of the end of the measurment
+ * @param _description description of the measure displayed in Gauger
+ * @param _unit the unit of the data measured, typicly something/sec
+ * @param _divide number of measurments in the interval
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER(_label, _label_start, _label_stop, _category, _description, _unit, _divide) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GAUGER, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.gauger = { \
+ .label_start = _label_start, \
+ .label_stop = _label_stop, \
+ .category = _category, \
+ .description = _description, \
+ .unit = _unit, \
+ .divide = _divide, \
+ } \
+}
+
+/**
+ * Initiate a database transaction
+ *
+ * @param _label the label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+}
+
+/**
+ * Commits a database transaction
+ *
+ * @param _label the label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+}
+
+/**
+ * Abort the current transaction
+ *
+ * @param _label the label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_ABORT_TRANSACTION(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION, \
+ .label = _label,
+
+/**
+ * Saves randomly selected items from @a _label_save
+ * Saved items can latter be access using #PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY
+ *
+ * @param _label the label of the command, used by other commands to reference it
+ * @param _label_loop the label of the loop the array iterates over
+ * @param _label_save the label of the command which outout is saved by this command
+ * @param _nb_saved the total number of items to be saved
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY(_label, _label_loop, _label_save, _nb_saved) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.save_array = { \
+ .label_loop = _label_loop, \
+ .label_save = _label_save, \
+ .nb_saved = _nb_saved, \
+ } \
+}
+
+/**
+ * Loads data from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY to allow other
+ * commands to access it
+ *
+ * @param _label the label of this command, referenced by commands to access it's outpout
+ * @param _label_loop the label of the loop to iterate over
+ * @param _label_save the label of the #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY providing data
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY(_label, _label_loop, _label_save) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.load_array = { \
+ .label_loop = _label_loop, \
+ .label_save = _label_save \
+ } \
+}
+
+/**
+ * Create a denomination key to use
+ * Exposes a #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO to be used by other commands
+ * @exposed #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO
+ *
+ * @param _label the label of this command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_DENOMINATION_INFO, \
+}
+
+/**
+ * Inserts informations about a denomination key in the database
+ *
+ * @param _label the label of this command
+ * @param _label_denom the label of the denomination to insert
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION(_label, _label_denom) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.insert_denomination.label_denom = _label_denom, \
+}
+
+/**
+ * Polls the database about informations regarding a specific denomination key
+ *
+ * @param _label the label of this command
+ * @param _label_denom the label of the command providing information about the denomination key
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_DENOMINATION(_label, _label_denom) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.get_denomination.label_denom = _label_denom \
+}
+
+/**
+ * Create a reserve to be used later
+ * Exposes a #PERF_TALER_EXCHANGEDB_RESERVE
+ *
+ * @param _label the label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_RESERVE \
+}
+
+/**
+ * Insert a new reserve in the database containing 1000 Euros
+ *
+ * @param _label the name of this command
+ * @param _label_reserve the label of the reserve to insert
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE(_label, _label_reserve) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.insert_reserve.label_reserve = _label_reserve \
+}
+
+/**
+ * Polls the database for a secific reserve's details
+ *
+ * @param _label the label of this command
+ * @param _label_reserve the reserve to poll
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE(_label, _label_reserve) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.get_reserve.label_reserve = _label_reserve \
+}
+
+/**
+ * Polls the database for the history of a reserve
+ *
+ * @param _label the label of the command
+ * @param _label_reserve the reserve to examine
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE_HISTORY(_label, _label_reserve) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.get_reserve_history.label_reserve = _label_reserve \
+}
+
+/**
+ * Creates a coin to be used later
+ *
+ * @param _label the label of this command
+ * @param _label_dki denomination key used to sign the coin
+ * @param _label_reserve reserve used to emmit the coin
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW(_label, _label_dki, _label_reserve) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_COIN, \
+ .details.create_withdraw = {\
+ .label_dki = _label_dki, \
+ .label_reserve = _label_reserve, \
+ } \
+}
+
+/**
+ * Inserts informations about a withdrawal in the database
+ *
+ * @exposes #PERF_TALER_EXCHANGEDB_COIN
+ *
+ * @param _label the label of this command
+ * @param _label_coin the coin to insert
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW(_label, _label_coin) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.insert_withdraw.label_coin = _label_coin\
+}
+
+
+/**
+ * Polls the database about informations regarding a specific withdrawal
+ *
+ * @param _label the label of this command
+ * @param _label_coin the coin to check
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_WITHDRAW(_label, _label_coin) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.get_withdraw.label_coin = _label_coin, \
+}
+
+
+/**
+ * The /reserve/withdraw api call
+ *
+ * Exposes #PERF_TALER_EXCHANGEDB_COIN
+ *
+ * @param _label the label of this command
+ * @param _label_dki the denomination of the created coin
+ * @param _label_reserve the reserve used to provide currency
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_WITHDRAW_SIGN(_label, _label_dki, _label_reserve) \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW (_label "withdraw", \
+ _label_dki, \
+ _label_reserve), \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_DENOMINATION(_label "withdraw info", \
+ _label_dki), \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE_HISTORY(_label "reserve_history", \
+ _label_reserve), \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW(_label "insert withdraw", \
+ _label "withdraw")
+
+/**
+ * Create a deposit for use later
+ * @exposes #PERF_TALER_EXCHANGEDB_DEPOSIT
+ *
+ * @param _label the label of this command
+ * @param _label_coin the coin used to pay
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT(_label, _label_coin) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_DEPOSIT, \
+ .details.create_deposit.label_coin = _label_coin, \
+}
+
+/**
+ * Insert a deposit into the database
+ *
+ * @param _label the label of this command
+ * @param _label_deposit the deposit inseerted
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT(_label, _label_deposit) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT,\
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.insert_deposit.label_deposit = _label_deposit, \
+}
+
+/**
+ * Check if a deposit is in the database
+ *
+ * @param _label the label of this command
+ * @param _label_deposit the deposit to use
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_DEPOSIT(_label, _label_deposit) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.get_deposit.label_deposit = _label_deposit \
+}
+
+/**
+ * Access the transaction history of a coin
+ *
+ * @param _label the label of the command
+ * @param _label_coin the coin which history is checked
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_COIN_TRANSACTION(_label, _label_coin) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \
+ .details.get_coin_transaction.label_coin = _label_coin \
+}
+
+/**
+ * The /deposit api call
+ *
+ * @param _label the label of the command
+ * @param _label_coin the coin used for the deposit
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_DEPOSIT(_label, _label_coin) \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_COIN_TRANSACTION (_label "coin history", \
+ _label_coin), \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT (_label "deposit", \
+ _label_coin), \
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT (_label "insert", \
+ _label "deposit")
+/**
+ * Insert informations about a refresh session
+ * melts one coin into another
+ *
+ * @param _label the label of the command
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION(_label) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_REFRESH_HASH \
+}
+
+/**
+ * Get informations about a refresh session
+ *
+ * @param _label the label of the command
+ * @param _label_hash the label of the hash to search
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_REFRESH_SESSION(_label, \
+ _label_hash) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION, \
+ .label = _label, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE \
+}
+
+/**
+ * Insert a melt operation in the database
+ *
+ * @param _label the label of the command
+ * @param _label_hash the label of the hash of the session
+ * @param _label_coin the label of the coin to melt
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_REFRESH_MELT(_label, \
+ _label_hash, \
+ _label_coin) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT, \
+ .label = _label, \
+ .details.insert_refresh_melt.label_hash = _label_hash, \
+ .details.insert_refresh_melt.label_coin = _label_coin, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE \
+}
+
+/**
+ * Get informations about a melt operation
+ *
+ * @param _label the label of the command
+ * @param _label_hash the label of the hash of the refresh session
+ */
+#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_REFRESH_MELT(_label, \
+ _label_hash) \
+{ \
+ .command = PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT, \
+ .label = _label, \
+ .detail.get_refresh_melt.label_hash = _label_hash, \
+ .exposed.type = PERF_TALER_EXCHANGEDB_NONE \
+}
+
+/**
+ * The type of data stored in #PERF_TALER_EXCHANGEDB_Memory
+ */
+enum PERF_TALER_EXCHANGEDB_Type
+{
+ PERF_TALER_EXCHANGEDB_NONE,
+ PERF_TALER_EXCHANGEDB_TIME,
+ PERF_TALER_EXCHANGEDB_DENOMINATION_INFO,
+ PERF_TALER_EXCHANGEDB_RESERVE,
+ PERF_TALER_EXCHANGEDB_COIN,
+ PERF_TALER_EXCHANGEDB_DEPOSIT,
+ PERF_TALER_EXCHANGEDB_REFRESH_HASH,
+ PERF_TALER_EXCHANGEDB_REFRESH_MELT
+};
+
+
+/**
+ * Structure used to handle several data type
+ */
+struct PERF_TALER_EXCHANGEDB_Data
+{
+ enum PERF_TALER_EXCHANGEDB_Type type;
+
+ /**
+ * Storage for a variety of data type
+ * The data saved should match #type
+ */
+ union PERF_TALER_EXCHANGEDB_Memory
+ {
+ /** #PERF_TALER_EXCHANGEDB_TIME */
+ struct GNUNET_TIME_Absolute *time;
+ /** #PERF_TALER_EXCHANGEDB_DEPOSIT */
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+ /** #PERF_TALER_EXCHANGEDB_COIN */
+ struct PERF_TALER_EXCHANGEDB_Coin *coin;
+ /** #PERF_TALER_EXCHANGEDB_RESERVE */
+ struct PERF_TALER_EXCHANGEDB_Reserve *reserve;
+ /** #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO */
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+ /** #PERF_TALER_EXCHANGEDB_REFRESH_HASH */
+ struct GNUNET_HashCode *session_hash;
+ /** #PERF_TALER_EXCHANGEDB_REFRESH_MELT */
+ struct TALER_EXCHANGEDB_RefreshMelt *refresh_melt;
+ } data;
+};
+
+
+/**
+ * Name of the command
+ */
+enum PERF_TALER_EXCHANGEDB_CMD_Name
+{
+ /**
+ * All comand chain must hace this as their last command
+ */
+ PERF_TALER_EXCHANGEDB_CMD_END,
+
+ /**
+ * Prints it's label
+ */
+ PERF_TALER_EXCHANGEDB_CMD_DEBUG,
+
+ /**
+ * Define the start of al command chain loop
+ */
+ PERF_TALER_EXCHANGEDB_CMD_LOOP,
+
+ /**
+ * Define the end of a command chain loop
+ */
+ PERF_TALER_EXCHANGEDB_CMD_END_LOOP,
+
+ /**
+ * Save the time at which the command was executed
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_TIME,
+
+ /**
+ * Upload performance to Gauger
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GAUGER,
+
+ /**
+ * Start a new session
+ */
+ PERF_TALER_EXCHANGEDB_CMD_NEW_SESSION,
+
+ /**
+ * Start a database transaction
+ */
+ PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION,
+
+ /**
+ * End a database transaction
+ */
+ PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION,
+
+ /**
+ * Abort a transaction started with #PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION
+ */
+ PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION,
+
+ /**
+ * Saves random deposits from a loop
+ */
+ PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY,
+
+ /**
+ * Load items saved earlier in a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY
+ * The items are loaded in a random order, but all of them will be loaded
+ */
+ PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY,
+
+ /**
+ * Loads a random item from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY
+ * A random item is loaded each time the command is run
+ */
+ PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM,
+
+ /**
+ * Create a denomination to be used later
+ */
+ PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION,
+
+ /**
+ * Insert informations about a denomination key in the database
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION,
+
+ /**
+ * Polls the database for informations about a specific denomination key
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION,
+
+ /**
+ * Create a reserve to be used later
+ */
+ PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE,
+
+ /**
+ * Insert currency in a reserve / Create a reserve
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE,
+
+ /**
+ * Get Informations about a reserve
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE,
+
+ /**
+ * Get the history of a reserve
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY,
+
+ /**
+ * Create a withdrawal to be used later
+ */
+ PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW,
+
+ /**
+ * Insert informations about a withdrawal in the database
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW,
+
+ /**
+ * Pulls informations about a withdrawal from the database
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW,
+
+ /**
+ * Get the list of all transactions the coin has been in
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION,
+
+ /**
+ * Create a deposit to be used later
+ */
+ PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT,
+
+ /**
+ * Insert a deposit into the database
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT,
+
+ /**
+ * Check if a deposit is in the database
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT,
+
+ /**
+ * Create a refresh session
+ * The number of melted coins is 1,
+ * The number of exchangeed coins is 1
+ */
+ PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION,
+
+ /**
+ * Get a refresh session informations
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION,
+
+ /**
+ * Insert a refresh melt
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT,
+
+ /**
+ * Get informations about a refresh melt operation
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT,
+
+ /**
+ * Insert a melt refresh order
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER,
+
+ /**
+ * Get informations about a refresh order
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER,
+
+ /**
+ * Insert refresh commit coin
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN,
+
+ /**
+ * Get refresh commit coin
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN,
+
+ /**
+ * Insert refresh commit link
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK,
+
+ /**
+ * Get refresh commit link
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK,
+
+ /**
+ * Get information avout the melt commit
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT,
+
+ /**
+ * Insert a new coin into the database after a melt operation
+ */
+ PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT,
+
+ /**
+ * Get the link data list of a coin
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST,
+
+ /**
+ * Get the shared secret and the transfere public key
+ */
+ PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER
+
+};
+
+
+/**
+ * Contains extra data required for any command
+ */
+union PERF_TALER_EXCHANGEDB_CMD_Details
+{
+ /**
+ * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_LOOP command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_loopDetails
+ {
+ /**
+ * Maximum number of iteration in the loop
+ */
+ const unsigned int max_iterations;
+
+ /**
+ * The current iteration of the loop
+ */
+ unsigned int curr_iteration;
+ } loop;
+
+ /**
+ * Extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_END_LOOP command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_endLoopDetails
+ {
+ /**
+ * Label of the loop closed by the command
+ */
+ const char *label_loop;
+ unsigned int index_loop;
+ } end_loop;
+
+ /**
+ * Details about the #PERF_TALER_EXCHANGEDB_CMD_GAUGER command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_gaugerDetails
+ {
+ /**
+ * Label of the starting timestamp
+ */
+ const char *label_start;
+ unsigned int index_start;
+
+ /**
+ * Label of the ending timestamp
+ */
+ const char *label_stop;
+ unsigned int index_stop;
+
+ /**
+ * The category of the measurment
+ */
+ const char *category;
+
+ /**
+ * Description of the metric, used in Gauger
+ */
+ const char *description;
+
+ /**
+ * The name of the metric beeing used
+ */
+ const char *unit;
+
+ /**
+ * Constant the result needs to be divided by
+ * to get the result per unit
+ */
+ float divide;
+ } gauger;
+
+ /**
+ * Contains extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_saveArrayDetails
+ {
+ /**
+ * Number of items to save
+ */
+ unsigned int nb_saved;
+
+ /**
+ * Number of items already saved
+ */
+ unsigned int index;
+
+ /**
+ * Label of the loop it is attached to
+ */
+ const char *label_loop;
+ unsigned int index_loop;
+
+ /**
+ * Label of the command exposing the item
+ */
+ const char *label_save;
+ unsigned int index_save;
+
+ /**
+ * Array of data saved
+ */
+ struct PERF_TALER_EXCHANGEDB_Data *data_saved;
+
+ /**
+ * Type of the data that will be stored in @a data_saved, for
+ * 'static' type checking.
+ */
+ enum PERF_TALER_EXCHANGEDB_Type type_saved;
+
+ } save_array;
+
+ /**
+ * Extra data required for the #PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_loadArrayDetails
+ {
+ /**
+ * The loop in which the command is located
+ */
+ const char *label_loop;
+ unsigned int index_loop;
+
+ /**
+ * Label of the command where the items were saved
+ */
+ const char *label_save;
+ unsigned int index_save;
+
+ /**
+ * A permutation array used to randomize the order the items are loaded in
+ */
+ unsigned int *permutation;
+ } load_array;
+
+ /**
+ * Contains data for the #PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_loadRandomDetails
+ {
+ /**
+ * The label of the #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY the items will be extracted from
+ */
+ const char *label_save;
+ unsigned int index_save;
+ } load_random;
+
+ /**
+ * Extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertDenominationDetails
+ {
+ /**
+ * The label of the source of the denomination to insert
+ */
+ const char *label_denom;
+ unsigned int index_denom;
+ } insert_denomination;
+
+ /**
+ * Extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getDenominationDetails
+ {
+ /**
+ * The label of the source of the denomination to check
+ */
+ const char *label_denom;
+ unsigned int index_denom;
+ } get_denomination;
+
+ /**
+ * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertReserveDetails
+ {
+ /**
+ * The label of the source of the reserve to insert
+ */
+ const char *label_reserve;
+ unsigned int index_reserve;
+ } insert_reserve;
+
+ /**
+ * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getReserveDetails
+ {
+ /**
+ * The label of the source of the reserve to check
+ */
+ const char *label_reserve;
+ unsigned int index_reserve;
+ } get_reserve;
+
+ /**
+ * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getReserveHistoryDetails
+ {
+ /**
+ * The label of the source of the reserve to check
+ */
+ const char *label_reserve;
+ unsigned int index_reserve;
+ } get_reserve_history;
+
+ /**
+ * Extra data related to the #PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_createWithdrawDetails
+ {
+ /**
+ * label of the denomination key used to sign the coin
+ */
+ const char *label_dki;
+ unsigned int index_dki;
+
+ /**
+ * label of the reserve the money to exchange the coin comes from
+ */
+ const char *label_reserve;
+ unsigned int index_reserve;
+ } create_withdraw;
+
+ /**
+ * data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertWithdrawDetails
+ {
+ /**
+ * label of the source for the coin information
+ */
+ const char *label_coin;
+ unsigned int index_coin;
+ } insert_withdraw;
+
+ /**
+ * data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getWithdraw
+ {
+ /**
+ * label of the source for the coin information
+ */
+ const char *label_coin;
+ unsigned int index_coin;
+ } get_withdraw;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getCoinTransactionDetails
+ {
+ /**
+ * The coin which history is checked
+ */
+ const char *label_coin;
+ unsigned int index_coin;
+ } get_coin_transaction;
+
+ /**
+ * Data used by the #PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_createDepositDetails
+ {
+ /**
+ * Label of the source where the reserve used to create the coin is
+ */
+ const char *label_coin;
+ unsigned int index_coin;
+ } create_deposit;
+
+ /**
+ * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertDepositDetails
+ {
+ /**
+ * The label of the source of the deposit to check
+ */
+ const char *label_deposit;
+ unsigned int index_deposit;
+ } insert_deposit;
+
+ /**
+ * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getDepositDetails
+ {
+ /**
+ * The label of the source of the deposit to check
+ */
+ const char *label_deposit;
+ unsigned int index_deposit;
+ } get_deposit;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getRefreshSessionDetails
+ {
+ /**
+ * label of the source of the hash of the session
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } get_refresh_session;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshMeltDetails
+ {
+ /**
+ * The label of the hash of the refresh session
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+
+ /**
+ * The label of the coin to melt
+ */
+ const char *label_coin;
+ unsigned int index_coin;
+ } insert_refresh_melt;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getRefreshMeltDetails
+ {
+ /**
+ * The label of the hash of the session
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } get_refresh_melt;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshOrderDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+
+ /**
+ * The new coin denomination
+ */
+ const char *label_denom;
+ unsigned int index_denom;
+ } insert_refresh_order;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getRefreshOrderDetails
+ {
+ /**
+ * The session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+
+ } get_refresh_order;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshCommitCoinDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+
+ } insert_refresh_commit_coin;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getRefreshCommitCoinDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+
+ } get_refresh_commit_coin;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshCommitLinkDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+
+ } insert_refresh_commit_link;
+
+ /**
+ * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getRefreshCommitLinkDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } get_refresh_commit_link;
+
+ /**
+ * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getMeltCommitmentDaetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } get_melt_commitment;
+
+ /**
+ * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshOutDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } insert_refresh_out;
+
+ /**
+ * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getLinkDataListDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } get_link_data_list;
+
+ /**
+ * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER command
+ */
+ struct PERF_TALER_EXCHANGEDB_CMD_getTransferDetails
+ {
+ /**
+ * The refresh session hash
+ */
+ const char *label_hash;
+ unsigned int index_hash;
+ } get_transfer;
+
+};
+
+
+/**
+ * Command to be interpreted.
+ */
+struct PERF_TALER_EXCHANGEDB_Cmd
+{
+ /**
+ * Type of the command
+ */
+ enum PERF_TALER_EXCHANGEDB_CMD_Name command;
+
+ /**
+ * Label to refer to the command
+ */
+ const char *label;
+
+ /**
+ * Command specific data
+ */
+ union PERF_TALER_EXCHANGEDB_CMD_Details details;
+
+ /**
+ * Data easily accessible
+ */
+ struct PERF_TALER_EXCHANGEDB_Data exposed;
+};
+
+
+/**
+ * Run a benchmark
+ *
+ * @param benchmark_name the name of the benchmark, displayed in the logs
+ * @param configuration_file path to the taler configuration file to use
+ * @param init the commands to use for the database initialisation,
+ * if #NULL the standard initialization is used
+ * @param benchmark the commands for the benchmark
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+int
+PERF_TALER_EXCHANGEDB_run_benchmark (const char *benchmark_name,
+ const char *configuration_file,
+ struct PERF_TALER_EXCHANGEDB_Cmd *init,
+ struct PERF_TALER_EXCHANGEDB_Cmd *benchmark);
+
+
+/**
+ * Runs the command array @a cmd
+ * using @a db_plugin to connect to the database
+ *
+ * @param db_plugin the connection to the database
+ * @param cmd the commands to run
+ */
+int
+PERF_TALER_EXCHANGEDB_interpret(
+ struct TALER_EXCHANGEDB_Plugin *db_plugin,
+ struct PERF_TALER_EXCHANGEDB_Cmd cmd[]);
+
+
+/**
+ * Check if the given command array is syntaxicly correct
+ * This will check if the label are corrects but will not check if
+ * they are pointing to an apropriate command.
+ *
+ * @param cmd the command array to check
+ * @return #GNUNET_OK is @a cmd is correct; #GNUNET_SYSERR if it is'nt
+ */
+int
+PERF_TALER_EXCHANGEDB_check (const struct PERF_TALER_EXCHANGEDB_Cmd *cmd);
+
+#endif
diff --git a/src/exchangedb/perf_taler_exchangedb_values.h b/src/exchangedb/perf_taler_exchangedb_values.h
new file mode 100644
index 000000000..c3b50fea2
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_values.h
@@ -0,0 +1,25 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/perf_taler_exchangedb_values.h
+ * @brief Values for tweaking the performance analysis
+ * @author Nicolas Fournier
+ */
+#ifndef __PERF_TALER_EXCHANGEDB__VALUES_H__
+#define __PERF_TALER_EXCHANGEDB__VALUES_H__
+
+
+#endif
diff --git a/src/exchangedb/plugin_exchangedb_common.c b/src/exchangedb/plugin_exchangedb_common.c
new file mode 100644
index 000000000..c8e689cfd
--- /dev/null
+++ b/src/exchangedb/plugin_exchangedb_common.c
@@ -0,0 +1,162 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchangedb/plugin_exchangedb_common.c
+ * @brief Functions shared across plugins, this file is meant to be
+ * included in each plugin.
+ * @author Christian Grothoff
+ */
+
+/**
+ * Free memory associated with the given reserve history.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param rh history to free.
+ */
+static void
+common_free_reserve_history (void *cls,
+ struct TALER_EXCHANGEDB_ReserveHistory *rh)
+{
+ struct TALER_EXCHANGEDB_BankTransfer *bt;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc;
+ struct TALER_EXCHANGEDB_ReserveHistory *backref;
+
+ while (NULL != rh)
+ {
+ switch(rh->type)
+ {
+ case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
+ bt = rh->details.bank;
+ if (NULL != bt->wire)
+ json_decref (bt->wire);
+ GNUNET_free (bt);
+ break;
+ case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
+ cbc = rh->details.withdraw;
+ GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key);
+ GNUNET_free (cbc);
+ break;
+ }
+ backref = rh;
+ rh = rh->next;
+ GNUNET_free (backref);
+ }
+}
+
+
+/**
+ * Free memory of the link data list.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param ldl link data list to release
+ */
+static void
+common_free_link_data_list (void *cls,
+ struct TALER_EXCHANGEDB_LinkDataList *ldl)
+{
+ struct TALER_EXCHANGEDB_LinkDataList *next;
+
+ while (NULL != ldl)
+ {
+ next = ldl->next;
+ GNUNET_free (ldl->link_data_enc);
+ GNUNET_free (ldl);
+ ldl = next;
+ }
+}
+
+
+/**
+ * Free linked list of transactions.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param list list to free
+ */
+static void
+common_free_coin_transaction_list (void *cls,
+ struct TALER_EXCHANGEDB_TransactionList *list)
+{
+ struct TALER_EXCHANGEDB_TransactionList *next;
+
+ while (NULL != list)
+ {
+ next = list->next;
+
+ switch (list->type)
+ {
+ case TALER_EXCHANGEDB_TT_DEPOSIT:
+ json_decref (list->details.deposit->wire);
+ GNUNET_CRYPTO_rsa_public_key_free (list->details.deposit->coin.denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (list->details.deposit->coin.denom_sig.rsa_signature);
+ GNUNET_free (list->details.deposit);
+ break;
+ case TALER_EXCHANGEDB_TT_REFRESH_MELT:
+ GNUNET_free (list->details.melt);
+ break;
+ }
+ GNUNET_free (list);
+ list = next;
+ }
+}
+
+
+/**
+ * Free melt commitment data.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param mc data structure to free
+ */
+static void
+common_free_melt_commitment (void *cls,
+ struct TALER_EXCHANGEDB_MeltCommitment *mc)
+{
+ unsigned int i;
+ unsigned int k;
+
+ if (NULL != mc->melts)
+ {
+ for (i=0;i<mc->num_oldcoins;i++)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (mc->melts[i].coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (mc->melts[i].coin.denom_pub.rsa_public_key);
+ }
+ GNUNET_free (mc->melts);
+ }
+ if (NULL != mc->denom_pubs)
+ {
+ for (i=0;i<mc->num_newcoins;i++)
+ if (NULL != mc->denom_pubs[i].rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (mc->denom_pubs[i].rsa_public_key);
+ GNUNET_free (mc->denom_pubs);
+ }
+ for (k=0;k<TALER_CNC_KAPPA;k++)
+ {
+ if (NULL != mc->commit_coins[k])
+ {
+ for (i=0;i<mc->num_newcoins;i++)
+ {
+ GNUNET_free (mc->commit_coins[k][i].refresh_link);
+ GNUNET_free (mc->commit_coins[k][i].coin_ev);
+ }
+ GNUNET_free (mc->commit_coins[k]);
+ }
+ GNUNET_free_non_null (mc->commit_links[k]);
+ }
+ GNUNET_free (mc);
+}
+
+/* end of plugin_exchangedb_common.c */
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
new file mode 100644
index 000000000..0395c208e
--- /dev/null
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -0,0 +1,4295 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file plugin_exchangedb_postgres.c
+ * @brief Low-level (statement-level) Postgres database access for the exchange
+ * @author Florian Dold
+ * @author Christian Grothoff
+ * @author Sree Harsha Totakura
+ */
+#include "platform.h"
+#include "taler_pq_lib.h"
+#include "taler_exchangedb_plugin.h"
+#include <pthread.h>
+#include <libpq-fe.h>
+
+#include "plugin_exchangedb_common.c"
+
+/**
+ * For testing / experiments, we set the Postgres schema to
+ * #TALER_TEMP_SCHEMA_NAME so we can easily purge everything
+ * associated with a test. We *also* should use the database
+ * "talercheck" instead of "taler" for testing, but we're doing
+ * both: better safe than sorry.
+ */
+#define TALER_TEMP_SCHEMA_NAME "taler_temporary"
+
+/**
+ * Log a query error.
+ *
+ * @param result PQ result object of the query that failed
+ */
+#define QUERY_ERR(result) \
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result))
+
+
+/**
+ * Log a really unexpected PQ error.
+ *
+ * @param result PQ result object of the PQ operation that failed
+ */
+#define BREAK_DB_ERR(result) do { \
+ GNUNET_break (0); \
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
+ } while (0)
+
+
+/**
+ * Shorthand for exit jumps. Logs the current line number
+ * and jumps to the "EXITIF_exit" label.
+ *
+ * @param cond condition that must be TRUE to exit with an error
+ */
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+
+/**
+ * Execute an SQL statement and log errors on failure. Must be
+ * run in a function that has an "SQLEXEC_fail" label to jump
+ * to in case the SQL statement failed.
+ *
+ * @param conn database connection
+ * @param sql SQL statement to run
+ */
+#define SQLEXEC_(conn, sql) \
+ do { \
+ PGresult *result = PQexec (conn, sql); \
+ if (PGRES_COMMAND_OK != PQresultStatus (result)) \
+ { \
+ BREAK_DB_ERR (result); \
+ PQclear (result); \
+ goto SQLEXEC_fail; \
+ } \
+ PQclear (result); \
+ } while (0)
+
+
+/**
+ * Run an SQL statement, ignoring errors and clearing the result.
+ *
+ * @param conn database connection
+ * @param sql SQL statement to run
+ */
+#define SQLEXEC_IGNORE_ERROR_(conn, sql) \
+ do { \
+ PGresult *result = PQexec (conn, sql); \
+ PQclear (result); \
+ } while (0)
+
+
+/**
+ * Handle for a database session (per-thread, for transactions).
+ */
+struct TALER_EXCHANGEDB_Session
+{
+ /**
+ * Postgres connection handle.
+ */
+ PGconn *conn;
+};
+
+
+/**
+ * Type of the "cls" argument given to each of the functions in
+ * our API.
+ */
+struct PostgresClosure
+{
+
+ /**
+ * Thread-local database connection.
+ * Contains a pointer to `PGconn` or NULL.
+ */
+ pthread_key_t db_conn_threadlocal;
+
+ /**
+ * Database connection string, as read from
+ * the configuration.
+ */
+ char *connection_cfg_str;
+};
+
+
+
+/**
+ * Set the given connection to use a temporary schema
+ *
+ * @param db the database connection
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error
+ */
+static int
+set_temporary_schema (PGconn *db)
+{
+ SQLEXEC_(db,
+ "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";"
+ "SET search_path to " TALER_TEMP_SCHEMA_NAME ";");
+ return GNUNET_OK;
+ SQLEXEC_fail:
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Drop the temporary taler schema. This is only useful for testcases
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database session to use
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+static int
+postgres_drop_temporary (void *cls,
+ struct TALER_EXCHANGEDB_Session *session)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Dropping temporary tables\n");
+ SQLEXEC_ (session->conn,
+ "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;");
+ return GNUNET_OK;
+ SQLEXEC_fail:
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Function called by libpq whenever it wants to log something.
+ * We already log whenever we care, so this function does nothing
+ * and merely exists to silence the libpq logging.
+ *
+ * @param arg NULL
+ * @param res information about some libpq event
+ */
+static void
+pq_notice_receiver_cb (void *arg,
+ const PGresult *res)
+{
+ /* do nothing, intentionally */
+}
+
+
+/**
+ * Function called by libpq whenever it wants to log something.
+ * We log those using the Taler logger.
+ *
+ * @param arg NULL
+ * @param message information about some libpq event
+ */
+static void
+pq_notice_processor_cb (void *arg,
+ const char *message)
+{
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
+ "pq",
+ "%s",
+ message);
+}
+
+
+/**
+ * Create the necessary tables if they are not present
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param temporary should we use a temporary schema
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+static int
+postgres_create_tables (void *cls,
+ int temporary)
+{
+ struct PostgresClosure *pc = cls;
+ PGconn *conn;
+
+ conn = PQconnectdb (pc->connection_cfg_str);
+ if (CONNECTION_OK != PQstatus (conn))
+ {
+ TALER_LOG_ERROR ("Database connection failed: %s\n",
+ PQerrorMessage (conn));
+ PQfinish (conn);
+ return GNUNET_SYSERR;
+ }
+ PQsetNoticeReceiver (conn,
+ &pq_notice_receiver_cb,
+ NULL);
+ PQsetNoticeProcessor (conn,
+ &pq_notice_processor_cb,
+ NULL);
+ if ( (GNUNET_YES == temporary) &&
+ (GNUNET_SYSERR == set_temporary_schema (conn)))
+ {
+ PQfinish (conn);
+ return GNUNET_SYSERR;
+ }
+#define SQLEXEC(sql) SQLEXEC_(conn, sql);
+#define SQLEXEC_INDEX(sql) SQLEXEC_IGNORE_ERROR_(conn, sql);
+ /* Denomination table for holding the publicly available information of
+ denominations keys. The denominations are to be referred to by using
+ foreign keys. The denominations are deleted by a housekeeping tool;
+ hence, do not use `ON DELETE CASCADE' on these rows in the tables
+ referencing these rows */
+ SQLEXEC ("CREATE TABLE IF NOT EXISTS denominations"
+ "(pub BYTEA PRIMARY KEY"
+ ",master_pub BYTEA NOT NULL CHECK (LENGTH(master_pub)=32)"
+ ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)"
+ ",valid_from INT8 NOT NULL"
+ ",expire_withdraw INT8 NOT NULL"
+ ",expire_spend INT8 NOT NULL"
+ ",expire_legal INT8 NOT NULL"
+ ",coin_val INT8 NOT NULL" /* value of this denom */
+ ",coin_frac INT4 NOT NULL" /* fractional value of this denom */
+ ",coin_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" /* assuming same currency for fees */
+ ",fee_withdraw_val INT8 NOT NULL"
+ ",fee_withdraw_frac INT4 NOT NULL"
+ ",fee_withdraw_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",fee_deposit_val INT8 NOT NULL"
+ ",fee_deposit_frac INT4 NOT NULL"
+ ",fee_deposit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",fee_refresh_val INT8 NOT NULL"
+ ",fee_refresh_frac INT4 NOT NULL"
+ ",fee_refresh_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ")");
+ /* reserves table is for summarization of a reserve. It is updated when new
+ funds are added and existing funds are withdrawn. The 'expiration_date'
+ can be used to eventually get rid of reserves that have not been used
+ for a very long time (either by refunding the owner or by greedily
+ grabbing the money, depending on the Exchange's terms of service) */
+ SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves"
+ "(reserve_pub BYTEA PRIMARY KEY"
+ ",current_balance_val INT8 NOT NULL"
+ ",current_balance_frac INT4 NOT NULL"
+ ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",expiration_date INT8 NOT NULL"
+ ")");
+ /* index on reserves table */
+ SQLEXEC_INDEX ("CREATE INDEX reserves_reserve_pub_index ON "
+ "reserves (reserve_pub)");
+ /* reserves_in table collects the transactions which transfer funds
+ into the reserve. The rows of this table correspond to each
+ incoming transaction. */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in"
+ "(reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
+ ",balance_val INT8 NOT NULL"
+ ",balance_frac INT4 NOT NULL"
+ ",balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",details TEXT NOT NULL "
+ ",execution_date INT8 NOT NULL"
+ ",PRIMARY KEY (reserve_pub,details)"
+ ");");
+ /* Create indices on reserves_in */
+ SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_index"
+ " ON reserves_in (reserve_pub);");
+ SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_details_index"
+ " ON reserves_in (reserve_pub,details);");
+ SQLEXEC_INDEX ("CREATE INDEX execution_index"
+ " ON reserves_in (execution_date);");
+ /* Table with the withdraw operations that have been performed on a reserve.
+ The 'h_blind_ev' is the hash of the blinded coin. It serves as a primary
+ key, as (broken) clients that use a non-random coin and blinding factor
+ should fail to even withdraw, as otherwise the coins will fail to deposit
+ (as they really must be unique). */
+ SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out"
+ "(h_blind_ev BYTEA PRIMARY KEY"
+ ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
+ ",denom_sig BYTEA NOT NULL"
+ ",reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32) REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
+ ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)"
+ ",execution_date INT8 NOT NULL"
+ ",amount_with_fee_val INT8 NOT NULL"
+ ",amount_with_fee_frac INT4 NOT NULL"
+ ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",withdraw_fee_val INT8 NOT NULL"
+ ",withdraw_fee_frac INT4 NOT NULL"
+ ",withdraw_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ");");
+ /* Index blindcoins(reserve_pub) for get_reserves_out statement */
+ SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON"
+ " reserves_out (reserve_pub)");
+ SQLEXEC_INDEX ("CREATE INDEX reserves_out_h_blind_ev_index ON "
+ "reserves_out (h_blind_ev)");
+ /* Table with coins that have been (partially) spent, used to track
+ coin information only once. */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins "
+ "(coin_pub BYTEA NOT NULL PRIMARY KEY"
+ ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
+ ",denom_sig BYTEA NOT NULL"
+ ")");
+ /**
+ * The DB will show negative values for some values of the following fields as
+ * we use them as 16 bit unsigned integers
+ * @a num_oldcoins
+ * @a num_newcoins
+ * Do not do arithmetic in SQL on these fields.
+ * NOTE: maybe we should instead forbid values >= 2^15 categorically?
+ */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions "
+ "(session_hash BYTEA PRIMARY KEY CHECK (LENGTH(session_hash)=64)"
+ ",num_oldcoins INT2 NOT NULL"
+ ",num_newcoins INT2 NOT NULL"
+ ",noreveal_index INT2 NOT NULL"
+ ")");
+ /* Table with coins that have been melted. Gives the coin's public
+ key (coin_pub), the melting session, the index of this coin in that
+ session, the signature affirming the melting and the amount that
+ this coin contributed to the melting session.
+ */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melts "
+ "(coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)"
+ ",session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)"
+ ",oldcoin_index INT2 NOT NULL"
+ ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)"
+ ",amount_with_fee_val INT8 NOT NULL"
+ ",amount_with_fee_frac INT4 NOT NULL"
+ ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",melt_fee_val INT8 NOT NULL"
+ ",melt_fee_frac INT4 NOT NULL"
+ ",melt_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",PRIMARY KEY (session_hash, oldcoin_index)" /* a coin can be used only
+ once in a refresh session */
+ ") ");
+ /* Table with information about the desired denominations to be created
+ during a refresh operation; contains the denomination key for each
+ of the coins (for a given refresh session) */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order "
+ "(session_hash BYTEA NOT NULL CHECK (LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash)"
+ ",newcoin_index INT2 NOT NULL "
+ ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
+ ",PRIMARY KEY (session_hash, newcoin_index)"
+ ")");
+
+ /* Table with the commitments for a refresh operation; includes
+ the session_hash for which this is the link information, the
+ oldcoin index and the cut-and-choose index (from 0 to #TALER_CNC_KAPPA-1),
+ as well as the actual link data (the transfer public key and the encrypted
+ link secret).
+ NOTE: We might want to simplify this and not have the oldcoin_index
+ and instead store all link secrets, one after the other, in one big BYTEA.
+ (#3814) */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link "
+ "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)"
+ ",transfer_pub BYTEA NOT NULL CHECK(LENGTH(transfer_pub)=32)"
+ ",link_secret_enc BYTEA NOT NULL"
+ ",oldcoin_index INT2 NOT NULL"
+ ",cnc_index INT2 NOT NULL"
+ ")");
+ /* Table with the commitments for the new coins that are to be created
+ during a melting session. Includes the session, the cut-and-choose
+ index and the index of the new coin, and the envelope of the new
+ coin to be signed, as well as the encrypted information about the
+ private key and the blinding factor for the coin (for verification
+ in case this cnc_index is chosen to be revealed)
+
+ NOTE: We might want to simplify this and not have the
+ newcoin_index and instead store all coin_evs and
+ link_vector_encs, one after the other, in two big BYTEAs.
+ (#3815) */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin "
+ "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) "
+ ",cnc_index INT2 NOT NULL"
+ ",newcoin_index INT2 NOT NULL"
+ ",link_vector_enc BYTEA NOT NULL"
+ ",coin_ev BYTEA NOT NULL"
+ ")");
+ /* Table with the signatures over coins generated during a refresh
+ operation. Needed to answer /refresh/link queries later. Stores
+ the coin signatures under the respective session hash and index. */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_out "
+ "(session_hash BYTEA NOT NULL CHECK(LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash) "
+ ",newcoin_index INT2 NOT NULL"
+ ",ev_sig BYTEA NOT NULL"
+ ")");
+ /* This table contains the wire transfers the exchange is supposed to
+ execute to transmit funds to the merchants (and manage refunds). */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS deposits "
+ "(serial_id BIGSERIAL PRIMARY KEY"
+ ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
+ ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
+ ",denom_sig BYTEA NOT NULL"
+ ",transaction_id INT8 NOT NULL"
+ ",amount_with_fee_val INT8 NOT NULL"
+ ",amount_with_fee_frac INT4 NOT NULL"
+ ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",deposit_fee_val INT8 NOT NULL"
+ ",deposit_fee_frac INT4 NOT NULL"
+ ",deposit_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",timestamp INT8 NOT NULL"
+ ",refund_deadline INT8 NOT NULL"
+ ",wire_deadline INT8 NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
+ ",h_contract BYTEA NOT NULL CHECK (LENGTH(h_contract)=64)"
+ ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)"
+ ",coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)"
+ ",wire TEXT NOT NULL"
+ ",tiny BOOLEAN NOT NULL DEFAULT false"
+ ",done BOOLEAN NOT NULL DEFAULT false"
+ ")");
+ /* Index for get_deposit statement on coin_pub, transaction_id and merchant_pub */
+ SQLEXEC_INDEX("CREATE INDEX deposits_coin_pub_index "
+ "ON deposits(coin_pub, transaction_id, merchant_pub)");
+ /* Table for the tracking API, mapping from wire transfer identifiers
+ to transactions and back */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking "
+ "(h_contract BYTEA CHECK (LENGTH(h_contract)=64)"
+ ",h_wire BYTEA CHECK (LENGTH(h_wire)=64)"
+ ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
+ ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
+ ",transaction_id INT8 NOT NULL"
+ ",wtid_raw BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=" TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR ")"
+ ",execution_time INT8 NOT NULL"
+ ",coin_amount_val INT8 NOT NULL"
+ ",coin_amount_frac INT4 NOT NULL"
+ ",coin_amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",coin_fee_val INT8 NOT NULL"
+ ",coin_fee_frac INT4 NOT NULL"
+ ",coin_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ")");
+ /* Index for lookup_transactions statement on wtid */
+ SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
+ "ON aggregation_tracking(wtid_raw)");
+ /* Index for lookup_deposit_wtid statement */
+ SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_deposit_index "
+ "ON aggregation_tracking(coin_pub,h_contract,h_wire,transaction_id,merchant_pub)");
+
+ /* This table contains the pre-commit data for
+ wire transfers the exchange is about to execute. */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS prewire "
+ "(serial_id BIGSERIAL PRIMARY KEY"
+ ",type TEXT NOT NULL"
+ ",finished BOOLEAN NOT NULL DEFAULT false"
+ ",buf BYTEA NOT NULL"
+ ")");
+ /* Index for prepare_data_iterate statement */
+ SQLEXEC_INDEX("CREATE INDEX prepare_iteration_index "
+ "ON prewire(type,finished)");
+
+
+#undef SQLEXEC
+#undef SQLEXEC_INDEX
+
+ PQfinish (conn);
+ return GNUNET_OK;
+
+ SQLEXEC_fail:
+ PQfinish (conn);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Setup prepared statements.
+ *
+ * @param db_conn connection handle to initialize
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ */
+static int
+postgres_prepare (PGconn *db_conn)
+{
+ PGresult *result;
+
+#define PREPARE(name, sql, ...) \
+ do { \
+ result = PQprepare (db_conn, name, sql, __VA_ARGS__); \
+ if (PGRES_COMMAND_OK != PQresultStatus (result)) \
+ { \
+ BREAK_DB_ERR (result); \
+ PQclear (result); result = NULL; \
+ return GNUNET_SYSERR; \
+ } \
+ PQclear (result); result = NULL; \
+ } while (0);
+
+ /* Used in #postgres_insert_denomination_info() */
+ PREPARE ("denomination_insert",
+ "INSERT INTO denominations "
+ "(pub"
+ ",master_pub"
+ ",master_sig"
+ ",valid_from"
+ ",expire_withdraw"
+ ",expire_spend"
+ ",expire_legal"
+ ",coin_val" /* value of this denom */
+ ",coin_frac" /* fractional value of this denom */
+ ",coin_curr" /* assuming same currency for fees */
+ ",fee_withdraw_val"
+ ",fee_withdraw_frac"
+ ",fee_withdraw_curr" /* must match coin_curr */
+ ",fee_deposit_val"
+ ",fee_deposit_frac"
+ ",fee_deposit_curr" /* must match coin_curr */
+ ",fee_refresh_val"
+ ",fee_refresh_frac"
+ ",fee_refresh_curr" /* must match coin_curr */
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
+ " $11, $12, $13, $14, $15, $16, $17, $18, $19);",
+ 19, NULL);
+
+ /* Used in #postgres_get_denomination_info() */
+ PREPARE ("denomination_get",
+ "SELECT"
+ " master_pub"
+ ",master_sig"
+ ",valid_from"
+ ",expire_withdraw"
+ ",expire_spend"
+ ",expire_legal"
+ ",coin_val" /* value of this denom */
+ ",coin_frac" /* fractional value of this denom */
+ ",coin_curr" /* assuming same currency for fees */
+ ",fee_withdraw_val"
+ ",fee_withdraw_frac"
+ ",fee_withdraw_curr" /* must match coin_curr */
+ ",fee_deposit_val"
+ ",fee_deposit_frac"
+ ",fee_deposit_curr" /* must match coin_curr */
+ ",fee_refresh_val"
+ ",fee_refresh_frac"
+ ",fee_refresh_curr" /* must match coin_curr */
+ " FROM denominations"
+ " WHERE pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_reserve_get() */
+ PREPARE ("reserve_get",
+ "SELECT"
+ " current_balance_val"
+ ",current_balance_frac"
+ ",current_balance_curr"
+ ",expiration_date"
+ " FROM reserves"
+ " WHERE reserve_pub=$1"
+ " LIMIT 1;",
+ 1, NULL);
+
+ /* Used in #postgres_reserves_in_insert() when the reserve is new */
+ PREPARE ("reserve_create",
+ "INSERT INTO reserves "
+ "(reserve_pub"
+ ",current_balance_val"
+ ",current_balance_frac"
+ ",current_balance_curr"
+ ",expiration_date"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);",
+ 5, NULL);
+
+ /* Used in #postgres_reserves_update() when the reserve is updated */
+ PREPARE ("reserve_update",
+ "UPDATE reserves"
+ " SET"
+ " expiration_date=$1 "
+ ",current_balance_val=$2 "
+ ",current_balance_frac=$3 "
+ "WHERE current_balance_curr=$4 AND reserve_pub=$5",
+ 5, NULL);
+
+ /* Used in #postgres_reserves_in_insert() to store transaction details */
+ PREPARE ("reserves_in_add_transaction",
+ "INSERT INTO reserves_in "
+ "(reserve_pub"
+ ",balance_val"
+ ",balance_frac"
+ ",balance_curr"
+ ",details"
+ ",execution_date"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6);",
+ 6, NULL);
+
+ /* Used in #postgres_get_reserve_history() to obtain inbound transactions
+ for a reserve */
+ PREPARE ("reserves_in_get_transactions",
+ "SELECT"
+ " balance_val"
+ ",balance_frac"
+ ",balance_curr"
+ ",execution_date"
+ ",details"
+ " FROM reserves_in"
+ " WHERE reserve_pub=$1",
+ 1, NULL);
+
+ /* Used in #postgres_insert_withdraw_info() to store
+ the signature of a blinded coin with the blinded coin's
+ details before returning it during /reserve/withdraw. We store
+ the coin's denomination information (public key, signature)
+ and the blinded message as well as the reserve that the coin
+ is being withdrawn from and the signature of the message
+ authorizing the withdrawal. */
+ PREPARE ("insert_withdraw_info",
+ "INSERT INTO reserves_out "
+ "(h_blind_ev"
+ ",denom_pub"
+ ",denom_sig"
+ ",reserve_pub"
+ ",reserve_sig"
+ ",execution_date"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",withdraw_fee_val"
+ ",withdraw_fee_frac"
+ ",withdraw_fee_curr"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);",
+ 12, NULL);
+
+ /* Used in #postgres_get_withdraw_info() to
+ locate the response for a /reserve/withdraw request
+ using the hash of the blinded message. Used to
+ make sure /reserve/withdraw requests are idempotent. */
+ PREPARE ("get_withdraw_info",
+ "SELECT"
+ " denom_pub"
+ ",denom_sig"
+ ",reserve_sig"
+ ",reserve_pub"
+ ",execution_date"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",withdraw_fee_val"
+ ",withdraw_fee_frac"
+ ",withdraw_fee_curr"
+ " FROM reserves_out"
+ " WHERE h_blind_ev=$1",
+ 1, NULL);
+
+ /* Used during #postgres_get_reserve_history() to
+ obtain all of the /reserve/withdraw operations that
+ have been performed on a given reserve. (i.e. to
+ demonstrate double-spending) */
+ PREPARE ("get_reserves_out",
+ "SELECT"
+ " h_blind_ev"
+ ",denom_pub"
+ ",denom_sig"
+ ",reserve_sig"
+ ",execution_date"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",withdraw_fee_val"
+ ",withdraw_fee_frac"
+ ",withdraw_fee_curr"
+ " FROM reserves_out"
+ " WHERE reserve_pub=$1;",
+ 1, NULL);
+
+ /* Used in #postgres_get_refresh_session() to fetch
+ high-level information about a refresh session */
+ PREPARE ("get_refresh_session",
+ "SELECT"
+ " num_oldcoins"
+ ",num_newcoins"
+ ",noreveal_index"
+ " FROM refresh_sessions "
+ " WHERE session_hash=$1 ",
+ 1, NULL);
+
+ /* Used in #postgres_create_refresh_session() to store
+ high-level information about a refresh session */
+ PREPARE ("insert_refresh_session",
+ "INSERT INTO refresh_sessions "
+ "(session_hash "
+ ",num_oldcoins "
+ ",num_newcoins "
+ ",noreveal_index "
+ ") VALUES "
+ "($1, $2, $3, $4);",
+ 4, NULL);
+
+ /* Used in #postgres_get_known_coin() to fetch
+ the denomination public key and signature for
+ a coin known to the exchange. */
+ PREPARE ("get_known_coin",
+ "SELECT"
+ " denom_pub"
+ ",denom_sig"
+ " FROM known_coins"
+ " WHERE coin_pub=$1",
+ 1, NULL);
+
+ /* Used in #postgres_insert_known_coin() to store
+ the denomination public key and signature for
+ a coin known to the exchange. */
+ PREPARE ("insert_known_coin",
+ "INSERT INTO known_coins "
+ "(coin_pub"
+ ",denom_pub"
+ ",denom_sig"
+ ") VALUES "
+ "($1,$2,$3);",
+ 3, NULL);
+
+ /* Store information about the desired denominations for a
+ refresh operation, used in #postgres_insert_refresh_order() */
+ PREPARE ("insert_refresh_order",
+ "INSERT INTO refresh_order "
+ "(newcoin_index "
+ ",session_hash "
+ ",denom_pub "
+ ") VALUES "
+ "($1, $2, $3);",
+ 3, NULL);
+
+ /* Obtain information about the desired denominations for a
+ refresh operation, used in #postgres_get_refresh_order() */
+ PREPARE ("get_refresh_order",
+ "SELECT denom_pub"
+ " FROM refresh_order"
+ " WHERE session_hash=$1 AND newcoin_index=$2",
+ 2, NULL);
+
+ /* Used in #postgres_insert_refresh_melt to store information
+ about melted coins */
+ PREPARE ("insert_refresh_melt",
+ "INSERT INTO refresh_melts "
+ "(coin_pub "
+ ",session_hash"
+ ",oldcoin_index "
+ ",coin_sig "
+ ",amount_with_fee_val "
+ ",amount_with_fee_frac "
+ ",amount_with_fee_curr "
+ ",melt_fee_val "
+ ",melt_fee_frac "
+ ",melt_fee_curr "
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);",
+ 10, NULL);
+
+ /* Used in #postgres_get_refresh_melt to obtain information
+ about melted coins */
+ PREPARE ("get_refresh_melt",
+ "SELECT"
+ " coin_pub"
+ ",coin_sig"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",melt_fee_val "
+ ",melt_fee_frac "
+ ",melt_fee_curr "
+ " FROM refresh_melts"
+ " WHERE session_hash=$1 AND oldcoin_index=$2",
+ 2, NULL);
+
+ /* Query the 'refresh_melts' by coin public key */
+ PREPARE ("get_refresh_melt_by_coin",
+ "SELECT"
+ " session_hash"
+ /* ",oldcoin_index" // not needed */
+ ",coin_sig"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",melt_fee_val "
+ ",melt_fee_frac "
+ ",melt_fee_curr "
+ " FROM refresh_melts"
+ " WHERE coin_pub=$1",
+ 1, NULL);
+
+ /* Used in #postgres_insert_refresh_commit_links() to
+ store commitments */
+ PREPARE ("insert_refresh_commit_link",
+ "INSERT INTO refresh_commit_link "
+ "(session_hash"
+ ",transfer_pub"
+ ",cnc_index"
+ ",oldcoin_index"
+ ",link_secret_enc"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);",
+ 5, NULL);
+
+ /* Used in #postgres_get_refresh_commit_links() to
+ retrieve original commitments during /refresh/reveal */
+ PREPARE ("get_refresh_commit_link",
+ "SELECT"
+ " transfer_pub"
+ ",link_secret_enc"
+ " FROM refresh_commit_link"
+ " WHERE session_hash=$1 AND cnc_index=$2 AND oldcoin_index=$3",
+ 3, NULL);
+
+ /* Used in #postgres_insert_refresh_commit_coins() to
+ store coin commitments. */
+ PREPARE ("insert_refresh_commit_coin",
+ "INSERT INTO refresh_commit_coin "
+ "(session_hash"
+ ",cnc_index"
+ ",newcoin_index"
+ ",link_vector_enc"
+ ",coin_ev"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);",
+ 5, NULL);
+
+ /* Used in #postgres_get_refresh_commit_coins() to
+ retrieve the original coin envelopes, to either be
+ verified or signed. */
+ PREPARE ("get_refresh_commit_coin",
+ "SELECT"
+ " link_vector_enc"
+ ",coin_ev"
+ " FROM refresh_commit_coin"
+ " WHERE session_hash=$1 AND cnc_index=$2 AND newcoin_index=$3",
+ 3, NULL);
+
+ /* Store information about a /deposit the exchange is to execute.
+ Used in #postgres_insert_deposit(). */
+ PREPARE ("insert_deposit",
+ "INSERT INTO deposits "
+ "(coin_pub"
+ ",denom_pub"
+ ",denom_sig"
+ ",transaction_id"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",deposit_fee_curr"
+ ",timestamp"
+ ",refund_deadline"
+ ",wire_deadline"
+ ",merchant_pub"
+ ",h_contract"
+ ",h_wire"
+ ",coin_sig"
+ ",wire"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
+ " $11, $12, $13, $14, $15, $16, $17, $18);",
+ 18, NULL);
+
+ /* Fetch an existing deposit request, used to ensure idempotency
+ during /deposit processing. Used in #postgres_have_deposit(). */
+ PREPARE ("get_deposit",
+ "SELECT"
+ " amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",timestamp"
+ ",refund_deadline"
+ ",wire_deadline"
+ ",h_contract"
+ ",h_wire"
+ " FROM deposits"
+ " WHERE ("
+ " (coin_pub=$1) AND"
+ " (transaction_id=$2) AND"
+ " (merchant_pub=$3)"
+ " )",
+ 3, NULL);
+
+ /* Fetch an existing deposit request.
+ Used in #postgres_wire_lookup_deposit_wtid(). */
+ PREPARE ("get_deposit_for_wtid",
+ "SELECT"
+ " amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",deposit_fee_curr"
+ ",wire_deadline"
+ " FROM deposits"
+ " WHERE ("
+ " (coin_pub=$1) AND"
+ " (transaction_id=$2) AND"
+ " (merchant_pub=$3) AND"
+ " (h_contract=$4) AND"
+ " (h_wire=$5)"
+ " )",
+ 5, NULL);
+
+ /* Used in #postgres_get_ready_deposit() */
+ PREPARE ("deposits_get_ready",
+ "SELECT"
+ " serial_id"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",deposit_fee_curr"
+ ",wire_deadline"
+ ",transaction_id"
+ ",h_contract"
+ ",wire"
+ ",merchant_pub"
+ ",coin_pub"
+ " FROM deposits"
+ " WHERE"
+ " tiny=false AND"
+ " done=false"
+ " ORDER BY wire_deadline ASC"
+ " LIMIT 1;",
+ 0, NULL);
+
+ /* Used in #postgres_iterate_matching_deposits() */
+ PREPARE ("deposits_iterate_matching",
+ "SELECT"
+ " serial_id"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",deposit_fee_curr"
+ ",wire_deadline"
+ ",transaction_id"
+ ",h_contract"
+ ",coin_pub"
+ " FROM deposits"
+ " WHERE"
+ " merchant_pub=$1 AND"
+ " h_wire=$2 AND"
+ " done=false"
+ " ORDER BY wire_deadline ASC"
+ " LIMIT $3",
+ 3, NULL);
+
+ /* Used in #postgres_mark_deposit_tiny() */
+ PREPARE ("mark_deposit_tiny",
+ "UPDATE deposits"
+ " SET tiny=true"
+ " WHERE serial_id=$1",
+ 1, NULL);
+
+ /* Used in #postgres_mark_deposit_done() */
+ PREPARE ("mark_deposit_done",
+ "UPDATE deposits"
+ " SET done=true"
+ " WHERE serial_id=$1",
+ 1, NULL);
+
+ /* Used in #postgres_get_coin_transactions() to obtain information
+ about how a coin has been spend with /deposit requests. */
+ PREPARE ("get_deposit_with_coin_pub",
+ "SELECT"
+ " denom_pub"
+ ",denom_sig"
+ ",transaction_id"
+ ",amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",deposit_fee_curr"
+ ",timestamp"
+ ",refund_deadline"
+ ",merchant_pub"
+ ",h_contract"
+ ",h_wire"
+ ",wire"
+ ",coin_sig"
+ " FROM deposits"
+ " WHERE coin_pub=$1",
+ 1, NULL);
+
+ /* Used in #postgres_insert_refresh_out() to store the
+ generated signature(s) for future requests, i.e. /refresh/link */
+ PREPARE ("insert_refresh_out",
+ "INSERT INTO refresh_out "
+ "(session_hash"
+ ",newcoin_index"
+ ",ev_sig"
+ ") VALUES "
+ "($1, $2, $3)",
+ 3, NULL);
+
+ /* Used in #postgres_get_link_data_list(). We use the session_hash
+ to obtain the "noreveal_index" for that session, and then select
+ the encrypted link vectors (link_vector_enc) and the
+ corresponding signatures (ev_sig) and the denomination keys from
+ the respective tables (namely refresh_melts and refresh_order)
+ using the session_hash as the primary filter (on join) and the
+ 'noreveal_index' to constrain the selection on the commitment.
+ We also want to get the triplet for each of the newcoins, so we
+ have another constraint to ensure we get each triplet with
+ matching "newcoin_index" values. NOTE: This may return many
+ results, both for different sessions and for the different coins
+ being exchangeed in the refresh ops. NOTE: There may be more
+ efficient ways to express the same query. */
+ PREPARE ("get_link",
+ "SELECT link_vector_enc,ev_sig,ro.denom_pub"
+ " FROM refresh_melts rm "
+ " JOIN refresh_order ro USING (session_hash)"
+ " JOIN refresh_commit_coin rcc USING (session_hash)"
+ " JOIN refresh_sessions rs USING (session_hash)"
+ " JOIN refresh_out rc USING (session_hash)"
+ " WHERE ro.session_hash=$1"
+ " AND ro.newcoin_index=rcc.newcoin_index"
+ " AND ro.newcoin_index=rc.newcoin_index"
+ " AND rcc.cnc_index=rs.noreveal_index",
+ 1, NULL);
+
+ /* Used in #postgres_get_transfer(). Given the public key of a
+ melted coin, we obtain the corresponding encrypted link secret
+ and the transfer public key. This is done by first finding
+ the session_hash(es) of all sessions the coin was melted into,
+ and then constraining the result to the selected "noreveal_index"
+ and the transfer public key to the corresponding index of the
+ old coin.
+ NOTE: This may (in theory) return multiple results, one per session
+ that the old coin was melted into. */
+ PREPARE ("get_transfer",
+ "SELECT transfer_pub,link_secret_enc,session_hash"
+ " FROM refresh_melts rm"
+ " JOIN refresh_commit_link rcl USING (session_hash)"
+ " JOIN refresh_sessions rs USING (session_hash)"
+ " WHERE rm.coin_pub=$1"
+ " AND rm.oldcoin_index = rcl.oldcoin_index"
+ " AND rcl.cnc_index=rs.noreveal_index",
+ 1, NULL);
+
+ /* Used in #postgres_lookup_wire_transfer */
+ PREPARE ("lookup_transactions",
+ "SELECT"
+ " h_contract"
+ ",h_wire"
+ ",coin_pub"
+ ",merchant_pub"
+ ",transaction_id"
+ ",execution_time"
+ ",coin_amount_val"
+ ",coin_amount_frac"
+ ",coin_amount_curr"
+ ",coin_fee_val"
+ ",coin_fee_frac"
+ ",coin_fee_curr"
+ " FROM aggregation_tracking"
+ " WHERE wtid_raw=$1",
+ 1, NULL);
+
+ /* Used in #postgres_wire_lookup_deposit_wtid */
+ PREPARE ("lookup_deposit_wtid",
+ "SELECT"
+ " wtid_raw"
+ ",execution_time"
+ ",coin_amount_val"
+ ",coin_amount_frac"
+ ",coin_amount_curr"
+ ",coin_fee_val"
+ ",coin_fee_frac"
+ ",coin_fee_curr"
+ " FROM aggregation_tracking"
+ " WHERE"
+ " coin_pub=$1 AND"
+ " h_contract=$2 AND"
+ " h_wire=$3 AND"
+ " transaction_id=$4 AND"
+ " merchant_pub=$5",
+ 5, NULL);
+
+ /* Used in #postgres_insert_aggregation_tracking */
+ PREPARE ("insert_aggregation_tracking",
+ "INSERT INTO aggregation_tracking "
+ "(h_contract"
+ ",h_wire"
+ ",coin_pub"
+ ",merchant_pub"
+ ",transaction_id"
+ ",wtid_raw"
+ ",execution_time"
+ ",coin_amount_val"
+ ",coin_amount_frac"
+ ",coin_amount_curr"
+ ",coin_fee_val"
+ ",coin_fee_frac"
+ ",coin_fee_curr"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
+ 13, NULL);
+
+
+ /* Used in #postgres_wire_prepare_data_insert() to store
+ wire transfer information before actually committing it with the bank */
+ PREPARE ("wire_prepare_data_insert",
+ "INSERT INTO prewire "
+ "(type"
+ ",buf"
+ ") VALUES "
+ "($1, $2)",
+ 2, NULL);
+
+ /* Used in #postgres_wire_prepare_data_mark_finished() */
+ PREPARE ("wire_prepare_data_mark_done",
+ "UPDATE prewire"
+ " SET finished=true"
+ " WHERE serial_id=$1",
+ 1, NULL);
+
+ /* Used in #postgres_wire_prepare_data_get() */
+ PREPARE ("wire_prepare_data_get",
+ "SELECT"
+ " serial_id"
+ ",buf"
+ " FROM prewire"
+ " WHERE"
+ " type=$1 AND"
+ " finished=false"
+ " ORDER BY serial_id ASC"
+ " LIMIT 1",
+ 1, NULL);
+
+ return GNUNET_OK;
+#undef PREPARE
+}
+
+
+/**
+ * Close thread-local database connection when a thread is destroyed.
+ *
+ * @param cls closure we get from pthreads (the db handle)
+ */
+static void
+db_conn_destroy (void *cls)
+{
+ struct TALER_EXCHANGEDB_Session *session = cls;
+ PGconn *db_conn = session->conn;
+
+ if (NULL != db_conn)
+ PQfinish (db_conn);
+ GNUNET_free (session);
+}
+
+
+/**
+ * Get the thread-local database-handle.
+ * Connect to the db if the connection does not exist yet.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
+ * database default one
+ * @return the database connection, or NULL on error
+ */
+static struct TALER_EXCHANGEDB_Session *
+postgres_get_session (void *cls,
+ int temporary)
+{
+ struct PostgresClosure *pc = cls;
+ PGconn *db_conn;
+ struct TALER_EXCHANGEDB_Session *session;
+
+ if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal)))
+ return session;
+ db_conn = PQconnectdb (pc->connection_cfg_str);
+ if (CONNECTION_OK !=
+ PQstatus (db_conn))
+ {
+ TALER_LOG_ERROR ("Database connection failed: %s\n",
+ PQerrorMessage (db_conn));
+ GNUNET_break (0);
+ return NULL;
+ }
+ PQsetNoticeReceiver (db_conn,
+ &pq_notice_receiver_cb,
+ NULL);
+ PQsetNoticeProcessor (db_conn,
+ &pq_notice_processor_cb,
+ NULL);
+ if ( (GNUNET_YES == temporary) &&
+ (GNUNET_SYSERR == set_temporary_schema(db_conn)) )
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ postgres_prepare (db_conn))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ session = GNUNET_new (struct TALER_EXCHANGEDB_Session);
+ session->conn = db_conn;
+ if (0 != pthread_setspecific (pc->db_conn_threadlocal,
+ session))
+ {
+ GNUNET_break (0);
+ PQfinish (db_conn);
+ GNUNET_free (session);
+ return NULL;
+ }
+ return session;
+}
+
+
+/**
+ * Start a transaction.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
+ * @return #GNUNET_OK on success
+ */
+static int
+postgres_start (void *cls,
+ struct TALER_EXCHANGEDB_Session *session)
+{
+ PGresult *result;
+
+ result = PQexec (session->conn,
+ "BEGIN");
+ if (PGRES_COMMAND_OK !=
+ PQresultStatus (result))
+ {
+ TALER_LOG_ERROR ("Failed to start transaction: %s\n",
+ PQresultErrorMessage (result));
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Roll back the current transaction of a database connection.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
+ * @return #GNUNET_OK on success
+ */
+static void
+postgres_rollback (void *cls,
+ struct TALER_EXCHANGEDB_Session *session)
+{
+ PGresult *result;
+
+ result = PQexec (session->conn,
+ "ROLLBACK");
+ GNUNET_break (PGRES_COMMAND_OK ==
+ PQresultStatus (result));
+ PQclear (result);
+}
+
+
+/**
+ * Commit the current transaction of a database connection.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
+ * @return #GNUNET_OK on success
+ */
+static int
+postgres_commit (void *cls,
+ struct TALER_EXCHANGEDB_Session *session)
+{
+ PGresult *result;
+
+ result = PQexec (session->conn,
+ "COMMIT");
+ if (PGRES_COMMAND_OK !=
+ PQresultStatus (result))
+ {
+ const char *sqlstate;
+
+ sqlstate = PQresultErrorField (result,
+ PG_DIAG_SQLSTATE);
+ if (NULL == sqlstate)
+ {
+ /* very unexpected... */
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ /* 40P01: deadlock, 40001: serialization failure */
+ if ( (0 == strcmp (sqlstate,
+ "40P01")) ||
+ (0 == strcmp (sqlstate,
+ "40001")) )
+ {
+ /* These two can be retried and have a fair chance of working
+ the next time */
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Database commit failure: %s\n",
+ sqlstate);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Insert a denomination key's public information into the database for
+ * reference by auditors and other consistency checks.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param denom_pub the public key used for signing coins of this denomination
+ * @param issue issuing information with value, fees and other info about the coin
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ */
+static int
+postgres_insert_denomination_info (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ const struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
+{
+ PGresult *result;
+ int ret;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key),
+ GNUNET_PQ_query_param_auto_from_type (&issue->properties.master),
+ GNUNET_PQ_query_param_auto_from_type (&issue->signature),
+ GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.start),
+ GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_withdraw),
+ GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_spend),
+ GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_legal),
+ TALER_PQ_query_param_amount_nbo (&issue->properties.value),
+ TALER_PQ_query_param_amount_nbo (&issue->properties.fee_withdraw),
+ TALER_PQ_query_param_amount_nbo (&issue->properties.fee_deposit),
+ TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refresh),
+ GNUNET_PQ_query_param_end
+ };
+ /* check fees match coin currency */
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->properties.value,
+ &issue->properties.fee_withdraw));
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->properties.value,
+ &issue->properties.fee_deposit));
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency_nbo (&issue->properties.value,
+ &issue->properties.fee_refresh));
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "denomination_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ ret = GNUNET_SYSERR;
+ BREAK_DB_ERR (result);
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Fetch information about a denomination key.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param denom_pub the public key used for signing coins of this denomination
+ * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL
+ * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure
+ */
+static int
+postgres_get_denomination_info (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "denomination_get",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ if (1 != PQntuples (result))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (NULL == issue)
+ {
+ PQclear (result);
+ return GNUNET_OK;
+ }
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("master_pub",
+ &issue->properties.master),
+ GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+ &issue->signature),
+ GNUNET_PQ_result_spec_absolute_time_nbo ("valid_from",
+ &issue->properties.start),
+ GNUNET_PQ_result_spec_absolute_time_nbo ("expire_withdraw",
+ &issue->properties.expire_withdraw),
+ GNUNET_PQ_result_spec_absolute_time_nbo ("expire_spend",
+ &issue->properties.expire_spend),
+ GNUNET_PQ_result_spec_absolute_time_nbo ("expire_legal",
+ &issue->properties.expire_legal),
+ TALER_PQ_result_spec_amount_nbo ("coin",
+ &issue->properties.value),
+ TALER_PQ_result_spec_amount_nbo ("fee_withdraw",
+ &issue->properties.fee_withdraw),
+ TALER_PQ_result_spec_amount_nbo ("fee_deposit",
+ &issue->properties.fee_deposit),
+ TALER_PQ_result_spec_amount_nbo ("fee_refresh",
+ &issue->properties.fee_refresh),
+ GNUNET_PQ_result_spec_end
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ 0));
+ }
+ PQclear (result);
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ PQclear (result);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Get the summary of a reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection handle
+ * @param[in,out] reserve the reserve data. The public key of the reserve should be
+ * set in this structure; it is used to query the database. The balance
+ * and expiration are then filled accordingly.
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+static int
+postgres_reserve_get (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ struct TALER_EXCHANGEDB_Reserve *reserve)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type(&reserve->pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "reserve_get",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount("current_balance", &reserve->balance),
+ GNUNET_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry),
+ GNUNET_PQ_result_spec_end
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ 0));
+ }
+ PQclear (result);
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ PQclear (result);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Updates a reserve with the data from the given reserve structure.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
+ * @param reserve the reserve structure whose data will be used to update the
+ * corresponding record in the database.
+ * @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error
+ */
+static int
+reserves_update (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_Reserve *reserve)
+{
+ PGresult *result;
+ int ret;
+
+ if (NULL == reserve)
+ return GNUNET_SYSERR;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_absolute_time (&reserve->expiry),
+ TALER_PQ_query_param_amount (&reserve->balance),
+ GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
+ GNUNET_PQ_query_param_end
+ };
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "reserve_update",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus(result))
+ {
+ QUERY_ERR (result);
+ ret = GNUNET_SYSERR;
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Insert an incoming transaction into reserves. New reserves are also created
+ * through this function. Note that this API call starts (and stops) its
+ * own transaction scope (so the application must not do so).
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection handle
+ * @param reserve_pub public key of the reserve
+ * @param balance the amount that has to be added to the reserve
+ * @param execution_time when was the amount added
+ * @param details bank transaction details justifying the increment,
+ * must be unique for each incoming transaction
+ * @return #GNUNET_OK upon success; #GNUNET_NO if the given
+ * @a details are already known for this @a reserve_pub,
+ * #GNUNET_SYSERR upon failures (DB error, incompatible currency)
+ */
+static int
+postgres_reserves_in_insert (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *balance,
+ struct GNUNET_TIME_Absolute execution_time,
+ const json_t *details)
+{
+ PGresult *result;
+ int reserve_exists;
+ struct TALER_EXCHANGEDB_Reserve reserve;
+ struct GNUNET_TIME_Absolute expiry;
+
+ if (GNUNET_OK != postgres_start (cls,
+ session))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ reserve.pub = *reserve_pub;
+ reserve_exists = postgres_reserve_get (cls,
+ session,
+ &reserve);
+ if (GNUNET_SYSERR == reserve_exists)
+ {
+ GNUNET_break (0);
+ goto rollback;
+ }
+ expiry = GNUNET_TIME_absolute_add (execution_time,
+ TALER_IDLE_RESERVE_EXPIRATION_TIME);
+ if (GNUNET_NO == reserve_exists)
+ {
+ /* New reserve, create balance for the first time; we do this
+ before adding the actual transaction to "reserves_in", as
+ for a new reserve it can't be a duplicate 'add' operation,
+ and as the 'add' operation may need the reserve entry
+ as a foreign key. */
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ TALER_PQ_query_param_amount (balance),
+ GNUNET_PQ_query_param_absolute_time (&expiry),
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Reserve does not exist; creating a new one\n");
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "reserve_create",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus(result))
+ {
+ QUERY_ERR (result);
+ PQclear (result);
+ goto rollback;
+ }
+ PQclear (result);
+ }
+ /* Create new incoming transaction, SQL "primary key" logic
+ is used to guard against duplicates. If a duplicate is
+ detected, we rollback (which really shouldn't undo
+ anything) and return #GNUNET_NO to indicate that this failure
+ is kind-of harmless (already executed). */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&reserve.pub),
+ TALER_PQ_query_param_amount (balance),
+ TALER_PQ_query_param_json (details),
+ GNUNET_PQ_query_param_absolute_time (&execution_time),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "reserves_in_add_transaction",
+ params);
+ }
+ if (PGRES_COMMAND_OK != PQresultStatus(result))
+ {
+ const char *efield;
+
+ efield = PQresultErrorField (result,
+ PG_DIAG_SQLSTATE);
+ if ( (PGRES_FATAL_ERROR == PQresultStatus(result)) &&
+ (NULL != strstr ("23505", /* unique violation */
+ efield)) )
+ {
+ /* This means we had the same reserve/justification/details
+ before */
+ PQclear (result);
+ postgres_rollback (cls,
+ session);
+ return GNUNET_NO;
+ }
+ QUERY_ERR (result);
+ PQclear (result);
+ goto rollback;
+ }
+ PQclear (result);
+
+ if (GNUNET_YES == reserve_exists)
+ {
+ /* If the reserve already existed, we need to still update the
+ balance; we do this after checking for duplication, as
+ otherwise we might have to actually pay the cost to roll this
+ back for duplicate transactions; like this, we should virtually
+ never actually have to rollback anything. */
+ struct TALER_EXCHANGEDB_Reserve updated_reserve;
+
+ updated_reserve.pub = reserve.pub;
+ if (GNUNET_OK !=
+ TALER_amount_add (&updated_reserve.balance,
+ &reserve.balance,
+ balance))
+ {
+ /* currency overflow or incompatible currency */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Attempt to deposit incompatible amount into reserve\n");
+ goto rollback;
+ }
+ updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry,
+ reserve.expiry);
+ if (GNUNET_OK != reserves_update (cls,
+ session,
+ &updated_reserve))
+ goto rollback;
+ }
+ if (GNUNET_OK != postgres_commit (cls,
+ session))
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+
+ rollback:
+ postgres_rollback (cls,
+ session);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Locate the response for a /reserve/withdraw request under the
+ * key of the hash of the blinded message.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param h_blind hash of the blinded coin to be signed (will match
+ * `h_coin_envelope` in the @a collectable to be returned)
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+static int
+postgres_get_withdraw_info (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *h_blind,
+ struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_blind),
+ GNUNET_PQ_query_param_end
+ };
+ int ret;
+
+ ret = GNUNET_SYSERR;
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_withdraw_info",
+ params);
+
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ goto cleanup;
+ }
+ if (0 == PQntuples (result))
+ {
+ ret = GNUNET_NO;
+ goto cleanup;
+ }
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &collectable->denom_pub.rsa_public_key),
+ GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+ &collectable->sig.rsa_signature),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
+ &collectable->reserve_sig),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ &collectable->reserve_pub),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &collectable->amount_with_fee),
+ TALER_PQ_result_spec_amount ("withdraw_fee",
+ &collectable->withdraw_fee),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ goto cleanup;
+ }
+ }
+ collectable->h_coin_envelope = *h_blind;
+ ret = GNUNET_YES;
+
+ cleanup:
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Store collectable bit coin under the corresponding
+ * hash of the blinded message.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+static int
+postgres_insert_withdraw_info (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
+{
+ PGresult *result;
+ struct TALER_EXCHANGEDB_Reserve reserve;
+ int ret = GNUNET_SYSERR;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute expiry;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
+ GNUNET_PQ_query_param_rsa_public_key (collectable->denom_pub.rsa_public_key),
+ GNUNET_PQ_query_param_rsa_signature (collectable->sig.rsa_signature),
+ GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ TALER_PQ_query_param_amount (&collectable->amount_with_fee),
+ TALER_PQ_query_param_amount (&collectable->withdraw_fee),
+ GNUNET_PQ_query_param_end
+ };
+
+ now = GNUNET_TIME_absolute_get ();
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_withdraw_info",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ goto cleanup;
+ }
+ reserve.pub = collectable->reserve_pub;
+ if (GNUNET_OK != postgres_reserve_get (cls,
+ session,
+ &reserve))
+ {
+ /* Should have been checked before we got here... */
+ GNUNET_break (0);
+ goto cleanup;
+ }
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&reserve.balance,
+ &reserve.balance,
+ &collectable->amount_with_fee))
+ {
+ /* Should have been checked before we got here... */
+ GNUNET_break (0);
+ goto cleanup;
+ }
+ expiry = GNUNET_TIME_absolute_add (now,
+ TALER_IDLE_RESERVE_EXPIRATION_TIME);
+ reserve.expiry = GNUNET_TIME_absolute_max (expiry,
+ reserve.expiry);
+ if (GNUNET_OK != reserves_update (cls,
+ session,
+ &reserve))
+ {
+ GNUNET_break (0);
+ goto cleanup;
+ }
+ ret = GNUNET_OK;
+ cleanup:
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to use
+ * @param reserve_pub public key of the reserve
+ * @return known transaction history (NULL if reserve is unknown)
+ */
+static struct TALER_EXCHANGEDB_ReserveHistory *
+postgres_get_reserve_history (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_ReservePublicKeyP *reserve_pub)
+{
+ PGresult *result;
+ struct TALER_EXCHANGEDB_ReserveHistory *rh;
+ struct TALER_EXCHANGEDB_ReserveHistory *rh_tail;
+ int rows;
+ int ret;
+
+ rh = NULL;
+ rh_tail = NULL;
+ ret = GNUNET_SYSERR;
+ {
+ struct TALER_EXCHANGEDB_BankTransfer *bt;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "reserves_in_get_transactions",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ goto cleanup;
+ }
+ if (0 == (rows = PQntuples (result)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Asked to fetch history for an unknown reserve.\n");
+ goto cleanup;
+ }
+ while (0 < rows)
+ {
+ bt = GNUNET_new (struct TALER_EXCHANGEDB_BankTransfer);
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("balance",
+ &bt->amount),
+ GNUNET_PQ_result_spec_absolute_time ("execution_date",
+ &bt->execution_date),
+ TALER_PQ_result_spec_json ("details",
+ &bt->wire),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_YES !=
+ GNUNET_PQ_extract_result (result, rs, --rows))
+ {
+ GNUNET_break (0);
+ GNUNET_free (bt);
+ PQclear (result);
+ goto cleanup;
+ }
+ }
+ bt->reserve_pub = *reserve_pub;
+ if (NULL != rh_tail)
+ {
+ rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
+ rh_tail = rh_tail->next;
+ }
+ else
+ {
+ rh_tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
+ rh = rh_tail;
+ }
+ rh_tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
+ rh_tail->details.bank = bt;
+ }
+ PQclear (result);
+ }
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_assert (NULL != rh);
+ GNUNET_assert (NULL != rh_tail);
+ GNUNET_assert (NULL == rh_tail->next);
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_reserves_out",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ PQclear (result);
+ goto cleanup;
+ }
+ rows = PQntuples (result);
+ while (0 < rows)
+ {
+ struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc;
+
+ cbc = GNUNET_new (struct TALER_EXCHANGEDB_CollectableBlindcoin);
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
+ &cbc->h_coin_envelope),
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &cbc->denom_pub.rsa_public_key),
+ GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+ &cbc->sig.rsa_signature),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
+ &cbc->reserve_sig),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &cbc->amount_with_fee),
+ TALER_PQ_result_spec_amount ("withdraw_fee",
+ &cbc->withdraw_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_YES !=
+ GNUNET_PQ_extract_result (result, rs, --rows))
+ {
+ GNUNET_break (0);
+ GNUNET_free (cbc);
+ PQclear (result);
+ goto cleanup;
+ }
+ cbc->reserve_pub = *reserve_pub;
+ }
+ rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
+ rh_tail = rh_tail->next;
+ rh_tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
+ rh_tail->details.withdraw = cbc;
+ }
+ ret = GNUNET_OK;
+ PQclear (result);
+ }
+ cleanup:
+ if (GNUNET_SYSERR == ret)
+ {
+ common_free_reserve_history (cls,
+ rh);
+ rh = NULL;
+ }
+ return rh;
+}
+
+
+/**
+ * Check if we have the specified deposit already in the database.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param deposit deposit to search for
+ * @return #GNUNET_YES if we know this operation,
+ * #GNUNET_NO if this exact deposit is unknown to us
+ * #GNUNET_SYSERR on DB error
+ */
+static int
+postgres_have_deposit (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_Deposit *deposit)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
+ GNUNET_PQ_query_param_uint64 (&deposit->transaction_id),
+ GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_deposit",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+
+ /* Now we check that the other information in @a deposit
+ also matches, and if not report inconsistencies. */
+ {
+ struct TALER_EXCHANGEDB_Deposit deposit2;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &deposit2.amount_with_fee),
+ GNUNET_PQ_result_spec_absolute_time ("timestamp",
+ &deposit2.timestamp),
+ GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
+ &deposit2.refund_deadline),
+ GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
+ &deposit2.wire_deadline),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract",
+ &deposit2.h_contract),
+ GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+ &deposit2.h_wire),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if ( (0 != TALER_amount_cmp (&deposit->amount_with_fee,
+ &deposit2.amount_with_fee)) ||
+ (deposit->timestamp.abs_value_us !=
+ deposit2.timestamp.abs_value_us) ||
+ (deposit->refund_deadline.abs_value_us !=
+ deposit2.refund_deadline.abs_value_us) ||
+ (0 != memcmp (&deposit->h_contract,
+ &deposit2.h_contract,
+ sizeof (struct GNUNET_HashCode))) ||
+ (0 != memcmp (&deposit->h_wire,
+ &deposit2.h_wire,
+ sizeof (struct GNUNET_HashCode))) )
+ {
+ /* Inconsistencies detected! Does not match! (We might want to
+ expand the API with a 'get_deposit' function to return the
+ original transaction details to be used for an error message
+ in the future!) #3838 */
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ }
+ PQclear (result);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Mark a deposit as tiny, thereby declaring that it cannot be
+ * executed by itself and should no longer be returned by
+ * @e iterate_ready_deposits()
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit_rowid identifies the deposit row to modify
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+postgres_mark_deposit_tiny (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ unsigned long long rowid)
+{
+ uint64_t serial_id = rowid;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "mark_deposit_tiny",
+ params);
+ if (PGRES_COMMAND_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Mark a deposit as done, thereby declaring that it cannot be
+ * executed at all anymore, and should no longer be returned by
+ * @e iterate_ready_deposits() or @e iterate_matching_deposits().
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit_rowid identifies the deposit row to modify
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+postgres_mark_deposit_done (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ unsigned long long rowid)
+{
+ uint64_t serial_id = rowid;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "mark_deposit_done",
+ params);
+ if (PGRES_COMMAND_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Obtain information about deposits that are ready to be executed.
+ * Such deposits must not be marked as "tiny" or "done", and the
+ * execution time must be in the past.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit_cb function to call for ONE such deposit
+ * @param deposit_cb_cls closure for @a deposit_cb
+ * @return number of rows processed, 0 if none exist,
+ * #GNUNET_SYSERR on error
+ */
+static int
+postgres_get_ready_deposit (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ TALER_EXCHANGEDB_DepositIterator deposit_cb,
+ void *deposit_cb_cls)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ unsigned int n;
+ int ret;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "deposits_get_ready",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == (n = PQntuples (result)))
+ {
+ PQclear (result);
+ return 0;
+ }
+ GNUNET_break (1 == n);
+ {
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
+ struct GNUNET_TIME_Absolute wire_deadline;
+ struct GNUNET_HashCode h_contract;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ uint64_t transaction_id;
+ uint64_t serial_id;
+ json_t *wire;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial_id",
+ &serial_id),
+ GNUNET_PQ_result_spec_uint64 ("transaction_id",
+ &transaction_id),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &amount_with_fee),
+ TALER_PQ_result_spec_amount ("deposit_fee",
+ &deposit_fee),
+ GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
+ &wire_deadline),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract",
+ &h_contract),
+ GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
+ &merchant_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &coin_pub),
+ TALER_PQ_result_spec_json ("wire",
+ &wire),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ ret = deposit_cb (deposit_cb_cls,
+ serial_id,
+ &merchant_pub,
+ &coin_pub,
+ &amount_with_fee,
+ &deposit_fee,
+ transaction_id,
+ &h_contract,
+ wire_deadline,
+ wire);
+ GNUNET_PQ_cleanup_result (rs);
+ PQclear (result);
+ }
+ return (GNUNET_OK == ret) ? 1 : 0;
+}
+
+
+/**
+ * Obtain information about other pending deposits for the same
+ * destination. Those deposits must not already be "done".
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param h_wire destination of the wire transfer
+ * @param merchant_pub public key of the merchant
+ * @param deposit_cb function to call for each deposit
+ * @param deposit_cb_cls closure for @a deposit_cb
+ * @param limit maximum number of matching deposits to return
+ * @return number of rows processed, 0 if none exist,
+ * #GNUNET_SYSERR on error
+ */
+static int
+postgres_iterate_matching_deposits (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ TALER_EXCHANGEDB_DepositIterator deposit_cb,
+ void *deposit_cb_cls,
+ uint32_t limit)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_wire),
+ GNUNET_PQ_query_param_uint32 (&limit),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ unsigned int i;
+ unsigned int n;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "deposits_iterate_matching",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == (n = PQntuples (result)))
+ {
+ PQclear (result);
+ return 0;
+ }
+ if (n > limit)
+ n = limit;
+ for (i=0;i<n;i++)
+ {
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
+ struct GNUNET_TIME_Absolute wire_deadline;
+ struct GNUNET_HashCode h_contract;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ uint64_t transaction_id;
+ uint64_t serial_id;
+ int ret;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial_id",
+ &serial_id),
+ GNUNET_PQ_result_spec_uint64 ("transaction_id",
+ &transaction_id),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &amount_with_fee),
+ TALER_PQ_result_spec_amount ("deposit_fee",
+ &deposit_fee),
+ GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
+ &wire_deadline),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract",
+ &h_contract),
+ GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
+ &merchant_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &coin_pub),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, i))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ ret = deposit_cb (deposit_cb_cls,
+ serial_id,
+ &merchant_pub,
+ &coin_pub,
+ &amount_with_fee,
+ &deposit_fee,
+ transaction_id,
+ &h_contract,
+ wire_deadline,
+ NULL);
+ GNUNET_PQ_cleanup_result (rs);
+ PQclear (result);
+ if (GNUNET_OK != ret)
+ break;
+ }
+ return i;
+}
+
+
+/**
+ * Insert information about deposited coin into the database.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit deposit information to store
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+postgres_insert_deposit (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_Deposit *deposit)
+{
+ PGresult *result;
+ int ret;
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
+ GNUNET_PQ_query_param_rsa_public_key (deposit->coin.denom_pub.rsa_public_key),
+ GNUNET_PQ_query_param_rsa_signature (deposit->coin.denom_sig.rsa_signature),
+ GNUNET_PQ_query_param_uint64 (&deposit->transaction_id),
+ TALER_PQ_query_param_amount (&deposit->amount_with_fee),
+ TALER_PQ_query_param_amount (&deposit->deposit_fee),
+ GNUNET_PQ_query_param_absolute_time (&deposit->timestamp),
+ GNUNET_PQ_query_param_absolute_time (&deposit->refund_deadline),
+ GNUNET_PQ_query_param_absolute_time (&deposit->wire_deadline),
+ GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract),
+ GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire),
+ GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
+ TALER_PQ_query_param_json (deposit->wire),
+ GNUNET_PQ_query_param_end
+ };
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_deposit",
+ params);
+ }
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ ret = GNUNET_SYSERR;
+ }
+ else
+ {
+ ret = GNUNET_OK;
+ }
+ PQclear (result);
+ return ret;
+}
+
+
+/**
+ * Lookup refresh session data under the given @a session_hash.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database handle to use
+ * @param session_hash hash over the melt to use to locate the session
+ * @param[out] refresh_session where to store the result, can be NULL
+ * to just check if the session exists
+ * @return #GNUNET_YES on success,
+ * #GNUNET_NO if not found,
+ * #GNUNET_SYSERR on DB failure
+ */
+static int
+postgres_get_refresh_session (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ struct TALER_EXCHANGEDB_RefreshSession *refresh_session)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_refresh_session",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == PQntuples (result));
+ if (NULL == refresh_session)
+ {
+ /* We're done if the caller is only interested in whether the
+ * session exists or not */
+ PQclear (result);
+ return GNUNET_YES;
+ }
+ memset (refresh_session,
+ 0,
+ sizeof (struct TALER_EXCHANGEDB_RefreshSession));
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint16 ("num_oldcoins",
+ &refresh_session->num_oldcoins),
+ GNUNET_PQ_result_spec_uint16 ("num_newcoins",
+ &refresh_session->num_newcoins),
+ GNUNET_PQ_result_spec_uint16 ("noreveal_index",
+ &refresh_session->noreveal_index),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ }
+ PQclear (result);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Store new refresh session data under the given @a session_hash.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database handle to use
+ * @param session_hash hash over the melt to use to locate the session
+ * @param refresh_session session data to store
+ * @return #GNUNET_YES on success,
+ * #GNUNET_SYSERR on DB failure
+ */
+static int
+postgres_create_refresh_session (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ const struct TALER_EXCHANGEDB_RefreshSession *refresh_session)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&refresh_session->num_oldcoins),
+ GNUNET_PQ_query_param_uint16 (&refresh_session->num_newcoins),
+ GNUNET_PQ_query_param_uint16 (&refresh_session->noreveal_index),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_refresh_session",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Insert a coin we know of into the DB. The coin can then be referenced by
+ * tables for deposits, lock and refresh functionality.
+ *
+ * @param cls plugin closure
+ * @param session the shared database session
+ * @param coin_info the public coin info
+ * @return #GNUNET_SYSERR upon error; #GNUNET_OK upon success
+ */
+static int
+insert_known_coin (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_CoinPublicInfo *coin_info)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub),
+ GNUNET_PQ_query_param_rsa_public_key (coin_info->denom_pub.rsa_public_key),
+ GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature),
+ GNUNET_PQ_query_param_end
+ };
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_known_coin",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Retrieve the record for a known coin.
+ *
+ * @param cls the plugin closure
+ * @param session the database session handle
+ * @param coin_pub the public key of the coin to search for
+ * @param coin_info place holder for the returned coin information object
+ * @return #GNUNET_SYSERR upon error; #GNUNET_NO if no coin is found; #GNUNET_OK
+ * if upon succesfullying retrieving the record data info @a
+ * coin_info
+ */
+static int
+get_known_coin (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_CoinPublicInfo *coin_info)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_end
+ };
+ int nrows;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_known_coin",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows); /* due to primary key */
+ if (NULL == coin_info)
+ return GNUNET_YES;
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &coin_info->denom_pub.rsa_public_key),
+ GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+ &coin_info->denom_sig.rsa_signature),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ PQclear (result);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ PQclear (result);
+ coin_info->coin_pub = *coin_pub;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Store the given /refresh/melt request in the database.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param oldcoin_index index of the coin to store
+ * @param melt melt operation details to store; includes
+ * the session hash of the melt
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+static int
+postgres_insert_refresh_melt (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ uint16_t oldcoin_index,
+ const struct TALER_EXCHANGEDB_RefreshMelt *melt)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&melt->coin.coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&melt->session_hash),
+ GNUNET_PQ_query_param_uint16 (&oldcoin_index),
+ GNUNET_PQ_query_param_auto_from_type (&melt->coin_sig),
+ TALER_PQ_query_param_amount (&melt->amount_with_fee),
+ TALER_PQ_query_param_amount (&melt->melt_fee),
+ GNUNET_PQ_query_param_end
+ };
+ int ret;
+
+ /* check if the coin is already known */
+ ret = get_known_coin (cls,
+ session,
+ &melt->coin.coin_pub,
+ NULL);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_NO == ret) /* if not, insert it */
+ {
+ ret = insert_known_coin (cls,
+ session,
+ &melt->coin);
+ if (ret == GNUNET_SYSERR)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ /* insert the melt */
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_refresh_melt",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Get information about melted coin details from the database.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash session hash of the melt operation
+ * @param oldcoin_index index of the coin to retrieve
+ * @param melt melt data to fill in, can be NULL
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+static int
+postgres_get_refresh_melt (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t oldcoin_index,
+ struct TALER_EXCHANGEDB_RefreshMelt *melt)
+{
+ PGresult *result;
+ struct TALER_CoinPublicInfo coin;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount melt_fee;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&oldcoin_index),
+ GNUNET_PQ_query_param_end
+ };
+ int nrows;
+
+ /* check if the melt record exists and get it */
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_refresh_melt",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "get_refresh_melt() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (1 == nrows); /* due to primary key constraint */
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin.coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_sig", &coin_sig),
+ TALER_PQ_result_spec_amount ("amount_with_fee", &amount_with_fee),
+ TALER_PQ_result_spec_amount ("melt_fee", &melt_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ }
+ /* fetch the coin info and denomination info */
+ if (GNUNET_OK != get_known_coin (cls,
+ session,
+ &coin.coin_pub,
+ &coin))
+ return GNUNET_SYSERR;
+ if (NULL == melt)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (coin.denom_pub.rsa_public_key);
+ return GNUNET_OK;
+ }
+ melt->coin = coin;
+ melt->coin_sig = coin_sig;
+ melt->session_hash = *session_hash;
+ melt->amount_with_fee = amount_with_fee;
+ melt->melt_fee = melt_fee;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Store in the database which coin(s) we want to create
+ * in a given refresh operation.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
+ * @param denom_pubs array denominations of the coins to create
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+static int
+postgres_insert_refresh_order (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ const struct TALER_DenominationPublicKey *denom_pubs)
+{
+ unsigned int i;
+
+ for (i=0;i<(unsigned int) num_newcoins;i++)
+ {
+ uint16_t newcoin_off = (uint16_t) i;
+ PGresult *result;
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint16 (&newcoin_off),
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_rsa_public_key (denom_pubs[i].rsa_public_key),
+ GNUNET_PQ_query_param_end
+ };
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_refresh_order",
+ params);
+ }
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp ("1", PQcmdTuples (result)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * We allocated some @a denom_pubs information, but now need
+ * to abort. Free allocated memory.
+ *
+ * @param denom_pubs data to free (but not the array itself)
+ * @param denom_pubs_len length of @a denom_pubs array
+ */
+static void
+free_dpk_result (struct TALER_DenominationPublicKey *denom_pubs,
+ unsigned int denom_pubs_len)
+{
+ unsigned int i;
+
+ for (i=0;i<denom_pubs_len;i++)
+ {
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key);
+ denom_pubs[i].rsa_public_key = NULL;
+ }
+}
+
+
+/**
+ * Lookup in the database the coins that we want to
+ * create in the given refresh operation.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins size of the array of the @a denom_pubs array
+ * @param denom_pubs where to store the deomination keys
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+static int
+postgres_get_refresh_order (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ struct TALER_DenominationPublicKey *denom_pubs)
+{
+ unsigned int i;
+
+ for (i=0;i<(unsigned int) num_newcoins;i++)
+ {
+ uint16_t newcoin_off = (uint16_t) i;
+ PGresult *result;
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&newcoin_off),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_refresh_order",
+ params);
+ }
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ free_dpk_result (denom_pubs, i);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ /* FIXME: may want to distinguish between different error cases! */
+ free_dpk_result (denom_pubs, i);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (1 == PQntuples (result));
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &denom_pubs[i].rsa_public_key),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ PQclear (result);
+ GNUNET_break (0);
+ free_dpk_result (denom_pubs, i);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Store information about the commitment of the
+ * given coin for the given refresh session in the database.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose index (1st dimension)
+ * @param num_newcoins coin index size of the @a commit_coins array
+ * @param commit_coins array of coin commitments to store
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on error
+ */
+static int
+postgres_insert_refresh_commit_coins (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_newcoins,
+ const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins)
+{
+ char *rle;
+ size_t rle_size;
+ PGresult *result;
+ unsigned int i;
+ uint16_t coin_off;
+
+ for (i=0;i<(unsigned int) num_newcoins;i++)
+ {
+ rle = TALER_refresh_link_encrypted_encode (commit_coins[i].refresh_link,
+ &rle_size);
+ if (NULL == rle)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ coin_off = (uint16_t) i;
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&cnc_index),
+ GNUNET_PQ_query_param_uint16 (&coin_off),
+ GNUNET_PQ_query_param_fixed_size (rle,
+ rle_size),
+ GNUNET_PQ_query_param_fixed_size (commit_coins[i].coin_ev,
+ commit_coins[i].coin_ev_size),
+ GNUNET_PQ_query_param_end
+ };
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_refresh_commit_coin",
+ params);
+ }
+ GNUNET_free (rle);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp ("1", PQcmdTuples (result)))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * We allocated some @a commit_coin information, but now need
+ * to abort. Free allocated memory.
+ *
+ * @param commit_coins data to free (but not the array itself)
+ * @param commit_coins_len length of @a commit_coins array
+ */
+static void
+free_cc_result (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins,
+ unsigned int commit_coins_len)
+{
+ unsigned int i;
+
+ for (i=0;i<commit_coins_len;i++)
+ {
+ GNUNET_free (commit_coins[i].refresh_link);
+ commit_coins[i].refresh_link = NULL;
+ GNUNET_free (commit_coins[i].coin_ev);
+ commit_coins[i].coin_ev = NULL;
+ commit_coins[i].coin_ev_size = 0;
+ }
+}
+
+
+/**
+ * Obtain information about the commitment of the
+ * given coin of the given refresh session from the database.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index set index (1st dimension)
+ * @param num_newcoins size of the @a commit_coins array
+ * @param[out] commit_coins array of coin commitments to return
+ * @return #GNUNET_OK on success
+ * #GNUNET_NO if not found
+ * #GNUNET_SYSERR on error
+ */
+static int
+postgres_get_refresh_commit_coins (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_newcoins,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins)
+{
+ unsigned int i;
+
+ for (i=0;i<(unsigned int) num_newcoins;i++)
+ {
+ uint16_t newcoin_off = (uint16_t) i;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&cnc_index),
+ GNUNET_PQ_query_param_uint16 (&newcoin_off),
+ GNUNET_PQ_query_param_end
+ };
+ void *c_buf;
+ size_t c_buf_size;
+ void *rl_buf;
+ size_t rl_buf_size;
+ struct TALER_RefreshLinkEncrypted *rl;
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_refresh_commit_coin",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ free_cc_result (commit_coins, i);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ free_cc_result (commit_coins, i);
+ return GNUNET_NO;
+ }
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_variable_size ("link_vector_enc",
+ &rl_buf,
+ &rl_buf_size),
+ GNUNET_PQ_result_spec_variable_size ("coin_ev",
+ &c_buf,
+ &c_buf_size),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_YES !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ PQclear (result);
+ free_cc_result (commit_coins, i);
+ return GNUNET_SYSERR;
+ }
+ }
+ PQclear (result);
+ if (rl_buf_size < sizeof (struct TALER_CoinSpendPrivateKeyP))
+ {
+ GNUNET_free (c_buf);
+ GNUNET_free (rl_buf);
+ free_cc_result (commit_coins, i);
+ return GNUNET_SYSERR;
+ }
+ rl = TALER_refresh_link_encrypted_decode (rl_buf,
+ rl_buf_size);
+ GNUNET_free (rl_buf);
+ commit_coins[i].refresh_link = rl;
+ commit_coins[i].coin_ev = c_buf;
+ commit_coins[i].coin_ev_size = c_buf_size;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Store the commitment to the given (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose index (1st dimension)
+ * @param num_links size of the @a links array to return
+ * @param[out] links array of link information to store return
+ * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
+ */
+static int
+postgres_insert_refresh_commit_links (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_links,
+ const struct TALER_RefreshCommitLinkP *links)
+{
+ uint16_t i;
+
+ for (i=0;i<num_links;i++)
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_auto_from_type (&links[i].transfer_pub),
+ GNUNET_PQ_query_param_uint16 (&cnc_index),
+ GNUNET_PQ_query_param_uint16 (&i),
+ GNUNET_PQ_query_param_auto_from_type (&links[i].shared_secret_enc),
+ GNUNET_PQ_query_param_end
+ };
+
+ PGresult *result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_refresh_commit_link",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ if (0 != strcmp ("1", PQcmdTuples (result)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Obtain the commited (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose index (1st dimension)
+ * @param num_links size of the @a commit_link array
+ * @param[out] links array of link information to return
+ * @return #GNUNET_SYSERR on internal error,
+ * #GNUNET_NO if commitment was not found
+ * #GNUNET_OK on success
+ */
+static int
+postgres_get_refresh_commit_links (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_links,
+ struct TALER_RefreshCommitLinkP *links)
+{
+ uint16_t i;
+
+ for (i=0;i<num_links;i++)
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&cnc_index),
+ GNUNET_PQ_query_param_uint16 (&i),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_refresh_commit_link",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
+ &links[i].transfer_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc",
+ &links[i].shared_secret_enc),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_YES !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ }
+ PQclear (result);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Get all of the information from the given melt commit operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @return NULL if the @a session_hash does not correspond to any known melt
+ * operation
+ */
+static struct TALER_EXCHANGEDB_MeltCommitment *
+postgres_get_melt_commitment (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash)
+{
+ struct TALER_EXCHANGEDB_RefreshSession rs;
+ struct TALER_EXCHANGEDB_MeltCommitment *mc;
+ uint16_t cnc_index;
+ unsigned int i;
+
+ if (GNUNET_OK !=
+ postgres_get_refresh_session (cls,
+ session,
+ session_hash,
+ &rs))
+ return NULL;
+ mc = GNUNET_new (struct TALER_EXCHANGEDB_MeltCommitment);
+ mc->num_newcoins = rs.num_newcoins;
+ mc->num_oldcoins = rs.num_oldcoins;
+ mc->melts = GNUNET_malloc (mc->num_oldcoins *
+ sizeof (struct TALER_EXCHANGEDB_RefreshMelt));
+ for (i=0;i<mc->num_oldcoins;i++)
+ if (GNUNET_OK !=
+ postgres_get_refresh_melt (cls,
+ session,
+ session_hash,
+ (uint16_t) i,
+ &mc->melts[i]))
+ goto cleanup;
+ mc->denom_pubs = GNUNET_malloc (mc->num_newcoins *
+ sizeof (struct TALER_DenominationPublicKey));
+ if (GNUNET_OK !=
+ postgres_get_refresh_order (cls,
+ session,
+ session_hash,
+ mc->num_newcoins,
+ mc->denom_pubs))
+ goto cleanup;
+ for (cnc_index=0;cnc_index<TALER_CNC_KAPPA;cnc_index++)
+ {
+ mc->commit_coins[cnc_index]
+ = GNUNET_malloc (mc->num_newcoins *
+ sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin));
+ if (GNUNET_OK !=
+ postgres_get_refresh_commit_coins (cls,
+ session,
+ session_hash,
+ cnc_index,
+ mc->num_newcoins,
+ mc->commit_coins[cnc_index]))
+ goto cleanup;
+ mc->commit_links[cnc_index]
+ = GNUNET_malloc (mc->num_oldcoins *
+ sizeof (struct TALER_RefreshCommitLinkP));
+ if (GNUNET_OK !=
+ postgres_get_refresh_commit_links (cls,
+ session,
+ session_hash,
+ cnc_index,
+ mc->num_oldcoins,
+ mc->commit_links[cnc_index]))
+ goto cleanup;
+ }
+ return mc;
+
+ cleanup:
+ common_free_melt_commitment (cls, mc);
+ return NULL;
+}
+
+
+/**
+ * Insert signature of a new coin generated during refresh into
+ * the database indexed by the refresh session and the index
+ * of the coin. This data is later used should an old coin
+ * be used to try to obtain the private keys during "/refresh/link".
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param newcoin_index coin index
+ * @param ev_sig coin signature
+ * @return #GNUNET_OK on success
+ */
+static int
+postgres_insert_refresh_out (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t newcoin_index,
+ const struct TALER_DenominationSignature *ev_sig)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_uint16 (&newcoin_index),
+ GNUNET_PQ_query_param_rsa_signature (ev_sig->rsa_signature),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_refresh_out",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Obtain the link data of a coin, that is the encrypted link
+ * information, the denomination keys and the signatures.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash refresh session to get linkage data for
+ * @return all known link data for the session
+ */
+static struct TALER_EXCHANGEDB_LinkDataList *
+postgres_get_link_data_list (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash)
+{
+ struct TALER_EXCHANGEDB_LinkDataList *ldl;
+ struct TALER_EXCHANGEDB_LinkDataList *pos;
+ int i;
+ int nrows;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (session_hash),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_link",
+ params);
+
+ ldl = NULL;
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return NULL;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ PQclear (result);
+ return NULL;
+ }
+
+ for (i = 0; i < nrows; i++)
+ {
+ struct TALER_RefreshLinkEncrypted *link_enc;
+ struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
+ struct GNUNET_CRYPTO_rsa_Signature *sig;
+ void *ld_buf;
+ size_t ld_buf_size;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_variable_size ("link_vector_enc",
+ &ld_buf,
+ &ld_buf_size),
+ GNUNET_PQ_result_spec_rsa_signature ("ev_sig",
+ &sig),
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &denom_pub),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, i))
+ {
+ PQclear (result);
+ GNUNET_break (0);
+ common_free_link_data_list (cls,
+ ldl);
+ return NULL;
+ }
+ if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
+ {
+ PQclear (result);
+ GNUNET_free (ld_buf);
+ common_free_link_data_list (cls,
+ ldl);
+ return NULL;
+ }
+ link_enc = TALER_refresh_link_encrypted_decode (ld_buf,
+ ld_buf_size);
+ GNUNET_free (ld_buf);
+ pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkDataList);
+ pos->next = ldl;
+ pos->link_data_enc = link_enc;
+ pos->denom_pub.rsa_public_key = denom_pub;
+ pos->ev_sig.rsa_signature = sig;
+ ldl = pos;
+ }
+ return ldl;
+}
+
+
+/**
+ * Obtain shared secret and transfer public key from the public key of
+ * the coin. This information and the link information returned by
+ * #postgres_get_link_data_list() enable the owner of an old coin to
+ * determine the private keys of the new coins after the melt.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param coin_pub public key of the coin
+ * @param tdc function to call for each session the coin was melted into
+ * @param tdc_cls closure for @a tdc
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO on failure (not found)
+ * #GNUNET_SYSERR on internal failure (database issue)
+ */
+static int
+postgres_get_transfer (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ TALER_EXCHANGEDB_TransferDataCallback tdc,
+ void *tdc_cls)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ int nrows;
+ int i;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_transfer",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ /* no matches found */
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (i=0;i<nrows;i++)
+ {
+ struct GNUNET_HashCode session_hash;
+ struct TALER_TransferPublicKeyP transfer_pub;
+ struct TALER_EncryptedLinkSecretP shared_secret_enc;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", &transfer_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc", &shared_secret_enc),
+ GNUNET_PQ_result_spec_auto_from_type ("session_hash", &session_hash),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ PQclear (result);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ tdc (tdc_cls,
+ &session_hash,
+ &transfer_pub,
+ &shared_secret_enc);
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Compile a list of all (historic) transactions performed
+ * with the given coin (/refresh/melt and /deposit operations).
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param coin_pub coin to investigate
+ * @return list of transactions, NULL if coin is fresh
+ */
+static struct TALER_EXCHANGEDB_TransactionList *
+postgres_get_coin_transactions (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub)
+{
+ struct TALER_EXCHANGEDB_TransactionList *head;
+
+ head = NULL;
+ /* check deposits */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub),
+ GNUNET_PQ_query_param_end
+ };
+ int nrows;
+ int i;
+ PGresult *result;
+ struct TALER_EXCHANGEDB_TransactionList *tl;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_deposit_with_coin_pub",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ PQclear (result);
+ goto cleanup;
+ }
+ nrows = PQntuples (result);
+ for (i = 0; i < nrows; i++)
+ {
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+
+ deposit = GNUNET_new (struct TALER_EXCHANGEDB_Deposit);
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+ &deposit->coin.denom_pub.rsa_public_key),
+ GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+ &deposit->coin.denom_sig.rsa_signature),
+ GNUNET_PQ_result_spec_uint64 ("transaction_id",
+ &deposit->transaction_id),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &deposit->amount_with_fee),
+ TALER_PQ_result_spec_amount ("deposit_fee",
+ &deposit->deposit_fee),
+ GNUNET_PQ_result_spec_absolute_time ("timestamp",
+ &deposit->timestamp),
+ GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
+ &deposit->refund_deadline),
+ GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
+ &deposit->merchant_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract",
+ &deposit->h_contract),
+ GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+ &deposit->h_wire),
+ TALER_PQ_result_spec_json ("wire",
+ &deposit->wire),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
+ &deposit->csig),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, i))
+ {
+ GNUNET_break (0);
+ GNUNET_free (deposit);
+ PQclear (result);
+ goto cleanup;
+ }
+ deposit->coin.coin_pub = *coin_pub;
+ }
+ tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
+ tl->next = head;
+ tl->type = TALER_EXCHANGEDB_TT_DEPOSIT;
+ tl->details.deposit = deposit;
+ head = tl;
+ continue;
+ }
+ PQclear (result);
+ }
+ /* Handle refreshing */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub),
+ GNUNET_PQ_query_param_end
+ };
+ int nrows;
+ int i;
+ PGresult *result;
+ struct TALER_EXCHANGEDB_TransactionList *tl;
+
+ /* check if the melt record exists and get it */
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_refresh_melt_by_coin",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ goto cleanup;
+ }
+ nrows = PQntuples (result);
+ for (i=0;i<nrows;i++)
+ {
+ struct TALER_EXCHANGEDB_RefreshMelt *melt;
+
+ melt = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt);
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("session_hash",
+ &melt->session_hash),
+ /* oldcoin_index not needed */
+ GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
+ &melt->coin_sig),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ &melt->amount_with_fee),
+ TALER_PQ_result_spec_amount ("melt_fee",
+ &melt->melt_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ GNUNET_free (melt);
+ PQclear (result);
+ goto cleanup;
+ }
+ melt->coin.coin_pub = *coin_pub;
+ }
+ tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
+ tl->next = head;
+ tl->type = TALER_EXCHANGEDB_TT_REFRESH_MELT;
+ tl->details.melt = melt;
+ head = tl;
+ continue;
+ }
+ PQclear (result);
+ }
+ return head;
+ cleanup:
+ if (NULL != head)
+ common_free_coin_transaction_list (cls,
+ head);
+ return NULL;
+}
+
+
+/**
+ * Lookup the list of Taler transactions that were aggregated
+ * into a wire transfer by the respective @a wtid.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param wtid the raw wire transfer identifier we used
+ * @param cb function to call on each transaction found
+ * @param cb_cls closure for @a cb
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
+ * #GNUNET_NO if we found no results
+ */
+static int
+postgres_lookup_wire_transfer (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_EXCHANGEDB_WireTransferDataCallback cb,
+ void *cb_cls)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_end
+ };
+ int nrows;
+ int i;
+
+ /* check if the melt record exists and get it */
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "lookup_transactions",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "lookup_wire_transfer() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (i=0;i<nrows;i++)
+ {
+ struct GNUNET_HashCode h_contract;
+ struct GNUNET_HashCode h_wire;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ uint64_t transaction_id;
+ struct GNUNET_TIME_Absolute exec_time;
+ struct TALER_Amount coin_amount;
+ struct TALER_Amount coin_fee;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract", &h_contract),
+ GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub),
+ GNUNET_PQ_result_spec_uint64 ("transaction_id", &transaction_id),
+ GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time),
+ TALER_PQ_result_spec_amount ("coin_amount", &coin_amount),
+ TALER_PQ_result_spec_amount ("coin_fee", &coin_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, i))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ &merchant_pub,
+ &h_wire,
+ &h_contract,
+ transaction_id,
+ &coin_pub,
+ &coin_amount,
+ &coin_fee);
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Try to find the wire transfer details for a deposit operation.
+ * If we did not execute the deposit yet, return when it is supposed
+ * to be executed.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param h_contract hash of the contract
+ * @param h_wire hash of merchant wire details
+ * @param coin_pub public key of deposited coin
+ * @param merchant_pub merchant public key
+ * @param transaction_id transaction identifier
+ * @param cb function to call with the result
+ * @param cb_cls closure to pass to @a cb
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
+ * #GNUNET_NO if nothing was found
+ */
+static int
+postgres_wire_lookup_deposit_wtid (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ uint64_t transaction_id,
+ TALER_EXCHANGEDB_DepositWtidCallback cb,
+ void *cb_cls)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_contract),
+ GNUNET_PQ_query_param_auto_from_type (h_wire),
+ GNUNET_PQ_query_param_uint64 (&transaction_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_end
+ };
+ int nrows;
+
+ /* check if the melt record exists and get it */
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "lookup_deposit_wtid",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "lookup_deposit_wtid returned 0 matching rows\n");
+ PQclear (result);
+
+ /* Check if transaction exists in deposits, so that we just
+ do not have a WTID yet, if so, do call the CB with a NULL wtid
+ and return GNUNET_YES! */
+ {
+ struct GNUNET_PQ_QueryParam params2[] = {
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_uint64 (&transaction_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_contract),
+ GNUNET_PQ_query_param_auto_from_type (h_wire),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_deposit_for_wtid",
+ params2);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "get_deposit_for_wtid returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+
+ /* Ok, we're aware of the transaction, but it has not yet been
+ executed */
+ {
+ struct GNUNET_TIME_Absolute exec_time;
+ struct TALER_Amount coin_amount;
+ struct TALER_Amount coin_fee;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("amount_with_fee", &coin_amount),
+ TALER_PQ_result_spec_amount ("deposit_fee", &coin_fee),
+ GNUNET_PQ_result_spec_absolute_time ("wire_deadline", &exec_time),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ NULL,
+ &coin_amount,
+ &coin_fee,
+ exec_time);
+ PQclear (result);
+ return GNUNET_YES;
+ }
+ }
+ if (1 != nrows)
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TALER_WireTransferIdentifierRawP wtid;
+ struct GNUNET_TIME_Absolute exec_time;
+ struct TALER_Amount coin_amount;
+ struct TALER_Amount coin_fee;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("wtid_raw", &wtid),
+ GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time),
+ TALER_PQ_result_spec_amount ("coin_amount", &coin_amount),
+ TALER_PQ_result_spec_amount ("coin_fee", &coin_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ &wtid,
+ &coin_amount,
+ &coin_fee,
+ exec_time);
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to insert aggregation information into the DB.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param wtid the raw wire transfer identifier we used
+ * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_contract which contract was this payment about
+ * @param transaction_id merchant's transaction ID for the payment
+ * @param coin_pub which public key was this payment about
+ * @param coin_value amount contributed by this coin in total
+ * @param coin_fee deposit fee charged by exchange for this coin
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ */
+static int
+postgres_insert_aggregation_tracking (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_contract),
+ GNUNET_PQ_query_param_auto_from_type (h_wire),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_uint64 (&transaction_id),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_absolute_time (&execution_time),
+ TALER_PQ_query_param_amount (coin_value),
+ TALER_PQ_query_param_amount (coin_fee),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_aggregation_tracking",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp ("1", PQcmdTuples (result)))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to insert wire transfer commit data into the DB.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of the wire transfer (i.e. "sepa")
+ * @param buf buffer with wire transfer preparation data
+ * @param buf_size number of bytes in @a buf
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ */
+static int
+postgres_wire_prepare_data_insert (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ const char *buf,
+ size_t buf_size)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1),
+ GNUNET_PQ_query_param_fixed_size (buf, buf_size),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "wire_prepare_data_insert",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to mark wire transfer commit data as finished.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param rowid which entry to mark as finished
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ */
+static int
+postgres_wire_prepare_data_mark_finished (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ unsigned long long rowid)
+{
+ uint64_t serial_id = rowid;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "wire_prepare_data_mark_done",
+ params);
+ if (PGRES_COMMAND_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to get an unfinished wire transfer
+ * preparation data. Fetches at most one item.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type fo the wire transfer (i.e. "sepa")
+ * @param cb function to call for ONE unfinished item
+ * @param cb_cls closure for @a cb
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if there are no entries,
+ * #GNUNET_SYSERR on DB errors
+ */
+static int
+postgres_wire_prepare_data_get (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ TALER_EXCHANGEDB_WirePreparationCallback cb,
+ void *cb_cls)
+{
+ PGresult *result;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "wire_prepare_data_get",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ QUERY_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ if (1 != PQntuples (result))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ {
+ uint64_t serial_id;
+ void *buf = NULL;
+ size_t buf_size;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial_id",
+ &serial_id),
+ GNUNET_PQ_result_spec_variable_size ("buf",
+ &buf,
+ &buf_size),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ serial_id,
+ buf,
+ buf_size);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Initialize Postgres database subsystem.
+ *
+ * @param cls a configuration instance
+ * @return NULL on error, otherwise a `struct TALER_EXCHANGEDB_Plugin`
+ */
+void *
+libtaler_plugin_exchangedb_postgres_init (void *cls)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct PostgresClosure *pg;
+ struct TALER_EXCHANGEDB_Plugin *plugin;
+
+ pg = GNUNET_new (struct PostgresClosure);
+
+ if (0 != pthread_key_create (&pg->db_conn_threadlocal,
+ &db_conn_destroy))
+ {
+ TALER_LOG_ERROR ("Cannnot create pthread key.\n");
+ GNUNET_free (pg);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchangedb-postgres",
+ "db_conn_str",
+ &pg->connection_cfg_str))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchangedb-postgres",
+ "db_conn_str");
+ GNUNET_free (pg);
+ return NULL;
+ }
+ plugin = GNUNET_new (struct TALER_EXCHANGEDB_Plugin);
+ plugin->cls = pg;
+ plugin->get_session = &postgres_get_session;
+ plugin->drop_temporary = &postgres_drop_temporary;
+ plugin->create_tables = &postgres_create_tables;
+ plugin->start = &postgres_start;
+ plugin->commit = &postgres_commit;
+ plugin->rollback = &postgres_rollback;
+ plugin->insert_denomination_info = &postgres_insert_denomination_info;
+ plugin->get_denomination_info = &postgres_get_denomination_info;
+ plugin->reserve_get = &postgres_reserve_get;
+ plugin->reserves_in_insert = &postgres_reserves_in_insert;
+ plugin->get_withdraw_info = &postgres_get_withdraw_info;
+ plugin->insert_withdraw_info = &postgres_insert_withdraw_info;
+ plugin->get_reserve_history = &postgres_get_reserve_history;
+ plugin->free_reserve_history = &common_free_reserve_history;
+ plugin->have_deposit = &postgres_have_deposit;
+ plugin->mark_deposit_tiny = &postgres_mark_deposit_tiny;
+ plugin->mark_deposit_done = &postgres_mark_deposit_done;
+ plugin->get_ready_deposit = &postgres_get_ready_deposit;
+ plugin->iterate_matching_deposits = &postgres_iterate_matching_deposits;
+ plugin->insert_deposit = &postgres_insert_deposit;
+ plugin->get_refresh_session = &postgres_get_refresh_session;
+ plugin->create_refresh_session = &postgres_create_refresh_session;
+ plugin->insert_refresh_melt = &postgres_insert_refresh_melt;
+ plugin->get_refresh_melt = &postgres_get_refresh_melt;
+ plugin->insert_refresh_order = &postgres_insert_refresh_order;
+ plugin->get_refresh_order = &postgres_get_refresh_order;
+ plugin->insert_refresh_commit_coins = &postgres_insert_refresh_commit_coins;
+ plugin->get_refresh_commit_coins = &postgres_get_refresh_commit_coins;
+ plugin->insert_refresh_commit_links = &postgres_insert_refresh_commit_links;
+ plugin->get_refresh_commit_links = &postgres_get_refresh_commit_links;
+ plugin->get_melt_commitment = &postgres_get_melt_commitment;
+ plugin->free_melt_commitment = &common_free_melt_commitment;
+ plugin->insert_refresh_out = &postgres_insert_refresh_out;
+ plugin->get_link_data_list = &postgres_get_link_data_list;
+ plugin->free_link_data_list = &common_free_link_data_list;
+ plugin->get_transfer = &postgres_get_transfer;
+ plugin->get_coin_transactions = &postgres_get_coin_transactions;
+ plugin->free_coin_transaction_list = &common_free_coin_transaction_list;
+ plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
+ plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid;
+ plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
+ plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert;
+ plugin->wire_prepare_data_mark_finished = &postgres_wire_prepare_data_mark_finished;
+ plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get;
+ return plugin;
+}
+
+
+/**
+ * Shutdown Postgres database subsystem.
+ *
+ * @param cls a `struct TALER_EXCHANGEDB_Plugin`
+ * @return NULL (always)
+ */
+void *
+libtaler_plugin_exchangedb_postgres_done (void *cls)
+{
+ struct TALER_EXCHANGEDB_Plugin *plugin = cls;
+ struct PostgresClosure *pg = plugin->cls;
+
+ GNUNET_free (pg->connection_cfg_str);
+ GNUNET_free (pg);
+ GNUNET_free (plugin);
+ return NULL;
+}
+
+/* end of plugin_exchangedb_postgres.c */
diff --git a/src/exchangedb/test-exchange-db-postgres.conf b/src/exchangedb/test-exchange-db-postgres.conf
new file mode 100644
index 000000000..0822bab44
--- /dev/null
+++ b/src/exchangedb/test-exchange-db-postgres.conf
@@ -0,0 +1,8 @@
+[exchange]
+#The DB plugin to use
+DB = postgres
+
+[exchangedb-postgres]
+
+#The connection string the plugin has to use for connecting to the database
+DB_CONN_STR = postgres:///talercheck
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
new file mode 100644
index 000000000..df1adf561
--- /dev/null
+++ b/src/exchangedb/test_exchangedb.c
@@ -0,0 +1,907 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchangedb/test_exchangedb.c
+ * @brief test cases for DB interaction functions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "taler_exchangedb_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+static int result;
+
+#define FAILIF(cond) \
+ do { \
+ if (!(cond)){ break;} \
+ GNUNET_break (0); \
+ goto drop; \
+ } while (0)
+
+
+#define RND_BLK(ptr) \
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
+
+#define ZR_BLK(ptr) \
+ memset (ptr, 0, sizeof (*ptr))
+
+
+#define CURRENCY "EUR"
+
+static struct TALER_EXCHANGEDB_Plugin *plugin;
+
+/**
+ * Checks if the given reserve has the given amount of balance and expiry
+ *
+ * @param session the database connection
+ * @param pub the public key of the reserve
+ * @param value balance value
+ * @param fraction balance fraction
+ * @param currency currency of the reserve
+ * @return #GNUNET_OK if the given reserve has the same balance and expiration
+ * as the given parameters; #GNUNET_SYSERR if not
+ */
+static int
+check_reserve (struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_ReservePublicKeyP *pub,
+ uint64_t value,
+ uint32_t fraction,
+ const char *currency)
+{
+ struct TALER_EXCHANGEDB_Reserve reserve;
+
+ reserve.pub = *pub;
+
+ FAILIF (GNUNET_OK !=
+ plugin->reserve_get (plugin->cls,
+ session,
+ &reserve));
+ FAILIF (value != reserve.balance.value);
+ FAILIF (fraction != reserve.balance.fraction);
+ FAILIF (0 != strcmp (currency, reserve.balance.currency));
+
+ return GNUNET_OK;
+ drop:
+ return GNUNET_SYSERR;
+}
+
+
+struct DenomKeyPair
+{
+ struct TALER_DenominationPrivateKey priv;
+ struct TALER_DenominationPublicKey pub;
+};
+
+
+/**
+ * Destroy a denomination key pair. The key is not necessarily removed from the DB.
+ *
+ * @param dkp the keypair to destroy
+ */
+static void
+destroy_denom_key_pair (struct DenomKeyPair *dkp)
+{
+ GNUNET_CRYPTO_rsa_public_key_free (dkp->pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_private_key_free (dkp->priv.rsa_private_key);
+ GNUNET_free (dkp);
+}
+
+
+/**
+ * Create a denominaiton key pair by registering the denomination in the DB.
+ *
+ * @param size the size of the denomination key
+ * @param session the DB session
+ * @return the denominaiton key pair; NULL upon error
+ */
+static struct DenomKeyPair *
+create_denom_key_pair (unsigned int size,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_Amount *value,
+ const struct TALER_Amount *fee_withdraw,
+ const struct TALER_Amount *fee_deposit,
+ const struct TALER_Amount *fee_refresh)
+{
+ struct DenomKeyPair *dkp;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki;
+
+ dkp = GNUNET_new (struct DenomKeyPair);
+ dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size);
+ GNUNET_assert (NULL != dkp->priv.rsa_private_key);
+ dkp->pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_private_key_get_public (dkp->priv.rsa_private_key);
+
+ /* Using memset() as fields like master key and signature
+ are not properly initialized for this test. */
+ memset (&dki,
+ 0,
+ sizeof (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation));
+ dki.denom_pub = dkp->pub;
+ dki.issue.properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+ dki.issue.properties.expire_withdraw = GNUNET_TIME_absolute_hton
+ (GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_UNIT_HOURS));
+ dki.issue.properties.expire_spend = GNUNET_TIME_absolute_hton
+ (GNUNET_TIME_absolute_add
+ (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 2)));
+ dki.issue.properties.expire_legal = GNUNET_TIME_absolute_hton
+ (GNUNET_TIME_absolute_add
+ (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 3)));
+ TALER_amount_hton (&dki.issue.properties.value, value);
+ TALER_amount_hton (&dki.issue.properties.fee_withdraw, fee_withdraw);
+ TALER_amount_hton (&dki.issue.properties.fee_deposit, fee_deposit);
+ TALER_amount_hton (&dki.issue.properties.fee_refresh, fee_refresh);
+ GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key,
+ &dki.issue.properties.denom_hash);
+ if (GNUNET_OK !=
+ plugin->insert_denomination_info (plugin->cls,
+ session,
+ &dki.denom_pub,
+ &dki.issue))
+ {
+ GNUNET_break(0);
+ destroy_denom_key_pair (dkp);
+ return NULL;
+ }
+ return dkp;
+}
+
+static struct TALER_Amount value;
+static struct TALER_Amount fee_withdraw;
+static struct TALER_Amount fee_deposit;
+static struct TALER_Amount fee_refresh;
+static struct TALER_Amount amount_with_fee;
+
+static void
+free_refresh_commit_coins_array(struct TALER_EXCHANGEDB_RefreshCommitCoin
+ *commit_coins,
+ unsigned int size)
+{
+ unsigned int cnt;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *ccoin;
+ struct TALER_RefreshLinkEncrypted *rlink;
+
+ for (cnt = 0; cnt < size; cnt++)
+ {
+ ccoin = &commit_coins[cnt];
+ GNUNET_free_non_null (ccoin->coin_ev);
+ rlink = (struct TALER_RefreshLinkEncrypted *) ccoin->refresh_link;
+ GNUNET_free_non_null (rlink);
+ }
+ GNUNET_free (commit_coins);
+}
+
+#define MELT_NEW_COINS 5
+
+static int
+test_refresh_commit_coins (struct TALER_EXCHANGEDB_Session *session,
+ struct TALER_EXCHANGEDB_RefreshSession *refresh_session,
+ const struct GNUNET_HashCode *session_hash)
+{
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *ret_commit_coins;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *a_ccoin;
+ struct TALER_RefreshLinkEncrypted *a_rlink;
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *b_ccoin;
+ struct TALER_RefreshLinkEncrypted *b_rlink;
+ size_t size;
+ unsigned int cnt;
+ uint16_t cnc_index;
+ int ret;
+
+ #define COIN_ENC_MAX_SIZE 512
+ ret = GNUNET_SYSERR;
+ ret_commit_coins = NULL;
+ commit_coins = GNUNET_new_array (MELT_NEW_COINS,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin);
+ cnc_index = (uint16_t) GNUNET_CRYPTO_random_u32
+ (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_MIN (MELT_NEW_COINS, UINT16_MAX));
+ for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
+ {
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *ccoin;
+ struct TALER_RefreshLinkEncrypted *rlink;
+ ccoin = &commit_coins[cnt];
+ size = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ COIN_ENC_MAX_SIZE);
+ rlink = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + size);
+ ccoin->refresh_link = rlink;
+ ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64
+ (GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE);
+ ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ ccoin->coin_ev,
+ ccoin->coin_ev_size);
+ rlink->blinding_key_enc_size = size;
+ RND_BLK (&rlink->coin_priv_enc);
+ rlink->blinding_key_enc = (const char *) &rlink[1];
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ (void *)rlink->blinding_key_enc,
+ rlink->blinding_key_enc_size);
+ }
+ FAILIF (GNUNET_OK !=
+ plugin->insert_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ cnc_index,
+ MELT_NEW_COINS,
+ commit_coins));
+ ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin);
+ FAILIF (GNUNET_OK !=
+ plugin->get_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ cnc_index,
+ MELT_NEW_COINS,
+ ret_commit_coins));
+ /* compare the refresh commit coin arrays */
+ for (cnt = 0; cnt < MELT_NEW_COINS; cnt++)
+ {
+ a_ccoin = &commit_coins[cnt];
+ b_ccoin = &ret_commit_coins[cnt];
+ FAILIF (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size);
+ FAILIF (0 != memcmp (a_ccoin->coin_ev,
+ a_ccoin->coin_ev,
+ a_ccoin->coin_ev_size));
+ a_rlink = a_ccoin->refresh_link;
+ b_rlink = b_ccoin->refresh_link;
+ FAILIF (a_rlink->blinding_key_enc_size != b_rlink->blinding_key_enc_size);
+ FAILIF (0 != memcmp (a_rlink->blinding_key_enc,
+ b_rlink->blinding_key_enc,
+ a_rlink->blinding_key_enc_size));
+ FAILIF (0 != memcmp (a_rlink->coin_priv_enc,
+ b_rlink->coin_priv_enc,
+ sizeof (a_rlink->coin_priv_enc)));
+ }
+ ret = GNUNET_OK;
+
+ drop:
+ if (NULL != ret_commit_coins)
+ free_refresh_commit_coins_array (ret_commit_coins, MELT_NEW_COINS);
+ if (NULL != commit_coins)
+ free_refresh_commit_coins_array (commit_coins, MELT_NEW_COINS);
+ return ret;
+}
+
+/**
+ * Function to test melting of coins as part of a refresh session
+ *
+ * @param session the database session
+ * @param refresh_session the refresh session
+ * @return #GNUNET_OK if everything went well; #GNUNET_SYSERR if not
+ */
+static int
+test_melting (struct TALER_EXCHANGEDB_Session *session)
+{
+#define MELT_OLD_COINS 10
+ struct TALER_EXCHANGEDB_RefreshSession refresh_session;
+ struct TALER_EXCHANGEDB_RefreshSession ret_refresh_session;
+ struct GNUNET_HashCode session_hash;
+ struct DenomKeyPair *dkp;
+ struct DenomKeyPair **new_dkp;
+ /* struct TALER_CoinPublicInfo *coins; */
+ struct TALER_EXCHANGEDB_RefreshMelt *melts;
+ struct TALER_DenominationPublicKey *new_denom_pubs;
+ struct TALER_DenominationPublicKey *ret_denom_pubs;
+ unsigned int cnt;
+ int ret;
+
+ ret = GNUNET_SYSERR;
+ RND_BLK (&refresh_session);
+ RND_BLK (&session_hash);
+ melts = NULL;
+ dkp = NULL;
+ new_dkp = NULL;
+ new_denom_pubs = NULL;
+ ret_denom_pubs = NULL;
+ /* create and test a refresh session */
+ refresh_session.num_oldcoins = MELT_OLD_COINS;
+ refresh_session.num_newcoins = 1;
+ refresh_session.noreveal_index = 1;
+ FAILIF (GNUNET_OK != plugin->create_refresh_session (plugin->cls,
+ session,
+ &session_hash,
+ &refresh_session));
+ FAILIF (GNUNET_OK != plugin->get_refresh_session (plugin->cls,
+ session,
+ &session_hash,
+ &ret_refresh_session));
+ FAILIF (0 != memcmp (&ret_refresh_session,
+ &refresh_session,
+ sizeof (refresh_session)));
+
+ /* create a denomination (value: 1; fraction: 100) */
+ dkp = create_denom_key_pair (512, session,
+ &value,
+ &fee_withdraw,
+ &fee_deposit,
+ &fee_refresh);
+ /* create MELT_OLD_COINS number of refresh melts */
+ melts = GNUNET_new_array (MELT_OLD_COINS, struct TALER_EXCHANGEDB_RefreshMelt);
+ for (cnt=0; cnt < MELT_OLD_COINS; cnt++)
+ {
+ RND_BLK (&melts[cnt].coin.coin_pub);
+ melts[cnt].coin.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
+ &melts[cnt].coin.coin_pub,
+ sizeof (melts[cnt].coin.coin_pub));
+ melts[cnt].coin.denom_pub = dkp->pub;
+ RND_BLK (&melts[cnt].coin_sig);
+ melts[cnt].session_hash = session_hash;
+ melts[cnt].amount_with_fee = amount_with_fee;
+ melts[cnt].melt_fee = fee_refresh;
+ FAILIF (GNUNET_OK != plugin->insert_refresh_melt (plugin->cls,
+ session,
+ cnt,
+ &melts[cnt]));
+ }
+ for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
+ {
+ struct TALER_EXCHANGEDB_RefreshMelt ret_melt;
+ FAILIF (GNUNET_OK != plugin->get_refresh_melt (plugin->cls,
+ session,
+ &session_hash,
+ cnt,
+ &ret_melt));
+ FAILIF (0 != GNUNET_CRYPTO_rsa_signature_cmp
+ (ret_melt.coin.denom_sig.rsa_signature,
+ melts[cnt].coin.denom_sig.rsa_signature));
+ FAILIF (0 != memcmp (&ret_melt.coin.coin_pub,
+ &melts[cnt].coin.coin_pub,
+ sizeof (ret_melt.coin.coin_pub)));
+ FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp
+ (ret_melt.coin.denom_pub.rsa_public_key,
+ melts[cnt].coin.denom_pub.rsa_public_key));
+ FAILIF (0 != memcmp (&ret_melt.coin_sig,
+ &melts[cnt].coin_sig,
+ sizeof (ret_melt.coin_sig)));
+ FAILIF (0 != memcmp (&ret_melt.session_hash,
+ &melts[cnt].session_hash,
+ sizeof (ret_melt.session_hash)));
+ FAILIF (0 != TALER_amount_cmp (&ret_melt.amount_with_fee,
+ &melts[cnt].amount_with_fee));
+ FAILIF (0 != TALER_amount_cmp (&ret_melt.melt_fee,
+ &melts[cnt].melt_fee));
+ GNUNET_CRYPTO_rsa_signature_free (ret_melt.coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (ret_melt.coin.denom_pub.rsa_public_key);
+ }
+ new_dkp = GNUNET_new_array (MELT_NEW_COINS, struct DenomKeyPair *);
+ new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
+ struct TALER_DenominationPublicKey);
+ for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
+ {
+ new_dkp[cnt] = create_denom_key_pair (128, session,
+ &value,
+ &fee_withdraw,
+ &fee_deposit,
+ &fee_refresh);
+ new_denom_pubs[cnt]=new_dkp[cnt]->pub;
+ }
+ FAILIF (GNUNET_OK != plugin->insert_refresh_order (plugin->cls,
+ session,
+ &session_hash,
+ MELT_NEW_COINS,
+ new_denom_pubs));
+ ret_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
+ struct TALER_DenominationPublicKey);
+ FAILIF (GNUNET_OK != plugin->get_refresh_order (plugin->cls,
+ session,
+ &session_hash,
+ MELT_NEW_COINS,
+ ret_denom_pubs));
+ for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
+ {
+ FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp
+ (ret_denom_pubs[cnt].rsa_public_key,
+ new_denom_pubs[cnt].rsa_public_key));
+ }
+ FAILIF (GNUNET_OK !=
+ test_refresh_commit_coins (session,
+ &refresh_session,
+ &session_hash));
+
+ ret = GNUNET_OK;
+
+ drop:
+ if (NULL != dkp)
+ destroy_denom_key_pair (dkp);
+ if (NULL != melts)
+ {
+ for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
+ GNUNET_CRYPTO_rsa_signature_free (melts[cnt].coin.denom_sig.rsa_signature);
+ GNUNET_free (melts);
+ }
+ for (cnt = 0;
+ (NULL != ret_denom_pubs) && (cnt < MELT_NEW_COINS)
+ && (NULL != ret_denom_pubs[cnt].rsa_public_key);
+ cnt++)
+ GNUNET_CRYPTO_rsa_public_key_free (ret_denom_pubs[cnt].rsa_public_key);
+ GNUNET_free_non_null (ret_denom_pubs);
+ GNUNET_free_non_null (new_denom_pubs);
+ for (cnt = 0;
+ (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]);
+ cnt++)
+ destroy_denom_key_pair (new_dkp[cnt]);
+ GNUNET_free_non_null (new_dkp);
+ return ret;
+}
+
+
+/**
+ * Callback that should never be called.
+ */
+static void
+cb_wt_never (void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee)
+{
+ GNUNET_assert (0); /* this statement should be unreachable */
+}
+
+
+/**
+ * Callback that should never be called.
+ */
+static void
+cb_wtid_never (void *cls,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
+ struct GNUNET_TIME_Absolute execution_time)
+{
+ GNUNET_assert (0);
+}
+
+
+static struct TALER_MerchantPublicKeyP merchant_pub_wt;
+static struct GNUNET_HashCode h_wire_wt;
+static struct GNUNET_HashCode h_contract_wt;
+static uint64_t transaction_id_wt;
+static struct TALER_CoinSpendPublicKeyP coin_pub_wt;
+static struct TALER_Amount coin_value_wt;
+static struct TALER_Amount coin_fee_wt;
+static struct TALER_Amount transfer_value_wt;
+static struct GNUNET_TIME_Absolute execution_time_wt;
+static struct TALER_WireTransferIdentifierRawP wtid_wt;
+
+
+/**
+ * Callback that should be called with the WT data.
+ */
+static void
+cb_wt_check (void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee)
+{
+ GNUNET_assert (cls == &cb_wt_never);
+ GNUNET_assert (0 == memcmp (merchant_pub,
+ &merchant_pub_wt,
+ sizeof (struct TALER_MerchantPublicKeyP)));
+ GNUNET_assert (0 == memcmp (h_wire,
+ &h_wire_wt,
+ sizeof (struct GNUNET_HashCode)));
+ GNUNET_assert (0 == memcmp (h_contract,
+ &h_contract_wt,
+ sizeof (struct GNUNET_HashCode)));
+ GNUNET_assert (transaction_id == transaction_id_wt);
+ GNUNET_assert (0 == memcmp (coin_pub,
+ &coin_pub_wt,
+ sizeof (struct TALER_CoinSpendPublicKeyP)));
+ GNUNET_assert (0 == TALER_amount_cmp (coin_value,
+ &coin_value_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
+ &coin_fee_wt));
+}
+
+
+/**
+ * Callback that should be called with the WT data.
+ */
+static void
+cb_wtid_check (void *cls,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
+ struct GNUNET_TIME_Absolute execution_time)
+{
+ GNUNET_assert (cls == &cb_wtid_never);
+ GNUNET_assert (0 == memcmp (wtid,
+ &wtid_wt,
+ sizeof (struct TALER_WireTransferIdentifierRawP)));
+ GNUNET_assert (execution_time.abs_value_us ==
+ execution_time_wt.abs_value_us);
+ GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
+ &coin_value_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
+ &coin_fee_wt));
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct TALER_EXCHANGEDB_Session *session;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct DenomKeyPair *dkp;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin cbc2;
+ struct TALER_EXCHANGEDB_ReserveHistory *rh;
+ struct TALER_EXCHANGEDB_ReserveHistory *rh_head;
+ struct TALER_EXCHANGEDB_BankTransfer *bt;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw;
+ struct TALER_EXCHANGEDB_Deposit deposit;
+ struct TALER_EXCHANGEDB_Deposit deposit2;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ json_t *wire;
+ json_t *just;
+ const char * const json_wire_str =
+ "{ \"type\":\"SEPA\", \
+\"IBAN\":\"DE67830654080004822650\", \
+\"name\":\"GNUnet e.V.\", \
+\"bic\":\"GENODEF1SLR\", \
+\"edate\":\"1449930207000\", \
+\"r\":123456789, \
+\"address\": \"foobar\"}";
+ unsigned int cnt;
+
+ dkp = NULL;
+ rh = NULL;
+ wire = NULL;
+ session = NULL;
+ ZR_BLK (&cbc);
+ ZR_BLK (&cbc2);
+ if (NULL ==
+ (plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
+ {
+ result = 1;
+ return;
+ }
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ GNUNET_YES))
+ {
+ result = 2;
+ goto drop;
+ }
+ if (NULL ==
+ (session = plugin->get_session (plugin->cls,
+ GNUNET_YES)))
+ {
+ result = 3;
+ goto drop;
+ }
+ RND_BLK (&reserve_pub);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.000010",
+ &value));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000010",
+ &fee_withdraw));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000010",
+ &fee_deposit));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.000010",
+ &fee_refresh));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.000010",
+ &amount_with_fee));
+
+ result = 4;
+ just = json_loads ("{ \"justification\":\"1\" }", 0, NULL);
+ FAILIF (GNUNET_OK !=
+ plugin->reserves_in_insert (plugin->cls,
+ session,
+ &reserve_pub,
+ &value,
+ GNUNET_TIME_absolute_get (),
+ just));
+ json_decref (just);
+ FAILIF (GNUNET_OK !=
+ check_reserve (session,
+ &reserve_pub,
+ value.value,
+ value.fraction,
+ value.currency));
+ just = json_loads ("{ \"justification\":\"2\" }", 0, NULL);
+ FAILIF (GNUNET_OK !=
+ plugin->reserves_in_insert (plugin->cls,
+ session,
+ &reserve_pub,
+ &value,
+ GNUNET_TIME_absolute_get (),
+ just));
+ json_decref (just);
+ FAILIF (GNUNET_OK !=
+ check_reserve (session,
+ &reserve_pub,
+ value.value * 2,
+ value.fraction * 2,
+ value.currency));
+ dkp = create_denom_key_pair (1024, session,
+ &value,
+ &fee_withdraw,
+ &fee_deposit,
+ &fee_refresh);
+ RND_BLK(&cbc.h_coin_envelope);
+ RND_BLK(&cbc.reserve_sig);
+ cbc.denom_pub = dkp->pub;
+ cbc.sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
+ &cbc.h_coin_envelope,
+ sizeof (cbc.h_coin_envelope));
+ cbc.reserve_pub = reserve_pub;
+ cbc.amount_with_fee = value;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee));
+ FAILIF (GNUNET_OK !=
+ plugin->insert_withdraw_info (plugin->cls,
+ session,
+ &cbc));
+ FAILIF (GNUNET_OK !=
+ check_reserve (session,
+ &reserve_pub,
+ value.value,
+ value.fraction,
+ value.currency));
+ FAILIF (GNUNET_YES !=
+ plugin->get_withdraw_info (plugin->cls,
+ session,
+ &cbc.h_coin_envelope,
+ &cbc2));
+ FAILIF (NULL == cbc2.denom_pub.rsa_public_key);
+ FAILIF (0 != memcmp (&cbc2.reserve_sig,
+ &cbc.reserve_sig,
+ sizeof (cbc2.reserve_sig)));
+ FAILIF (0 != memcmp (&cbc2.reserve_pub,
+ &cbc.reserve_pub,
+ sizeof (cbc2.reserve_pub)));
+ FAILIF (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope,
+ cbc2.sig.rsa_signature,
+ dkp->pub.rsa_public_key));
+ rh = plugin->get_reserve_history (plugin->cls,
+ session,
+ &reserve_pub);
+ FAILIF (NULL == rh);
+ rh_head = rh;
+ for (cnt=0; NULL != rh_head; rh_head=rh_head->next, cnt++)
+ {
+ switch (rh_head->type)
+ {
+ case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
+ bt = rh_head->details.bank;
+ FAILIF (0 != memcmp (&bt->reserve_pub,
+ &reserve_pub,
+ sizeof (reserve_pub)));
+ /* this is the amount we trasferred twice*/
+ FAILIF (1 != bt->amount.value);
+ FAILIF (10 != bt->amount.fraction);
+ FAILIF (0 != strcmp (CURRENCY, bt->amount.currency));
+ FAILIF (NULL == bt->wire);
+ break;
+ case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
+ withdraw = rh_head->details.withdraw;
+ FAILIF (0 != memcmp (&withdraw->reserve_pub,
+ &reserve_pub,
+ sizeof (reserve_pub)));
+ FAILIF (0 != memcmp (&withdraw->h_coin_envelope,
+ &cbc.h_coin_envelope,
+ sizeof (cbc.h_coin_envelope)));
+ break;
+ }
+ }
+ FAILIF (3 != cnt);
+ /* Tests for deposits */
+ memset (&deposit, 0, sizeof (deposit));
+ RND_BLK (&deposit.coin.coin_pub);
+ deposit.coin.denom_pub = dkp->pub;
+ deposit.coin.denom_sig = cbc.sig;
+ RND_BLK (&deposit.csig);
+ RND_BLK (&deposit.merchant_pub);
+ RND_BLK (&deposit.h_contract);
+ RND_BLK (&deposit.h_wire);
+ wire = json_loads (json_wire_str, 0, NULL);
+ deposit.wire = wire;
+ deposit.transaction_id =
+ GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
+ deposit.amount_with_fee = value;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (CURRENCY, &deposit.deposit_fee));
+ FAILIF (GNUNET_OK !=
+ plugin->insert_deposit (plugin->cls,
+ session, &deposit));
+ FAILIF (GNUNET_YES !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit));
+ deposit2 = deposit;
+ deposit2.transaction_id++; /* should fail if transaction id is different */
+ FAILIF (GNUNET_NO !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit2));
+ deposit2.transaction_id = deposit.transaction_id;
+ RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
+ FAILIF (GNUNET_NO !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit2));
+ deposit2.merchant_pub = deposit.merchant_pub;
+ RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
+ FAILIF (GNUNET_NO !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit2));
+ FAILIF (GNUNET_OK != test_melting (session));
+
+ /* setup values for wire transfer aggregation data */
+ memset (&wtid, 42, sizeof (wtid));
+ memset (&merchant_pub_wt, 43, sizeof (merchant_pub_wt));
+ memset (&h_wire_wt, 44, sizeof (h_wire_wt));
+ memset (&h_contract_wt, 45, sizeof (h_contract_wt));
+ memset (&coin_pub_wt, 46, sizeof (coin_pub_wt));
+ transaction_id_wt = 47;
+ execution_time_wt = GNUNET_TIME_absolute_get ();
+ memset (&merchant_pub_wt, 48, sizeof (merchant_pub_wt));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY "KUDOS:1.000010",
+ &coin_value_wt));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY "KUDOS:0.000010",
+ &coin_fee_wt));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY "KUDOS:1.000000",
+ &transfer_value_wt));
+
+ FAILIF (GNUNET_NO !=
+ plugin->lookup_wire_transfer (plugin->cls,
+ session,
+ &wtid_wt,
+ &cb_wt_never,
+ NULL));
+ FAILIF (GNUNET_NO !=
+ plugin->wire_lookup_deposit_wtid (plugin->cls,
+ session,
+ &h_contract_wt,
+ &h_wire_wt,
+ &coin_pub_wt,
+ &merchant_pub_wt,
+ transaction_id_wt,
+ &cb_wtid_never,
+ NULL));
+ /* insert WT data */
+ FAILIF (GNUNET_OK !=
+ plugin->insert_aggregation_tracking (plugin->cls,
+ session,
+ &wtid_wt,
+ &merchant_pub_wt,
+ &h_wire_wt,
+ &h_contract_wt,
+ transaction_id_wt,
+ execution_time_wt,
+ &coin_pub_wt,
+ &coin_value_wt,
+ &coin_fee_wt));
+ FAILIF (GNUNET_OK !=
+ plugin->lookup_wire_transfer (plugin->cls,
+ session,
+ &wtid_wt,
+ &cb_wt_check,
+ &cb_wt_never));
+ FAILIF (GNUNET_OK !=
+ plugin->wire_lookup_deposit_wtid (plugin->cls,
+ session,
+ &h_contract_wt,
+ &h_wire_wt,
+ &coin_pub_wt,
+ &merchant_pub_wt,
+ transaction_id_wt,
+ &cb_wtid_check,
+ &cb_wtid_never));
+ result = 0;
+
+ drop:
+ if (NULL != wire)
+ json_decref (wire);
+ if (NULL != rh)
+ plugin->free_reserve_history (plugin->cls,
+ rh);
+ rh = NULL;
+ if (NULL != session)
+ GNUNET_break (GNUNET_OK ==
+ plugin->drop_temporary (plugin->cls,
+ session));
+ if (NULL != dkp)
+ destroy_denom_key_pair (dkp);
+ if (NULL != cbc.sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (cbc.sig.rsa_signature);
+ if (NULL != cbc2.denom_pub.rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub.rsa_public_key);
+ if (NULL != cbc2.sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature);
+ dkp = NULL;
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ plugin = NULL;
+}
+
+
+int
+main (int argc,
+ char *const argv[])
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ char *argv2[] = {
+ "test-exchange-db-<plugin_name>", /* will be replaced later */
+ "-c", "test-exchange-db-<plugin_name>.conf", /* will be replaced later */
+ NULL,
+ };
+ const char *plugin_name;
+ char *config_filename;
+ char *testname;
+
+ result = -1;
+ if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ plugin_name++;
+ (void) GNUNET_asprintf (&testname,
+ "test-exchange-db-%s", plugin_name);
+ (void) GNUNET_asprintf (&config_filename,
+ "%s.conf", testname);
+ argv2[0] = argv[0];
+ argv2[2] = config_filename;
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run ((sizeof (argv2)/sizeof (char *)) - 1, argv2,
+ testname,
+ "Test cases for exchange database helper functions.",
+ options, &run, NULL))
+ {
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return 3;
+ }
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return result;
+}
diff --git a/src/exchangedb/test_exchangedb_deposits.c b/src/exchangedb/test_exchangedb_deposits.c
new file mode 100644
index 000000000..09c65b2b2
--- /dev/null
+++ b/src/exchangedb/test_exchangedb_deposits.c
@@ -0,0 +1,152 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange/test_exchange_deposits.c
+ * @brief testcase for exchange deposits
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include <libpq-fe.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_pq_lib.h"
+#include "taler_exchangedb_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+#define EXCHANGE_CURRENCY "EUR"
+
+#define DB_URI "postgres:///taler"
+
+#define break_db_err(result) do { \
+ GNUNET_break(0); \
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
+ } while (0)
+
+/**
+ * Shorthand for exit jumps.
+ */
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+
+/**
+ * Should we not interact with a temporary table?
+ */
+static int persistent;
+
+/**
+ * Testcase result
+ */
+static int result;
+
+/**
+ * The plugin.
+ */
+static struct TALER_EXCHANGEDB_Plugin *plugin;
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ static const char wire[] = "{"
+ "\"type\":\"SEPA\","
+ "\"IBAN\":\"DE67830654080004822650\","
+ "\"NAME\":\"GNUNET E.V\","
+ "\"BIC\":\"GENODEF1SRL\""
+ "}";
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+ uint64_t transaction_id;
+ struct TALER_EXCHANGEDB_Session *session;
+
+ deposit = NULL;
+ EXITIF (NULL == (plugin = TALER_EXCHANGEDB_plugin_load (cfg)));
+ EXITIF (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ ! persistent));
+ session = plugin->get_session (plugin->cls,
+ ! persistent);
+ EXITIF (NULL == session);
+ deposit = GNUNET_malloc (sizeof (struct TALER_EXCHANGEDB_Deposit) + sizeof (wire));
+ /* Makeup a random coin public key */
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ deposit,
+ sizeof (struct TALER_EXCHANGEDB_Deposit));
+ /* Makeup a random 64bit transaction ID */
+ transaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT64_MAX);
+ deposit->transaction_id = GNUNET_htonll (transaction_id);
+ /* Random amount */
+ deposit->amount_with_fee.value =
+ htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
+ deposit->amount_with_fee.fraction =
+ htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
+ GNUNET_assert (strlen (EXCHANGE_CURRENCY) < sizeof (deposit->amount_with_fee.currency));
+ strcpy (deposit->amount_with_fee.currency, EXCHANGE_CURRENCY);
+ /* Copy wireformat */
+ deposit->wire = json_loads (wire, 0, NULL);
+ EXITIF (GNUNET_OK !=
+ plugin->insert_deposit (plugin->cls,
+ session,
+ deposit));
+ EXITIF (GNUNET_OK !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ deposit));
+ result = GNUNET_OK;
+
+ EXITIF_exit:
+ GNUNET_free_non_null (deposit);
+ if (NULL != plugin)
+ {
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ plugin = NULL;
+ }
+}
+
+
+int
+main (int argc,
+ char *const argv[])
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'T', "persist", NULL,
+ gettext_noop ("Use a persistent database table instead of a temporary one"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &persistent},
+ GNUNET_GETOPT_OPTION_END
+ };
+
+
+ persistent = GNUNET_NO;
+ result = GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run (argc, argv,
+ "test-exchange-deposits",
+ "testcase for exchange deposits",
+ options, &run, NULL))
+ return 3;
+ return (GNUNET_OK == result) ? 0 : 1;
+}
diff --git a/src/exchangedb/test_exchangedb_keyio.c b/src/exchangedb/test_exchangedb_keyio.c
new file mode 100644
index 000000000..2485da8ae
--- /dev/null
+++ b/src/exchangedb/test_exchangedb_keyio.c
@@ -0,0 +1,85 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014 GNUnet e. V. (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchange/test_exchange_common.c
+ * @brief test cases for some functions in exchange/exchange_common.c
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "gnunet/gnunet_util_lib.h"
+#include "taler_signatures.h"
+#include "taler_exchangedb_lib.h"
+
+#define RSA_KEY_SIZE 1024
+
+
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+
+int
+main (int argc,
+ const char *const argv[])
+{
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki;
+ char *enc;
+ size_t enc_size;
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki_read;
+ char *enc_read;
+ size_t enc_read_size;
+ char *tmpfile;
+ int ret;
+
+ ret = 1;
+ enc = NULL;
+ enc_read = NULL;
+ tmpfile = NULL;
+ dki.denom_priv.rsa_private_key = NULL;
+ dki_read.denom_priv.rsa_private_key = NULL;
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &dki.issue.signature,
+ sizeof (struct TALER_MasterSignatureP));
+ dki.denom_priv.rsa_private_key
+ = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEY_SIZE);
+ enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki.denom_priv.rsa_private_key,
+ &enc);
+ EXITIF (NULL == (tmpfile = GNUNET_DISK_mktemp ("test_exchange_common")));
+ EXITIF (GNUNET_OK != TALER_EXCHANGEDB_denomination_key_write (tmpfile, &dki));
+ EXITIF (GNUNET_OK != TALER_EXCHANGEDB_denomination_key_read (tmpfile, &dki_read));
+ enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key,
+ &enc_read);
+ EXITIF (enc_size != enc_read_size);
+ EXITIF (0 != memcmp (enc,
+ enc_read,
+ enc_size));
+ ret = 0;
+
+ EXITIF_exit:
+ GNUNET_free_non_null (enc);
+ if (NULL != tmpfile)
+ {
+ (void) unlink (tmpfile);
+ GNUNET_free (tmpfile);
+ }
+ GNUNET_free_non_null (enc_read);
+ if (NULL != dki.denom_priv.rsa_private_key)
+ GNUNET_CRYPTO_rsa_private_key_free (dki.denom_priv.rsa_private_key);
+ if (NULL != dki_read.denom_priv.rsa_private_key)
+ GNUNET_CRYPTO_rsa_private_key_free (dki_read.denom_priv.rsa_private_key);
+ return ret;
+}
diff --git a/src/exchangedb/test_perf_taler_exchangedb.c b/src/exchangedb/test_perf_taler_exchangedb.c
new file mode 100644
index 000000000..a4ec9591d
--- /dev/null
+++ b/src/exchangedb/test_perf_taler_exchangedb.c
@@ -0,0 +1,182 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/test_perf_taler_exchangedb.c
+ * @brief Exchange database performance analysis
+ * @author Nicolas Fournier
+ */
+#include "platform.h"
+#include "perf_taler_exchangedb_interpreter.h"
+#include "perf_taler_exchangedb_init.h"
+
+
+#define NB_DENOMINATION_INIT 2
+#define NB_DENOMINATION_SAVE 2
+
+#define NB_RESERVE_INIT 4
+#define NB_RESERVE_SAVE 1
+
+#define NB_DEPOSIT_INIT 1
+#define NB_DEPOSIT_SAVE 1
+
+#define NB_WITHDRAW_INIT 1
+#define NB_WITHDRAW_SAVE 1
+
+/**
+ * Allocate, copies and free all the data used in the interpreter
+ * Used to check for memory leaks
+ */
+static void
+test_allocate ()
+{
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, *dki_copy;
+ struct PERF_TALER_EXCHANGEDB_Reserve *reserve, *reserve_copy;
+ struct PERF_TALER_EXCHANGEDB_Coin *coin, *coin_copy;
+ struct TALER_EXCHANGEDB_Deposit *deposit, *deposit_copy;
+
+ dki = PERF_TALER_EXCHANGEDB_denomination_init ();
+ reserve = PERF_TALER_EXCHANGEDB_reserve_init ();
+ coin = PERF_TALER_EXCHANGEDB_coin_init (dki,
+ reserve);
+ deposit = PERF_TALER_EXCHANGEDB_deposit_init (coin);
+
+ dki_copy = PERF_TALER_EXCHANGEDB_denomination_copy (dki);
+ reserve_copy = PERF_TALER_EXCHANGEDB_reserve_copy (reserve);
+ coin_copy = PERF_TALER_EXCHANGEDB_coin_copy (coin);
+ deposit_copy = PERF_TALER_EXCHANGEDB_deposit_copy (deposit);
+
+ PERF_TALER_EXCHANGEDB_denomination_free (dki);
+ PERF_TALER_EXCHANGEDB_denomination_free (dki_copy);
+ PERF_TALER_EXCHANGEDB_reserve_free (reserve);
+ PERF_TALER_EXCHANGEDB_reserve_free (reserve_copy);
+ PERF_TALER_EXCHANGEDB_coin_free (coin);
+ PERF_TALER_EXCHANGEDB_coin_free (coin_copy);
+ PERF_TALER_EXCHANGEDB_deposit_free (deposit);
+ PERF_TALER_EXCHANGEDB_deposit_free (deposit_copy);
+}
+
+/**
+ * Runs the performances tests for the exchange database
+ * and logs the results using Gauger
+ */
+int
+main (int argc, char ** argv)
+{
+ int ret = 0;
+ struct PERF_TALER_EXCHANGEDB_Cmd init[] =
+ {
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END ("init")
+ };
+ struct PERF_TALER_EXCHANGEDB_Cmd benchmark[] =
+ {
+ // Denomination used to create coins
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("00 - Start of interpreter"),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("01 - denomination loop",
+ NB_DENOMINATION_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("01 - start transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert",
+ "01 - denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("01 - commit transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination",
+ "01 - denomination loop",
+ "01 - denomination",
+ NB_DENOMINATION_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("01 - denomination loop end",
+ "01 - denomination loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("01 - init denomination complete"),
+ // End of initialization
+ // Reserve initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("02 - init reserve loop",
+ NB_RESERVE_INIT),
+
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("02 - insert",
+ "02 - reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve",
+ "02 - init reserve loop",
+ "02 - reserve",
+ NB_RESERVE_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("02 - init reserve end loop",
+ "02 - init reserve loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("02 - reserve init complete"),
+ // End reserve init
+ // Withdrawal initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("03 - init withdraw loop",
+ NB_WITHDRAW_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("03 - start transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load",
+ "03 - init withdraw loop",
+ "01 - save denomination"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load",
+ "03 - init withdraw loop",
+ "02 - save reserve"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw",
+ "03 - denomination load",
+ "03 - reserve load"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert withdraw",
+ "03 - withdraw"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("03 - commit transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("03 - coin array",
+ "03 - init withdraw loop",
+ "03 - withdraw",
+ NB_WITHDRAW_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("03 - withdraw init end loop",
+ "03 - init withdraw loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("03 - withdraw init complete"),
+ //End of withdrawal initialization
+ //Deposit initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("04 - time start"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("04 - deposit init loop",
+ NB_DEPOSIT_INIT),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("04 - coin load",
+ "04 - deposit init loop",
+ "03 - coin array"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit",
+ "04 - coin load"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert deposit",
+ "04 - deposit"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array",
+ "04 - deposit init loop",
+ "04 - deposit",
+ NB_DEPOSIT_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("04 - deposit init loop end",
+ "04 - deposit init loop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("04 - time stop"),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("04 - gauger",
+ "04 - time start",
+ "04 - time stop",
+ "TEST",
+ "time to insert a deposit",
+ "deposit/sec",
+ NB_DEPOSIT_SAVE),
+ PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("04 - deposit init complete"),
+ // End of deposit initialization
+ PERF_TALER_EXCHANGEDB_INIT_CMD_END ("end"),
+ };
+
+ test_allocate ();
+ ret = PERF_TALER_EXCHANGEDB_run_benchmark ("test-perf-taler-exchangedb",
+ "./test-exchange-db-postgres.conf",
+ init,
+ benchmark);
+ if (GNUNET_SYSERR == ret)
+ return 1;
+ return 0;
+}
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 4d7ae3cb2..6f7f53acb 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -16,9 +16,9 @@ talerinclude_HEADERS = \
taler_crypto_lib.h \
taler_json_lib.h \
taler_util.h \
- taler_mint_service.h \
- taler_mintdb_lib.h \
- taler_mintdb_plugin.h \
+ taler_exchange_service.h \
+ taler_exchangedb_lib.h \
+ taler_exchangedb_plugin.h \
taler_pq_lib.h \
taler_signatures.h \
taler_wire_lib.h \
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 6056270fa..e948fa28a 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -140,23 +140,23 @@ struct TALER_TransferPrivateKeyP
/**
- * @brief Type of online public keys used by the mint to sign
+ * @brief Type of online public keys used by the exchange to sign
* messages.
*/
-struct TALER_MintPublicKeyP
+struct TALER_ExchangePublicKeyP
{
/**
- * Taler uses EdDSA for online mint message signing.
+ * Taler uses EdDSA for online exchange message signing.
*/
struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
};
/**
- * @brief Type of online public keys used by the mint to
+ * @brief Type of online public keys used by the exchange to
* sign messages.
*/
-struct TALER_MintPrivateKeyP
+struct TALER_ExchangePrivateKeyP
{
/**
* Taler uses EdDSA for online signatures sessions.
@@ -166,9 +166,9 @@ struct TALER_MintPrivateKeyP
/**
- * @brief Type of signatures used by the mint to sign messages online.
+ * @brief Type of signatures used by the exchange to sign messages online.
*/
-struct TALER_MintSignatureP
+struct TALER_ExchangeSignatureP
{
/**
* Taler uses EdDSA for online signatures sessions.
@@ -178,7 +178,7 @@ struct TALER_MintSignatureP
/**
- * @brief Type of the offline master public key used by the mint.
+ * @brief Type of the offline master public key used by the exchange.
*/
struct TALER_MasterPublicKeyP
{
@@ -214,7 +214,7 @@ struct TALER_AuditorSignatureP
/**
- * @brief Type of the offline master public keys used by the mint.
+ * @brief Type of the offline master public keys used by the exchange.
*/
struct TALER_MasterPrivateKeyP
{
@@ -226,7 +226,7 @@ struct TALER_MasterPrivateKeyP
/**
- * @brief Type of signatures by the offline master public key used by the mint.
+ * @brief Type of signatures by the offline master public key used by the exchange.
*/
struct TALER_MasterSignatureP
{
@@ -464,8 +464,8 @@ struct TALER_WireTransferIdentifierRawP
/**
* Binary information encoded in Crockford's Base32 in wire transfer
* subjects of transfers from Taler to a merchant. The actual value
- * is chosen by the mint and has no particular semantics, other than
- * being unique so that the mint can lookup details about the wire
+ * is chosen by the exchange and has no particular semantics, other than
+ * being unique so that the exchange can lookup details about the wire
* transfer when needed.
*/
struct TALER_WireTransferIdentifierP
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
new file mode 100644
index 000000000..566dec6f8
--- /dev/null
+++ b/src/include/taler_exchange_service.h
@@ -0,0 +1,1220 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/taler_exchange_service.h
+ * @brief C interface of libtalerexchange, a C library to use exchange's HTTP API
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#ifndef _TALER_EXCHANGE_SERVICE_H
+#define _TALER_EXCHANGE_SERVICE_H
+
+#include "taler_util.h"
+
+/* ********************* event loop *********************** */
+
+/**
+ * @brief Handle to this library context. This is where the
+ * main event loop logic lives.
+ */
+struct TALER_EXCHANGE_Context;
+
+
+/**
+ * Initialise a context. A context should be used for each thread and should
+ * not be shared among multiple threads.
+ *
+ * @return the context, NULL on error (failure to initialize)
+ */
+struct TALER_EXCHANGE_Context *
+TALER_EXCHANGE_init (void);
+
+
+/**
+ * Obtain the information for a select() call to wait until
+ * #TALER_EXCHANGE_perform() is ready again. Note that calling
+ * any other TALER_EXCHANGE-API may also imply that the library
+ * is again ready for #TALER_EXCHANGE_perform().
+ *
+ * Basically, a client should use this API to prepare for select(),
+ * then block on select(), then call #TALER_EXCHANGE_perform() and then
+ * start again until the work with the context is done.
+ *
+ * This function will NOT zero out the sets and assumes that @a max_fd
+ * and @a timeout are already set to minimal applicable values. It is
+ * safe to give this API FD-sets and @a max_fd and @a timeout that are
+ * already initialized to some other descriptors that need to go into
+ * the select() call.
+ *
+ * @param ctx context to get the event loop information for
+ * @param read_fd_set will be set for any pending read operations
+ * @param write_fd_set will be set for any pending write operations
+ * @param except_fd_set is here because curl_multi_fdset() has this argument
+ * @param max_fd set to the highest FD included in any set;
+ * if the existing sets have no FDs in it, the initial
+ * value should be "-1". (Note that `max_fd + 1` will need
+ * to be passed to select().)
+ * @param timeout set to the timeout in milliseconds (!); -1 means
+ * no timeout (NULL, blocking forever is OK), 0 means to
+ * proceed immediately with #TALER_EXCHANGE_perform().
+ */
+void
+TALER_EXCHANGE_get_select_info (struct TALER_EXCHANGE_Context *ctx,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *except_fd_set,
+ int *max_fd,
+ long *timeout);
+
+
+/**
+ * Run the main event loop for the Taler interaction.
+ *
+ * @param ctx the library context
+ */
+void
+TALER_EXCHANGE_perform (struct TALER_EXCHANGE_Context *ctx);
+
+
+/**
+ * Cleanup library initialisation resources. This function should be called
+ * after using this library to cleanup the resources occupied during library's
+ * initialisation.
+ *
+ * @param ctx the library context
+ */
+void
+TALER_EXCHANGE_fini (struct TALER_EXCHANGE_Context *ctx);
+
+
+/* ********************* /keys *********************** */
+
+
+/**
+ * List of possible options to be passed to
+ * #TALER_EXCHANGE_connect().
+ */
+enum TALER_EXCHANGE_Option
+{
+ /**
+ * Terminator (end of option list).
+ */
+ TALER_EXCHANGE_OPTION_END = 0
+
+};
+
+
+/**
+ * @brief Exchange's signature key
+ */
+struct TALER_EXCHANGE_SigningPublicKey
+{
+ /**
+ * The signing public key
+ */
+ struct TALER_ExchangePublicKeyP key;
+
+ /**
+ * Validity start time
+ */
+ struct GNUNET_TIME_Absolute valid_from;
+
+ /**
+ * Validity expiration time
+ */
+ struct GNUNET_TIME_Absolute valid_until;
+};
+
+
+/**
+ * @brief Public information about a exchange's denomination key
+ */
+struct TALER_EXCHANGE_DenomPublicKey
+{
+ /**
+ * The public key
+ */
+ struct TALER_DenominationPublicKey key;
+
+ /**
+ * The hash of the public key.
+ */
+ struct GNUNET_HashCode h_key;
+
+ /**
+ * Timestamp indicating when the denomination key becomes valid
+ */
+ struct GNUNET_TIME_Absolute valid_from;
+
+ /**
+ * Timestamp indicating when the denomination key can’t be used anymore to
+ * withdraw new coins.
+ */
+ struct GNUNET_TIME_Absolute withdraw_valid_until;
+
+ /**
+ * Timestamp indicating when coins of this denomination become invalid.
+ */
+ struct GNUNET_TIME_Absolute deposit_valid_until;
+
+ /**
+ * When do signatures with this denomination key become invalid?
+ * After this point, these signatures cannot be used in (legal)
+ * disputes anymore, as the Exchange is then allowed to destroy its side
+ * of the evidence. @e expire_legal is expected to be significantly
+ * larger than @e expire_spend (by a year or more).
+ */
+ struct GNUNET_TIME_Absolute expire_legal;
+
+ /**
+ * The value of this denomination
+ */
+ struct TALER_Amount value;
+
+ /**
+ * The applicable fee for withdrawing a coin of this denomination
+ */
+ struct TALER_Amount fee_withdraw;
+
+ /**
+ * The applicable fee to spend a coin of this denomination
+ */
+ struct TALER_Amount fee_deposit;
+
+ /**
+ *The applicable fee to melt/refresh a coin of this denomination
+ */
+ struct TALER_Amount fee_refresh;
+};
+
+
+/**
+ * @brief Information we get from the exchange about auditors.
+ */
+struct TALER_EXCHANGE_AuditorInformation
+{
+ /**
+ * Public key of the auditing institution.
+ */
+ struct TALER_AuditorPublicKeyP auditor_pub;
+
+ /**
+ * URL of the auditing institution. The application must check that
+ * this is an acceptable auditor for its purpose and also verify
+ * that the @a auditor_pub matches the auditor's public key given at
+ * that website. We expect that in practice software is going to
+ * often ship with an initial list of accepted auditors, just like
+ * browsers ship with a CA root store.
+ *
+ * This field may be NULL. (#3987).
+ */
+ const char *auditor_url;
+
+ /**
+ * Number of denomination keys audited by this auditor.
+ */
+ unsigned int num_denom_keys;
+
+ /**
+ * Array of length @a denom_keys with the denomination
+ * keys audited by this auditor. Note that the array
+ * elements point to the same locations as the entries
+ * in the key's main `denom_keys` array.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey **denom_keys;
+};
+
+
+/**
+ * @brief Information about keys from the exchange.
+ */
+struct TALER_EXCHANGE_Keys
+{
+
+ /**
+ * Long-term offline signing key of the exchange.
+ */
+ struct TALER_MasterPublicKeyP master_pub;
+
+ /**
+ * Array of the exchange's online signing keys.
+ */
+ struct TALER_EXCHANGE_SigningPublicKey *sign_keys;
+
+ /**
+ * Array of the exchange's denomination keys.
+ */
+ struct TALER_EXCHANGE_DenomPublicKey *denom_keys;
+
+ /**
+ * Array of the keys of the auditors of the exchange.
+ */
+ struct TALER_EXCHANGE_AuditorInformation *auditors;
+
+ /**
+ * Length of the @e sign_keys array.
+ */
+ unsigned int num_sign_keys;
+
+ /**
+ * Length of the @e denom_keys array.
+ */
+ unsigned int num_denom_keys;
+
+ /**
+ * Length of the @e auditors array.
+ */
+ unsigned int num_auditors;
+
+};
+
+
+/**
+ * Function called with information about who is auditing
+ * a particular exchange and what key the exchange is using.
+ *
+ * @param cls closure
+ * @param keys information about the various keys used
+ * by the exchange
+ */
+typedef void
+(*TALER_EXCHANGE_CertificationCallback) (void *cls,
+ const struct TALER_EXCHANGE_Keys *keys);
+
+
+/**
+ * @brief Handle to the exchange. This is where we interact with
+ * a particular exchange and keep the per-exchange information.
+ */
+struct TALER_EXCHANGE_Handle;
+
+
+/**
+ * Initialise a connection to the exchange. Will connect to the
+ * exchange and obtain information about the exchange's master public
+ * key and the exchange's auditor. The respective information will
+ * be passed to the @a cert_cb once available, and all future
+ * interactions with the exchange will be checked to be signed
+ * (where appropriate) by the respective master key.
+ *
+ * @param ctx the context
+ * @param url HTTP base URL for the exchange
+ * @param cert_cb function to call with the exchange's certification information
+ * @param cert_cb_cls closure for @a cert_cb
+ * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END.
+ * @return the exchange handle; NULL upon error
+ */
+struct TALER_EXCHANGE_Handle *
+TALER_EXCHANGE_connect (struct TALER_EXCHANGE_Context *ctx,
+ const char *url,
+ TALER_EXCHANGE_CertificationCallback cert_cb,
+ void *cert_cb_cls,
+ ...);
+
+
+/**
+ * Disconnect from the exchange.
+ *
+ * @param exchange the exchange handle
+ */
+void
+TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange);
+
+
+/**
+ * Obtain the keys from the exchange.
+ *
+ * @param exchange the exchange handle
+ * @return the exchange's key set
+ */
+const struct TALER_EXCHANGE_Keys *
+TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange);
+
+
+/**
+ * Test if the given @a pub is a the current signing key from the exchange
+ * according to @a keys.
+ *
+ * @param keys the exchange's key set
+ * @param pub claimed current online signing key for the exchange
+ * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key
+ */
+int
+TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_ExchangePublicKeyP *pub);
+
+
+/**
+ * Obtain the denomination key details from the exchange.
+ *
+ * @param keys the exchange's key set
+ * @param pk public key of the denomination to lookup
+ * @return details about the given denomination key, NULL if the key is not
+ * found
+ */
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_DenominationPublicKey *pk);
+
+
+/**
+ * Obtain the denomination key details from the exchange.
+ *
+ * @param keys the exchange's key set
+ * @param hc hash of the public key of the denomination to lookup
+ * @return details about the given denomination key
+ */
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys,
+ const struct GNUNET_HashCode *hc);
+
+
+/* ********************* /wire *********************** */
+
+
+/**
+ * @brief A Wire format inquiry handle
+ */
+struct TALER_EXCHANGE_WireHandle;
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * wire format inquiry request to a exchange.
+ *
+ * The callback is invoked multiple times, once for each supported @a
+ * method. Finally, it is invoked one more time with cls/0/NULL/NULL
+ * to indicate the end of the iteration. If any request fails to
+ * generate a valid response from the exchange, @a http_status will also
+ * be zero and the iteration will also end. Thus, the iteration
+ * always ends with a final call with an @a http_status of 0. If the
+ * @a http_status is already 0 on the first call, then the response to
+ * the /wire request was invalid. Later, clients can tell the
+ * difference between @a http_status of 0 indicating a failed
+ * /wire/method request and a regular end of the iteration by @a
+ * method being non-NULL. If the exchange simply correctly asserts that
+ * it does not support any methods, @a method will be NULL but the @a
+ * http_status will be #MHD_HTTP_OK for the first call (followed by a
+ * cls/0/NULL/NULL call to signal the end of the iteration).
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param method wire format method supported, i.e. "test" or "sepa", or NULL
+ * if already the /wire request failed.
+ * @param obj the received JSON reply, if successful this should be the wire
+ * format details as provided by /wire/METHOD/, or NULL if the
+ * reply was not in JSON format (in this case, the client might
+ * want to do an HTTP request to /wire/METHOD/ with a browser to
+ * provide more information to the user about the @a method).
+ */
+typedef void
+(*TALER_EXCHANGE_WireResultCallback) (void *cls,
+ unsigned int http_status,
+ const char *method,
+ json_t *obj);
+
+
+/**
+ * Obtain information about a exchange's wire instructions.
+ * A exchange may provide wire instructions for creating
+ * a reserve. The wire instructions also indicate
+ * which wire formats merchants may use with the exchange.
+ * This API is typically used by a wallet for wiring
+ * funds, and possibly by a merchant to determine
+ * supported wire formats.
+ *
+ * Note that while we return the (main) response verbatim to the
+ * caller for further processing, we do already verify that the
+ * response is well-formed (i.e. that signatures included in the
+ * response are all valid). If the exchange's reply is not well-formed,
+ * we return an HTTP status code of zero to @a cb.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param wire_cb the callback to call when a reply for this request is available
+ * @param wire_cb_cls closure for the above callback
+ * @return a handle for this request
+ */
+struct TALER_EXCHANGE_WireHandle *
+TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange,
+ TALER_EXCHANGE_WireResultCallback wire_cb,
+ void *wire_cb_cls);
+
+
+/**
+ * Cancel a wire information request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param wh the wire information request handle
+ */
+void
+TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh);
+
+
+/* ********************* /deposit *********************** */
+
+
+/**
+ * @brief A Deposit Handle
+ */
+struct TALER_EXCHANGE_DepositHandle;
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * deposit permission request to a exchange.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param obj the received JSON reply, should be kept as proof (and, in case of errors,
+ * be forwarded to the customer)
+ */
+typedef void
+(*TALER_EXCHANGE_DepositResultCallback) (void *cls,
+ unsigned int http_status,
+ json_t *obj);
+
+
+/**
+ * Submit a deposit permission to the exchange and get the exchange's
+ * response. This API is typically used by a merchant. Note that
+ * while we return the response verbatim to the caller for further
+ * processing, we do already verify that the response is well-formed
+ * (i.e. that signatures included in the response are all valid). If
+ * the exchange's reply is not well-formed, we return an HTTP status code
+ * of zero to @a cb.
+ *
+ * We also verify that the @a coin_sig is valid for this deposit
+ * request, and that the @a ub_sig is a valid signature for @a
+ * coin_pub. Also, the @a exchange must be ready to operate (i.e. have
+ * finished processing the /keys reply). If either check fails, we do
+ * NOT initiate the transaction with the exchange and instead return NULL.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param amount the amount to be deposited
+ * @param wire_deadline execution date, until which the merchant would like the exchange to settle the balance (advisory, the exchange cannot be
+ * forced to settle in the past or upon very short notice, but of course a well-behaved exchange will limit aggregation based on the advice received)
+ * @param wire_details the merchant’s account details, in a format supported by the exchange
+ * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
+ * @param coin_pub coin’s public key
+ * @param denom_pub denomination key with which the coin is signed
+ * @param denom_sig exchange’s unblinded signature of the coin
+ * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the exchange
+ * @param transaction_id transaction id for the transaction between merchant and customer
+ * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
+ * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed)
+ * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the inputs are invalid (i.e.
+ * signatures fail to verify). In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_DepositHandle *
+TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ json_t *wire_details,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_DenominationSignature *denom_sig,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ struct GNUNET_TIME_Absolute timestamp,
+ uint64_t transaction_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ TALER_EXCHANGE_DepositResultCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel a deposit permission request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param deposit the deposit permission request handle
+ */
+void
+TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit);
+
+
+/* ********************* /reserve/status *********************** */
+
+
+/**
+ * @brief A /reserve/status Handle
+ */
+struct TALER_EXCHANGE_ReserveStatusHandle;
+
+
+/**
+ * Ways how a reserve's balance may change.
+ */
+enum TALER_EXCHANGE_ReserveTransactionType {
+
+ /**
+ * Deposit into the reserve.
+ */
+ TALER_EXCHANGE_RTT_DEPOSIT,
+
+ /**
+ * Withdrawal from the reserve.
+ */
+ TALER_EXCHANGE_RTT_WITHDRAWAL
+
+};
+
+
+/**
+ * @brief Entry in the reserve's transaction history.
+ */
+struct TALER_EXCHANGE_ReserveHistory
+{
+
+ /**
+ * Type of the transaction.
+ */
+ enum TALER_EXCHANGE_ReserveTransactionType type;
+
+ /**
+ * Amount transferred (in or out).
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Details depending on @e type.
+ */
+ union {
+
+ /**
+ * Transaction details for the incoming transaction.
+ */
+ json_t *wire_in_details;
+
+ /**
+ * Signature authorizing the withdrawal for outgoing transaction.
+ */
+ json_t *out_authorization_sig;
+
+ } details;
+
+};
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * deposit permission request to a exchange.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param[in] json original response in JSON format (useful only for diagnostics)
+ * @param balance current balance in the reserve, NULL on error
+ * @param history_length number of entries in the transaction history, 0 on error
+ * @param history detailed transaction history, NULL on error
+ */
+typedef void
+(*TALER_EXCHANGE_ReserveStatusResultCallback) (void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct TALER_Amount *balance,
+ unsigned int history_length,
+ const struct TALER_EXCHANGE_ReserveHistory *history);
+
+
+/**
+ * Submit a request to obtain the transaction history of a reserve
+ * from the exchange. Note that while we return the full response to the
+ * caller for further processing, we do already verify that the
+ * response is well-formed (i.e. that signatures included in the
+ * response are all valid and add up to the balance). If the exchange's
+ * reply is not well-formed, we return an HTTP status code of zero to
+ * @a cb.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param reserve_pub public key of the reserve to inspect
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the inputs are invalid (i.e.
+ * signatures fail to verify). In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_ReserveStatusHandle *
+TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ TALER_EXCHANGE_ReserveStatusResultCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel a withdraw status request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param wsh the withdraw status request handle
+ */
+void
+TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *wsh);
+
+
+/* ********************* /reserve/withdraw *********************** */
+
+
+/**
+ * @brief A /reserve/withdraw Handle
+ */
+struct TALER_EXCHANGE_ReserveWithdrawHandle;
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * deposit permission request to a exchange.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param sig signature over the coin, NULL on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+typedef void
+(*TALER_EXCHANGE_ReserveWithdrawResultCallback) (void *cls,
+ unsigned int http_status,
+ const struct TALER_DenominationSignature *sig,
+ json_t *full_response);
+
+
+/**
+ * Withdraw a coin from the exchange using a /reserve/withdraw request. This
+ * API is typically used by a wallet. Note that to ensure that no
+ * money is lost in case of hardware failures, the caller must have
+ * committed (most of) the arguments to disk before calling, and be
+ * ready to repeat the request with the same arguments in case of
+ * failures.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param pk kind of coin to create
+ * @param reserve_priv private key of the reserve to withdraw from
+ * @param coin_priv where to store the coin's private key,
+ * caller must have committed this value to disk before the call (with @a pk)
+ * @param blinding_key where to store the coin's blinding key
+ * caller must have committed this value to disk before the call (with @a pk)
+ * @param res_cb the callback to call when the final result for this request is available
+ * @param res_cb_cls closure for @a res_cb
+ * @return NULL
+ * if the inputs are invalid (i.e. denomination key not with this exchange).
+ * In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_ReserveWithdrawHandle *
+TALER_EXCHANGE_reserve_withdraw (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_EXCHANGE_DenomPublicKey *pk,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+ const struct TALER_DenominationBlindingKey *blinding_key,
+ TALER_EXCHANGE_ReserveWithdrawResultCallback res_cb,
+ void *res_cb_cls);
+
+
+/**
+ * Cancel a withdraw status request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param sign the withdraw sign request handle
+ */
+void
+TALER_EXCHANGE_reserve_withdraw_cancel (struct TALER_EXCHANGE_ReserveWithdrawHandle *sign);
+
+
+/* ********************* /refresh/melt+reveal ***************************** */
+
+
+/**
+ * Melt (partially spent) coins to obtain fresh coins that are
+ * unlinkable to the original coin(s). Note that melting more
+ * than one coin in a single request will make those coins linkable,
+ * so the safest operation only melts one coin at a time.
+ *
+ * This API is typically used by a wallet. Note that to ensure that
+ * no money is lost in case of hardware failures, is operation does
+ * not actually initiate the request. Instead, it generates a buffer
+ * which the caller must store before proceeding with the actual call
+ * to #TALER_EXCHANGE_refresh_melt() that will generate the request.
+ *
+ * This function does verify that the given request data is internally
+ * consistent. However, the @a melts_sigs are only verified if @a
+ * check_sigs is set to #GNUNET_YES, as this may be relatively
+ * expensive and should be redundant.
+ *
+ * Aside from some non-trivial cryptographic operations that might
+ * take a bit of CPU time to complete, this function returns
+ * its result immediately and does not start any asynchronous
+ * processing. This function is also thread-safe.
+ *
+ * @param num_melts number of coins that are being melted (typically 1)
+ * @param melt_privs array of @a num_melts private keys of the coins to melt
+ * @param melt_amounts array of @a num_melts amounts specifying how much
+ * each coin will contribute to the melt (including fee)
+ * @param melt_sigs array of @a num_melts signatures affirming the
+ * validity of the public keys corresponding to the
+ * @a melt_privs private keys
+ * @param melt_pks array of @a num_melts denomination key information
+ * records corresponding to the @a melt_sigs
+ * validity of the keys
+ * @param check_sigs verify the validity of the signatures of @a melt_sigs
+ * @param fresh_pks_len length of the @a pks array
+ * @param fresh_pks array of @a pks_len denominations of fresh coins to create
+ * @param[out] res_size set to the size of the return value, or 0 on error
+ * @return NULL
+ * if the inputs are invalid (i.e. denomination key not with this exchange).
+ * Otherwise, pointer to a buffer of @a res_size to store persistently
+ * before proceeding to #TALER_EXCHANGE_refresh_melt().
+ * Non-null results should be freed using #GNUNET_free().
+ */
+char *
+TALER_EXCHANGE_refresh_prepare (unsigned int num_melts,
+ const struct TALER_CoinSpendPrivateKeyP *melt_privs,
+ const struct TALER_Amount *melt_amounts,
+ const struct TALER_DenominationSignature *melt_sigs,
+ const struct TALER_EXCHANGE_DenomPublicKey *melt_pks,
+ int check_sigs,
+ unsigned int fresh_pks_len,
+ const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks,
+ size_t *res_size);
+
+
+/* ********************* /refresh/melt ***************************** */
+
+/**
+ * @brief A /refresh/melt Handle
+ */
+struct TALER_EXCHANGE_RefreshMeltHandle;
+
+
+/**
+ * Callbacks of this type are used to notify the application about the
+ * result of the /refresh/melt stage. If successful, the @a noreveal_index
+ * should be committed to disk prior to proceeding #TALER_EXCHANGE_refresh_reveal().
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
+ * UINT16_MAX on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+typedef void
+(*TALER_EXCHANGE_RefreshMeltCallback) (void *cls,
+ unsigned int http_status,
+ uint16_t noreveal_index,
+ json_t *full_response);
+
+
+/**
+ * Submit a melt request to the exchange and get the exchange's
+ * response.
+ *
+ * This API is typically used by a wallet. Note that to ensure that
+ * no money is lost in case of hardware failures, the provided
+ * argument should have been constructed using
+ * #TALER_EXCHANGE_refresh_prepare and committed to persistent storage
+ * prior to calling this function.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param refresh_data_length size of the @a refresh_data (returned
+ * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare())
+ * @param refresh_data the refresh data as returned from
+ #TALER_EXCHANGE_refresh_prepare())
+ * @param melt_cb the callback to call with the result
+ * @param melt_cb_cls closure for @a melt_cb
+ * @return a handle for this request; NULL if the argument was invalid.
+ * In this case, neither callback will be called.
+ */
+struct TALER_EXCHANGE_RefreshMeltHandle *
+TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange,
+ size_t refresh_data_length,
+ const char *refresh_data,
+ TALER_EXCHANGE_RefreshMeltCallback melt_cb,
+ void *melt_cb_cls);
+
+
+/**
+ * Cancel a refresh melt request. This function cannot be used
+ * on a request handle if the callback was already invoked.
+ *
+ * @param rmh the refresh handle
+ */
+void
+TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh);
+
+
+/* ********************* /refresh/reveal ***************************** */
+
+
+/**
+ * Callbacks of this type are used to return the final result of
+ * submitting a refresh request to a exchange. If the operation was
+ * successful, this function returns the signatures over the coins
+ * that were remelted. The @a coin_privs and @a sigs arrays give the
+ * coins in the same order (and should have the same length) in which
+ * the original request specified the respective denomination keys.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
+ * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
+ * @param sigs array of signature over @a num_coins coins, NULL on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+typedef void
+(*TALER_EXCHANGE_RefreshRevealCallback) (void *cls,
+ unsigned int http_status,
+
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPrivateKeyP *coin_privs,
+ const struct TALER_DenominationSignature *sigs,
+ json_t *full_response);
+
+
+/**
+ * @brief A /refresh/reveal Handle
+ */
+struct TALER_EXCHANGE_RefreshRevealHandle;
+
+
+/**
+ * Submit a /refresh/reval request to the exchange and get the exchange's
+ * response.
+ *
+ * This API is typically used by a wallet. Note that to ensure that
+ * no money is lost in case of hardware failures, the provided
+ * arguments should have been committed to persistent storage
+ * prior to calling this function.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param refresh_data_length size of the @a refresh_data (returned
+ * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare())
+ * @param refresh_data the refresh data as returned from
+ #TALER_EXCHANGE_refresh_prepare())
+ * @param noreveal_index response from the exchange to the
+ * #TALER_EXCHANGE_refresh_melt() invocation
+ * @param reveal_cb the callback to call with the final result of the
+ * refresh operation
+ * @param reveal_cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the argument was invalid.
+ * In this case, neither callback will be called.
+ */
+struct TALER_EXCHANGE_RefreshRevealHandle *
+TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
+ size_t refresh_data_length,
+ const char *refresh_data,
+ uint16_t noreveal_index,
+ TALER_EXCHANGE_RefreshRevealCallback reveal_cb,
+ void *reveal_cb_cls);
+
+
+/**
+ * Cancel a refresh reveal request. This function cannot be used
+ * on a request handle if the callback was already invoked.
+ *
+ * @param rrh the refresh reval handle
+ */
+void
+TALER_EXCHANGE_refresh_reveal_cancel (struct TALER_EXCHANGE_RefreshRevealHandle *rrh);
+
+
+/* ********************* /refresh/link ***************************** */
+
+
+/**
+ * @brief A /refresh/link Handle
+ */
+struct TALER_EXCHANGE_RefreshLinkHandle;
+
+
+/**
+ * Callbacks of this type are used to return the final result of
+ * submitting a /refresh/link request to a exchange. If the operation was
+ * successful, this function returns the signatures over the coins
+ * that were created when the original coin was melted.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
+ * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
+ * @param sigs array of signature over @a num_coins coins, NULL on error
+ * @param pubs array of public keys for the @a sigs, NULL on error
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+typedef void
+(*TALER_EXCHANGE_RefreshLinkCallback) (void *cls,
+ unsigned int http_status,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPrivateKeyP *coin_privs,
+ const struct TALER_DenominationSignature *sigs,
+ const struct TALER_DenominationPublicKey *pubs,
+ json_t *full_response);
+
+
+/**
+ * Submit a link request to the exchange and get the exchange's response.
+ *
+ * This API is typically not used by anyone, it is more a threat
+ * against those trying to receive a funds transfer by abusing the
+ * /refresh protocol.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param coin_priv private key to request link data for
+ * @param link_cb the callback to call with the useful result of the
+ * refresh operation the @a coin_priv was involved in (if any)
+ * @param link_cb_cls closure for @a link_cb
+ * @return a handle for this request
+ */
+struct TALER_EXCHANGE_RefreshLinkHandle *
+TALER_EXCHANGE_refresh_link (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+ TALER_EXCHANGE_RefreshLinkCallback link_cb,
+ void *link_cb_cls);
+
+
+/**
+ * Cancel a refresh link request. This function cannot be used
+ * on a request handle if the callback was already invoked.
+ *
+ * @param rlh the refresh link handle
+ */
+void
+TALER_EXCHANGE_refresh_link_cancel (struct TALER_EXCHANGE_RefreshLinkHandle *rlh);
+
+
+/* ********************* /admin/add/incoming *********************** */
+
+
+/**
+ * @brief A /admin/add/incoming Handle
+ */
+struct TALER_EXCHANGE_AdminAddIncomingHandle;
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting
+ * information about an incoming transaction to a exchange.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param full_response full response from the exchange (for logging, in case of errors)
+ */
+typedef void
+(*TALER_EXCHANGE_AdminAddIncomingResultCallback) (void *cls,
+ unsigned int http_status,
+ json_t *full_response);
+
+
+/**
+ * Notify the exchange that we have received an incoming transaction
+ * which fills a reserve. Note that this API is an administrative
+ * API and thus not accessible to typical exchange clients, but only
+ * to the operators of the exchange.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param reserve_pub public key of the reserve
+ * @param amount amount that was deposited
+ * @param execution_date when did we receive the amount
+ * @param wire wire details
+ * @param res_cb the callback to call when the final result for this request is available
+ * @param res_cb_cls closure for the above callback
+ * @return NULL
+ * if the inputs are invalid (i.e. invalid amount).
+ * In this case, the callback is not called.
+ */
+struct TALER_EXCHANGE_AdminAddIncomingHandle *
+TALER_EXCHANGE_admin_add_incoming (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute execution_date,
+ const json_t *wire,
+ TALER_EXCHANGE_AdminAddIncomingResultCallback res_cb,
+ void *res_cb_cls);
+
+
+/**
+ * Cancel an add incoming. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param aai the admin add incoming request handle
+ */
+void
+TALER_EXCHANGE_admin_add_incoming_cancel (struct TALER_EXCHANGE_AdminAddIncomingHandle *aai);
+
+
+/* ********************* /wire/deposits *********************** */
+
+/**
+ * @brief A /wire/deposits Handle
+ */
+struct TALER_EXCHANGE_WireDepositsHandle;
+
+
+/**
+ * Details for one of the /deposit operations that the
+ * exchange combined into a single wire transfer.
+ */
+struct TALER_WireDepositDetails
+{
+ /**
+ * Hash of the contract.
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Which coin was deposited?
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Value of the deposit (including fee).
+ */
+ struct TALER_Amount coin_value;
+
+ /**
+ * Fee charged by the exchange for the deposit.
+ */
+ struct TALER_Amount coin_fee;
+
+ /**
+ * Merchant's transaction identifier.
+ */
+ uint64_t transaction_id;
+
+};
+
+
+/**
+ * Function called with detailed wire transfer data, including all
+ * of the coin transactions that were combined into the wire transfer.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param json original json reply (may include signatures, those have then been
+ * validated already)
+ * @param wtid extracted wire transfer identifier, or NULL if the exchange could
+ * not provide any (set only if @a http_status is #MHD_HTTP_OK)
+ * @param total_amount total amount of the wire transfer, or NULL if the exchange could
+ * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ * @param details_length length of the @a details array
+ * @param details array with details about the combined transactions
+ */
+typedef void
+(*TALER_EXCHANGE_WireDepositsCallback)(void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_Amount *total_amount,
+ unsigned int details_length,
+ const struct TALER_WireDepositDetails *details);
+
+
+/**
+ * Query the exchange about which transactions were combined
+ * to create a wire transfer.
+ *
+ * @param exchange exchange to query
+ * @param wtid raw wire transfer identifier to get information about
+ * @param cb callback to call
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel operation
+ */
+struct TALER_EXCHANGE_WireDepositsHandle *
+TALER_EXCHANGE_wire_deposits (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_EXCHANGE_WireDepositsCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel wire deposits request. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param wdh the wire deposits request handle
+ */
+void
+TALER_EXCHANGE_wire_deposits_cancel (struct TALER_EXCHANGE_WireDepositsHandle *wdh);
+
+
+/* ********************* /deposit/wtid *********************** */
+
+
+/**
+ * @brief A /deposit/wtid Handle
+ */
+struct TALER_EXCHANGE_DepositWtidHandle;
+
+
+/**
+ * Function called with detailed wire transfer data.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code we got, 0 on exchange protocol violation
+ * @param json original json reply (may include signatures, those have then been
+ * validated already)
+ * @param wtid wire transfer identifier used by the exchange, NULL if exchange did not
+ * yet execute the transaction
+ * @param execution_time actual or planned execution time for the wire transfer
+ * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
+ */
+typedef void
+(*TALER_EXCHANGE_DepositWtidCallback)(void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_Amount *coin_contribution);
+
+
+/**
+ * Obtain the wire transfer details for a given deposit.
+ *
+ * @param exchange the exchange to query
+ * @param merchant_priv the merchant's private key
+ * @param h_wire hash of merchant's wire transfer details
+ * @param h_contract hash of the contract
+ * @param coin_pub public key of the coin
+ * @param transaction_id transaction identifier
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return handle to abort request
+ */
+struct TALER_EXCHANGE_DepositWtidHandle *
+TALER_EXCHANGE_deposit_wtid (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t transaction_id,
+ TALER_EXCHANGE_DepositWtidCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel deposit wtid request. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param dwh the wire deposits request handle
+ */
+void
+TALER_EXCHANGE_deposit_wtid_cancel (struct TALER_EXCHANGE_DepositWtidHandle *dwh);
+
+
+#endif /* _TALER_EXCHANGE_SERVICE_H */
diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h
new file mode 100644
index 000000000..347ad0650
--- /dev/null
+++ b/src/include/taler_exchangedb_lib.h
@@ -0,0 +1,291 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/taler_exchangedb_lib.h
+ * @brief IO operations for the exchange's private keys
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGEDB_LIB_H
+#define TALER_EXCHANGEDB_LIB_H
+
+#include "taler_signatures.h"
+
+/**
+ * Subdirectroy under the exchange's base directory which contains
+ * the exchange's signing keys.
+ */
+#define TALER_EXCHANGEDB_DIR_SIGNING_KEYS "signkeys"
+
+/**
+ * Subdirectory under the exchange's base directory which contains
+ * the exchange's denomination keys.
+ */
+#define TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS "denomkeys"
+
+/**
+ * Subdirectory under the exchange's base directory which contains
+ * the exchange's auditing information.
+ */
+#define TALER_EXCHANGEDB_DIR_AUDITORS "auditors"
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * @brief On disk format used for a exchange signing key. Signing keys are used
+ * by the exchange to affirm its messages, but not to create coins.
+ * Includes the private key followed by the public information about
+ * the signing key.
+ */
+struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP
+{
+ /**
+ * Private key part of the exchange's signing key.
+ */
+ struct TALER_ExchangePrivateKeyP signkey_priv;
+
+ /**
+ * Public information about a exchange signing key.
+ */
+ struct TALER_ExchangeSigningKeyValidityPS issue;
+};
+
+
+/**
+ * Information about a denomination key.
+ */
+struct TALER_EXCHANGEDB_DenominationKeyInformationP
+{
+
+ /**
+ * Signature over this struct to affirm the validity of the key.
+ */
+ struct TALER_MasterSignatureP signature;
+
+ /**
+ * Signed properties of the denomination key.
+ */
+ struct TALER_DenominationKeyValidityPS properties;
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * @brief All information about a denomination key (which is used to
+ * sign coins into existence).
+ */
+struct TALER_EXCHANGEDB_DenominationKeyIssueInformation
+{
+ /**
+ * The private key of the denomination. Will be NULL if the private
+ * key is not available (this is the case after the key has expired
+ * for signing coins, but is still valid for depositing coins).
+ */
+ struct TALER_DenominationPrivateKey denom_priv;
+
+ /**
+ * Decoded denomination public key (the hash of it is in
+ * @e issue, but we sometimes need the full public key as well).
+ */
+ struct TALER_DenominationPublicKey denom_pub;
+
+ /**
+ * Signed public information about a denomination key.
+ */
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
+};
+
+
+/**
+ * @brief Iterator over signing keys.
+ *
+ * @param cls closure
+ * @param filename name of the file the key came from
+ * @param ski the sign key
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+typedef int
+(*TALER_EXCHANGEDB_SigningKeyIterator)(void *cls,
+ const char *filename,
+ const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski);
+
+
+/**
+ * Call @a it for each signing key found in the @a exchange_base_dir.
+ *
+ * @param exchange_base_dir base directory for the exchange,
+ * the signing keys must be in the #TALER_EXCHANGEDB_DIR_SIGNING_KEYS
+ * subdirectory
+ * @param it function to call on each signing key
+ * @param it_cls closure for @a it
+ * @return number of files found (may not match
+ * number of keys given to @a it as malformed
+ * files are simply skipped), -1 on error
+ */
+int
+TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir,
+ TALER_EXCHANGEDB_SigningKeyIterator it,
+ void *it_cls);
+
+
+
+/**
+ * @brief Iterator over denomination keys.
+ *
+ * @param cls closure
+ * @param dki the denomination key
+ * @param alias coin alias
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+typedef int
+(*TALER_EXCHANGEDB_DenominationKeyIterator)(void *cls,
+ const char *alias,
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
+
+
+/**
+ * Call @a it for each denomination key found in the @a exchange_base_dir.
+ *
+ * @param exchange_base_dir base directory for the exchange,
+ * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
+ * subdirectory
+ * @param it function to call on each denomination key found
+ * @param it_cls closure for @a it
+ * @return -1 on error, 0 if no files were found, otherwise
+ * a positive number (however, even with a positive
+ * number it is possible that @a it was never called
+ * as maybe none of the files were well-formed)
+ */
+int
+TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
+ TALER_EXCHANGEDB_DenominationKeyIterator it,
+ void *it_cls);
+
+
+/**
+ * Exports a denomination key to the given file.
+ *
+ * @param filename the file where to write the denomination key
+ * @param dki the denomination key
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
+ */
+int
+TALER_EXCHANGEDB_denomination_key_write (const char *filename,
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
+
+
+/**
+ * Import a denomination key from the given file.
+ *
+ * @param filename the file to import the key from
+ * @param[out] dki set to the imported denomination key
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+int
+TALER_EXCHANGEDB_denomination_key_read (const char *filename,
+ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
+
+
+/**
+ * @brief Iterator over auditor information.
+ *
+ * @param cls closure
+ * @param apub the auditor's public key
+ * @param mpub the exchange's public key (as expected by the auditor)
+ * @param dki_len length of @a asig and @a dki arrays
+ * @param asigs array of the auditor's signatures over the @a dks, of length @a dki_len
+ * @param dki array of denomination coin data signed by the auditor, of length @a dki_len
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+typedef int
+(*TALER_EXCHANGEDB_AuditorIterator)(void *cls,
+ const struct TALER_AuditorPublicKeyP *apub,
+ const struct TALER_MasterPublicKeyP *mpub,
+ unsigned int dki_len,
+ const struct TALER_AuditorSignatureP *asigs,
+ const struct TALER_DenominationKeyValidityPS *dki);
+
+
+/**
+ * Call @a it with information for each auditor found in the @a exchange_base_dir.
+ *
+ * @param exchange_base_dir base directory for the exchange,
+ * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
+ * subdirectory
+ * @param it function to call with auditor information
+ * @param it_cls closure for @a it
+ * @return -1 on error, 0 if no files were found, otherwise
+ * a positive number (however, even with a positive
+ * number it is possible that @a it was never called
+ * as maybe none of the files were well-formed)
+ */
+int
+TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir,
+ TALER_EXCHANGEDB_AuditorIterator it,
+ void *it_cls);
+
+
+/**
+ * Write auditor information to the given file.
+ *
+ * @param filename the file where to write the auditor information to
+ * @param apub the auditor's public key
+ * @param asigs the auditor's signatures, array of length @a dki_len
+ * @param mpub the exchange's public key (as expected by the auditor)
+ * @param dki_len length of @a dki and @a asigs arrays
+ * @param dki array of denomination coin data signed by the auditor
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
+ */
+int
+TALER_EXCHANGEDB_auditor_write (const char *filename,
+ const struct TALER_AuditorPublicKeyP *apub,
+ const struct TALER_AuditorSignatureP *asigs,
+ const struct TALER_MasterPublicKeyP *mpub,
+ unsigned int dki_len,
+ const struct TALER_DenominationKeyValidityPS *dki);
+
+
+/**
+ * Initialize the plugin.
+ *
+ * @param cfg configuration to use
+ * @return NULL on failure
+ */
+struct TALER_EXCHANGEDB_Plugin *
+TALER_EXCHANGEDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Shutdown the plugin.
+ *
+ * @param plugin plugin to unload
+ */
+void
+TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin);
+
+
+
+#endif
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
new file mode 100644
index 000000000..aecb050a7
--- /dev/null
+++ b/src/include/taler_exchangedb_plugin.h
@@ -0,0 +1,1431 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file include/taler_exchangedb_plugin.h
+ * @brief Low-level (statement-level) database access for the exchange
+ * @author Florian Dold
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGEDB_PLUGIN_H
+#define TALER_EXCHANGEDB_PLUGIN_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchangedb_lib.h"
+
+
+/**
+ * @brief Information we keep on bank transfer(s) that established a reserve.
+ */
+struct TALER_EXCHANGEDB_BankTransfer
+{
+
+ /**
+ * Public key of the reserve that was filled.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Amount that was transferred to the exchange.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * When did the exchange receive the incoming transaction?
+ * (This is the execution date of the exchange's database,
+ * the execution date of the bank should be in @e wire).
+ */
+ struct GNUNET_TIME_Absolute execution_date;
+
+ /**
+ * Detailed wire information about the transaction.
+ */
+ json_t *wire;
+
+};
+
+
+/**
+ * @brief A summary of a Reserve
+ */
+struct TALER_EXCHANGEDB_Reserve
+{
+ /**
+ * The reserve's public key. This uniquely identifies the reserve
+ */
+ struct TALER_ReservePublicKeyP pub;
+
+ /**
+ * The balance amount existing in the reserve
+ */
+ struct TALER_Amount balance;
+
+ /**
+ * The expiration date of this reserve
+ */
+ struct GNUNET_TIME_Absolute expiry;
+};
+
+
+/**
+ * @brief Information we keep for a withdrawn coin to reproduce
+ * the /withdraw operation if needed, and to have proof
+ * that a reserve was drained by this amount.
+ */
+struct TALER_EXCHANGEDB_CollectableBlindcoin
+{
+
+ /**
+ * Our signature over the (blinded) coin.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Denomination key (which coin was generated).
+ */
+ struct TALER_DenominationPublicKey denom_pub;
+
+ /**
+ * Value of the coin being exchangeed (matching the denomination key)
+ * plus the transaction fee. We include this in what is being
+ * signed so that we can verify a reserve's remaining total balance
+ * without needing to access the respective denomination key
+ * information each time.
+ */
+ struct TALER_Amount amount_with_fee;
+
+ /**
+ * Withdrawl fee charged by the exchange. This must match the Exchange's
+ * denomination key's withdrawl fee. If the client puts in an
+ * invalid withdrawl fee (too high or too low) that does not match
+ * the Exchange's denomination key, the withdraw operation is invalid
+ * and will be rejected by the exchange. The @e amount_with_fee minus
+ * the @e withdraw_fee is must match the value of the generated
+ * coin. We include this in what is being signed so that we can
+ * verify a exchange's accounting without needing to access the
+ * respective denomination key information each time.
+ */
+ struct TALER_Amount withdraw_fee;
+
+ /**
+ * Public key of the reserve that was drained.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Hash over the blinded message, needed to verify
+ * the @e reserve_sig.
+ */
+ struct GNUNET_HashCode h_coin_envelope;
+
+ /**
+ * Signature confirming the withdrawl, matching @e reserve_pub,
+ * @e denom_pub and @e h_coin_envelope.
+ */
+ struct TALER_ReserveSignatureP reserve_sig;
+};
+
+
+
+/**
+ * @brief Types of operations on a reserved.
+ */
+enum TALER_EXCHANGEDB_ReserveOperation
+{
+ /**
+ * Money was deposited into the reserve via a bank transfer.
+ */
+ TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE = 0,
+
+ /**
+ * A Coin was withdrawn from the reserve using /withdraw.
+ */
+ TALER_EXCHANGEDB_RO_WITHDRAW_COIN = 1
+};
+
+
+/**
+ * @brief Reserve history as a linked list. Lists all of the transactions
+ * associated with this reserve (such as the bank transfers that
+ * established the reserve and all /withdraw operations we have done
+ * since).
+ */
+struct TALER_EXCHANGEDB_ReserveHistory
+{
+
+ /**
+ * Next entry in the reserve history.
+ */
+ struct TALER_EXCHANGEDB_ReserveHistory *next;
+
+ /**
+ * Type of the event, determins @e details.
+ */
+ enum TALER_EXCHANGEDB_ReserveOperation type;
+
+ /**
+ * Details of the operation, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details about a bank transfer to the exchange.
+ */
+ struct TALER_EXCHANGEDB_BankTransfer *bank;
+
+ /**
+ * Details about a /withdraw operation.
+ */
+ struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw;
+
+ } details;
+
+};
+
+
+/**
+ * @brief Specification for a /deposit operation. The combination of
+ * the coin's public key, the merchant's public key and the
+ * transaction ID must be unique. While a coin can (theoretically) be
+ * deposited at the same merchant twice (with partial spending), the
+ * merchant must either use a different public key or a different
+ * transaction ID for the two transactions. The same coin must not
+ * be used twice at the same merchant for the same transaction
+ * (as determined by transaction ID). (Note: we might want to
+ * fix #3819 and include at least h_contract as well.)
+ */
+struct TALER_EXCHANGEDB_Deposit
+{
+ /**
+ * Information about the coin that is being deposited.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * ECDSA signature affirming that the customer intends
+ * this coin to be deposited at the merchant identified
+ * by @e h_wire in relation to the contract identified
+ * by @e h_contract.
+ */
+ struct TALER_CoinSpendSignatureP csig;
+
+ /**
+ * Public key of the merchant. Enables later identification
+ * of the merchant in case of a need to rollback transactions.
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * Hash over the contract between merchant and customer
+ * (remains unknown to the Exchange).
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Hash of the (canonical) representation of @e wire, used
+ * to check the signature on the request. Generated by
+ * the exchange from the detailed wire data provided by the
+ * merchant.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Detailed wire information for executing the transaction.
+ */
+ json_t *wire;
+
+ /**
+ * Merchant-generated transaction ID to detect duplicate
+ * transactions.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * Time when this request was generated. Used, for example, to
+ * assess when (roughly) the income was achieved for tax purposes.
+ * Note that the Exchange will only check that the timestamp is not "too
+ * far" into the future (i.e. several days). The fact that the
+ * timestamp falls within the validity period of the coin's
+ * denomination key is irrelevant for the validity of the deposit
+ * request, as obviously the customer and merchant could conspire to
+ * set any timestamp. Also, the Exchange must accept very old deposit
+ * requests, as the merchant might have been unable to transmit the
+ * deposit request in a timely fashion (so back-dating is not
+ * prevented).
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * How much time does the merchant have to issue a refund request?
+ * Zero if refunds are not allowed. After this time, the coin
+ * cannot be refunded.
+ */
+ struct GNUNET_TIME_Absolute refund_deadline;
+
+ /**
+ * How much time does the merchant have to execute the wire transfer?
+ * This time is advisory for aggregating transactions, not a hard
+ * constraint (as the merchant can theoretically pick any time,
+ * including one in the past).
+ */
+ struct GNUNET_TIME_Absolute wire_deadline;
+
+ /**
+ * Fraction of the coin's remaining value to be deposited, including
+ * depositing fee (if any). The coin is identified by @e coin_pub.
+ */
+ struct TALER_Amount amount_with_fee;
+
+ /**
+ * Depositing fee.
+ */
+ struct TALER_Amount deposit_fee;
+
+};
+
+
+/**
+ * @brief Global information for a refreshing session. Includes
+ * dimensions of the operation, security parameters and
+ * client signatures from "/refresh/melt" and "/refresh/commit".
+ */
+struct TALER_EXCHANGEDB_RefreshSession
+{
+
+ /**
+ * Number of coins we are melting.
+ */
+ uint16_t num_oldcoins;
+
+ /**
+ * Number of new coins we are creating.
+ */
+ uint16_t num_newcoins;
+
+ /**
+ * Index (smaller #TALER_CNC_KAPPA) which the exchange has chosen to not
+ * have revealed during cut and choose.
+ */
+ uint16_t noreveal_index;
+
+};
+
+
+/**
+ * @brief Specification for coin in a /refresh/melt operation.
+ */
+struct TALER_EXCHANGEDB_RefreshMelt
+{
+ /**
+ * Information about the coin that is being melted.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * Signature over the melting operation.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
+ * Hash of the refresh session this coin is melted into.
+ */
+ struct GNUNET_HashCode session_hash;
+
+ /**
+ * How much value is being melted? This amount includes the fees,
+ * so the final amount contributed to the melt is this value minus
+ * the fee for melting the coin. We include the fee in what is
+ * being signed so that we can verify a reserve's remaining total
+ * balance without needing to access the respective denomination key
+ * information each time.
+ */
+ struct TALER_Amount amount_with_fee;
+
+ /**
+ * Melting fee charged by the exchange. This must match the Exchange's
+ * denomination key's melting fee. If the client puts in an invalid
+ * melting fee (too high or too low) that does not match the Exchange's
+ * denomination key, the melting operation is invalid and will be
+ * rejected by the exchange. The @e amount_with_fee minus the @e
+ * melt_fee is the amount that will be credited to the melting
+ * session.
+ */
+ struct TALER_Amount melt_fee;
+
+};
+
+
+/**
+ * @brief We have as many `struct TALER_EXCHANGEDB_RefreshCommitCoin` as there are new
+ * coins being created by the refresh (for each of the #TALER_CNC_KAPPA
+ * sets). These are the coins we ask the exchange to sign if the
+ * respective set is selected.
+ */
+struct TALER_EXCHANGEDB_RefreshCommitCoin
+{
+
+ /**
+ * Encrypted data allowing those able to decrypt it to derive
+ * the private keys of the new coins created by the refresh.
+ */
+ struct TALER_RefreshLinkEncrypted *refresh_link;
+
+ /**
+ * Blinded message to be signed (in envelope), with @e coin_env_size bytes.
+ */
+ char *coin_ev;
+
+ /**
+ * Number of bytes in @e coin_ev.
+ */
+ size_t coin_ev_size;
+
+};
+
+
+/**
+ * @brief Linked list of refresh information linked to a coin.
+ */
+struct TALER_EXCHANGEDB_LinkDataList
+{
+ /**
+ * Information is stored in a NULL-terminated linked list.
+ */
+ struct TALER_EXCHANGEDB_LinkDataList *next;
+
+ /**
+ * Link data, used to recover the private key of the coin
+ * by the owner of the old coin.
+ */
+ struct TALER_RefreshLinkEncrypted *link_data_enc;
+
+ /**
+ * Denomination public key, determines the value of the coin.
+ */
+ struct TALER_DenominationPublicKey denom_pub;
+
+ /**
+ * Signature over the blinded envelope.
+ */
+ struct TALER_DenominationSignature ev_sig;
+};
+
+
+/**
+ * @brief Enumeration to classify the different types of transactions
+ * that can be done with a coin.
+ */
+enum TALER_EXCHANGEDB_TransactionType
+{
+ /**
+ * /deposit operation.
+ */
+ TALER_EXCHANGEDB_TT_DEPOSIT = 0,
+
+ /**
+ * /refresh/melt operation.
+ */
+ TALER_EXCHANGEDB_TT_REFRESH_MELT = 1
+
+};
+
+
+/**
+ * @brief List of transactions we performed for a particular coin.
+ */
+struct TALER_EXCHANGEDB_TransactionList
+{
+
+ /**
+ * Next pointer in the NULL-terminated linked list.
+ */
+ struct TALER_EXCHANGEDB_TransactionList *next;
+
+ /**
+ * Type of the transaction, determines what is stored in @e details.
+ */
+ enum TALER_EXCHANGEDB_TransactionType type;
+
+ /**
+ * Details about the transaction, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details if transaction was a /deposit operation.
+ */
+ struct TALER_EXCHANGEDB_Deposit *deposit;
+
+ /**
+ * Details if transaction was a /refresh/melt operation.
+ */
+ struct TALER_EXCHANGEDB_RefreshMelt *melt;
+
+ } details;
+
+};
+
+
+/**
+ * @brief All of the information from a /refresh/melt commitment.
+ */
+struct TALER_EXCHANGEDB_MeltCommitment
+{
+
+ /**
+ * Number of coins we are melting.
+ */
+ uint16_t num_oldcoins;
+
+ /**
+ * Number of new coins we are creating.
+ */
+ uint16_t num_newcoins;
+
+ /**
+ * Array of @e num_oldcoins melt operation details.
+ */
+ struct TALER_EXCHANGEDB_RefreshMelt *melts;
+
+ /**
+ * Array of @e num_newcoins denomination keys
+ */
+ struct TALER_DenominationPublicKey *denom_pubs;
+
+ /**
+ * 2D-Array of #TALER_CNC_KAPPA and @e num_newcoins commitments.
+ */
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins[TALER_CNC_KAPPA];
+
+ /**
+ * 2D-Array of #TALER_CNC_KAPPA and @e new_oldcoins links.
+ */
+ struct TALER_RefreshCommitLinkP *commit_links[TALER_CNC_KAPPA];
+};
+
+
+/**
+ * @brief Handle for a database session (per-thread, for transactions).
+ */
+struct TALER_EXCHANGEDB_Session;
+
+
+/**
+ * Function called with details about deposits that
+ * have been made, with the goal of executing the
+ * corresponding wire transaction.
+ *
+ * @param cls closure
+ * @param rowid unique ID for the deposit in our DB, used for marking
+ * it as 'tiny' or 'done'
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param deposit_fee amount the exchange gets to keep as transaction fees
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param wire wire details for the merchant, NULL from iterate_matching_deposits()
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+typedef int
+(*TALER_EXCHANGEDB_DepositIterator)(void *cls,
+ unsigned long long rowid,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ uint64_t transaction_id,
+ const struct GNUNET_HashCode *h_contract,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ const json_t *wire);
+
+
+/**
+ * Function called with the session hashes and transfer secret
+ * information for a given coin.
+ *
+ * @param cls closure
+ * @param session_hash a session the coin was melted in
+ * @param transfer_pub public transfer key for the session
+ * @param shared_secret_enc set to shared secret for the session
+ */
+typedef void
+(*TALER_EXCHANGEDB_TransferDataCallback)(void *cls,
+ const struct GNUNET_HashCode *session_hash,
+ const struct TALER_TransferPublicKeyP *transfer_pub,
+ const struct TALER_EncryptedLinkSecretP *shared_secret_enc);
+
+
+/**
+ * Function called with the results of the lookup of the
+ * wire transfer identifier information. Only called if
+ * we are at least aware of the transaction existing.
+ *
+ * @param cls closure
+ * @param wtid wire transfer identifier, NULL
+ * if the transaction was not yet done
+ * @param coin_contribution how much did the coin we asked about
+ * contribute to the total transfer value? (deposit value including fee)
+ * @param coin_fee how much did the exchange charge for the deposit fee
+ * @param execution_time when was the transaction done, or
+ * when we expect it to be done (if @a wtid was NULL)
+ */
+typedef void
+(*TALER_EXCHANGEDB_DepositWtidCallback)(void *cls,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
+ struct GNUNET_TIME_Absolute execution_time);
+
+
+/**
+ * Function called with the results of the lookup of the
+ * transaction data associated with a wire transfer identifier.
+ *
+ * @param cls closure
+ * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_contract which contract was this payment about
+ * @param transaction_id merchant's transaction ID for the payment
+ * @param coin_pub which public key was this payment about
+ * @param coin_value amount contributed by this coin in total (with fee)
+ * @param coin_fee applicable fee for this coin
+ */
+typedef void
+(*TALER_EXCHANGEDB_WireTransferDataCallback)(void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee);
+
+
+/**
+ * Callback with data about a prepared transaction.
+ *
+ * @param cls closure
+ * @param rowid row identifier used to mark prepared transaction as done
+ * @param buf transaction data that was persisted, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+typedef void
+(*TALER_EXCHANGEDB_WirePreparationCallback) (void *cls,
+ unsigned long long rowid,
+ const char *buf,
+ size_t buf_size);
+
+
+/**
+ * @brief The plugin API, returned from the plugin's "init" function.
+ * The argument given to "init" is simply a configuration handle.
+ */
+struct TALER_EXCHANGEDB_Plugin
+{
+
+ /**
+ * Closure for all callbacks.
+ */
+ void *cls;
+
+ /**
+ * Name of the library which generated this plugin. Set by the
+ * plugin loader.
+ */
+ char *library_name;
+
+ /**
+ * Get the thread-local database-handle.
+ * Connect to the db if the connection does not exist yet.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
+ * database default one
+ * @param the database connection, or NULL on error
+ */
+ struct TALER_EXCHANGEDB_Session *
+ (*get_session) (void *cls,
+ int temporary);
+
+
+ /**
+ * Drop the temporary taler schema. This is only useful for testcases.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*drop_temporary) (void *cls,
+ struct TALER_EXCHANGEDB_Session *db);
+
+
+ /**
+ * Create the necessary tables if they are not present
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param temporary should we use a temporary schema
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*create_tables) (void *cls,
+ int temporary);
+
+
+ /**
+ * Start a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*start) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session);
+
+
+ /**
+ * Commit a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @return #GNUNET_OK on success, #GNUNET_NO if the transaction
+ * can be retried, #GNUNET_SYSERR on hard failures
+ */
+ int
+ (*commit) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session);
+
+
+ /**
+ * Abort/rollback a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ */
+ void
+ (*rollback) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session);
+
+
+ /**
+ * Insert information about a denomination key and in particular
+ * the properties (value, fees, expiration times) the coins signed
+ * with this key have.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param denom_pub the public key used for signing coins of this denomination
+ * @param issue issuing information with value, fees and other info about the coin
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
+ */
+ int
+ (*insert_denomination_info) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ const struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue);
+
+
+ /**
+ * Fetch information about a denomination key.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param denom_pub the public key used for signing coins of this denomination
+ * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL
+ * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure
+ */
+ int
+ (*get_denomination_info) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue);
+
+
+ /**
+ * Get the summary of a reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db the database connection handle
+ * @param[in,out] reserve the reserve data. The public key of the reserve should be set
+ * in this structure; it is used to query the database. The balance
+ * and expiration are then filled accordingly.
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*reserve_get) (void *cls,
+ struct TALER_EXCHANGEDB_Session *db,
+ struct TALER_EXCHANGEDB_Reserve *reserve);
+
+
+ /**
+ * Insert a incoming transaction into reserves. New reserves are
+ * also created through this function. Note that this API call
+ * starts (and stops) its own transaction scope (so the application
+ * must not do so).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db the database connection handle
+ * @param reserve_pub public key of the reserve
+ * @param balance the amount that has to be added to the reserve
+ * @param execution_time when was the amount added
+ * @param details bank transaction details justifying the increment,
+ * must be unique for each incoming transaction
+ * @return #GNUNET_OK upon success; #GNUNET_NO if the given
+ * @a details are already known for this @a reserve_pub,
+ * #GNUNET_SYSERR upon failures (DB error, incompatible currency)
+ */
+ int
+ (*reserves_in_insert) (void *cls,
+ struct TALER_EXCHANGEDB_Session *db,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *balance,
+ struct GNUNET_TIME_Absolute execution_time,
+ const json_t *details);
+
+
+ /**
+ * Locate the response for a /withdraw request under the
+ * key of the hash of the blinded message.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param h_blind hash of the blinded coin to be signed (will match
+ * `h_coin_envelope` in the @a collectable to be returned)
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+ int
+ (*get_withdraw_info) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *h_blind,
+ struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
+
+
+ /**
+ * Store collectable bit coin under the corresponding
+ * hash of the blinded message.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+ int
+ (*insert_withdraw_info) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
+
+
+ /**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to use
+ * @param reserve_pub public key of the reserve
+ * @return known transaction history (NULL if reserve is unknown)
+ */
+ struct TALER_EXCHANGEDB_ReserveHistory *
+ (*get_reserve_history) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_ReservePublicKeyP *reserve_pub);
+
+
+ /**
+ * Free memory associated with the given reserve history.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param rh history to free.
+ */
+ void
+ (*free_reserve_history) (void *cls,
+ struct TALER_EXCHANGEDB_ReserveHistory *rh);
+
+
+ /**
+ * Check if we have the specified deposit already in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param deposit deposit to search for
+ * @return #GNUNET_YES if we know this operation,
+ * #GNUNET_NO if this exact deposit is unknown to us,
+ * #GNUNET_SYSERR on DB error
+ */
+ int
+ (*have_deposit) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_Deposit *deposit);
+
+
+ /**
+ * Insert information about deposited coin into the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit deposit information to store
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+ int
+ (*insert_deposit) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_EXCHANGEDB_Deposit *deposit);
+
+
+ /**
+ * Mark a deposit as tiny, thereby declaring that it cannot be
+ * executed by itself and should no longer be returned by
+ * @e iterate_ready_deposits()
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit_rowid identifies the deposit row to modify
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+ int
+ (*mark_deposit_tiny) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ unsigned long long rowid);
+
+
+ /**
+ * Mark a deposit as done, thereby declaring that it cannot be
+ * executed at all anymore, and should no longer be returned by
+ * @e iterate_ready_deposits() or @e iterate_matching_deposits().
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit_rowid identifies the deposit row to modify
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+ int
+ (*mark_deposit_done) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ unsigned long long rowid);
+
+
+ /**
+ * Obtain information about deposits that are ready to be executed.
+ * Such deposits must not be marked as "tiny" or "done", and the
+ * execution time must be in the past.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param deposit_cb function to call for ONE such deposit
+ * @param deposit_cb_cls closure for @a deposit_cb
+ * @return number of rows processed, 0 if none exist,
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*get_ready_deposit) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ TALER_EXCHANGEDB_DepositIterator deposit_cb,
+ void *deposit_cb_cls);
+
+
+ /**
+ * Obtain information about other pending deposits for the same
+ * destination. Those deposits must not already be "done".
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session connection to the database
+ * @param h_wire destination of the wire transfer
+ * @param merchant_pub public key of the merchant
+ * @param deposit_cb function to call for each deposit
+ * @param deposit_cb_cls closure for @a deposit_cb
+ * @param limit maximum number of matching deposits to return
+ * @return number of rows processed, 0 if none exist,
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*iterate_matching_deposits) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ TALER_EXCHANGEDB_DepositIterator deposit_cb,
+ void *deposit_cb_cls,
+ uint32_t limit);
+
+
+ /**
+ * Lookup refresh session data under the given @a session_hash.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database handle to use
+ * @param session_hash hash over the melt to use for the lookup
+ * @param[out] refresh_session where to store the result
+ * @return #GNUNET_YES on success,
+ * #GNUNET_NO if not found,
+ * #GNUNET_SYSERR on DB failure
+ */
+ int
+ (*get_refresh_session) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ struct TALER_EXCHANGEDB_RefreshSession *refresh_session);
+
+
+ /**
+ * Store new refresh session data under the given @a session_hash.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database handle to use
+ * @param session_hash hash over the melt to use to locate the session
+ * @param refresh_session session data to store
+ * @return #GNUNET_YES on success,
+ * #GNUNET_SYSERR on DB failure
+ */
+ int
+ (*create_refresh_session) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ const struct TALER_EXCHANGEDB_RefreshSession *refresh_session);
+
+
+ /**
+ * Store the given /refresh/melt request in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param oldcoin_index index of the coin to store
+ * @param melt coin melt operation details to store; includes
+ * the session hash of the melt
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_refresh_melt) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ uint16_t oldcoin_index,
+ const struct TALER_EXCHANGEDB_RefreshMelt *melt);
+
+
+ /**
+ * Get information about melted coin details from the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param oldcoin_index index of the coin to retrieve
+ * @param melt melt data to fill in, can be NULL
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*get_refresh_melt) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t oldcoin_index,
+ struct TALER_EXCHANGEDB_RefreshMelt *melt);
+
+
+ /**
+ * Store in the database which coin(s) we want to create
+ * in a given refresh operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
+ * @param denom_pubs array denominations of the coins to create
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_refresh_order) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ const struct TALER_DenominationPublicKey *denom_pubs);
+
+
+ /**
+ * Lookup in the database for the @a num_newcoins coins that we want to
+ * create in the given refresh operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins size of the @a denom_pubs array
+ * @param[out] denom_pubs where to write @a num_newcoins denomination keys
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*get_refresh_order) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ struct TALER_DenominationPublicKey *denom_pubs);
+
+
+ /**
+ * Store information about the commitments of the given index @a i
+ * for the given refresh session in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA
+ * @param num_newcoins coin index size of the @a commit_coins array
+ * @param commit_coin array of coin commitments to store
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*insert_refresh_commit_coins) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_newcoins,
+ const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins);
+
+
+ /**
+ * Obtain information about the commitment of the
+ * given coin of the given refresh session from the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose set index (1st dimension)
+ * @param num_coins size of the @a commit_coins array
+ * @param[out] commit_coins array of coin commitments to return
+ * @return #GNUNET_OK on success
+ * #GNUNET_NO if not found
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*get_refresh_commit_coins) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_coins,
+ struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins);
+
+
+ /**
+ * Store the commitment to the given (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA
+ * @param num_links size of the @a commit_link array
+ * @param commit_links array of link information to store
+ * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
+ */
+ int
+ (*insert_refresh_commit_links) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_links,
+ const struct TALER_RefreshCommitLinkP *commit_links);
+
+ /**
+ * Obtain the commited (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param cnc_index cut and choose index (1st dimension)
+ * @param num_links size of the @a links array to return
+ * @param[out] links array link information to return
+ * @return #GNUNET_SYSERR on internal error,
+ * #GNUNET_NO if commitment was not found
+ * #GNUNET_OK on success
+ */
+ int
+ (*get_refresh_commit_links) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t cnc_index,
+ uint16_t num_links,
+ struct TALER_RefreshCommitLinkP *links);
+
+
+ /**
+ * Get all of the information from the given melt commit operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
+ * @return NULL if the @a session_hash does not correspond to any known melt
+ * operation
+ */
+ struct TALER_EXCHANGEDB_MeltCommitment *
+ (*get_melt_commitment) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash);
+
+
+ /**
+ * Free information about a melt commitment.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param mc melt commitment data to free
+ */
+ void
+ (*free_melt_commitment) (void *cls,
+ struct TALER_EXCHANGEDB_MeltCommitment *mc);
+
+
+ /**
+ * Insert signature of a new coin generated during refresh into
+ * the database indexed by the refresh session and the index
+ * of the coin. This data is later used should an old coin
+ * be used to try to obtain the private keys during "/refresh/link".
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param newcoin_index coin index
+ * @param ev_sig coin signature
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*insert_refresh_out) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t newcoin_index,
+ const struct TALER_DenominationSignature *ev_sig);
+
+
+ /**
+ * Obtain the link data of a coin, that is the encrypted link
+ * information, the denomination keys and the signatures.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param session_hash session to get linkage data for
+ * @return all known link data for the session
+ */
+ struct TALER_EXCHANGEDB_LinkDataList *
+ (*get_link_data_list) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *session_hash);
+
+
+ /**
+ * Free memory of the link data list.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param ldl link data list to release
+ */
+ void
+ (*free_link_data_list) (void *cls,
+ struct TALER_EXCHANGEDB_LinkDataList *ldl);
+
+
+ /**
+ * Obtain shared secret and transfer public key from the public key of
+ * the coin. This information and the link information returned by
+ * @e get_link_data_list() enable the owner of an old coin to determine
+ * the private keys of the new coins after the melt.
+ *
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param coin_pub public key of the coin
+ * @param tdc function to call for each session the coin was melted into
+ * @param tdc_cls closure for @a tdc
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO on failure (not found)
+ * #GNUNET_SYSERR on internal failure (database issue)
+ */
+ int
+ (*get_transfer) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ TALER_EXCHANGEDB_TransferDataCallback tdc,
+ void *tdc_cls);
+
+
+ /**
+ * Compile a list of all (historic) transactions performed
+ * with the given coin (/refresh/melt and /deposit operations).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param coin_pub coin to investigate
+ * @return list of transactions, NULL if coin is fresh
+ */
+ struct TALER_EXCHANGEDB_TransactionList *
+ (*get_coin_transactions) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub);
+
+
+ /**
+ * Free linked list of transactions.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param list list to free
+ */
+ void
+ (*free_coin_transaction_list) (void *cls,
+ struct TALER_EXCHANGEDB_TransactionList *list);
+
+
+ /**
+ * Lookup the list of Taler transactions that was aggregated
+ * into a wire transfer by the respective @a raw_wtid.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
+ * @param wtid the raw wire transfer identifier we used
+ * @param cb function to call on each transaction found
+ * @param cb_cls closure for @a cb
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
+ * #GNUNET_NO if we found no results
+ */
+ int
+ (*lookup_wire_transfer) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_EXCHANGEDB_WireTransferDataCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Try to find the wire transfer details for a deposit operation.
+ * If we did not execute the deposit yet, return when it is supposed
+ * to be executed.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param h_contract hash of the contract
+ * @param h_wire hash of merchant wire details
+ * @param coin_pub public key of deposited coin
+ * @param merchant_pub merchant public key
+ * @param transaction_id transaction identifier
+ * @param cb function to call with the result
+ * @param cb_cls closure to pass to @a cb
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
+ * #GNUNET_NO if nothing was found
+ */
+ int
+ (*wire_lookup_deposit_wtid)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ uint64_t transaction_id,
+ TALER_EXCHANGEDB_DepositWtidCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Function called to insert aggregation information into the DB.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param wtid the raw wire transfer identifier we used
+ * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param h_contract which contract was this payment about
+ * @param transaction_id merchant's transaction ID for the payment
+ * @param execution_time when did we execute the transaction
+ * @param coin_pub which public key was this payment about
+ * @param coin_value amount contributed by this coin in total
+ * @param coin_fee deposit fee charged by exchange for this coin
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ */
+ int
+ (*insert_aggregation_tracking)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee);
+
+
+ /**
+ * Function called to insert wire transfer commit data into the DB.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of the wire transfer (i.e. "sepa")
+ * @param buf buffer with wire transfer preparation data
+ * @param buf_size number of bytes in @a buf
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ */
+ int
+ (*wire_prepare_data_insert)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ const char *buf,
+ size_t buf_size);
+
+
+ /**
+ * Function called to mark wire transfer commit data as finished.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param rowid which entry to mark as finished
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ */
+ int
+ (*wire_prepare_data_mark_finished)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ unsigned long long rowid);
+
+
+ /**
+ * Function called to get an unfinished wire transfer
+ * preparation data. Fetches at most one item.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type fo the wire transfer (i.e. "sepa")
+ * @param cb function to call for ONE unfinished item
+ * @param cb_cls closure for @a cb
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if there are no entries,
+ * #GNUNET_SYSERR on DB errors
+ */
+ int
+ (*wire_prepare_data_get)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ TALER_EXCHANGEDB_WirePreparationCallback cb,
+ void *cb_cls);
+
+
+};
+
+
+#endif /* _TALER_EXCHANGE_DB_H */
diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h
deleted file mode 100644
index 1502edfbc..000000000
--- a/src/include/taler_mint_service.h
+++ /dev/null
@@ -1,1220 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file include/taler_mint_service.h
- * @brief C interface of libtalermint, a C library to use mint's HTTP API
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#ifndef _TALER_MINT_SERVICE_H
-#define _TALER_MINT_SERVICE_H
-
-#include "taler_util.h"
-
-/* ********************* event loop *********************** */
-
-/**
- * @brief Handle to this library context. This is where the
- * main event loop logic lives.
- */
-struct TALER_MINT_Context;
-
-
-/**
- * Initialise a context. A context should be used for each thread and should
- * not be shared among multiple threads.
- *
- * @return the context, NULL on error (failure to initialize)
- */
-struct TALER_MINT_Context *
-TALER_MINT_init (void);
-
-
-/**
- * Obtain the information for a select() call to wait until
- * #TALER_MINT_perform() is ready again. Note that calling
- * any other TALER_MINT-API may also imply that the library
- * is again ready for #TALER_MINT_perform().
- *
- * Basically, a client should use this API to prepare for select(),
- * then block on select(), then call #TALER_MINT_perform() and then
- * start again until the work with the context is done.
- *
- * This function will NOT zero out the sets and assumes that @a max_fd
- * and @a timeout are already set to minimal applicable values. It is
- * safe to give this API FD-sets and @a max_fd and @a timeout that are
- * already initialized to some other descriptors that need to go into
- * the select() call.
- *
- * @param ctx context to get the event loop information for
- * @param read_fd_set will be set for any pending read operations
- * @param write_fd_set will be set for any pending write operations
- * @param except_fd_set is here because curl_multi_fdset() has this argument
- * @param max_fd set to the highest FD included in any set;
- * if the existing sets have no FDs in it, the initial
- * value should be "-1". (Note that `max_fd + 1` will need
- * to be passed to select().)
- * @param timeout set to the timeout in milliseconds (!); -1 means
- * no timeout (NULL, blocking forever is OK), 0 means to
- * proceed immediately with #TALER_MINT_perform().
- */
-void
-TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- fd_set *except_fd_set,
- int *max_fd,
- long *timeout);
-
-
-/**
- * Run the main event loop for the Taler interaction.
- *
- * @param ctx the library context
- */
-void
-TALER_MINT_perform (struct TALER_MINT_Context *ctx);
-
-
-/**
- * Cleanup library initialisation resources. This function should be called
- * after using this library to cleanup the resources occupied during library's
- * initialisation.
- *
- * @param ctx the library context
- */
-void
-TALER_MINT_fini (struct TALER_MINT_Context *ctx);
-
-
-/* ********************* /keys *********************** */
-
-
-/**
- * List of possible options to be passed to
- * #TALER_MINT_connect().
- */
-enum TALER_MINT_Option
-{
- /**
- * Terminator (end of option list).
- */
- TALER_MINT_OPTION_END = 0
-
-};
-
-
-/**
- * @brief Mint's signature key
- */
-struct TALER_MINT_SigningPublicKey
-{
- /**
- * The signing public key
- */
- struct TALER_MintPublicKeyP key;
-
- /**
- * Validity start time
- */
- struct GNUNET_TIME_Absolute valid_from;
-
- /**
- * Validity expiration time
- */
- struct GNUNET_TIME_Absolute valid_until;
-};
-
-
-/**
- * @brief Public information about a mint's denomination key
- */
-struct TALER_MINT_DenomPublicKey
-{
- /**
- * The public key
- */
- struct TALER_DenominationPublicKey key;
-
- /**
- * The hash of the public key.
- */
- struct GNUNET_HashCode h_key;
-
- /**
- * Timestamp indicating when the denomination key becomes valid
- */
- struct GNUNET_TIME_Absolute valid_from;
-
- /**
- * Timestamp indicating when the denomination key can’t be used anymore to
- * withdraw new coins.
- */
- struct GNUNET_TIME_Absolute withdraw_valid_until;
-
- /**
- * Timestamp indicating when coins of this denomination become invalid.
- */
- struct GNUNET_TIME_Absolute deposit_valid_until;
-
- /**
- * When do signatures with this denomination key become invalid?
- * After this point, these signatures cannot be used in (legal)
- * disputes anymore, as the Mint is then allowed to destroy its side
- * of the evidence. @e expire_legal is expected to be significantly
- * larger than @e expire_spend (by a year or more).
- */
- struct GNUNET_TIME_Absolute expire_legal;
-
- /**
- * The value of this denomination
- */
- struct TALER_Amount value;
-
- /**
- * The applicable fee for withdrawing a coin of this denomination
- */
- struct TALER_Amount fee_withdraw;
-
- /**
- * The applicable fee to spend a coin of this denomination
- */
- struct TALER_Amount fee_deposit;
-
- /**
- *The applicable fee to melt/refresh a coin of this denomination
- */
- struct TALER_Amount fee_refresh;
-};
-
-
-/**
- * @brief Information we get from the mint about auditors.
- */
-struct TALER_MINT_AuditorInformation
-{
- /**
- * Public key of the auditing institution.
- */
- struct TALER_AuditorPublicKeyP auditor_pub;
-
- /**
- * URL of the auditing institution. The application must check that
- * this is an acceptable auditor for its purpose and also verify
- * that the @a auditor_pub matches the auditor's public key given at
- * that website. We expect that in practice software is going to
- * often ship with an initial list of accepted auditors, just like
- * browsers ship with a CA root store.
- *
- * This field may be NULL. (#3987).
- */
- const char *auditor_url;
-
- /**
- * Number of denomination keys audited by this auditor.
- */
- unsigned int num_denom_keys;
-
- /**
- * Array of length @a denom_keys with the denomination
- * keys audited by this auditor. Note that the array
- * elements point to the same locations as the entries
- * in the key's main `denom_keys` array.
- */
- const struct TALER_MINT_DenomPublicKey **denom_keys;
-};
-
-
-/**
- * @brief Information about keys from the mint.
- */
-struct TALER_MINT_Keys
-{
-
- /**
- * Long-term offline signing key of the mint.
- */
- struct TALER_MasterPublicKeyP master_pub;
-
- /**
- * Array of the mint's online signing keys.
- */
- struct TALER_MINT_SigningPublicKey *sign_keys;
-
- /**
- * Array of the mint's denomination keys.
- */
- struct TALER_MINT_DenomPublicKey *denom_keys;
-
- /**
- * Array of the keys of the auditors of the mint.
- */
- struct TALER_MINT_AuditorInformation *auditors;
-
- /**
- * Length of the @e sign_keys array.
- */
- unsigned int num_sign_keys;
-
- /**
- * Length of the @e denom_keys array.
- */
- unsigned int num_denom_keys;
-
- /**
- * Length of the @e auditors array.
- */
- unsigned int num_auditors;
-
-};
-
-
-/**
- * Function called with information about who is auditing
- * a particular mint and what key the mint is using.
- *
- * @param cls closure
- * @param keys information about the various keys used
- * by the mint
- */
-typedef void
-(*TALER_MINT_CertificationCallback) (void *cls,
- const struct TALER_MINT_Keys *keys);
-
-
-/**
- * @brief Handle to the mint. This is where we interact with
- * a particular mint and keep the per-mint information.
- */
-struct TALER_MINT_Handle;
-
-
-/**
- * Initialise a connection to the mint. Will connect to the
- * mint and obtain information about the mint's master public
- * key and the mint's auditor. The respective information will
- * be passed to the @a cert_cb once available, and all future
- * interactions with the mint will be checked to be signed
- * (where appropriate) by the respective master key.
- *
- * @param ctx the context
- * @param url HTTP base URL for the mint
- * @param cert_cb function to call with the mint's certification information
- * @param cert_cb_cls closure for @a cert_cb
- * @param ... list of additional arguments, terminated by #TALER_MINT_OPTION_END.
- * @return the mint handle; NULL upon error
- */
-struct TALER_MINT_Handle *
-TALER_MINT_connect (struct TALER_MINT_Context *ctx,
- const char *url,
- TALER_MINT_CertificationCallback cert_cb,
- void *cert_cb_cls,
- ...);
-
-
-/**
- * Disconnect from the mint.
- *
- * @param mint the mint handle
- */
-void
-TALER_MINT_disconnect (struct TALER_MINT_Handle *mint);
-
-
-/**
- * Obtain the keys from the mint.
- *
- * @param mint the mint handle
- * @return the mint's key set
- */
-const struct TALER_MINT_Keys *
-TALER_MINT_get_keys (const struct TALER_MINT_Handle *mint);
-
-
-/**
- * Test if the given @a pub is a the current signing key from the mint
- * according to @a keys.
- *
- * @param keys the mint's key set
- * @param pub claimed current online signing key for the mint
- * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key
- */
-int
-TALER_MINT_test_signing_key (const struct TALER_MINT_Keys *keys,
- const struct TALER_MintPublicKeyP *pub);
-
-
-/**
- * Obtain the denomination key details from the mint.
- *
- * @param keys the mint's key set
- * @param pk public key of the denomination to lookup
- * @return details about the given denomination key, NULL if the key is not
- * found
- */
-const struct TALER_MINT_DenomPublicKey *
-TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys,
- const struct TALER_DenominationPublicKey *pk);
-
-
-/**
- * Obtain the denomination key details from the mint.
- *
- * @param keys the mint's key set
- * @param hc hash of the public key of the denomination to lookup
- * @return details about the given denomination key
- */
-const struct TALER_MINT_DenomPublicKey *
-TALER_MINT_get_denomination_key_by_hash (const struct TALER_MINT_Keys *keys,
- const struct GNUNET_HashCode *hc);
-
-
-/* ********************* /wire *********************** */
-
-
-/**
- * @brief A Wire format inquiry handle
- */
-struct TALER_MINT_WireHandle;
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * wire format inquiry request to a mint.
- *
- * The callback is invoked multiple times, once for each supported @a
- * method. Finally, it is invoked one more time with cls/0/NULL/NULL
- * to indicate the end of the iteration. If any request fails to
- * generate a valid response from the mint, @a http_status will also
- * be zero and the iteration will also end. Thus, the iteration
- * always ends with a final call with an @a http_status of 0. If the
- * @a http_status is already 0 on the first call, then the response to
- * the /wire request was invalid. Later, clients can tell the
- * difference between @a http_status of 0 indicating a failed
- * /wire/method request and a regular end of the iteration by @a
- * method being non-NULL. If the mint simply correctly asserts that
- * it does not support any methods, @a method will be NULL but the @a
- * http_status will be #MHD_HTTP_OK for the first call (followed by a
- * cls/0/NULL/NULL call to signal the end of the iteration).
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param method wire format method supported, i.e. "test" or "sepa", or NULL
- * if already the /wire request failed.
- * @param obj the received JSON reply, if successful this should be the wire
- * format details as provided by /wire/METHOD/, or NULL if the
- * reply was not in JSON format (in this case, the client might
- * want to do an HTTP request to /wire/METHOD/ with a browser to
- * provide more information to the user about the @a method).
- */
-typedef void
-(*TALER_MINT_WireResultCallback) (void *cls,
- unsigned int http_status,
- const char *method,
- json_t *obj);
-
-
-/**
- * Obtain information about a mint's wire instructions.
- * A mint may provide wire instructions for creating
- * a reserve. The wire instructions also indicate
- * which wire formats merchants may use with the mint.
- * This API is typically used by a wallet for wiring
- * funds, and possibly by a merchant to determine
- * supported wire formats.
- *
- * Note that while we return the (main) response verbatim to the
- * caller for further processing, we do already verify that the
- * response is well-formed (i.e. that signatures included in the
- * response are all valid). If the mint's reply is not well-formed,
- * we return an HTTP status code of zero to @a cb.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param wire_cb the callback to call when a reply for this request is available
- * @param wire_cb_cls closure for the above callback
- * @return a handle for this request
- */
-struct TALER_MINT_WireHandle *
-TALER_MINT_wire (struct TALER_MINT_Handle *mint,
- TALER_MINT_WireResultCallback wire_cb,
- void *wire_cb_cls);
-
-
-/**
- * Cancel a wire information request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param wh the wire information request handle
- */
-void
-TALER_MINT_wire_cancel (struct TALER_MINT_WireHandle *wh);
-
-
-/* ********************* /deposit *********************** */
-
-
-/**
- * @brief A Deposit Handle
- */
-struct TALER_MINT_DepositHandle;
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * deposit permission request to a mint.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param obj the received JSON reply, should be kept as proof (and, in case of errors,
- * be forwarded to the customer)
- */
-typedef void
-(*TALER_MINT_DepositResultCallback) (void *cls,
- unsigned int http_status,
- json_t *obj);
-
-
-/**
- * Submit a deposit permission to the mint and get the mint's
- * response. This API is typically used by a merchant. Note that
- * while we return the response verbatim to the caller for further
- * processing, we do already verify that the response is well-formed
- * (i.e. that signatures included in the response are all valid). If
- * the mint's reply is not well-formed, we return an HTTP status code
- * of zero to @a cb.
- *
- * We also verify that the @a coin_sig is valid for this deposit
- * request, and that the @a ub_sig is a valid signature for @a
- * coin_pub. Also, the @a mint must be ready to operate (i.e. have
- * finished processing the /keys reply). If either check fails, we do
- * NOT initiate the transaction with the mint and instead return NULL.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param amount the amount to be deposited
- * @param wire_deadline execution date, until which the merchant would like the mint to settle the balance (advisory, the mint cannot be
- * forced to settle in the past or upon very short notice, but of course a well-behaved mint will limit aggregation based on the advice received)
- * @param wire_details the merchant’s account details, in a format supported by the mint
- * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
- * @param coin_pub coin’s public key
- * @param denom_pub denomination key with which the coin is signed
- * @param denom_sig mint’s unblinded signature of the coin
- * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
- * @param transaction_id transaction id for the transaction between merchant and customer
- * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
- * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed)
- * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
- * @param cb the callback to call when a reply for this request is available
- * @param cb_cls closure for the above callback
- * @return a handle for this request; NULL if the inputs are invalid (i.e.
- * signatures fail to verify). In this case, the callback is not called.
- */
-struct TALER_MINT_DepositHandle *
-TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute wire_deadline,
- json_t *wire_details,
- const struct GNUNET_HashCode *h_contract,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_DenominationSignature *denom_sig,
- const struct TALER_DenominationPublicKey *denom_pub,
- struct GNUNET_TIME_Absolute timestamp,
- uint64_t transaction_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- struct GNUNET_TIME_Absolute refund_deadline,
- const struct TALER_CoinSpendSignatureP *coin_sig,
- TALER_MINT_DepositResultCallback cb,
- void *cb_cls);
-
-
-/**
- * Cancel a deposit permission request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param deposit the deposit permission request handle
- */
-void
-TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit);
-
-
-/* ********************* /reserve/status *********************** */
-
-
-/**
- * @brief A /reserve/status Handle
- */
-struct TALER_MINT_ReserveStatusHandle;
-
-
-/**
- * Ways how a reserve's balance may change.
- */
-enum TALER_MINT_ReserveTransactionType {
-
- /**
- * Deposit into the reserve.
- */
- TALER_MINT_RTT_DEPOSIT,
-
- /**
- * Withdrawal from the reserve.
- */
- TALER_MINT_RTT_WITHDRAWAL
-
-};
-
-
-/**
- * @brief Entry in the reserve's transaction history.
- */
-struct TALER_MINT_ReserveHistory
-{
-
- /**
- * Type of the transaction.
- */
- enum TALER_MINT_ReserveTransactionType type;
-
- /**
- * Amount transferred (in or out).
- */
- struct TALER_Amount amount;
-
- /**
- * Details depending on @e type.
- */
- union {
-
- /**
- * Transaction details for the incoming transaction.
- */
- json_t *wire_in_details;
-
- /**
- * Signature authorizing the withdrawal for outgoing transaction.
- */
- json_t *out_authorization_sig;
-
- } details;
-
-};
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * deposit permission request to a mint.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param[in] json original response in JSON format (useful only for diagnostics)
- * @param balance current balance in the reserve, NULL on error
- * @param history_length number of entries in the transaction history, 0 on error
- * @param history detailed transaction history, NULL on error
- */
-typedef void
-(*TALER_MINT_ReserveStatusResultCallback) (void *cls,
- unsigned int http_status,
- json_t *json,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_MINT_ReserveHistory *history);
-
-
-/**
- * Submit a request to obtain the transaction history of a reserve
- * from the mint. Note that while we return the full response to the
- * caller for further processing, we do already verify that the
- * response is well-formed (i.e. that signatures included in the
- * response are all valid and add up to the balance). If the mint's
- * reply is not well-formed, we return an HTTP status code of zero to
- * @a cb.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param reserve_pub public key of the reserve to inspect
- * @param cb the callback to call when a reply for this request is available
- * @param cb_cls closure for the above callback
- * @return a handle for this request; NULL if the inputs are invalid (i.e.
- * signatures fail to verify). In this case, the callback is not called.
- */
-struct TALER_MINT_ReserveStatusHandle *
-TALER_MINT_reserve_status (struct TALER_MINT_Handle *mint,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- TALER_MINT_ReserveStatusResultCallback cb,
- void *cb_cls);
-
-
-/**
- * Cancel a withdraw status request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param wsh the withdraw status request handle
- */
-void
-TALER_MINT_reserve_status_cancel (struct TALER_MINT_ReserveStatusHandle *wsh);
-
-
-/* ********************* /reserve/withdraw *********************** */
-
-
-/**
- * @brief A /reserve/withdraw Handle
- */
-struct TALER_MINT_ReserveWithdrawHandle;
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * deposit permission request to a mint.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param sig signature over the coin, NULL on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-typedef void
-(*TALER_MINT_ReserveWithdrawResultCallback) (void *cls,
- unsigned int http_status,
- const struct TALER_DenominationSignature *sig,
- json_t *full_response);
-
-
-/**
- * Withdraw a coin from the mint using a /reserve/withdraw request. This
- * API is typically used by a wallet. Note that to ensure that no
- * money is lost in case of hardware failures, the caller must have
- * committed (most of) the arguments to disk before calling, and be
- * ready to repeat the request with the same arguments in case of
- * failures.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_priv private key of the reserve to withdraw from
- * @param coin_priv where to store the coin's private key,
- * caller must have committed this value to disk before the call (with @a pk)
- * @param blinding_key where to store the coin's blinding key
- * caller must have committed this value to disk before the call (with @a pk)
- * @param res_cb the callback to call when the final result for this request is available
- * @param res_cb_cls closure for @a res_cb
- * @return NULL
- * if the inputs are invalid (i.e. denomination key not with this mint).
- * In this case, the callback is not called.
- */
-struct TALER_MINT_ReserveWithdrawHandle *
-TALER_MINT_reserve_withdraw (struct TALER_MINT_Handle *mint,
- const struct TALER_MINT_DenomPublicKey *pk,
- const struct TALER_ReservePrivateKeyP *reserve_priv,
- const struct TALER_CoinSpendPrivateKeyP *coin_priv,
- const struct TALER_DenominationBlindingKey *blinding_key,
- TALER_MINT_ReserveWithdrawResultCallback res_cb,
- void *res_cb_cls);
-
-
-/**
- * Cancel a withdraw status request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param sign the withdraw sign request handle
- */
-void
-TALER_MINT_reserve_withdraw_cancel (struct TALER_MINT_ReserveWithdrawHandle *sign);
-
-
-/* ********************* /refresh/melt+reveal ***************************** */
-
-
-/**
- * Melt (partially spent) coins to obtain fresh coins that are
- * unlinkable to the original coin(s). Note that melting more
- * than one coin in a single request will make those coins linkable,
- * so the safest operation only melts one coin at a time.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, is operation does
- * not actually initiate the request. Instead, it generates a buffer
- * which the caller must store before proceeding with the actual call
- * to #TALER_MINT_refresh_melt() that will generate the request.
- *
- * This function does verify that the given request data is internally
- * consistent. However, the @a melts_sigs are only verified if @a
- * check_sigs is set to #GNUNET_YES, as this may be relatively
- * expensive and should be redundant.
- *
- * Aside from some non-trivial cryptographic operations that might
- * take a bit of CPU time to complete, this function returns
- * its result immediately and does not start any asynchronous
- * processing. This function is also thread-safe.
- *
- * @param num_melts number of coins that are being melted (typically 1)
- * @param melt_privs array of @a num_melts private keys of the coins to melt
- * @param melt_amounts array of @a num_melts amounts specifying how much
- * each coin will contribute to the melt (including fee)
- * @param melt_sigs array of @a num_melts signatures affirming the
- * validity of the public keys corresponding to the
- * @a melt_privs private keys
- * @param melt_pks array of @a num_melts denomination key information
- * records corresponding to the @a melt_sigs
- * validity of the keys
- * @param check_sigs verify the validity of the signatures of @a melt_sigs
- * @param fresh_pks_len length of the @a pks array
- * @param fresh_pks array of @a pks_len denominations of fresh coins to create
- * @param[out] res_size set to the size of the return value, or 0 on error
- * @return NULL
- * if the inputs are invalid (i.e. denomination key not with this mint).
- * Otherwise, pointer to a buffer of @a res_size to store persistently
- * before proceeding to #TALER_MINT_refresh_melt().
- * Non-null results should be freed using #GNUNET_free().
- */
-char *
-TALER_MINT_refresh_prepare (unsigned int num_melts,
- const struct TALER_CoinSpendPrivateKeyP *melt_privs,
- const struct TALER_Amount *melt_amounts,
- const struct TALER_DenominationSignature *melt_sigs,
- const struct TALER_MINT_DenomPublicKey *melt_pks,
- int check_sigs,
- unsigned int fresh_pks_len,
- const struct TALER_MINT_DenomPublicKey *fresh_pks,
- size_t *res_size);
-
-
-/* ********************* /refresh/melt ***************************** */
-
-/**
- * @brief A /refresh/melt Handle
- */
-struct TALER_MINT_RefreshMeltHandle;
-
-
-/**
- * Callbacks of this type are used to notify the application about the
- * result of the /refresh/melt stage. If successful, the @a noreveal_index
- * should be committed to disk prior to proceeding #TALER_MINT_refresh_reveal().
- *
- * @param cls closure
- * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param noreveal_index choice by the mint in the cut-and-choose protocol,
- * UINT16_MAX on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-typedef void
-(*TALER_MINT_RefreshMeltCallback) (void *cls,
- unsigned int http_status,
- uint16_t noreveal_index,
- json_t *full_response);
-
-
-/**
- * Submit a melt request to the mint and get the mint's
- * response.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, the provided
- * argument should have been constructed using
- * #TALER_MINT_refresh_prepare and committed to persistent storage
- * prior to calling this function.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param refresh_data_length size of the @a refresh_data (returned
- * in the `res_size` argument from #TALER_MINT_refresh_prepare())
- * @param refresh_data the refresh data as returned from
- #TALER_MINT_refresh_prepare())
- * @param melt_cb the callback to call with the result
- * @param melt_cb_cls closure for @a melt_cb
- * @return a handle for this request; NULL if the argument was invalid.
- * In this case, neither callback will be called.
- */
-struct TALER_MINT_RefreshMeltHandle *
-TALER_MINT_refresh_melt (struct TALER_MINT_Handle *mint,
- size_t refresh_data_length,
- const char *refresh_data,
- TALER_MINT_RefreshMeltCallback melt_cb,
- void *melt_cb_cls);
-
-
-/**
- * Cancel a refresh melt request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param rmh the refresh handle
- */
-void
-TALER_MINT_refresh_melt_cancel (struct TALER_MINT_RefreshMeltHandle *rmh);
-
-
-/* ********************* /refresh/reveal ***************************** */
-
-
-/**
- * Callbacks of this type are used to return the final result of
- * submitting a refresh request to a mint. If the operation was
- * successful, this function returns the signatures over the coins
- * that were remelted. The @a coin_privs and @a sigs arrays give the
- * coins in the same order (and should have the same length) in which
- * the original request specified the respective denomination keys.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
- * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
- * @param sigs array of signature over @a num_coins coins, NULL on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-typedef void
-(*TALER_MINT_RefreshRevealCallback) (void *cls,
- unsigned int http_status,
-
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- json_t *full_response);
-
-
-/**
- * @brief A /refresh/reveal Handle
- */
-struct TALER_MINT_RefreshRevealHandle;
-
-
-/**
- * Submit a /refresh/reval request to the mint and get the mint's
- * response.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, the provided
- * arguments should have been committed to persistent storage
- * prior to calling this function.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param refresh_data_length size of the @a refresh_data (returned
- * in the `res_size` argument from #TALER_MINT_refresh_prepare())
- * @param refresh_data the refresh data as returned from
- #TALER_MINT_refresh_prepare())
- * @param noreveal_index response from the mint to the
- * #TALER_MINT_refresh_melt() invocation
- * @param reveal_cb the callback to call with the final result of the
- * refresh operation
- * @param reveal_cb_cls closure for the above callback
- * @return a handle for this request; NULL if the argument was invalid.
- * In this case, neither callback will be called.
- */
-struct TALER_MINT_RefreshRevealHandle *
-TALER_MINT_refresh_reveal (struct TALER_MINT_Handle *mint,
- size_t refresh_data_length,
- const char *refresh_data,
- uint16_t noreveal_index,
- TALER_MINT_RefreshRevealCallback reveal_cb,
- void *reveal_cb_cls);
-
-
-/**
- * Cancel a refresh reveal request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param rrh the refresh reval handle
- */
-void
-TALER_MINT_refresh_reveal_cancel (struct TALER_MINT_RefreshRevealHandle *rrh);
-
-
-/* ********************* /refresh/link ***************************** */
-
-
-/**
- * @brief A /refresh/link Handle
- */
-struct TALER_MINT_RefreshLinkHandle;
-
-
-/**
- * Callbacks of this type are used to return the final result of
- * submitting a /refresh/link request to a mint. If the operation was
- * successful, this function returns the signatures over the coins
- * that were created when the original coin was melted.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
- * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
- * @param sigs array of signature over @a num_coins coins, NULL on error
- * @param pubs array of public keys for the @a sigs, NULL on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-typedef void
-(*TALER_MINT_RefreshLinkCallback) (void *cls,
- unsigned int http_status,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_DenominationPublicKey *pubs,
- json_t *full_response);
-
-
-/**
- * Submit a link request to the mint and get the mint's response.
- *
- * This API is typically not used by anyone, it is more a threat
- * against those trying to receive a funds transfer by abusing the
- * /refresh protocol.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param coin_priv private key to request link data for
- * @param link_cb the callback to call with the useful result of the
- * refresh operation the @a coin_priv was involved in (if any)
- * @param link_cb_cls closure for @a link_cb
- * @return a handle for this request
- */
-struct TALER_MINT_RefreshLinkHandle *
-TALER_MINT_refresh_link (struct TALER_MINT_Handle *mint,
- const struct TALER_CoinSpendPrivateKeyP *coin_priv,
- TALER_MINT_RefreshLinkCallback link_cb,
- void *link_cb_cls);
-
-
-/**
- * Cancel a refresh link request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param rlh the refresh link handle
- */
-void
-TALER_MINT_refresh_link_cancel (struct TALER_MINT_RefreshLinkHandle *rlh);
-
-
-/* ********************* /admin/add/incoming *********************** */
-
-
-/**
- * @brief A /admin/add/incoming Handle
- */
-struct TALER_MINT_AdminAddIncomingHandle;
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting
- * information about an incoming transaction to a mint.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-typedef void
-(*TALER_MINT_AdminAddIncomingResultCallback) (void *cls,
- unsigned int http_status,
- json_t *full_response);
-
-
-/**
- * Notify the mint that we have received an incoming transaction
- * which fills a reserve. Note that this API is an administrative
- * API and thus not accessible to typical mint clients, but only
- * to the operators of the mint.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param reserve_pub public key of the reserve
- * @param amount amount that was deposited
- * @param execution_date when did we receive the amount
- * @param wire wire details
- * @param res_cb the callback to call when the final result for this request is available
- * @param res_cb_cls closure for the above callback
- * @return NULL
- * if the inputs are invalid (i.e. invalid amount).
- * In this case, the callback is not called.
- */
-struct TALER_MINT_AdminAddIncomingHandle *
-TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute execution_date,
- const json_t *wire,
- TALER_MINT_AdminAddIncomingResultCallback res_cb,
- void *res_cb_cls);
-
-
-/**
- * Cancel an add incoming. This function cannot be used on a request
- * handle if a response is already served for it.
- *
- * @param aai the admin add incoming request handle
- */
-void
-TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle *aai);
-
-
-/* ********************* /wire/deposits *********************** */
-
-/**
- * @brief A /wire/deposits Handle
- */
-struct TALER_MINT_WireDepositsHandle;
-
-
-/**
- * Details for one of the /deposit operations that the
- * mint combined into a single wire transfer.
- */
-struct TALER_WireDepositDetails
-{
- /**
- * Hash of the contract.
- */
- struct GNUNET_HashCode h_contract;
-
- /**
- * Which coin was deposited?
- */
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- /**
- * Value of the deposit (including fee).
- */
- struct TALER_Amount coin_value;
-
- /**
- * Fee charged by the mint for the deposit.
- */
- struct TALER_Amount coin_fee;
-
- /**
- * Merchant's transaction identifier.
- */
- uint64_t transaction_id;
-
-};
-
-
-/**
- * Function called with detailed wire transfer data, including all
- * of the coin transactions that were combined into the wire transfer.
- *
- * @param cls closure
- * @param http_status HTTP status code we got, 0 on mint protocol violation
- * @param json original json reply (may include signatures, those have then been
- * validated already)
- * @param wtid extracted wire transfer identifier, or NULL if the mint could
- * not provide any (set only if @a http_status is #MHD_HTTP_OK)
- * @param total_amount total amount of the wire transfer, or NULL if the mint could
- * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
- * @param details_length length of the @a details array
- * @param details array with details about the combined transactions
- */
-typedef void
-(*TALER_MINT_WireDepositsCallback)(void *cls,
- unsigned int http_status,
- json_t *json,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_Amount *total_amount,
- unsigned int details_length,
- const struct TALER_WireDepositDetails *details);
-
-
-/**
- * Query the mint about which transactions were combined
- * to create a wire transfer.
- *
- * @param mint mint to query
- * @param wtid raw wire transfer identifier to get information about
- * @param cb callback to call
- * @param cb_cls closure for @a cb
- * @return handle to cancel operation
- */
-struct TALER_MINT_WireDepositsHandle *
-TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MINT_WireDepositsCallback cb,
- void *cb_cls);
-
-
-/**
- * Cancel wire deposits request. This function cannot be used on a request
- * handle if a response is already served for it.
- *
- * @param wdh the wire deposits request handle
- */
-void
-TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh);
-
-
-/* ********************* /deposit/wtid *********************** */
-
-
-/**
- * @brief A /deposit/wtid Handle
- */
-struct TALER_MINT_DepositWtidHandle;
-
-
-/**
- * Function called with detailed wire transfer data.
- *
- * @param cls closure
- * @param http_status HTTP status code we got, 0 on mint protocol violation
- * @param json original json reply (may include signatures, those have then been
- * validated already)
- * @param wtid wire transfer identifier used by the mint, NULL if mint did not
- * yet execute the transaction
- * @param execution_time actual or planned execution time for the wire transfer
- * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
- */
-typedef void
-(*TALER_MINT_DepositWtidCallback)(void *cls,
- unsigned int http_status,
- json_t *json,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_Amount *coin_contribution);
-
-
-/**
- * Obtain the wire transfer details for a given deposit.
- *
- * @param mint the mint to query
- * @param merchant_priv the merchant's private key
- * @param h_wire hash of merchant's wire transfer details
- * @param h_contract hash of the contract
- * @param coin_pub public key of the coin
- * @param transaction_id transaction identifier
- * @param cb function to call with the result
- * @param cb_cls closure for @a cb
- * @return handle to abort request
- */
-struct TALER_MINT_DepositWtidHandle *
-TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint,
- const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- uint64_t transaction_id,
- TALER_MINT_DepositWtidCallback cb,
- void *cb_cls);
-
-
-/**
- * Cancel deposit wtid request. This function cannot be used on a request
- * handle if a response is already served for it.
- *
- * @param dwh the wire deposits request handle
- */
-void
-TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh);
-
-
-#endif /* _TALER_MINT_SERVICE_H */
diff --git a/src/include/taler_mintdb_lib.h b/src/include/taler_mintdb_lib.h
deleted file mode 100644
index 70e314d9a..000000000
--- a/src/include/taler_mintdb_lib.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file include/taler_mintdb_lib.h
- * @brief IO operations for the mint's private keys
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINTDB_LIB_H
-#define TALER_MINTDB_LIB_H
-
-#include "taler_signatures.h"
-
-/**
- * Subdirectroy under the mint's base directory which contains
- * the mint's signing keys.
- */
-#define TALER_MINTDB_DIR_SIGNING_KEYS "signkeys"
-
-/**
- * Subdirectory under the mint's base directory which contains
- * the mint's denomination keys.
- */
-#define TALER_MINTDB_DIR_DENOMINATION_KEYS "denomkeys"
-
-/**
- * Subdirectory under the mint's base directory which contains
- * the mint's auditing information.
- */
-#define TALER_MINTDB_DIR_AUDITORS "auditors"
-
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * @brief On disk format used for a mint signing key. Signing keys are used
- * by the mint to affirm its messages, but not to create coins.
- * Includes the private key followed by the public information about
- * the signing key.
- */
-struct TALER_MINTDB_PrivateSigningKeyInformationP
-{
- /**
- * Private key part of the mint's signing key.
- */
- struct TALER_MintPrivateKeyP signkey_priv;
-
- /**
- * Public information about a mint signing key.
- */
- struct TALER_MintSigningKeyValidityPS issue;
-};
-
-
-/**
- * Information about a denomination key.
- */
-struct TALER_MINTDB_DenominationKeyInformationP
-{
-
- /**
- * Signature over this struct to affirm the validity of the key.
- */
- struct TALER_MasterSignatureP signature;
-
- /**
- * Signed properties of the denomination key.
- */
- struct TALER_DenominationKeyValidityPS properties;
-};
-
-
-GNUNET_NETWORK_STRUCT_END
-
-
-/**
- * @brief All information about a denomination key (which is used to
- * sign coins into existence).
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation
-{
- /**
- * The private key of the denomination. Will be NULL if the private
- * key is not available (this is the case after the key has expired
- * for signing coins, but is still valid for depositing coins).
- */
- struct TALER_DenominationPrivateKey denom_priv;
-
- /**
- * Decoded denomination public key (the hash of it is in
- * @e issue, but we sometimes need the full public key as well).
- */
- struct TALER_DenominationPublicKey denom_pub;
-
- /**
- * Signed public information about a denomination key.
- */
- struct TALER_MINTDB_DenominationKeyInformationP issue;
-};
-
-
-/**
- * @brief Iterator over signing keys.
- *
- * @param cls closure
- * @param filename name of the file the key came from
- * @param ski the sign key
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-typedef int
-(*TALER_MINTDB_SigningKeyIterator)(void *cls,
- const char *filename,
- const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski);
-
-
-/**
- * Call @a it for each signing key found in the @a mint_base_dir.
- *
- * @param mint_base_dir base directory for the mint,
- * the signing keys must be in the #TALER_MINTDB_DIR_SIGNING_KEYS
- * subdirectory
- * @param it function to call on each signing key
- * @param it_cls closure for @a it
- * @return number of files found (may not match
- * number of keys given to @a it as malformed
- * files are simply skipped), -1 on error
- */
-int
-TALER_MINTDB_signing_keys_iterate (const char *mint_base_dir,
- TALER_MINTDB_SigningKeyIterator it,
- void *it_cls);
-
-
-
-/**
- * @brief Iterator over denomination keys.
- *
- * @param cls closure
- * @param dki the denomination key
- * @param alias coin alias
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-typedef int
-(*TALER_MINTDB_DenominationKeyIterator)(void *cls,
- const char *alias,
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
-
-
-/**
- * Call @a it for each denomination key found in the @a mint_base_dir.
- *
- * @param mint_base_dir base directory for the mint,
- * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS
- * subdirectory
- * @param it function to call on each denomination key found
- * @param it_cls closure for @a it
- * @return -1 on error, 0 if no files were found, otherwise
- * a positive number (however, even with a positive
- * number it is possible that @a it was never called
- * as maybe none of the files were well-formed)
- */
-int
-TALER_MINTDB_denomination_keys_iterate (const char *mint_base_dir,
- TALER_MINTDB_DenominationKeyIterator it,
- void *it_cls);
-
-
-/**
- * Exports a denomination key to the given file.
- *
- * @param filename the file where to write the denomination key
- * @param dki the denomination key
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
- */
-int
-TALER_MINTDB_denomination_key_write (const char *filename,
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
-
-
-/**
- * Import a denomination key from the given file.
- *
- * @param filename the file to import the key from
- * @param[out] dki set to the imported denomination key
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINTDB_denomination_key_read (const char *filename,
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
-
-
-/**
- * @brief Iterator over auditor information.
- *
- * @param cls closure
- * @param apub the auditor's public key
- * @param mpub the mint's public key (as expected by the auditor)
- * @param dki_len length of @a asig and @a dki arrays
- * @param asigs array of the auditor's signatures over the @a dks, of length @a dki_len
- * @param dki array of denomination coin data signed by the auditor, of length @a dki_len
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-typedef int
-(*TALER_MINTDB_AuditorIterator)(void *cls,
- const struct TALER_AuditorPublicKeyP *apub,
- const struct TALER_MasterPublicKeyP *mpub,
- unsigned int dki_len,
- const struct TALER_AuditorSignatureP *asigs,
- const struct TALER_DenominationKeyValidityPS *dki);
-
-
-/**
- * Call @a it with information for each auditor found in the @a mint_base_dir.
- *
- * @param mint_base_dir base directory for the mint,
- * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS
- * subdirectory
- * @param it function to call with auditor information
- * @param it_cls closure for @a it
- * @return -1 on error, 0 if no files were found, otherwise
- * a positive number (however, even with a positive
- * number it is possible that @a it was never called
- * as maybe none of the files were well-formed)
- */
-int
-TALER_MINTDB_auditor_iterate (const char *mint_base_dir,
- TALER_MINTDB_AuditorIterator it,
- void *it_cls);
-
-
-/**
- * Write auditor information to the given file.
- *
- * @param filename the file where to write the auditor information to
- * @param apub the auditor's public key
- * @param asigs the auditor's signatures, array of length @a dki_len
- * @param mpub the mint's public key (as expected by the auditor)
- * @param dki_len length of @a dki and @a asigs arrays
- * @param dki array of denomination coin data signed by the auditor
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
- */
-int
-TALER_MINTDB_auditor_write (const char *filename,
- const struct TALER_AuditorPublicKeyP *apub,
- const struct TALER_AuditorSignatureP *asigs,
- const struct TALER_MasterPublicKeyP *mpub,
- unsigned int dki_len,
- const struct TALER_DenominationKeyValidityPS *dki);
-
-
-/**
- * Initialize the plugin.
- *
- * @param cfg configuration to use
- * @return NULL on failure
- */
-struct TALER_MINTDB_Plugin *
-TALER_MINTDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-
-/**
- * Shutdown the plugin.
- *
- * @param plugin plugin to unload
- */
-void
-TALER_MINTDB_plugin_unload (struct TALER_MINTDB_Plugin *plugin);
-
-
-
-#endif
diff --git a/src/include/taler_mintdb_plugin.h b/src/include/taler_mintdb_plugin.h
deleted file mode 100644
index b65b3e4f7..000000000
--- a/src/include/taler_mintdb_plugin.h
+++ /dev/null
@@ -1,1431 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file include/taler_mintdb_plugin.h
- * @brief Low-level (statement-level) database access for the mint
- * @author Florian Dold
- * @author Christian Grothoff
- */
-#ifndef TALER_MINTDB_PLUGIN_H
-#define TALER_MINTDB_PLUGIN_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mintdb_lib.h"
-
-
-/**
- * @brief Information we keep on bank transfer(s) that established a reserve.
- */
-struct TALER_MINTDB_BankTransfer
-{
-
- /**
- * Public key of the reserve that was filled.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- /**
- * Amount that was transferred to the mint.
- */
- struct TALER_Amount amount;
-
- /**
- * When did the mint receive the incoming transaction?
- * (This is the execution date of the mint's database,
- * the execution date of the bank should be in @e wire).
- */
- struct GNUNET_TIME_Absolute execution_date;
-
- /**
- * Detailed wire information about the transaction.
- */
- json_t *wire;
-
-};
-
-
-/**
- * @brief A summary of a Reserve
- */
-struct TALER_MINTDB_Reserve
-{
- /**
- * The reserve's public key. This uniquely identifies the reserve
- */
- struct TALER_ReservePublicKeyP pub;
-
- /**
- * The balance amount existing in the reserve
- */
- struct TALER_Amount balance;
-
- /**
- * The expiration date of this reserve
- */
- struct GNUNET_TIME_Absolute expiry;
-};
-
-
-/**
- * @brief Information we keep for a withdrawn coin to reproduce
- * the /withdraw operation if needed, and to have proof
- * that a reserve was drained by this amount.
- */
-struct TALER_MINTDB_CollectableBlindcoin
-{
-
- /**
- * Our signature over the (blinded) coin.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Denomination key (which coin was generated).
- */
- struct TALER_DenominationPublicKey denom_pub;
-
- /**
- * Value of the coin being minted (matching the denomination key)
- * plus the transaction fee. We include this in what is being
- * signed so that we can verify a reserve's remaining total balance
- * without needing to access the respective denomination key
- * information each time.
- */
- struct TALER_Amount amount_with_fee;
-
- /**
- * Withdrawl fee charged by the mint. This must match the Mint's
- * denomination key's withdrawl fee. If the client puts in an
- * invalid withdrawl fee (too high or too low) that does not match
- * the Mint's denomination key, the withdraw operation is invalid
- * and will be rejected by the mint. The @e amount_with_fee minus
- * the @e withdraw_fee is must match the value of the generated
- * coin. We include this in what is being signed so that we can
- * verify a mint's accounting without needing to access the
- * respective denomination key information each time.
- */
- struct TALER_Amount withdraw_fee;
-
- /**
- * Public key of the reserve that was drained.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- /**
- * Hash over the blinded message, needed to verify
- * the @e reserve_sig.
- */
- struct GNUNET_HashCode h_coin_envelope;
-
- /**
- * Signature confirming the withdrawl, matching @e reserve_pub,
- * @e denom_pub and @e h_coin_envelope.
- */
- struct TALER_ReserveSignatureP reserve_sig;
-};
-
-
-
-/**
- * @brief Types of operations on a reserved.
- */
-enum TALER_MINTDB_ReserveOperation
-{
- /**
- * Money was deposited into the reserve via a bank transfer.
- */
- TALER_MINTDB_RO_BANK_TO_MINT = 0,
-
- /**
- * A Coin was withdrawn from the reserve using /withdraw.
- */
- TALER_MINTDB_RO_WITHDRAW_COIN = 1
-};
-
-
-/**
- * @brief Reserve history as a linked list. Lists all of the transactions
- * associated with this reserve (such as the bank transfers that
- * established the reserve and all /withdraw operations we have done
- * since).
- */
-struct TALER_MINTDB_ReserveHistory
-{
-
- /**
- * Next entry in the reserve history.
- */
- struct TALER_MINTDB_ReserveHistory *next;
-
- /**
- * Type of the event, determins @e details.
- */
- enum TALER_MINTDB_ReserveOperation type;
-
- /**
- * Details of the operation, depending on @e type.
- */
- union
- {
-
- /**
- * Details about a bank transfer to the mint.
- */
- struct TALER_MINTDB_BankTransfer *bank;
-
- /**
- * Details about a /withdraw operation.
- */
- struct TALER_MINTDB_CollectableBlindcoin *withdraw;
-
- } details;
-
-};
-
-
-/**
- * @brief Specification for a /deposit operation. The combination of
- * the coin's public key, the merchant's public key and the
- * transaction ID must be unique. While a coin can (theoretically) be
- * deposited at the same merchant twice (with partial spending), the
- * merchant must either use a different public key or a different
- * transaction ID for the two transactions. The same coin must not
- * be used twice at the same merchant for the same transaction
- * (as determined by transaction ID). (Note: we might want to
- * fix #3819 and include at least h_contract as well.)
- */
-struct TALER_MINTDB_Deposit
-{
- /**
- * Information about the coin that is being deposited.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * ECDSA signature affirming that the customer intends
- * this coin to be deposited at the merchant identified
- * by @e h_wire in relation to the contract identified
- * by @e h_contract.
- */
- struct TALER_CoinSpendSignatureP csig;
-
- /**
- * Public key of the merchant. Enables later identification
- * of the merchant in case of a need to rollback transactions.
- */
- struct TALER_MerchantPublicKeyP merchant_pub;
-
- /**
- * Hash over the contract between merchant and customer
- * (remains unknown to the Mint).
- */
- struct GNUNET_HashCode h_contract;
-
- /**
- * Hash of the (canonical) representation of @e wire, used
- * to check the signature on the request. Generated by
- * the mint from the detailed wire data provided by the
- * merchant.
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * Detailed wire information for executing the transaction.
- */
- json_t *wire;
-
- /**
- * Merchant-generated transaction ID to detect duplicate
- * transactions.
- */
- uint64_t transaction_id;
-
- /**
- * Time when this request was generated. Used, for example, to
- * assess when (roughly) the income was achieved for tax purposes.
- * Note that the Mint will only check that the timestamp is not "too
- * far" into the future (i.e. several days). The fact that the
- * timestamp falls within the validity period of the coin's
- * denomination key is irrelevant for the validity of the deposit
- * request, as obviously the customer and merchant could conspire to
- * set any timestamp. Also, the Mint must accept very old deposit
- * requests, as the merchant might have been unable to transmit the
- * deposit request in a timely fashion (so back-dating is not
- * prevented).
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * How much time does the merchant have to issue a refund request?
- * Zero if refunds are not allowed. After this time, the coin
- * cannot be refunded.
- */
- struct GNUNET_TIME_Absolute refund_deadline;
-
- /**
- * How much time does the merchant have to execute the wire transfer?
- * This time is advisory for aggregating transactions, not a hard
- * constraint (as the merchant can theoretically pick any time,
- * including one in the past).
- */
- struct GNUNET_TIME_Absolute wire_deadline;
-
- /**
- * Fraction of the coin's remaining value to be deposited, including
- * depositing fee (if any). The coin is identified by @e coin_pub.
- */
- struct TALER_Amount amount_with_fee;
-
- /**
- * Depositing fee.
- */
- struct TALER_Amount deposit_fee;
-
-};
-
-
-/**
- * @brief Global information for a refreshing session. Includes
- * dimensions of the operation, security parameters and
- * client signatures from "/refresh/melt" and "/refresh/commit".
- */
-struct TALER_MINTDB_RefreshSession
-{
-
- /**
- * Number of coins we are melting.
- */
- uint16_t num_oldcoins;
-
- /**
- * Number of new coins we are creating.
- */
- uint16_t num_newcoins;
-
- /**
- * Index (smaller #TALER_CNC_KAPPA) which the mint has chosen to not
- * have revealed during cut and choose.
- */
- uint16_t noreveal_index;
-
-};
-
-
-/**
- * @brief Specification for coin in a /refresh/melt operation.
- */
-struct TALER_MINTDB_RefreshMelt
-{
- /**
- * Information about the coin that is being melted.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * Signature over the melting operation.
- */
- struct TALER_CoinSpendSignatureP coin_sig;
-
- /**
- * Hash of the refresh session this coin is melted into.
- */
- struct GNUNET_HashCode session_hash;
-
- /**
- * How much value is being melted? This amount includes the fees,
- * so the final amount contributed to the melt is this value minus
- * the fee for melting the coin. We include the fee in what is
- * being signed so that we can verify a reserve's remaining total
- * balance without needing to access the respective denomination key
- * information each time.
- */
- struct TALER_Amount amount_with_fee;
-
- /**
- * Melting fee charged by the mint. This must match the Mint's
- * denomination key's melting fee. If the client puts in an invalid
- * melting fee (too high or too low) that does not match the Mint's
- * denomination key, the melting operation is invalid and will be
- * rejected by the mint. The @e amount_with_fee minus the @e
- * melt_fee is the amount that will be credited to the melting
- * session.
- */
- struct TALER_Amount melt_fee;
-
-};
-
-
-/**
- * @brief We have as many `struct TALER_MINTDB_RefreshCommitCoin` as there are new
- * coins being created by the refresh (for each of the #TALER_CNC_KAPPA
- * sets). These are the coins we ask the mint to sign if the
- * respective set is selected.
- */
-struct TALER_MINTDB_RefreshCommitCoin
-{
-
- /**
- * Encrypted data allowing those able to decrypt it to derive
- * the private keys of the new coins created by the refresh.
- */
- struct TALER_RefreshLinkEncrypted *refresh_link;
-
- /**
- * Blinded message to be signed (in envelope), with @e coin_env_size bytes.
- */
- char *coin_ev;
-
- /**
- * Number of bytes in @e coin_ev.
- */
- size_t coin_ev_size;
-
-};
-
-
-/**
- * @brief Linked list of refresh information linked to a coin.
- */
-struct TALER_MINTDB_LinkDataList
-{
- /**
- * Information is stored in a NULL-terminated linked list.
- */
- struct TALER_MINTDB_LinkDataList *next;
-
- /**
- * Link data, used to recover the private key of the coin
- * by the owner of the old coin.
- */
- struct TALER_RefreshLinkEncrypted *link_data_enc;
-
- /**
- * Denomination public key, determines the value of the coin.
- */
- struct TALER_DenominationPublicKey denom_pub;
-
- /**
- * Signature over the blinded envelope.
- */
- struct TALER_DenominationSignature ev_sig;
-};
-
-
-/**
- * @brief Enumeration to classify the different types of transactions
- * that can be done with a coin.
- */
-enum TALER_MINTDB_TransactionType
-{
- /**
- * /deposit operation.
- */
- TALER_MINTDB_TT_DEPOSIT = 0,
-
- /**
- * /refresh/melt operation.
- */
- TALER_MINTDB_TT_REFRESH_MELT = 1
-
-};
-
-
-/**
- * @brief List of transactions we performed for a particular coin.
- */
-struct TALER_MINTDB_TransactionList
-{
-
- /**
- * Next pointer in the NULL-terminated linked list.
- */
- struct TALER_MINTDB_TransactionList *next;
-
- /**
- * Type of the transaction, determines what is stored in @e details.
- */
- enum TALER_MINTDB_TransactionType type;
-
- /**
- * Details about the transaction, depending on @e type.
- */
- union
- {
-
- /**
- * Details if transaction was a /deposit operation.
- */
- struct TALER_MINTDB_Deposit *deposit;
-
- /**
- * Details if transaction was a /refresh/melt operation.
- */
- struct TALER_MINTDB_RefreshMelt *melt;
-
- } details;
-
-};
-
-
-/**
- * @brief All of the information from a /refresh/melt commitment.
- */
-struct TALER_MINTDB_MeltCommitment
-{
-
- /**
- * Number of coins we are melting.
- */
- uint16_t num_oldcoins;
-
- /**
- * Number of new coins we are creating.
- */
- uint16_t num_newcoins;
-
- /**
- * Array of @e num_oldcoins melt operation details.
- */
- struct TALER_MINTDB_RefreshMelt *melts;
-
- /**
- * Array of @e num_newcoins denomination keys
- */
- struct TALER_DenominationPublicKey *denom_pubs;
-
- /**
- * 2D-Array of #TALER_CNC_KAPPA and @e num_newcoins commitments.
- */
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins[TALER_CNC_KAPPA];
-
- /**
- * 2D-Array of #TALER_CNC_KAPPA and @e new_oldcoins links.
- */
- struct TALER_RefreshCommitLinkP *commit_links[TALER_CNC_KAPPA];
-};
-
-
-/**
- * @brief Handle for a database session (per-thread, for transactions).
- */
-struct TALER_MINTDB_Session;
-
-
-/**
- * Function called with details about deposits that
- * have been made, with the goal of executing the
- * corresponding wire transaction.
- *
- * @param cls closure
- * @param rowid unique ID for the deposit in our DB, used for marking
- * it as 'tiny' or 'done'
- * @param merchant_pub public key of the merchant
- * @param coin_pub public key of the coin
- * @param amount_with_fee amount that was deposited including fee
- * @param deposit_fee amount the mint gets to keep as transaction fees
- * @param transaction_id unique transaction ID chosen by the merchant
- * @param h_contract hash of the contract between merchant and customer
- * @param wire_deadline by which the merchant adviced that he would like the
- * wire transfer to be executed
- * @param wire wire details for the merchant, NULL from iterate_matching_deposits()
- * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
- */
-typedef int
-(*TALER_MINTDB_DepositIterator)(void *cls,
- unsigned long long rowid,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *amount_with_fee,
- const struct TALER_Amount *deposit_fee,
- uint64_t transaction_id,
- const struct GNUNET_HashCode *h_contract,
- struct GNUNET_TIME_Absolute wire_deadline,
- const json_t *wire);
-
-
-/**
- * Function called with the session hashes and transfer secret
- * information for a given coin.
- *
- * @param cls closure
- * @param session_hash a session the coin was melted in
- * @param transfer_pub public transfer key for the session
- * @param shared_secret_enc set to shared secret for the session
- */
-typedef void
-(*TALER_MINTDB_TransferDataCallback)(void *cls,
- const struct GNUNET_HashCode *session_hash,
- const struct TALER_TransferPublicKeyP *transfer_pub,
- const struct TALER_EncryptedLinkSecretP *shared_secret_enc);
-
-
-/**
- * Function called with the results of the lookup of the
- * wire transfer identifier information. Only called if
- * we are at least aware of the transaction existing.
- *
- * @param cls closure
- * @param wtid wire transfer identifier, NULL
- * if the transaction was not yet done
- * @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value including fee)
- * @param coin_fee how much did the mint charge for the deposit fee
- * @param execution_time when was the transaction done, or
- * when we expect it to be done (if @a wtid was NULL)
- */
-typedef void
-(*TALER_MINTDB_DepositWtidCallback)(void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time);
-
-
-/**
- * Function called with the results of the lookup of the
- * transaction data associated with a wire transfer identifier.
- *
- * @param cls closure
- * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_contract which contract was this payment about
- * @param transaction_id merchant's transaction ID for the payment
- * @param coin_pub which public key was this payment about
- * @param coin_value amount contributed by this coin in total (with fee)
- * @param coin_fee applicable fee for this coin
- */
-typedef void
-(*TALER_MINTDB_WireTransferDataCallback)(void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_value,
- const struct TALER_Amount *coin_fee);
-
-
-/**
- * Callback with data about a prepared transaction.
- *
- * @param cls closure
- * @param rowid row identifier used to mark prepared transaction as done
- * @param buf transaction data that was persisted, NULL on error
- * @param buf_size number of bytes in @a buf, 0 on error
- */
-typedef void
-(*TALER_MINTDB_WirePreparationCallback) (void *cls,
- unsigned long long rowid,
- const char *buf,
- size_t buf_size);
-
-
-/**
- * @brief The plugin API, returned from the plugin's "init" function.
- * The argument given to "init" is simply a configuration handle.
- */
-struct TALER_MINTDB_Plugin
-{
-
- /**
- * Closure for all callbacks.
- */
- void *cls;
-
- /**
- * Name of the library which generated this plugin. Set by the
- * plugin loader.
- */
- char *library_name;
-
- /**
- * Get the thread-local database-handle.
- * Connect to the db if the connection does not exist yet.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
- * database default one
- * @param the database connection, or NULL on error
- */
- struct TALER_MINTDB_Session *
- (*get_session) (void *cls,
- int temporary);
-
-
- /**
- * Drop the temporary taler schema. This is only useful for testcases.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- int
- (*drop_temporary) (void *cls,
- struct TALER_MINTDB_Session *db);
-
-
- /**
- * Create the necessary tables if they are not present
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param temporary should we use a temporary schema
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- int
- (*create_tables) (void *cls,
- int temporary);
-
-
- /**
- * Start a transaction.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @return #GNUNET_OK on success
- */
- int
- (*start) (void *cls,
- struct TALER_MINTDB_Session *session);
-
-
- /**
- * Commit a transaction.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @return #GNUNET_OK on success, #GNUNET_NO if the transaction
- * can be retried, #GNUNET_SYSERR on hard failures
- */
- int
- (*commit) (void *cls,
- struct TALER_MINTDB_Session *session);
-
-
- /**
- * Abort/rollback a transaction.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- */
- void
- (*rollback) (void *cls,
- struct TALER_MINTDB_Session *session);
-
-
- /**
- * Insert information about a denomination key and in particular
- * the properties (value, fees, expiration times) the coins signed
- * with this key have.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @param denom_pub the public key used for signing coins of this denomination
- * @param issue issuing information with value, fees and other info about the coin
- * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
- */
- int
- (*insert_denomination_info) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_DenominationPublicKey *denom_pub,
- const struct TALER_MINTDB_DenominationKeyInformationP *issue);
-
-
- /**
- * Fetch information about a denomination key.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @param denom_pub the public key used for signing coins of this denomination
- * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL
- * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure
- */
- int
- (*get_denomination_info) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_DenominationPublicKey *denom_pub,
- struct TALER_MINTDB_DenominationKeyInformationP *issue);
-
-
- /**
- * Get the summary of a reserve.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param db the database connection handle
- * @param[in,out] reserve the reserve data. The public key of the reserve should be set
- * in this structure; it is used to query the database. The balance
- * and expiration are then filled accordingly.
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
- int
- (*reserve_get) (void *cls,
- struct TALER_MINTDB_Session *db,
- struct TALER_MINTDB_Reserve *reserve);
-
-
- /**
- * Insert a incoming transaction into reserves. New reserves are
- * also created through this function. Note that this API call
- * starts (and stops) its own transaction scope (so the application
- * must not do so).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param db the database connection handle
- * @param reserve_pub public key of the reserve
- * @param balance the amount that has to be added to the reserve
- * @param execution_time when was the amount added
- * @param details bank transaction details justifying the increment,
- * must be unique for each incoming transaction
- * @return #GNUNET_OK upon success; #GNUNET_NO if the given
- * @a details are already known for this @a reserve_pub,
- * #GNUNET_SYSERR upon failures (DB error, incompatible currency)
- */
- int
- (*reserves_in_insert) (void *cls,
- struct TALER_MINTDB_Session *db,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *balance,
- struct GNUNET_TIME_Absolute execution_time,
- const json_t *details);
-
-
- /**
- * Locate the response for a /withdraw request under the
- * key of the hash of the blinded message.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param h_blind hash of the blinded coin to be signed (will match
- * `h_coin_envelope` in the @a collectable to be returned)
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
- int
- (*get_withdraw_info) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *h_blind,
- struct TALER_MINTDB_CollectableBlindcoin *collectable);
-
-
- /**
- * Store collectable bit coin under the corresponding
- * hash of the blinded message.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
- int
- (*insert_withdraw_info) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_CollectableBlindcoin *collectable);
-
-
- /**
- * Get all of the transaction history associated with the specified
- * reserve.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @param reserve_pub public key of the reserve
- * @return known transaction history (NULL if reserve is unknown)
- */
- struct TALER_MINTDB_ReserveHistory *
- (*get_reserve_history) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_ReservePublicKeyP *reserve_pub);
-
-
- /**
- * Free memory associated with the given reserve history.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param rh history to free.
- */
- void
- (*free_reserve_history) (void *cls,
- struct TALER_MINTDB_ReserveHistory *rh);
-
-
- /**
- * Check if we have the specified deposit already in the database.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param deposit deposit to search for
- * @return #GNUNET_YES if we know this operation,
- * #GNUNET_NO if this exact deposit is unknown to us,
- * #GNUNET_SYSERR on DB error
- */
- int
- (*have_deposit) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_Deposit *deposit);
-
-
- /**
- * Insert information about deposited coin into the database.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit deposit information to store
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
- int
- (*insert_deposit) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_Deposit *deposit);
-
-
- /**
- * Mark a deposit as tiny, thereby declaring that it cannot be
- * executed by itself and should no longer be returned by
- * @e iterate_ready_deposits()
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit_rowid identifies the deposit row to modify
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
- int
- (*mark_deposit_tiny) (void *cls,
- struct TALER_MINTDB_Session *session,
- unsigned long long rowid);
-
-
- /**
- * Mark a deposit as done, thereby declaring that it cannot be
- * executed at all anymore, and should no longer be returned by
- * @e iterate_ready_deposits() or @e iterate_matching_deposits().
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit_rowid identifies the deposit row to modify
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
- int
- (*mark_deposit_done) (void *cls,
- struct TALER_MINTDB_Session *session,
- unsigned long long rowid);
-
-
- /**
- * Obtain information about deposits that are ready to be executed.
- * Such deposits must not be marked as "tiny" or "done", and the
- * execution time must be in the past.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit_cb function to call for ONE such deposit
- * @param deposit_cb_cls closure for @a deposit_cb
- * @return number of rows processed, 0 if none exist,
- * #GNUNET_SYSERR on error
- */
- int
- (*get_ready_deposit) (void *cls,
- struct TALER_MINTDB_Session *session,
- TALER_MINTDB_DepositIterator deposit_cb,
- void *deposit_cb_cls);
-
-
- /**
- * Obtain information about other pending deposits for the same
- * destination. Those deposits must not already be "done".
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param h_wire destination of the wire transfer
- * @param merchant_pub public key of the merchant
- * @param deposit_cb function to call for each deposit
- * @param deposit_cb_cls closure for @a deposit_cb
- * @param limit maximum number of matching deposits to return
- * @return number of rows processed, 0 if none exist,
- * #GNUNET_SYSERR on error
- */
- int
- (*iterate_matching_deposits) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- TALER_MINTDB_DepositIterator deposit_cb,
- void *deposit_cb_cls,
- uint32_t limit);
-
-
- /**
- * Lookup refresh session data under the given @a session_hash.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database handle to use
- * @param session_hash hash over the melt to use for the lookup
- * @param[out] refresh_session where to store the result
- * @return #GNUNET_YES on success,
- * #GNUNET_NO if not found,
- * #GNUNET_SYSERR on DB failure
- */
- int
- (*get_refresh_session) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- struct TALER_MINTDB_RefreshSession *refresh_session);
-
-
- /**
- * Store new refresh session data under the given @a session_hash.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database handle to use
- * @param session_hash hash over the melt to use to locate the session
- * @param refresh_session session data to store
- * @return #GNUNET_YES on success,
- * #GNUNET_SYSERR on DB failure
- */
- int
- (*create_refresh_session) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- const struct TALER_MINTDB_RefreshSession *refresh_session);
-
-
- /**
- * Store the given /refresh/melt request in the database.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param oldcoin_index index of the coin to store
- * @param melt coin melt operation details to store; includes
- * the session hash of the melt
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
- int
- (*insert_refresh_melt) (void *cls,
- struct TALER_MINTDB_Session *session,
- uint16_t oldcoin_index,
- const struct TALER_MINTDB_RefreshMelt *melt);
-
-
- /**
- * Get information about melted coin details from the database.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param oldcoin_index index of the coin to retrieve
- * @param melt melt data to fill in, can be NULL
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
- int
- (*get_refresh_melt) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t oldcoin_index,
- struct TALER_MINTDB_RefreshMelt *melt);
-
-
- /**
- * Store in the database which coin(s) we want to create
- * in a given refresh operation.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
- * @param denom_pubs array denominations of the coins to create
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
- int
- (*insert_refresh_order) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t num_newcoins,
- const struct TALER_DenominationPublicKey *denom_pubs);
-
-
- /**
- * Lookup in the database for the @a num_newcoins coins that we want to
- * create in the given refresh operation.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param num_newcoins size of the @a denom_pubs array
- * @param[out] denom_pubs where to write @a num_newcoins denomination keys
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
- int
- (*get_refresh_order) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t num_newcoins,
- struct TALER_DenominationPublicKey *denom_pubs);
-
-
- /**
- * Store information about the commitments of the given index @a i
- * for the given refresh session in the database.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA
- * @param num_newcoins coin index size of the @a commit_coins array
- * @param commit_coin array of coin commitments to store
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on error
- */
- int
- (*insert_refresh_commit_coins) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_newcoins,
- const struct TALER_MINTDB_RefreshCommitCoin *commit_coins);
-
-
- /**
- * Obtain information about the commitment of the
- * given coin of the given refresh session from the database.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose set index (1st dimension)
- * @param num_coins size of the @a commit_coins array
- * @param[out] commit_coins array of coin commitments to return
- * @return #GNUNET_OK on success
- * #GNUNET_NO if not found
- * #GNUNET_SYSERR on error
- */
- int
- (*get_refresh_commit_coins) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_coins,
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins);
-
-
- /**
- * Store the commitment to the given (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA
- * @param num_links size of the @a commit_link array
- * @param commit_links array of link information to store
- * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
- */
- int
- (*insert_refresh_commit_links) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_links,
- const struct TALER_RefreshCommitLinkP *commit_links);
-
- /**
- * Obtain the commited (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose index (1st dimension)
- * @param num_links size of the @a links array to return
- * @param[out] links array link information to return
- * @return #GNUNET_SYSERR on internal error,
- * #GNUNET_NO if commitment was not found
- * #GNUNET_OK on success
- */
- int
- (*get_refresh_commit_links) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_links,
- struct TALER_RefreshCommitLinkP *links);
-
-
- /**
- * Get all of the information from the given melt commit operation.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @return NULL if the @a session_hash does not correspond to any known melt
- * operation
- */
- struct TALER_MINTDB_MeltCommitment *
- (*get_melt_commitment) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash);
-
-
- /**
- * Free information about a melt commitment.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param mc melt commitment data to free
- */
- void
- (*free_melt_commitment) (void *cls,
- struct TALER_MINTDB_MeltCommitment *mc);
-
-
- /**
- * Insert signature of a new coin generated during refresh into
- * the database indexed by the refresh session and the index
- * of the coin. This data is later used should an old coin
- * be used to try to obtain the private keys during "/refresh/link".
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param newcoin_index coin index
- * @param ev_sig coin signature
- * @return #GNUNET_OK on success
- */
- int
- (*insert_refresh_out) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t newcoin_index,
- const struct TALER_DenominationSignature *ev_sig);
-
-
- /**
- * Obtain the link data of a coin, that is the encrypted link
- * information, the denomination keys and the signatures.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param session_hash session to get linkage data for
- * @return all known link data for the session
- */
- struct TALER_MINTDB_LinkDataList *
- (*get_link_data_list) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash);
-
-
- /**
- * Free memory of the link data list.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param ldl link data list to release
- */
- void
- (*free_link_data_list) (void *cls,
- struct TALER_MINTDB_LinkDataList *ldl);
-
-
- /**
- * Obtain shared secret and transfer public key from the public key of
- * the coin. This information and the link information returned by
- * @e get_link_data_list() enable the owner of an old coin to determine
- * the private keys of the new coins after the melt.
- *
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param coin_pub public key of the coin
- * @param tdc function to call for each session the coin was melted into
- * @param tdc_cls closure for @a tdc
- * @return #GNUNET_OK on success,
- * #GNUNET_NO on failure (not found)
- * #GNUNET_SYSERR on internal failure (database issue)
- */
- int
- (*get_transfer) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- TALER_MINTDB_TransferDataCallback tdc,
- void *tdc_cls);
-
-
- /**
- * Compile a list of all (historic) transactions performed
- * with the given coin (/refresh/melt and /deposit operations).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param coin_pub coin to investigate
- * @return list of transactions, NULL if coin is fresh
- */
- struct TALER_MINTDB_TransactionList *
- (*get_coin_transactions) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_CoinSpendPublicKeyP *coin_pub);
-
-
- /**
- * Free linked list of transactions.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param list list to free
- */
- void
- (*free_coin_transaction_list) (void *cls,
- struct TALER_MINTDB_TransactionList *list);
-
-
- /**
- * Lookup the list of Taler transactions that was aggregated
- * into a wire transfer by the respective @a raw_wtid.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection
- * @param wtid the raw wire transfer identifier we used
- * @param cb function to call on each transaction found
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
- * #GNUNET_NO if we found no results
- */
- int
- (*lookup_wire_transfer) (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MINTDB_WireTransferDataCallback cb,
- void *cb_cls);
-
-
- /**
- * Try to find the wire transfer details for a deposit operation.
- * If we did not execute the deposit yet, return when it is supposed
- * to be executed.
- *
- * @param cls closure
- * @param session database connection
- * @param h_contract hash of the contract
- * @param h_wire hash of merchant wire details
- * @param coin_pub public key of deposited coin
- * @param merchant_pub merchant public key
- * @param transaction_id transaction identifier
- * @param cb function to call with the result
- * @param cb_cls closure to pass to @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
- * #GNUNET_NO if nothing was found
- */
- int
- (*wire_lookup_deposit_wtid)(void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *h_contract,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- uint64_t transaction_id,
- TALER_MINTDB_DepositWtidCallback cb,
- void *cb_cls);
-
-
- /**
- * Function called to insert aggregation information into the DB.
- *
- * @param cls closure
- * @param session database connection
- * @param wtid the raw wire transfer identifier we used
- * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_contract which contract was this payment about
- * @param transaction_id merchant's transaction ID for the payment
- * @param execution_time when did we execute the transaction
- * @param coin_pub which public key was this payment about
- * @param coin_value amount contributed by this coin in total
- * @param coin_fee deposit fee charged by mint for this coin
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
- */
- int
- (*insert_aggregation_tracking)(void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_value,
- const struct TALER_Amount *coin_fee);
-
-
- /**
- * Function called to insert wire transfer commit data into the DB.
- *
- * @param cls closure
- * @param session database connection
- * @param type type of the wire transfer (i.e. "sepa")
- * @param buf buffer with wire transfer preparation data
- * @param buf_size number of bytes in @a buf
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
- */
- int
- (*wire_prepare_data_insert)(void *cls,
- struct TALER_MINTDB_Session *session,
- const char *type,
- const char *buf,
- size_t buf_size);
-
-
- /**
- * Function called to mark wire transfer commit data as finished.
- *
- * @param cls closure
- * @param session database connection
- * @param rowid which entry to mark as finished
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
- */
- int
- (*wire_prepare_data_mark_finished)(void *cls,
- struct TALER_MINTDB_Session *session,
- unsigned long long rowid);
-
-
- /**
- * Function called to get an unfinished wire transfer
- * preparation data. Fetches at most one item.
- *
- * @param cls closure
- * @param session database connection
- * @param type type fo the wire transfer (i.e. "sepa")
- * @param cb function to call for ONE unfinished item
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if there are no entries,
- * #GNUNET_SYSERR on DB errors
- */
- int
- (*wire_prepare_data_get)(void *cls,
- struct TALER_MINTDB_Session *session,
- const char *type,
- TALER_MINTDB_WirePreparationCallback cb,
- void *cb_cls);
-
-
-};
-
-
-#endif /* _TALER_MINT_DB_H */
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 2526597ee..729bed262 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -54,62 +54,62 @@
#define TALER_IDLE_RESERVE_EXPIRATION_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS, 5)
/*********************************************/
-/* Mint offline signatures (with master key) */
+/* Exchange offline signatures (with master key) */
/*********************************************/
/**
- * Purpose for signing public keys signed by the mint master key.
+ * Purpose for signing public keys signed by the exchange master key.
*/
#define TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY 1024
/**
- * Purpose for denomination keys signed by the mint master key.
+ * Purpose for denomination keys signed by the exchange master key.
*/
#define TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY 1025
/**
- * Signature where the Mint confirms its SEPA details in
+ * Signature where the Exchange confirms its SEPA details in
* the /wire/sepa response.
*/
#define TALER_SIGNATURE_MASTER_SEPA_DETAILS 1026
/*********************************************/
-/* Mint online signatures (with signing key) */
+/* Exchange online signatures (with signing key) */
/*********************************************/
/**
- * Purpose for the state of a reserve, signed by the mint's signing
+ * Purpose for the state of a reserve, signed by the exchange's signing
* key.
*/
-#define TALER_SIGNATURE_MINT_RESERVE_STATUS 1032
+#define TALER_SIGNATURE_EXCHANGE_RESERVE_STATUS 1032
/**
- * Signature where the Mint confirms a deposit request.
+ * Signature where the Exchange confirms a deposit request.
*/
-#define TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT 1033
+#define TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT 1033
/**
- * Signature where the mint (current signing key) confirms the
+ * Signature where the exchange (current signing key) confirms the
* no-reveal index for cut-and-choose and the validity of the melted
* coins.
*/
-#define TALER_SIGNATURE_MINT_CONFIRM_MELT 1034
+#define TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT 1034
/**
- * Signature where the Mint confirms the full /keys response set.
+ * Signature where the Exchange confirms the full /keys response set.
*/
-#define TALER_SIGNATURE_MINT_KEY_SET 1035
+#define TALER_SIGNATURE_EXCHANGE_KEY_SET 1035
/**
- * Signature where the Mint confirms the /wire response.
+ * Signature where the Exchange confirms the /wire response.
*/
-#define TALER_SIGNATURE_MINT_WIRE_TYPES 1036
+#define TALER_SIGNATURE_EXCHANGE_WIRE_TYPES 1036
/**
- * Signature where the Mint confirms the /deposit/wtid response.
+ * Signature where the Exchange confirms the /deposit/wtid response.
*/
-#define TALER_SIGNATURE_MINT_CONFIRM_WIRE 1036
+#define TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE 1036
/*********************/
@@ -118,9 +118,9 @@
/**
* Signature where the auditor confirms that he is
- * aware of certain denomination keys from the mint.
+ * aware of certain denomination keys from the exchange.
*/
-#define TALER_SIGNATURE_AUDITOR_MINT_KEYS 1064
+#define TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS 1064
/***********************/
@@ -176,7 +176,7 @@
/**
* EdDSA test signature.
*/
-#define TALER_SIGNATURE_MINT_TEST_EDDSA 1303
+#define TALER_SIGNATURE_EXCHANGE_TEST_EDDSA 1303
@@ -202,7 +202,7 @@ struct TALER_WithdrawRequestPS
struct TALER_ReservePublicKeyP reserve_pub;
/**
- * Value of the coin being minted (matching the denomination key)
+ * Value of the coin being exchangeed (matching the denomination key)
* plus the transaction fee. We include this in what is being
* signed so that we can verify a reserve's remaining total balance
* without needing to access the respective denomination key
@@ -211,14 +211,14 @@ struct TALER_WithdrawRequestPS
struct TALER_AmountNBO amount_with_fee;
/**
- * Withdrawl fee charged by the mint. This must match the Mint's
+ * Withdrawl fee charged by the exchange. This must match the Exchange's
* denomination key's withdrawl fee. If the client puts in an
* invalid withdrawl fee (too high or too low) that does not match
- * the Mint's denomination key, the withdraw operation is invalid
- * and will be rejected by the mint. The @e amount_with_fee minus
+ * the Exchange's denomination key, the withdraw operation is invalid
+ * and will be rejected by the exchange. The @e amount_with_fee minus
* the @e withdraw_fee is must match the value of the generated
* coin. We include this in what is being signed so that we can
- * verify a mint's accounting without needing to access the
+ * verify a exchange's accounting without needing to access the
* respective denomination key information each time.
*/
struct TALER_AmountNBO withdraw_fee;
@@ -229,7 +229,7 @@ struct TALER_WithdrawRequestPS
struct GNUNET_HashCode h_denomination_pub GNUNET_PACKED;
/**
- * Hash of the (blinded) message to be signed by the Mint.
+ * Hash of the (blinded) message to be signed by the Exchange.
*/
struct GNUNET_HashCode h_coin_envelope GNUNET_PACKED;
};
@@ -260,12 +260,12 @@ struct TALER_DepositRequestPS
/**
* Time when this request was generated. Used, for example, to
* assess when (roughly) the income was achieved for tax purposes.
- * Note that the Mint will only check that the timestamp is not "too
+ * Note that the Exchange will only check that the timestamp is not "too
* far" into the future (i.e. several days). The fact that the
* timestamp falls within the validity period of the coin's
* denomination key is irrelevant for the validity of the deposit
* request, as obviously the customer and merchant could conspire to
- * set any timestamp. Also, the Mint must accept very old deposit
+ * set any timestamp. Also, the Exchange must accept very old deposit
* requests, as the merchant might have been unable to transmit the
* deposit request in a timely fashion (so back-dating is not
* prevented).
@@ -293,17 +293,17 @@ struct TALER_DepositRequestPS
/**
* Amount to be deposited, including deposit fee charged by the
- * mint. This is the total amount that the coin's value at the mint
+ * exchange. This is the total amount that the coin's value at the exchange
* will be reduced by.
*/
struct TALER_AmountNBO amount_with_fee;
/**
- * Depositing fee charged by the mint. This must match the Mint's
+ * Depositing fee charged by the exchange. This must match the Exchange's
* denomination key's depositing fee. If the client puts in an
* invalid deposit fee (too high or too low) that does not match the
- * Mint's denomination key, the deposit operation is invalid and
- * will be rejected by the mint. The @e amount_with_fee minus the
+ * Exchange's denomination key, the deposit operation is invalid and
+ * will be rejected by the exchange. The @e amount_with_fee minus the
* @e deposit_fee is the amount that will be transferred to the
* account identified by @e h_wire.
*/
@@ -317,7 +317,7 @@ struct TALER_DepositRequestPS
/**
* The coin's public key. This is the value that must have been
- * signed (blindly) by the Mint. The deposit request is to be
+ * signed (blindly) by the Exchange. The deposit request is to be
* signed by the corresponding private key (using EdDSA).
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -327,13 +327,13 @@ struct TALER_DepositRequestPS
/**
* @brief Format used to generate the signature on a confirmation
- * from the mint that a deposit request succeeded.
+ * from the exchange that a deposit request succeeded.
*/
struct TALER_DepositConfirmationPS
{
/**
- * Purpose must be #TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT. Signed
- * by a `struct TALER_MintPublicKeyP` using EdDSA.
+ * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT. Signed
+ * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
@@ -362,7 +362,7 @@ struct TALER_DepositConfirmationPS
* How much time does the @e merchant have to issue a refund
* request? Zero if refunds are not allowed. After this time, the
* coin cannot be refunded. Note that the wire transfer will not be
- * performed by the mint until the refund deadline. This value
+ * performed by the exchange until the refund deadline. This value
* is taken from the original deposit request.
*/
struct GNUNET_TIME_AbsoluteNBO refund_deadline;
@@ -375,7 +375,7 @@ struct TALER_DepositConfirmationPS
/**
* The coin's public key. This is the value that must have been
- * signed (blindly) by the Mint. The deposit request is to be
+ * signed (blindly) by the Exchange. The deposit request is to be
* signed by the corresponding private key (using EdDSA).
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -417,11 +417,11 @@ struct TALER_RefreshMeltCoinAffirmationPS
struct TALER_AmountNBO amount_with_fee;
/**
- * Melting fee charged by the mint. This must match the Mint's
+ * Melting fee charged by the exchange. This must match the Exchange's
* denomination key's melting fee. If the client puts in an invalid
- * melting fee (too high or too low) that does not match the Mint's
+ * melting fee (too high or too low) that does not match the Exchange's
* denomination key, the melting operation is invalid and will be
- * rejected by the mint. The @e amount_with_fee minus the @e
+ * rejected by the exchange. The @e amount_with_fee minus the @e
* melt_fee is the amount that will be credited to the melting
* session.
*/
@@ -429,7 +429,7 @@ struct TALER_RefreshMeltCoinAffirmationPS
/**
* The coin's public key. This is the value that must have been
- * signed (blindly) by the Mint. The deposit request is to be
+ * signed (blindly) by the Exchange. The deposit request is to be
* signed by the corresponding private key (using EdDSA).
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -437,16 +437,16 @@ struct TALER_RefreshMeltCoinAffirmationPS
/**
- * @brief Format of the block signed by the Mint in response to a successful
- * "/refresh/melt" request. Hereby the mint affirms that all of the
- * coins were successfully melted. This also commits the mint to a
+ * @brief Format of the block signed by the Exchange in response to a successful
+ * "/refresh/melt" request. Hereby the exchange affirms that all of the
+ * coins were successfully melted. This also commits the exchange to a
* particular index to not be revealed during the refresh.
*/
struct TALER_RefreshMeltConfirmationPS
{
/**
- * Purpose is #TALER_SIGNATURE_MINT_CONFIRM_MELT. Signed
- * by a `struct TALER_MintPublicKeyP` using EdDSA.
+ * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT. Signed
+ * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
@@ -469,14 +469,14 @@ struct TALER_RefreshMeltConfirmationPS
/**
- * @brief Information about a signing key of the mint. Signing keys are used
- * to sign mint messages other than coins, i.e. to confirm that a
+ * @brief Information about a signing key of the exchange. Signing keys are used
+ * to sign exchange messages other than coins, i.e. to confirm that a
* deposit was successful or that a refresh was accepted.
*/
-struct TALER_MintSigningKeyValidityPS
+struct TALER_ExchangeSigningKeyValidityPS
{
/**
- * Signature over the signing key (by the master key of the mint).
+ * Signature over the signing key (by the master key of the exchange).
*
* FIXME: should be moved outside of the "PS" struct, this is ugly.
* (and makes this struct different from all of the others)
@@ -489,8 +489,8 @@ struct TALER_MintSigningKeyValidityPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * Master public key of the mint corresponding to @e signature.
- * This is the long-term offline master key of the mint.
+ * Master public key of the exchange corresponding to @e signature.
+ * This is the long-term offline master key of the exchange.
*/
struct TALER_MasterPublicKeyP master_public_key;
@@ -501,7 +501,7 @@ struct TALER_MintSigningKeyValidityPS
/**
* When does this signing key expire? Note: This is currently when
- * the Mint will definitively stop using it. Signatures made with
+ * the Exchange will definitively stop using it. Signatures made with
* the key remain valid until @e end. When checking validity periods,
* clients should allow for some overlap between keys and tolerate
* the use of either key during the overlap time (due to the
@@ -512,31 +512,31 @@ struct TALER_MintSigningKeyValidityPS
/**
* When do signatures with this signing key become invalid? After
* this point, these signatures cannot be used in (legal) disputes
- * anymore, as the Mint is then allowed to destroy its side of the
+ * anymore, as the Exchange is then allowed to destroy its side of the
* evidence. @e end is expected to be significantly larger than @e
* expire (by a year or more).
*/
struct GNUNET_TIME_AbsoluteNBO end;
/**
- * The public online signing key that the mint will use
+ * The public online signing key that the exchange will use
* between @e start and @e expire.
*/
- struct TALER_MintPublicKeyP signkey_pub;
+ struct TALER_ExchangePublicKeyP signkey_pub;
};
/**
- * @brief Signature made by the mint over the full set of keys, used
- * to detect cheating mints that give out different sets to
+ * @brief Signature made by the exchange over the full set of keys, used
+ * to detect cheating exchanges that give out different sets to
* different users.
*/
-struct TALER_MintKeySetPS
+struct TALER_ExchangeKeySetPS
{
/**
- * Purpose is #TALER_SIGNATURE_MINT_KEY_SET. Signed
- * by a `struct TALER_MintPublicKeyP` using EdDSA.
+ * Purpose is #TALER_SIGNATURE_EXCHANGE_KEY_SET. Signed
+ * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
@@ -565,7 +565,7 @@ struct TALER_DenominationKeyValidityPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * The long-term offline master key of the mint that was
+ * The long-term offline master key of the exchange that was
* used to create @e signature.
*/
struct TALER_MasterPublicKeyP master;
@@ -576,14 +576,14 @@ struct TALER_DenominationKeyValidityPS
struct GNUNET_TIME_AbsoluteNBO start;
/**
- * The mint will sign fresh coins between @e start and this time.
+ * The exchange will sign fresh coins between @e start and this time.
* @e expire_withdraw will be somewhat larger than @e start to
* ensure a sufficiently large anonymity set, while also allowing
- * the Mint to limit the financial damage in case of a key being
- * compromised. Thus, mints with low volume are expected to have a
- * longer withdraw period (@e expire_withdraw - @e start) than mints
+ * the Exchange to limit the financial damage in case of a key being
+ * compromised. Thus, exchanges with low volume are expected to have a
+ * longer withdraw period (@e expire_withdraw - @e start) than exchanges
* with high transaction volume. The period may also differ between
- * types of coins. A mint may also have a few denomination keys
+ * types of coins. A exchange may also have a few denomination keys
* with the same value with overlapping validity periods, to address
* issues such as clock skew.
*/
@@ -592,7 +592,7 @@ struct TALER_DenominationKeyValidityPS
/**
* Coins signed with the denomination key must be spent or refreshed
* between @e start and this expiration time. After this time, the
- * mint will refuse transactions involving this key as it will
+ * exchange will refuse transactions involving this key as it will
* "drop" the table with double-spending information (shortly after)
* this time. Note that wallets should refresh coins significantly
* before this time to be on the safe side. @e expire_spend must be
@@ -604,7 +604,7 @@ struct TALER_DenominationKeyValidityPS
/**
* When do signatures with this denomination key become invalid?
* After this point, these signatures cannot be used in (legal)
- * disputes anymore, as the Mint is then allowed to destroy its side
+ * disputes anymore, as the Exchange is then allowed to destroy its side
* of the evidence. @e expire_legal is expected to be significantly
* larger than @e expire_spend (by a year or more).
*/
@@ -616,19 +616,19 @@ struct TALER_DenominationKeyValidityPS
struct TALER_AmountNBO value;
/**
- * The fee the mint charges when a coin of this type is withdrawn.
+ * The fee the exchange charges when a coin of this type is withdrawn.
* (can be zero).
*/
struct TALER_AmountNBO fee_withdraw;
/**
- * The fee the mint charges when a coin of this type is deposited.
+ * The fee the exchange charges when a coin of this type is deposited.
* (can be zero).
*/
struct TALER_AmountNBO fee_deposit;
/**
- * The fee the mint charges when a coin of this type is refreshed.
+ * The fee the exchange charges when a coin of this type is refreshed.
* (can be zero).
*/
struct TALER_AmountNBO fee_refresh;
@@ -645,18 +645,18 @@ struct TALER_DenominationKeyValidityPS
/**
* @brief Information signed by an auditor affirming
* the master public key and the denomination keys
- * of a mint.
+ * of a exchange.
*/
-struct TALER_MintKeyValidityPS
+struct TALER_ExchangeKeyValidityPS
{
/**
- * Purpose is #TALER_SIGNATURE_AUDITOR_MINT_KEYS.
+ * Purpose is #TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * The long-term offline master key of the mint, affirmed by the
+ * The long-term offline master key of the exchange, affirmed by the
* auditor.
*/
struct TALER_MasterPublicKeyP master;
@@ -667,14 +667,14 @@ struct TALER_MintKeyValidityPS
struct GNUNET_TIME_AbsoluteNBO start;
/**
- * The mint will sign fresh coins between @e start and this time.
+ * The exchange will sign fresh coins between @e start and this time.
* @e expire_withdraw will be somewhat larger than @e start to
* ensure a sufficiently large anonymity set, while also allowing
- * the Mint to limit the financial damage in case of a key being
- * compromised. Thus, mints with low volume are expected to have a
- * longer withdraw period (@e expire_withdraw - @e start) than mints
+ * the Exchange to limit the financial damage in case of a key being
+ * compromised. Thus, exchanges with low volume are expected to have a
+ * longer withdraw period (@e expire_withdraw - @e start) than exchanges
* with high transaction volume. The period may also differ between
- * types of coins. A mint may also have a few denomination keys
+ * types of coins. A exchange may also have a few denomination keys
* with the same value with overlapping validity periods, to address
* issues such as clock skew.
*/
@@ -683,7 +683,7 @@ struct TALER_MintKeyValidityPS
/**
* Coins signed with the denomination key must be spent or refreshed
* between @e start and this expiration time. After this time, the
- * mint will refuse transactions involving this key as it will
+ * exchange will refuse transactions involving this key as it will
* "drop" the table with double-spending information (shortly after)
* this time. Note that wallets should refresh coins significantly
* before this time to be on the safe side. @e expire_spend must be
@@ -695,7 +695,7 @@ struct TALER_MintKeyValidityPS
/**
* When do signatures with this denomination key become invalid?
* After this point, these signatures cannot be used in (legal)
- * disputes anymore, as the Mint is then allowed to destroy its side
+ * disputes anymore, as the Exchange is then allowed to destroy its side
* of the evidence. @e expire_legal is expected to be significantly
* larger than @e expire_spend (by a year or more).
*/
@@ -707,19 +707,19 @@ struct TALER_MintKeyValidityPS
struct TALER_AmountNBO value;
/**
- * The fee the mint charges when a coin of this type is withdrawn.
+ * The fee the exchange charges when a coin of this type is withdrawn.
* (can be zero).
*/
struct TALER_AmountNBO fee_withdraw;
/**
- * The fee the mint charges when a coin of this type is deposited.
+ * The fee the exchange charges when a coin of this type is deposited.
* (can be zero).
*/
struct TALER_AmountNBO fee_deposit;
/**
- * The fee the mint charges when a coin of this type is refreshed.
+ * The fee the exchange charges when a coin of this type is refreshed.
* (can be zero).
*/
struct TALER_AmountNBO fee_refresh;
@@ -737,7 +737,7 @@ struct TALER_MintKeyValidityPS
* @brief For each (old) coin being melted, we have a `struct
* RefreshCommitLinkP` that allows the user to find the shared secret
* to decrypt the respective refresh links for the new coins in the
- * `struct TALER_MINTDB_RefreshCommitCoin`.
+ * `struct TALER_EXCHANGEDB_RefreshCommitCoin`.
*
* Part of the construction of the refresh session's hash and
* thus of what is signed there.
@@ -759,8 +759,8 @@ struct TALER_RefreshCommitLinkP
/**
- * @brief Information signed by the mint's master
- * key affirming the SEPA details for the mint.
+ * @brief Information signed by the exchange's master
+ * key affirming the SEPA details for the exchange.
*/
struct TALER_MasterWireSepaDetailsPS
{
@@ -780,19 +780,19 @@ struct TALER_MasterWireSepaDetailsPS
/**
- * @brief Information signed by a mint's online signing key affirming
- * the wire formats supported by the mint.
+ * @brief Information signed by a exchange's online signing key affirming
+ * the wire formats supported by the exchange.
*/
-struct TALER_MintWireSupportMethodsPS
+struct TALER_ExchangeWireSupportMethodsPS
{
/**
- * Purpose is #TALER_SIGNATURE_MINT_WIRE_TYPES.
+ * Purpose is #TALER_SIGNATURE_EXCHANGE_WIRE_TYPES.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * Hash over the various wire formats supported by this mint
+ * Hash over the various wire formats supported by this exchange
* (all as 0-terminated strings).
*/
struct GNUNET_HashCode h_wire_types GNUNET_PACKED;
@@ -841,7 +841,7 @@ struct TALER_DepositTrackPS
/**
* The coin's public key. This is the value that must have been
- * signed (blindly) by the Mint.
+ * signed (blindly) by the Exchange.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -896,14 +896,14 @@ struct TALER_ContractPS
/**
- * Details affirmed by the mint about a wire transfer the mint
+ * Details affirmed by the exchange about a wire transfer the exchange
* claims to have done with respect to a deposit operation.
*/
struct TALER_ConfirmWirePS
{
/**
* Purpose header for the signature over the contract with
- * purpose #TALER_SIGNATURE_MINT_CONFIRM_WIRE.
+ * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
@@ -924,7 +924,7 @@ struct TALER_ConfirmWirePS
/**
* The coin's public key. This is the value that must have been
- * signed (blindly) by the Mint.
+ * signed (blindly) by the Exchange.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -941,7 +941,7 @@ struct TALER_ConfirmWirePS
uint64_t transaction_id GNUNET_PACKED;
/**
- * When did the mint execute this transfer? Note that the
+ * When did the exchange execute this transfer? Note that the
* timestamp may not be exactly the same on the wire, i.e.
* because the wire has a different timezone or resolution.
*/
diff --git a/src/mint-lib/Makefile.am b/src/mint-lib/Makefile.am
deleted file mode 100644
index 171a42464..000000000
--- a/src/mint-lib/Makefile.am
+++ /dev/null
@@ -1,62 +0,0 @@
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
-if USE_COVERAGE
- AM_CFLAGS = --coverage -O0
- XLIB = -lgcov
-endif
-
-lib_LTLIBRARIES = \
- libtalermint.la
-
-libtalermint_la_LDFLAGS = \
- -version-info 0:0:0 \
- -no-undefined
-
-libtalermint_la_SOURCES = \
- mint_api_common.c mint_api_common.h \
- mint_api_context.c mint_api_context.h \
- mint_api_json.c mint_api_json.h \
- mint_api_handle.c mint_api_handle.h \
- mint_api_admin.c \
- mint_api_deposit.c \
- mint_api_deposit_wtid.c \
- mint_api_refresh.c \
- mint_api_refresh_link.c \
- mint_api_reserve.c \
- mint_api_wire.c \
- mint_api_wire_deposits.c
-
-libtalermint_la_LIBADD = \
- -lgnunetutil \
- -ljansson \
- $(XLIB)
-
-if HAVE_LIBCURL
-libtalermint_la_LIBADD += -lcurl
-else
-if HAVE_LIBGNURL
-libtalermint_la_LIBADD += -lgnurl
-endif
-endif
-
-check_PROGRAMS = \
- test_mint_api
-
-TESTS = \
- $(check_PROGRAMS)
-
-test_mint_api_SOURCES = \
- test_mint_api.c
-test_mint_api_LDADD = \
- libtalermint.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetutil \
- -ljansson
-
-EXTRA_DIST = \
- test-mint-home/config/mint-common.conf \
- test-mint-home/master.priv \
- test-mint-home/denomkeys/ \
- test-mint-home/signkeys/
diff --git a/src/mint-lib/afl-generate.sh b/src/mint-lib/afl-generate.sh
deleted file mode 100644
index 4b5051869..000000000
--- a/src/mint-lib/afl-generate.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-#
-# This file is part of TALER
-# Copyright (C) 2015 GNUnet e.V.
-#
-# TALER is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Affero General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License along with
-# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-#
-#
-# This will generate testcases in a directory 'afl-tests', which can then
-# be moved into src/mint/afl-tests/ to be run during mint-testing.
-#
-# This script uses American Fuzzy Loop (AFL) to fuzz the mint to
-# automatically create tests with good coverage. You must install
-# AFL and set AFL_HOME to the directory where AFL is installed
-# before running. Also, a directory "baseline/" should exist with
-# templates for inputs for AFL to fuzz. These can be generated
-# by running wireshark on loopback while running 'make check' in
-# this directory. Save each HTTP request to a new file.
-#
-# Note that you want to switch 'TESTRUN = NO' and pre-init the
-# database before running this, otherwise it will be awfully slow.
-#
-# Must be run from this directory.
-#
-$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-mint-httpd -f /tmp/afl-input -d test-mint-home/ -C
diff --git a/src/mint-lib/mint_api_admin.c b/src/mint-lib/mint_api_admin.c
deleted file mode 100644
index 641e0690f..000000000
--- a/src/mint-lib/mint_api_admin.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_admin.c
- * @brief Implementation of the /admin/ requests of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * @brief An admin/add/incoming Handle
- */
-struct TALER_MINT_AdminAddIncomingHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * JSON encoding of the request to POST.
- */
- char *json_enc;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * HTTP headers for the request.
- */
- struct curl_slist *headers;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_AdminAddIncomingResultCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
-};
-
-
-/**
- * Function called when we're done processing the
- * HTTP /admin/add/incoming request.
- *
- * @param cls the `struct TALER_MINT_AdminAddIncomingHandle`
- * @param eh the curl request handle
- */
-static void
-handle_admin_add_incoming_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_AdminAddIncomingHandle *aai = cls;
- long response_code;
- json_t *json;
-
- aai->job = NULL;
- json = MAC_download_get_result (&aai->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_FORBIDDEN:
- /* Access denied */
- break;
- case MHD_HTTP_UNAUTHORIZED:
- /* Nothing really to verify, mint says one of the signatures is
- invalid; as we checked them, this should never happen, we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- aai->cb (aai->cb_cls,
- response_code,
- json);
- json_decref (json);
- TALER_MINT_admin_add_incoming_cancel (aai);
-}
-
-
-/**
- * Notify the mint that we have received an incoming transaction
- * which fills a reserve. Note that this API is an administrative
- * API and thus not accessible to typical mint clients, but only
- * to the operators of the mint.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param reserve_pub public key of the reserve
- * @param amount amount that was deposited
- * @param execution_date when did we receive the amount
- * @param wire wire details
- * @param res_cb the callback to call when the final result for this request is available
- * @param res_cb_cls closure for the above callback
- * @return NULL
- * if the inputs are invalid (i.e. invalid amount).
- * In this case, the callback is not called.
- */
-struct TALER_MINT_AdminAddIncomingHandle *
-TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute execution_date,
- const json_t *wire,
- TALER_MINT_AdminAddIncomingResultCallback res_cb,
- void *res_cb_cls)
-{
- struct TALER_MINT_AdminAddIncomingHandle *aai;
- struct TALER_MINT_Context *ctx;
- json_t *admin_obj;
- CURL *eh;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_round_abs_time (&execution_date));
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */
- " s:o, s:O}", /* execution_Date/wire */
- "reserve_pub", TALER_json_from_data (reserve_pub,
- sizeof (*reserve_pub)),
- "amount", TALER_json_from_amount (amount),
- "execution_date", TALER_json_from_abs (execution_date),
- "wire", wire);
- aai = GNUNET_new (struct TALER_MINT_AdminAddIncomingHandle);
- aai->mint = mint;
- aai->cb = res_cb;
- aai->cb_cls = res_cb_cls;
- aai->url = MAH_path_to_url (mint, "/admin/add/incoming");
-
- eh = curl_easy_init ();
- GNUNET_assert (NULL != (aai->json_enc =
- json_dumps (admin_obj,
- JSON_COMPACT)));
- json_decref (admin_obj);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- aai->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDS,
- aai->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDSIZE,
- strlen (aai->json_enc)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &aai->db));
- ctx = MAH_handle_to_context (mint);
- aai->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_admin_add_incoming_finished,
- aai);
- return aai;
-}
-
-
-/**
- * Cancel an add incoming. This function cannot be used on a request
- * handle if a response is already served for it.
- *
- * @param aai the admin add incoming request handle
- */
-void
-TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle *aai)
-{
- if (NULL != aai->job)
- {
- MAC_job_cancel (aai->job);
- aai->job = NULL;
- }
- curl_slist_free_all (aai->headers);
- GNUNET_free_non_null (aai->db.buf);
- GNUNET_free (aai->url);
- GNUNET_free (aai->json_enc);
- GNUNET_free (aai);
-}
-
-
-/* end of mint_api_admin.c */
diff --git a/src/mint-lib/mint_api_common.c b/src/mint-lib/mint_api_common.c
deleted file mode 100644
index faba38c74..000000000
--- a/src/mint-lib/mint_api_common.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_common.c
- * @brief common functions for the mint API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "mint_api_common.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * Verify a coins transaction history as returned by the mint.
- *
- * @param currency expected currency for the coin
- * @param coin_pub public key of the coin
- * @param history history of the coin in json encoding
- * @param[out] total how much of the coin has been spent according to @a history
- * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
- */
-int
-TALER_MINT_verify_coin_history_ (const char *currency,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- json_t *history,
- struct TALER_Amount *total)
-{
- size_t len;
- size_t off;
-
- if (NULL == history)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- len = json_array_size (history);
- if (0 == len)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- TALER_amount_get_zero (currency,
- total);
- for (off=0;off<len;off++)
- {
- json_t *transaction;
- struct TALER_Amount amount;
- struct TALER_CoinSpendSignatureP sig;
- void *details;
- size_t details_size;
- const char *type;
- struct MAJ_Specification spec[] = {
- MAJ_spec_amount ("amount",
- &amount),
- MAJ_spec_string ("type",
- &type),
- MAJ_spec_fixed_auto ("signature",
- &sig),
- MAJ_spec_varsize ("details",
- &details,
- &details_size),
- MAJ_spec_end
- };
-
- transaction = json_array_get (history,
- off);
- if (GNUNET_OK !=
- MAJ_parse_json (transaction,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (0 == strcasecmp (type,
- "DEPOSIT"))
- {
- const struct TALER_DepositRequestPS *dr;
- struct TALER_Amount dr_amount;
-
- if (details_size != sizeof (struct TALER_DepositRequestPS))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- dr = (const struct TALER_DepositRequestPS *) details;
- if (details_size != ntohl (dr->purpose.size))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
- &dr->purpose,
- &sig.eddsa_signature,
- &coin_pub->eddsa_pub))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
-
- // FIXME: check sig!
- TALER_amount_ntoh (&dr_amount,
- &dr->amount_with_fee);
- if (0 != TALER_amount_cmp (&dr_amount,
- &amount))
- {
- GNUNET_break (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- }
- else if (0 == strcasecmp (type,
- "MELT"))
- {
- const struct TALER_RefreshMeltCoinAffirmationPS *rm;
- struct TALER_Amount rm_amount;
-
- if (details_size != sizeof (struct TALER_RefreshMeltCoinAffirmationPS))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details;
- if (details_size != ntohl (rm->purpose.size))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
- &rm->purpose,
- &sig.eddsa_signature,
- &coin_pub->eddsa_pub))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- TALER_amount_ntoh (&rm_amount,
- &rm->amount_with_fee);
- if (0 != TALER_amount_cmp (&rm_amount,
- &amount))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- }
- else
- {
- /* signature not supported, new version on server? */
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_amount_add (total,
- total,
- &amount))
- {
- /* overflow in history already!? inconceivable! Bad mint! */
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- MAJ_parse_free (spec);
- }
- return GNUNET_OK;
-}
-
-
-/* end of mint_api_common.c */
diff --git a/src/mint-lib/mint_api_common.h b/src/mint-lib/mint_api_common.h
deleted file mode 100644
index 10a202146..000000000
--- a/src/mint-lib/mint_api_common.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_common.h
- * @brief common functions for the mint API
- * @author Christian Grothoff
- */
-#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-
-/**
- * Verify a coins transaction history as returned by the mint.
- *
- * @param currency expected currency for the coin
- * @param coin_pub public key of the coin
- * @param history history of the coin in json encoding
- * @param[out] total how much of the coin has been spent according to @a history
- * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
- */
-int
-TALER_MINT_verify_coin_history_ (const char *currency,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- json_t *history,
- struct TALER_Amount *total);
-
-/* end of mint_api_common.h */
diff --git a/src/mint-lib/mint_api_context.c b/src/mint-lib/mint_api_context.c
deleted file mode 100644
index 2767906b5..000000000
--- a/src/mint-lib/mint_api_context.c
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_context.c
- * @brief Implementation of the context part of the mint's HTTP API
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include "taler_mint_service.h"
-#include "mint_api_context.h"
-
-
-/**
- * Log error related to CURL operations.
- *
- * @param type log level
- * @param function which function failed to run
- * @param code what was the curl error code
- */
-#define CURL_STRERROR(type, function, code) \
- GNUNET_log (type, \
- "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
- function, __FILE__, __LINE__, curl_easy_strerror (code));
-
-/**
- * Print JSON parsing related error information
- */
-#define JSON_WARN(error) \
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
- "JSON parsing failed at %s:%u: %s (%s)\n", \
- __FILE__, __LINE__, error.text, error.source)
-
-
-/**
- * Failsafe flag. Raised if our constructor fails to initialize
- * the Curl library.
- */
-static int TALER_MINT_curl_fail;
-
-
-/**
- * Jobs are CURL requests running within a `struct TALER_MINT_Context`.
- */
-struct MAC_Job
-{
-
- /**
- * We keep jobs in a DLL.
- */
- struct MAC_Job *next;
-
- /**
- * We keep jobs in a DLL.
- */
- struct MAC_Job *prev;
-
- /**
- * Easy handle of the job.
- */
- CURL *easy_handle;
-
- /**
- * Context this job runs in.
- */
- struct TALER_MINT_Context *ctx;
-
- /**
- * Function to call upon completion.
- */
- MAC_JobCompletionCallback jcc;
-
- /**
- * Closure for @e jcc.
- */
- void *jcc_cls;
-
-};
-
-
-/**
- * Context
- */
-struct TALER_MINT_Context
-{
- /**
- * Curl multi handle
- */
- CURLM *multi;
-
- /**
- * Curl share handle
- */
- CURLSH *share;
-
- /**
- * We keep jobs in a DLL.
- */
- struct MAC_Job *jobs_head;
-
- /**
- * We keep jobs in a DLL.
- */
- struct MAC_Job *jobs_tail;
-
- /**
- * HTTP header "application/json", created once and used
- * for all requests that need it.
- */
- struct curl_slist *json_header;
-
-};
-
-
-/**
- * Initialise this library. This function should be called before using any of
- * the following functions.
- *
- * @return library context
- */
-struct TALER_MINT_Context *
-TALER_MINT_init ()
-{
- struct TALER_MINT_Context *ctx;
- CURLM *multi;
- CURLSH *share;
-
- if (TALER_MINT_curl_fail)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Curl was not initialised properly\n");
- return NULL;
- }
- if (NULL == (multi = curl_multi_init ()))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to create a Curl multi handle\n");
- return NULL;
- }
- if (NULL == (share = curl_share_init ()))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to create a Curl share handle\n");
- return NULL;
- }
- ctx = GNUNET_new (struct TALER_MINT_Context);
- ctx->multi = multi;
- ctx->share = share;
- GNUNET_assert (NULL != (ctx->json_header =
- curl_slist_append (NULL,
- "Content-Type: application/json")));
- return ctx;
-}
-
-
-/**
- * Schedule a CURL request to be executed and call the given @a jcc
- * upon its completion. Note that the context will make use of the
- * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can
- * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument
- * from a valid @a eh afterwards.
- *
- * This function modifies the CURL handle to add the
- * "Content-Type: application/json" header if @a add_json is set.
- *
- * @param ctx context to execute the job in
- * @param eh curl easy handle for the request, will
- * be executed AND cleaned up
- * @param add_json add "application/json" content type header
- * @param jcc callback to invoke upon completion
- * @param jcc_cls closure for @a jcc
- */
-struct MAC_Job *
-MAC_job_add (struct TALER_MINT_Context *ctx,
- CURL *eh,
- int add_json,
- MAC_JobCompletionCallback jcc,
- void *jcc_cls)
-{
- struct MAC_Job *job;
-
- if (GNUNET_YES == add_json)
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_HTTPHEADER,
- ctx->json_header));
-
- job = GNUNET_new (struct MAC_Job);
- job->easy_handle = eh;
- job->ctx = ctx;
- job->jcc = jcc;
- job->jcc_cls = jcc_cls;
- GNUNET_CONTAINER_DLL_insert (ctx->jobs_head,
- ctx->jobs_tail,
- job);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_PRIVATE,
- job));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_SHARE,
- ctx->share));
- GNUNET_assert (CURLM_OK ==
- curl_multi_add_handle (ctx->multi,
- eh));
- return job;
-}
-
-
-/**
- * Obtain the `jcc_cls` argument from an `eh` that was
- * given to #MAC_job_add().
- *
- * @param eh easy handle that was used
- * @return the `jcc_cls` that was given to #MAC_job_add().
- */
-void *
-MAC_easy_to_closure (CURL *eh)
-{
- struct MAC_Job *job;
-
- GNUNET_assert (CURLE_OK ==
- curl_easy_getinfo (eh,
- CURLINFO_PRIVATE,
- (char **) &job));
- return job->jcc_cls;
-}
-
-
-/**
- * Cancel a job. Must only be called before the job completion
- * callback is called for the respective job.
- *
- * @param job job to cancel
- */
-void
-MAC_job_cancel (struct MAC_Job *job)
-{
- struct TALER_MINT_Context *ctx = job->ctx;
-
- GNUNET_CONTAINER_DLL_remove (ctx->jobs_head,
- ctx->jobs_tail,
- job);
- GNUNET_assert (CURLM_OK ==
- curl_multi_remove_handle (ctx->multi,
- job->easy_handle));
- curl_easy_cleanup (job->easy_handle);
- GNUNET_free (job);
-}
-
-
-/**
- * Run the main event loop for the Taler interaction.
- *
- * @param ctx the library context
- */
-void
-TALER_MINT_perform (struct TALER_MINT_Context *ctx)
-{
- CURLMsg *cmsg;
- struct MAC_Job *job;
- int n_running;
- int n_completed;
-
- (void) curl_multi_perform (ctx->multi,
- &n_running);
- while (NULL != (cmsg = curl_multi_info_read (ctx->multi,
- &n_completed)))
- {
- /* Only documented return value is CURLMSG_DONE */
- GNUNET_break (CURLMSG_DONE == cmsg->msg);
- GNUNET_assert (CURLE_OK ==
- curl_easy_getinfo (cmsg->easy_handle,
- CURLINFO_PRIVATE,
- (char **) &job));
- GNUNET_assert (job->ctx == ctx);
- job->jcc (job->jcc_cls,
- cmsg->easy_handle);
- MAC_job_cancel (job);
- }
-}
-
-
-/**
- * Obtain the information for a select() call to wait until
- * #TALER_MINT_perform() is ready again. Note that calling
- * any other TALER_MINT-API may also imply that the library
- * is again ready for #TALER_MINT_perform().
- *
- * Basically, a client should use this API to prepare for select(),
- * then block on select(), then call #TALER_MINT_perform() and then
- * start again until the work with the context is done.
- *
- * This function will NOT zero out the sets and assumes that @a max_fd
- * and @a timeout are already set to minimal applicable values. It is
- * safe to give this API FD-sets and @a max_fd and @a timeout that are
- * already initialized to some other descriptors that need to go into
- * the select() call.
- *
- * @param ctx context to get the event loop information for
- * @param read_fd_set will be set for any pending read operations
- * @param write_fd_set will be set for any pending write operations
- * @param except_fd_set is here because curl_multi_fdset() has this argument
- * @param max_fd set to the highest FD included in any set;
- * if the existing sets have no FDs in it, the initial
- * value should be "-1". (Note that `max_fd + 1` will need
- * to be passed to select().)
- * @param timeout set to the timeout in milliseconds (!); -1 means
- * no timeout (NULL, blocking forever is OK), 0 means to
- * proceed immediately with #TALER_MINT_perform().
- */
-void
-TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- fd_set *except_fd_set,
- int *max_fd,
- long *timeout)
-{
- long to;
- int m;
-
- m = -1;
- GNUNET_assert (CURLM_OK ==
- curl_multi_fdset (ctx->multi,
- read_fd_set,
- write_fd_set,
- except_fd_set,
- &m));
- to = *timeout;
- *max_fd = GNUNET_MAX (m, *max_fd);
- GNUNET_assert (CURLM_OK ==
- curl_multi_timeout (ctx->multi,
- &to));
-
- /* Only if what we got back from curl is smaller than what we
- already had (-1 == infinity!), then update timeout */
- if ( (to < *timeout) &&
- (-1 != to) )
- *timeout = to;
- if ( (-1 == (*timeout)) &&
- (NULL != ctx->jobs_head) )
- *timeout = to;
-}
-
-
-/**
- * Cleanup library initialisation resources. This function should be called
- * after using this library to cleanup the resources occupied during library's
- * initialisation.
- *
- * @param ctx the library context
- */
-void
-TALER_MINT_fini (struct TALER_MINT_Context *ctx)
-{
- /* all jobs must have been cancelled at this time, assert this */
- GNUNET_assert (NULL == ctx->jobs_head);
- curl_share_cleanup (ctx->share);
- curl_multi_cleanup (ctx->multi);
- curl_slist_free_all (ctx->json_header);
- GNUNET_free (ctx);
-}
-
-
-/**
- * Callback used when downloading the reply to an HTTP request.
- * Just appends all of the data to the `buf` in the
- * `struct MAC_DownloadBuffer` for further processing. The size of
- * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if
- * the download exceeds this size, we abort with an error.
- *
- * @param bufptr data downloaded via HTTP
- * @param size size of an item in @a bufptr
- * @param nitems number of items in @a bufptr
- * @param cls the `struct KeysRequest`
- * @return number of bytes processed from @a bufptr
- */
-size_t
-MAC_download_cb (char *bufptr,
- size_t size,
- size_t nitems,
- void *cls)
-{
- struct MAC_DownloadBuffer *db = cls;
- size_t msize;
- void *buf;
-
- if (0 == size * nitems)
- {
- /* Nothing (left) to do */
- return 0;
- }
- msize = size * nitems;
- if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
- {
- db->eno = ENOMEM;
- return 0; /* signals an error to curl */
- }
- db->buf = GNUNET_realloc (db->buf,
- db->buf_size + msize);
- buf = db->buf + db->buf_size;
- memcpy (buf, bufptr, msize);
- db->buf_size += msize;
- return msize;
-}
-
-
-/**
- * Obtain information about the final result about the
- * HTTP download. If the download was successful, parses
- * the JSON in the @a db and returns it. Also returns
- * the HTTP @a response_code. If the download failed,
- * the return value is NULL. The response code is set
- * in any case, on download errors to zero.
- *
- * Calling this function also cleans up @a db.
- *
- * @param db download buffer
- * @param eh CURL handle (to get the response code)
- * @param[out] response_code set to the HTTP response code
- * (or zero if we aborted the download, i.e.
- * because the response was too big, or if
- * the JSON we received was malformed).
- * @return NULL if downloading a JSON reply failed
- */
-json_t *
-MAC_download_get_result (struct MAC_DownloadBuffer *db,
- CURL *eh,
- long *response_code)
-{
- json_t *json;
- json_error_t error;
- char *ct;
-
- if ( (CURLE_OK !=
- curl_easy_getinfo (eh,
- CURLINFO_CONTENT_TYPE,
- &ct)) ||
- (NULL == ct) ||
- (0 != strcasecmp (ct,
- "application/json")) )
- {
- /* No content type or explicitly not JSON, refuse to parse
- (but keep response code) */
- if (CURLE_OK !=
- curl_easy_getinfo (eh,
- CURLINFO_RESPONSE_CODE,
- response_code))
- {
- /* unexpected error... */
- GNUNET_break (0);
- *response_code = 0;
- }
- return NULL;
- }
-
- json = NULL;
- if (0 == db->eno)
- {
- json = json_loadb (db->buf,
- db->buf_size,
- JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
- &error);
- if (NULL == json)
- {
- JSON_WARN (error);
- *response_code = 0;
- }
- }
- GNUNET_free_non_null (db->buf);
- db->buf = NULL;
- db->buf_size = 0;
- if (NULL != json)
- {
- if (CURLE_OK !=
- curl_easy_getinfo (eh,
- CURLINFO_RESPONSE_CODE,
- response_code))
- {
- /* unexpected error... */
- GNUNET_break (0);
- *response_code = 0;
- }
- }
- return json;
-}
-
-
-/**
- * Initial global setup logic, specifically runs the Curl setup.
- */
-__attribute__ ((constructor))
-void
-TALER_MINT_constructor__ (void)
-{
- CURLcode ret;
-
- if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
- {
- CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR,
- "curl_global_init",
- ret);
- TALER_MINT_curl_fail = 1;
- }
-}
-
-
-/**
- * Cleans up after us, specifically runs the Curl cleanup.
- */
-__attribute__ ((destructor))
-void
-TALER_MINT_destructor__ (void)
-{
- if (TALER_MINT_curl_fail)
- return;
- curl_global_cleanup ();
-}
-
-/* end of mint_api_context.c */
diff --git a/src/mint-lib/mint_api_context.h b/src/mint-lib/mint_api_context.h
deleted file mode 100644
index 181a4808f..000000000
--- a/src/mint-lib/mint_api_context.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_context.h
- * @brief Internal interface to the context part of the mint's HTTP API
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "taler_signatures.h"
-
-
-/**
- * Entry in the context's job queue.
- */
-struct MAC_Job;
-
-/**
- * Function to call upon completion of a job.
- *
- * @param cls closure
- * @param eh original easy handle (for inspection)
- */
-typedef void
-(*MAC_JobCompletionCallback)(void *cls,
- CURL *eh);
-
-
-/**
- * Schedule a CURL request to be executed and call the given @a jcc
- * upon its completion. Note that the context will make use of the
- * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can
- * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument
- * from a valid @a eh afterwards.
- *
- * This function modifies the CURL handle to add the
- * "Content-Type: application/json" header if @a add_json is set.
- *
- * @param ctx context to execute the job in
- * @param eh curl easy handle for the request, will
- * be executed AND cleaned up
- * @param add_json add "application/json" content type header
- * @param jcc callback to invoke upon completion
- * @param jcc_cls closure for @a jcc
- */
-struct MAC_Job *
-MAC_job_add (struct TALER_MINT_Context *ctx,
- CURL *eh,
- int add_json,
- MAC_JobCompletionCallback jcc,
- void *jcc_cls);
-
-
-/**
- * Obtain the `jcc_cls` argument from an `eh` that was
- * given to #MAC_job_add().
- *
- * @param eh easy handle that was used
- * @return the `jcc_cls` that was given to #MAC_job_add().
- */
-void *
-MAC_easy_to_closure (CURL *eh);
-
-
-/**
- * Cancel a job. Must only be called before the job completion
- * callback is called for the respective job.
- *
- * @param job job to cancel
- */
-void
-MAC_job_cancel (struct MAC_Job *job);
-
-
-/**
- * @brief Buffer data structure we use to buffer the HTTP download
- * before giving it to the JSON parser.
- */
-struct MAC_DownloadBuffer
-{
-
- /**
- * Download buffer
- */
- void *buf;
-
- /**
- * The size of the download buffer
- */
- size_t buf_size;
-
- /**
- * Error code (based on libc errno) if we failed to download
- * (i.e. response too large).
- */
- int eno;
-
-};
-
-
-/**
- * Callback used when downloading the reply to an HTTP request.
- * Just appends all of the data to the `buf` in the
- * `struct MAC_DownloadBuffer` for further processing. The size of
- * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if
- * the download exceeds this size, we abort with an error.
- *
- * Should be used by the various routines as the
- * CURLOPT_WRITEFUNCTION. A `struct MAC_DownloadBuffer` needs to be
- * passed to the CURLOPT_WRITEDATA.
- *
- * Afterwards, `eno` needs to be checked to ensure that the download
- * completed correctly.
- *
- * @param bufptr data downloaded via HTTP
- * @param size size of an item in @a bufptr
- * @param nitems number of items in @a bufptr
- * @param cls the `struct KeysRequest`
- * @return number of bytes processed from @a bufptr
- */
-size_t
-MAC_download_cb (char *bufptr,
- size_t size,
- size_t nitems,
- void *cls);
-
-
-/**
- * Obtain information about the final result about the
- * HTTP download. If the download was successful, parses
- * the JSON in the @a db and returns it. Also returns
- * the HTTP @a response_code. If the download failed,
- * the return value is NULL. The response code is set
- * in any case, on download errors to zero.
- *
- * Calling this function also cleans up @a db.
- *
- * @param db download buffer
- * @param eh CURL handle (to get the response code)
- * @param[out] response_code set to the HTTP response code
- * (or zero if we aborted the download, i.e.
- * because the response was too big, or if
- * the JSON we received was malformed).
- * @return NULL if downloading a JSON reply failed
- */
-json_t *
-MAC_download_get_result (struct MAC_DownloadBuffer *db,
- CURL *eh,
- long *response_code);
-
-
-/* end of mint_api_context.h */
diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c
deleted file mode 100644
index 400372925..000000000
--- a/src/mint-lib/mint_api_deposit.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_deposit.c
- * @brief Implementation of the /deposit request of the mint's HTTP API
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_common.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * @brief A Deposit Handle
- */
-struct TALER_MINT_DepositHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * JSON encoding of the request to POST.
- */
- char *json_enc;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_DepositResultCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Information the mint should sign in response.
- */
- struct TALER_DepositConfirmationPS depconf;
-
- /**
- * Value of the /deposit transaction, including fee.
- */
- struct TALER_Amount amount_with_fee;
-
- /**
- * Total value of the coin being transacted with.
- */
- struct TALER_Amount coin_value;
-
-};
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * from the mint is valid.
- *
- * @param dh deposit handle
- * @param json json reply with the signature
- * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
- */
-static int
-verify_deposit_signature_ok (const struct TALER_MINT_DepositHandle *dh,
- json_t *json)
-{
- struct TALER_MintSignatureP mint_sig;
- struct TALER_MintPublicKeyP mint_pub;
- const struct TALER_MINT_Keys *key_state;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("sig", &mint_sig),
- MAJ_spec_fixed_auto ("pub", &mint_pub),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- key_state = TALER_MINT_get_keys (dh->mint);
- if (GNUNET_OK !=
- TALER_MINT_test_signing_key (key_state,
- &mint_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT,
- &dh->depconf.purpose,
- &mint_sig.eddsa_signature,
- &mint_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Verify that the signatures on the "403 FORBIDDEN" response from the
- * mint demonstrating customer double-spending are valid.
- *
- * @param dh deposit handle
- * @param json json reply with the signature(s) and transaction history
- * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
- */
-static int
-verify_deposit_signature_forbidden (const struct TALER_MINT_DepositHandle *dh,
- json_t *json)
-{
- json_t *history;
- struct TALER_Amount total;
-
- history = json_object_get (json,
- "history");
- if (GNUNET_OK !=
- TALER_MINT_verify_coin_history_ (dh->coin_value.currency,
- &dh->depconf.coin_pub,
- history,
- &total))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_amount_add (&total,
- &total,
- &dh->amount_with_fee))
- {
- /* clearly not OK if our transaction would have caused
- the overflow... */
- return GNUNET_OK;
- }
-
- if (0 >= TALER_amount_cmp (&total,
- &dh->coin_value))
- {
- /* transaction should have still fit */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* everything OK, proof of double-spending was provided */
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /deposit request.
- *
- * @param cls the `struct TALER_MINT_DepositHandle`
- * @param eh the curl request handle
- */
-static void
-handle_deposit_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_DepositHandle *dh = cls;
- long response_code;
- json_t *json;
-
- dh->job = NULL;
- json = MAC_download_get_result (&dh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- if (GNUNET_OK !=
- verify_deposit_signature_ok (dh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_FORBIDDEN:
- /* Double spending; check signatures on transaction history */
- if (GNUNET_OK !=
- verify_deposit_signature_forbidden (dh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- break;
- case MHD_HTTP_UNAUTHORIZED:
- /* Nothing really to verify, mint says one of the signatures is
- invalid; as we checked them, this should never happen, we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- dh->cb (dh->cb_cls,
- response_code,
- json);
- json_decref (json);
- TALER_MINT_deposit_cancel (dh);
-}
-
-
-/**
- * Verify signature information about the deposit.
- *
- * @param dki public key information
- * @param amount the amount to be deposited
- * @param h_wire hash of the merchant’s account details
- * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
- * @param coin_pub coin’s public key
- * @param denom_pub denomination key with which the coin is signed
- * @param denom_sig mint’s unblinded signature of the coin
- * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
- * @param transaction_id transaction id for the transaction between merchant and customer
- * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
- * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed)
- * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
- * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
- */
-static int
-verify_signatures (const struct TALER_MINT_DenomPublicKey *dki,
- const struct TALER_Amount *amount,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_DenominationSignature *denom_sig,
- const struct TALER_DenominationPublicKey *denom_pub,
- struct GNUNET_TIME_Absolute timestamp,
- uint64_t transaction_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- struct GNUNET_TIME_Absolute refund_deadline,
- const struct TALER_CoinSpendSignatureP *coin_sig)
-{
- struct TALER_DepositRequestPS dr;
- struct TALER_CoinPublicInfo coin_info;
-
- dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
- dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
- dr.h_contract = *h_contract;
- dr.h_wire = *h_wire;
- dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
- dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
- dr.transaction_id = GNUNET_htonll (transaction_id);
- TALER_amount_hton (&dr.amount_with_fee,
- amount);
- TALER_amount_hton (&dr.deposit_fee,
- &dki->fee_deposit);
- dr.merchant = *merchant_pub;
- dr.coin_pub = *coin_pub;
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
- &dr.purpose,
- &coin_sig->eddsa_signature,
- &coin_pub->eddsa_pub))
- {
- TALER_LOG_WARNING ("Invalid coin signature on /deposit request\n");
- {
- char *s;
- s = TALER_amount_to_string (amount);
- TALER_LOG_DEBUG ("... amount_with_fee was %s\n", s);
- GNUNET_free (s);
- s = TALER_amount_to_string (&dki->fee_deposit);
- TALER_LOG_DEBUG ("... deposit_fee was %s\n", s);
- GNUNET_free (s);
- }
-
- return GNUNET_SYSERR;
- }
-
- /* check coin signature */
- coin_info.coin_pub = *coin_pub;
- coin_info.denom_pub = *denom_pub;
- coin_info.denom_sig = *denom_sig;
- if (GNUNET_YES !=
- TALER_test_coin_valid (&coin_info))
- {
- TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
- return GNUNET_SYSERR;
- }
- if (0 < TALER_amount_cmp (&dki->fee_deposit,
- amount))
- {
- TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Submit a deposit permission to the mint and get the mint's response.
- * Note that while we return the response verbatim to the caller for
- * further processing, we do already verify that the response is
- * well-formed (i.e. that signatures included in the response are all
- * valid). If the mint's reply is not well-formed, we return an
- * HTTP status code of zero to @a cb.
- *
- * We also verify that the @a coin_sig is valid for this deposit
- * request, and that the @a ub_sig is a valid signature for @a
- * coin_pub. Also, the @a mint must be ready to operate (i.e. have
- * finished processing the /keys reply). If either check fails, we do
- * NOT initiate the transaction with the mint and instead return NULL.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param amount the amount to be deposited
- * @param wire_deadline date until which the merchant would like the mint to settle the balance (advisory, the mint cannot be
- * forced to settle in the past or upon very short notice, but of course a well-behaved mint will limit aggregation based on the advice received)
- * @param wire_details the merchant’s account details, in a format supported by the mint
- * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
- * @param coin_pub coin’s public key
- * @param denom_pub denomination key with which the coin is signed
- * @param denom_sig mint’s unblinded signature of the coin
- * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
- * @param transaction_id transaction id for the transaction between merchant and customer
- * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
- * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed)
- * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
- * @param cb the callback to call when a reply for this request is available
- * @param cb_cls closure for the above callback
- * @return a handle for this request; NULL if the inputs are invalid (i.e.
- * signatures fail to verify). In this case, the callback is not called.
- */
-struct TALER_MINT_DepositHandle *
-TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute wire_deadline,
- json_t *wire_details,
- const struct GNUNET_HashCode *h_contract,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_DenominationSignature *denom_sig,
- const struct TALER_DenominationPublicKey *denom_pub,
- struct GNUNET_TIME_Absolute timestamp,
- uint64_t transaction_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- struct GNUNET_TIME_Absolute refund_deadline,
- const struct TALER_CoinSpendSignatureP *coin_sig,
- TALER_MINT_DepositResultCallback cb,
- void *cb_cls)
-{
- const struct TALER_MINT_Keys *key_state;
- const struct TALER_MINT_DenomPublicKey *dki;
- struct TALER_MINT_DepositHandle *dh;
- struct TALER_MINT_Context *ctx;
- json_t *deposit_obj;
- CURL *eh;
- struct GNUNET_HashCode h_wire;
- struct TALER_Amount amount_without_fee;
-
- (void) TALER_round_abs_time (&wire_deadline);
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- /* initialize h_wire */
- if (GNUNET_OK !=
- TALER_hash_json (wire_details,
- &h_wire))
- {
- GNUNET_break (0);
- return NULL;
- }
- key_state = TALER_MINT_get_keys (mint);
- dki = TALER_MINT_get_denomination_key (key_state,
- denom_pub);
- if (NULL == dki)
- {
- TALER_LOG_WARNING ("Denomination key unknown to mint\n");
- return NULL;
- }
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (&amount_without_fee,
- amount,
- &dki->fee_deposit))
- {
- GNUNET_break (0);
- return NULL;
- }
-
- if (GNUNET_OK !=
- verify_signatures (dki,
- amount,
- &h_wire,
- h_contract,
- coin_pub,
- denom_sig,
- denom_pub,
- timestamp,
- transaction_id,
- merchant_pub,
- refund_deadline,
- coin_sig))
- {
- GNUNET_break_op (0);
- return NULL;
- }
-
- deposit_obj = json_pack ("{s:o, s:O," /* f/wire */
- " s:o, s:o," /* H_wire, H_contract */
- " s:o, s:o," /* coin_pub, denom_pub */
- " s:o, s:o," /* ub_sig, timestamp */
- " s:I, s:o," /* transaction id, merchant_pub */
- " s:o, s:o," /* refund_deadline, wire_deadline */
- " s:o}", /* coin_sig */
- "f", TALER_json_from_amount (amount),
- "wire", wire_details,
- "H_wire", TALER_json_from_data (&h_wire,
- sizeof (h_wire)),
- "H_contract", TALER_json_from_data (h_contract,
- sizeof (struct GNUNET_HashCode)),
- "coin_pub", TALER_json_from_data (coin_pub,
- sizeof (*coin_pub)),
- "denom_pub", TALER_json_from_rsa_public_key (denom_pub->rsa_public_key),
- "ub_sig", TALER_json_from_rsa_signature (denom_sig->rsa_signature),
- "timestamp", TALER_json_from_abs (timestamp),
- "transaction_id", (json_int_t) transaction_id,
- "merchant_pub", TALER_json_from_data (merchant_pub,
- sizeof (*merchant_pub)),
- "refund_deadline", TALER_json_from_abs (refund_deadline),
- "edate", TALER_json_from_abs (wire_deadline),
- "coin_sig", TALER_json_from_data (coin_sig,
- sizeof (*coin_sig))
- );
-
- dh = GNUNET_new (struct TALER_MINT_DepositHandle);
- dh->mint = mint;
- dh->cb = cb;
- dh->cb_cls = cb_cls;
- dh->url = MAH_path_to_url (mint, "/deposit");
- dh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
- dh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT);
- dh->depconf.h_contract = *h_contract;
- dh->depconf.h_wire = h_wire;
- dh->depconf.transaction_id = GNUNET_htonll (transaction_id);
- dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp);
- dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
- TALER_amount_hton (&dh->depconf.amount_without_fee,
- &amount_without_fee);
- dh->depconf.coin_pub = *coin_pub;
- dh->depconf.merchant = *merchant_pub;
- dh->amount_with_fee = *amount;
- dh->coin_value = dki->value;
-
- eh = curl_easy_init ();
- GNUNET_assert (NULL != (dh->json_enc =
- json_dumps (deposit_obj,
- JSON_COMPACT)));
- json_decref (deposit_obj);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "URL for deposit: `%s'\n",
- dh->url);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- dh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDS,
- dh->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDSIZE,
- strlen (dh->json_enc)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &dh->db));
- ctx = MAH_handle_to_context (mint);
- dh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_deposit_finished,
- dh);
- return dh;
-}
-
-
-/**
- * Cancel a deposit permission request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param deposit the deposit permission request handle
- */
-void
-TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit)
-{
- if (NULL != deposit->job)
- {
- MAC_job_cancel (deposit->job);
- deposit->job = NULL;
- }
- GNUNET_free_non_null (deposit->db.buf);
- GNUNET_free (deposit->url);
- GNUNET_free (deposit->json_enc);
- GNUNET_free (deposit);
-}
-
-
-/* end of mint_api_deposit.c */
diff --git a/src/mint-lib/mint_api_deposit_wtid.c b/src/mint-lib/mint_api_deposit_wtid.c
deleted file mode 100644
index d29f406e3..000000000
--- a/src/mint-lib/mint_api_deposit_wtid.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_deposit_wtid.c
- * @brief Implementation of the /deposit/wtid request of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_common.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * @brief A Deposit Wtid Handle
- */
-struct TALER_MINT_DepositWtidHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * JSON encoding of the request to POST.
- */
- char *json_enc;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_DepositWtidCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Information the mint should sign in response.
- * (with pre-filled fields from the request).
- */
- struct TALER_ConfirmWirePS depconf;
-
-};
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * from the mint is valid.
- *
- * @param dwh deposit wtid handle
- * @param json json reply with the signature
- * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
- */
-static int
-verify_deposit_wtid_signature_ok (const struct TALER_MINT_DepositWtidHandle *dwh,
- json_t *json)
-{
- struct TALER_MintSignatureP mint_sig;
- struct TALER_MintPublicKeyP mint_pub;
- const struct TALER_MINT_Keys *key_state;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("mint_sig", &mint_sig),
- MAJ_spec_fixed_auto ("mint_pub", &mint_pub),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- key_state = TALER_MINT_get_keys (dwh->mint);
- if (GNUNET_OK !=
- TALER_MINT_test_signing_key (key_state,
- &mint_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_WIRE,
- &dwh->depconf.purpose,
- &mint_sig.eddsa_signature,
- &mint_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /deposit/wtid request.
- *
- * @param cls the `struct TALER_MINT_DepositWtidHandle`
- * @param eh the curl request handle
- */
-static void
-handle_deposit_wtid_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_DepositWtidHandle *dwh = cls;
- long response_code;
- json_t *json;
- const struct TALER_WireTransferIdentifierRawP *wtid = NULL;
- struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS;
- const struct TALER_Amount *coin_contribution = NULL;
- struct TALER_Amount coin_contribution_s;
-
- dwh->job = NULL;
- json = MAC_download_get_result (&dwh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- {
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
- MAJ_spec_absolute_time ("execution_time", &execution_time),
- MAJ_spec_amount ("coin_contribution", &coin_contribution_s),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- wtid = &dwh->depconf.wtid;
- dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time);
- TALER_amount_hton (&dwh->depconf.coin_contribution,
- &coin_contribution_s);
- coin_contribution = &coin_contribution_s;
- if (GNUNET_OK !=
- verify_deposit_wtid_signature_ok (dwh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- }
- break;
- case MHD_HTTP_ACCEPTED:
- {
- /* Transaction known, but not executed yet */
- struct MAJ_Specification spec[] = {
- MAJ_spec_absolute_time ("execution_time", &execution_time),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_UNAUTHORIZED:
- /* Nothing really to verify, mint says one of the signatures is
- invalid; as we checked them, this should never happen, we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Mint does not know about transaction;
- we should pass the reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- dwh->cb (dwh->cb_cls,
- response_code,
- json,
- wtid,
- execution_time,
- coin_contribution);
- json_decref (json);
- TALER_MINT_deposit_wtid_cancel (dwh);
-}
-
-
-/**
- * Obtain wire transfer details about an existing deposit operation.
- *
- * @param mint the mint to query
- * @param merchant_priv the merchant's private key
- * @param h_wire hash of merchant's wire transfer details
- * @param h_contract hash of the contract
- * @param coin_pub public key of the coin
- * @param transaction_id transaction identifier
- * @param cb function to call with the result
- * @param cb_cls closure for @a cb
- * @return handle to abort request
- */
-struct TALER_MINT_DepositWtidHandle *
-TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint,
- const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- uint64_t transaction_id,
- TALER_MINT_DepositWtidCallback cb,
- void *cb_cls)
-{
- struct TALER_DepositTrackPS dtp;
- struct TALER_MerchantSignatureP merchant_sig;
- struct TALER_MINT_DepositWtidHandle *dwh;
- struct TALER_MINT_Context *ctx;
- json_t *deposit_wtid_obj;
- CURL *eh;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID);
- dtp.purpose.size = htonl (sizeof (dtp));
- dtp.h_contract = *h_contract;
- dtp.h_wire = *h_wire;
- dtp.transaction_id = GNUNET_htonll (transaction_id);
- GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
- &dtp.merchant.eddsa_pub);
-
- dtp.coin_pub = *coin_pub;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
- &dtp.purpose,
- &merchant_sig.eddsa_sig));
- deposit_wtid_obj = json_pack ("{s:o, s:o," /* H_wire, H_contract */
- " s:o, s:I," /* coin_pub, transaction_id */
- " s:o, s:o}", /* merchant_pub, merchant_sig */
- "H_wire", TALER_json_from_data (h_wire,
- sizeof (struct GNUNET_HashCode)),
- "H_contract", TALER_json_from_data (h_contract,
- sizeof (struct GNUNET_HashCode)),
- "coin_pub", TALER_json_from_data (coin_pub,
- sizeof (*coin_pub)),
- "transaction_id", (json_int_t) transaction_id,
- "merchant_pub", TALER_json_from_data (&dtp.merchant,
- sizeof (struct TALER_MerchantPublicKeyP)),
- "merchant_sig", TALER_json_from_data (&merchant_sig,
- sizeof (merchant_sig)));
-
- dwh = GNUNET_new (struct TALER_MINT_DepositWtidHandle);
- dwh->mint = mint;
- dwh->cb = cb;
- dwh->cb_cls = cb_cls;
- dwh->url = MAH_path_to_url (mint, "/deposit/wtid");
- dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
- dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
- dwh->depconf.h_wire = *h_wire;
- dwh->depconf.h_contract = *h_contract;
- dwh->depconf.coin_pub = *coin_pub;
- dwh->depconf.transaction_id = GNUNET_htonll (transaction_id);
-
- eh = curl_easy_init ();
- GNUNET_assert (NULL != (dwh->json_enc =
- json_dumps (deposit_wtid_obj,
- JSON_COMPACT)));
- json_decref (deposit_wtid_obj);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- dwh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDS,
- dwh->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDSIZE,
- strlen (dwh->json_enc)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &dwh->db));
- ctx = MAH_handle_to_context (mint);
- dwh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_deposit_wtid_finished,
- dwh);
- return dwh;
-}
-
-
-/**
- * Cancel deposit wtid request. This function cannot be used on a request
- * handle if a response is already served for it.
- *
- * @param dwh the wire deposits request handle
- */
-void
-TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh)
-{
- if (NULL != dwh->job)
- {
- MAC_job_cancel (dwh->job);
- dwh->job = NULL;
- }
- GNUNET_free_non_null (dwh->db.buf);
- GNUNET_free (dwh->url);
- GNUNET_free (dwh->json_enc);
- GNUNET_free (dwh);
-}
-
-
-/* end of mint_api_deposit_wtid.c */
diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c
deleted file mode 100644
index ef26cd838..000000000
--- a/src/mint-lib/mint_api_handle.c
+++ /dev/null
@@ -1,902 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_handle.c
- * @brief Implementation of the "handle" component of the mint's HTTP API
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_mint_service.h"
-#include "taler_signatures.h"
-#include "mint_api_context.h"
-#include "mint_api_json.h"
-#include "mint_api_handle.h"
-
-
-/**
- * Log error related to CURL operations.
- *
- * @param type log level
- * @param function which function failed to run
- * @param code what was the curl error code
- */
-#define CURL_STRERROR(type, function, code) \
- GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
- function, __FILE__, __LINE__, curl_easy_strerror (code));
-
-
-/**
- * Stages of initialization for the `struct TALER_MINT_Handle`
- */
-enum MintHandleState
-{
- /**
- * Just allocated.
- */
- MHS_INIT = 0,
-
- /**
- * Obtained the mint's certification data and keys.
- */
- MHS_CERT = 1,
-
- /**
- * Failed to initialize (fatal).
- */
- MHS_FAILED = 2
-};
-
-
-/**
- * Data for the request to get the /keys of a mint.
- */
-struct KeysRequest;
-
-
-/**
- * Handle to the mint
- */
-struct TALER_MINT_Handle
-{
- /**
- * The context of this handle
- */
- struct TALER_MINT_Context *ctx;
-
- /**
- * The URL of the mint (i.e. "http://mint.taler.net/")
- */
- char *url;
-
- /**
- * Function to call with the mint's certification data,
- * NULL if this has already been done.
- */
- TALER_MINT_CertificationCallback cert_cb;
-
- /**
- * Closure to pass to @e cert_cb.
- */
- void *cert_cb_cls;
-
- /**
- * Data for the request to get the /keys of a mint,
- * NULL once we are past stage #MHS_INIT.
- */
- struct KeysRequest *kr;
-
- /**
- * Key data of the mint, only valid if
- * @e handshake_complete is past stage #MHS_CERT.
- */
- struct TALER_MINT_Keys key_data;
-
- /**
- * Stage of the mint's initialization routines.
- */
- enum MintHandleState state;
-
-};
-
-
-/* ***************** Internal /keys fetching ************* */
-
-/**
- * Data for the request to get the /keys of a mint.
- */
-struct KeysRequest
-{
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this handle
- */
- char *url;
-
- /**
- * Entry for this request with the `struct TALER_MINT_Context`.
- */
- struct MAC_Job *job;
-
- /**
- * Data structure for the download.
- */
- struct MAC_DownloadBuffer db;
-
-};
-
-
-/**
- * Release memory occupied by a keys request.
- * Note that this does not cancel the request
- * itself.
- *
- * @param kr request to free
- */
-static void
-free_keys_request (struct KeysRequest *kr)
-{
- GNUNET_free_non_null (kr->db.buf);
- GNUNET_free (kr->url);
- GNUNET_free (kr);
-}
-
-
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-
-/**
- * Parse a mint's signing key encoded in JSON.
- *
- * @param[out] sign_key where to return the result
- * @param[in] sign_key_obj json to parse
- * @param master_key master key to use to verify signature
- * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
- * invalid or the json malformed.
- */
-static int
-parse_json_signkey (struct TALER_MINT_SigningPublicKey *sign_key,
- json_t *sign_key_obj,
- const struct TALER_MasterPublicKeyP *master_key)
-{
- struct TALER_MintSigningKeyValidityPS sign_key_issue;
- struct GNUNET_CRYPTO_EddsaSignature sig;
- struct GNUNET_TIME_Absolute valid_from;
- struct GNUNET_TIME_Absolute valid_until;
- struct GNUNET_TIME_Absolute valid_legal;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("master_sig",
- &sig),
- MAJ_spec_fixed_auto ("key",
- &sign_key_issue.signkey_pub),
- MAJ_spec_absolute_time ("stamp_start",
- &valid_from),
- MAJ_spec_absolute_time ("stamp_expire",
- &valid_until),
- MAJ_spec_absolute_time ("stamp_end",
- &valid_legal),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (sign_key_obj,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
- sign_key_issue.purpose.size =
- htonl (sizeof (struct TALER_MintSigningKeyValidityPS)
- - offsetof (struct TALER_MintSigningKeyValidityPS,
- purpose));
- sign_key_issue.master_public_key = *master_key;
- sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
- sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until);
- sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
- &sign_key_issue.purpose,
- &sig,
- &master_key->eddsa_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- sign_key->valid_from = valid_from;
- sign_key->valid_until = valid_until;
- sign_key->key = sign_key_issue.signkey_pub;
- return GNUNET_OK;
-}
-
-
-/**
- * Parse a mint's denomination key encoded in JSON.
- *
- * @param[out] denom_key where to return the result
- * @param[in] denom_key_obj json to parse
- * @param master_key master key to use to verify signature
- * @param hash_context where to accumulate data for signature verification
- * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
- * invalid or the json malformed.
- */
-static int
-parse_json_denomkey (struct TALER_MINT_DenomPublicKey *denom_key,
- json_t *denom_key_obj,
- struct TALER_MasterPublicKeyP *master_key,
- struct GNUNET_HashContext *hash_context)
-{
- struct GNUNET_TIME_Absolute valid_from;
- struct GNUNET_TIME_Absolute withdraw_valid_until;
- struct GNUNET_TIME_Absolute deposit_valid_until;
- struct GNUNET_TIME_Absolute expire_legal;
- struct TALER_Amount value;
- struct TALER_Amount fee_withdraw;
- struct TALER_Amount fee_deposit;
- struct TALER_Amount fee_refresh;
- struct TALER_DenominationKeyValidityPS denom_key_issue;
- struct GNUNET_CRYPTO_rsa_PublicKey *pk;
- struct GNUNET_CRYPTO_EddsaSignature sig;
-
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("master_sig",
- &sig),
- MAJ_spec_absolute_time ("stamp_expire_deposit",
- &deposit_valid_until),
- MAJ_spec_absolute_time ("stamp_expire_withdraw",
- &withdraw_valid_until),
- MAJ_spec_absolute_time ("stamp_start",
- &valid_from),
- MAJ_spec_absolute_time ("stamp_expire_legal",
- &expire_legal),
- MAJ_spec_amount ("value",
- &value),
- MAJ_spec_amount ("fee_withdraw",
- &fee_withdraw),
- MAJ_spec_amount ("fee_deposit",
- &fee_deposit),
- MAJ_spec_amount ("fee_refresh",
- &fee_refresh),
- MAJ_spec_rsa_public_key ("denom_pub",
- &pk),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (denom_key_obj,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- memset (&denom_key_issue, 0, sizeof (denom_key_issue));
- GNUNET_CRYPTO_rsa_public_key_hash (pk,
- &denom_key_issue.denom_hash);
- denom_key_issue.purpose.purpose
- = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
- denom_key_issue.purpose.size
- = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
- denom_key_issue.master = *master_key;
- denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
- denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
- denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until);
- denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (expire_legal);
- TALER_amount_hton (&denom_key_issue.value,
- &value);
- TALER_amount_hton (&denom_key_issue.fee_withdraw,
- &fee_withdraw);
- TALER_amount_hton (&denom_key_issue.fee_deposit,
- &fee_deposit);
- TALER_amount_hton (&denom_key_issue.fee_refresh,
- &fee_refresh);
- EXITIF (GNUNET_SYSERR ==
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
- &denom_key_issue.purpose,
- &sig,
- &master_key->eddsa_pub));
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &denom_key_issue.denom_hash,
- sizeof (struct GNUNET_HashCode));
- denom_key->key.rsa_public_key = pk;
- denom_key->h_key = denom_key_issue.denom_hash;
- denom_key->valid_from = valid_from;
- denom_key->withdraw_valid_until = withdraw_valid_until;
- denom_key->deposit_valid_until = deposit_valid_until;
- denom_key->expire_legal = expire_legal;
- denom_key->value = value;
- denom_key->fee_withdraw = fee_withdraw;
- denom_key->fee_deposit = fee_deposit;
- denom_key->fee_refresh = fee_refresh;
- return GNUNET_OK;
-
- EXITIF_exit:
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Parse a mint's auditor information encoded in JSON.
- *
- * @param[out] auditor where to return the result
- * @param[in] auditor_obj json to parse
- * @param key_data information about denomination keys
- * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
- * invalid or the json malformed.
- */
-static int
-parse_json_auditor (struct TALER_MINT_AuditorInformation *auditor,
- json_t *auditor_obj,
- const struct TALER_MINT_Keys *key_data)
-{
- json_t *keys;
- json_t *key;
- unsigned int len;
- unsigned int off;
- unsigned int i;
- struct TALER_MintKeyValidityPS kv;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("auditor_pub",
- &auditor->auditor_pub),
- MAJ_spec_json ("denomination_keys",
- &keys),
- MAJ_spec_end
- };
-
- auditor->auditor_url = NULL; /* #3987 */
- if (GNUNET_OK !=
- MAJ_parse_json (auditor_obj,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_MINT_KEYS);
- kv.purpose.size = htonl (sizeof (struct TALER_MintKeyValidityPS));
- kv.master = key_data->master_pub;
- len = json_array_size (keys);
- auditor->denom_keys = GNUNET_new_array (len,
- const struct TALER_MINT_DenomPublicKey *);
- i = 0;
- off = 0;
- json_array_foreach (keys, i, key) {
- struct TALER_AuditorSignatureP auditor_sig;
- struct GNUNET_HashCode denom_h;
- const struct TALER_MINT_DenomPublicKey *dk;
- unsigned int j;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("denom_pub_h",
- &denom_h),
- MAJ_spec_fixed_auto ("auditor_sig",
- &auditor_sig),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (key,
- spec))
- {
- GNUNET_break_op (0);
- continue;
- }
- dk = NULL;
- for (j=0;j<key_data->num_denom_keys;j++)
- {
- if (0 == memcmp (&denom_h,
- &key_data->denom_keys[j].h_key,
- sizeof (struct GNUNET_HashCode)))
- {
- dk = &key_data->denom_keys[j];
- break;
- }
- }
- if (NULL == dk)
- {
- GNUNET_break_op (0);
- continue;
- }
- kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
- kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until);
- kv.expire_spend = GNUNET_TIME_absolute_hton (dk->deposit_valid_until);
- kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
- TALER_amount_hton (&kv.value,
- &dk->value);
- TALER_amount_hton (&kv.fee_withdraw,
- &dk->fee_withdraw);
- TALER_amount_hton (&kv.fee_deposit,
- &dk->fee_deposit);
- TALER_amount_hton (&kv.fee_refresh,
- &dk->fee_refresh);
- kv.denom_hash = dk->h_key;
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_MINT_KEYS,
- &kv.purpose,
- &auditor_sig.eddsa_sig,
- &auditor->auditor_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- continue;
- }
- auditor->denom_keys[off] = dk;
- off++;
- }
- auditor->num_denom_keys = off;
- return GNUNET_OK;
-}
-
-
-/**
- * Decode the JSON in @a resp_obj from the /keys response and store the data
- * in the @a key_data.
- *
- * @param[in] resp_obj JSON object to parse
- * @param[out] key_data where to store the results we decoded
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
- */
-static int
-decode_keys_json (json_t *resp_obj,
- struct TALER_MINT_Keys *key_data)
-{
- struct GNUNET_TIME_Absolute list_issue_date;
- struct TALER_MintSignatureP sig;
- struct TALER_MintKeySetPS ks;
- struct GNUNET_HashContext *hash_context;
- struct TALER_MintPublicKeyP pub;
-
- if (JSON_OBJECT != json_typeof (resp_obj))
- return GNUNET_SYSERR;
-
- hash_context = GNUNET_CRYPTO_hash_context_start ();
- /* parse the master public key and issue date of the response */
- {
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("master_public_key",
- &key_data->master_pub),
- MAJ_spec_fixed_auto ("eddsa_sig",
- &sig),
- MAJ_spec_fixed_auto ("eddsa_pub",
- &pub),
- MAJ_spec_absolute_time ("list_issue_date",
- &list_issue_date),
- MAJ_spec_end
- };
-
- EXITIF (GNUNET_OK !=
- MAJ_parse_json (resp_obj,
- spec));
- }
-
- /* parse the signing keys */
- {
- json_t *sign_keys_array;
- json_t *sign_key_obj;
- unsigned int index;
-
- EXITIF (NULL == (sign_keys_array =
- json_object_get (resp_obj,
- "signkeys")));
- EXITIF (JSON_ARRAY != json_typeof (sign_keys_array));
- EXITIF (0 == (key_data->num_sign_keys =
- json_array_size (sign_keys_array)));
- key_data->sign_keys
- = GNUNET_new_array (key_data->num_sign_keys,
- struct TALER_MINT_SigningPublicKey);
- index = 0;
- json_array_foreach (sign_keys_array, index, sign_key_obj) {
- EXITIF (GNUNET_SYSERR ==
- parse_json_signkey (&key_data->sign_keys[index],
- sign_key_obj,
- &key_data->master_pub));
- }
- }
-
- /* parse the denomination keys */
- {
- json_t *denom_keys_array;
- json_t *denom_key_obj;
- unsigned int index;
-
- EXITIF (NULL == (denom_keys_array =
- json_object_get (resp_obj, "denoms")));
- EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
- EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array)));
- key_data->denom_keys = GNUNET_new_array (key_data->num_denom_keys,
- struct TALER_MINT_DenomPublicKey);
- index = 0;
- json_array_foreach (denom_keys_array, index, denom_key_obj) {
- EXITIF (GNUNET_SYSERR ==
- parse_json_denomkey (&key_data->denom_keys[index],
- denom_key_obj,
- &key_data->master_pub,
- hash_context));
- }
- }
-
- /* parse the auditor information */
- {
- json_t *auditors_array;
- json_t *auditor_info;
- unsigned int len;
- unsigned int index;
-
- EXITIF (NULL == (auditors_array =
- json_object_get (resp_obj, "auditors")));
- EXITIF (JSON_ARRAY != json_typeof (auditors_array));
- len = json_array_size (auditors_array);
- if (0 != len)
- {
- key_data->auditors = GNUNET_new_array (len,
- struct TALER_MINT_AuditorInformation);
- index = 0;
- json_array_foreach (auditors_array, index, auditor_info) {
- EXITIF (GNUNET_SYSERR ==
- parse_json_auditor (&key_data->auditors[index],
- auditor_info,
- key_data));
- }
- }
- }
-
- /* Validate signature... */
- ks.purpose.size = htonl (sizeof (ks));
- ks.purpose.purpose = htonl (TALER_SIGNATURE_MINT_KEY_SET);
- ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date);
- GNUNET_CRYPTO_hash_context_finish (hash_context,
- &ks.hc);
- hash_context = NULL;
- EXITIF (GNUNET_OK !=
- TALER_MINT_test_signing_key (key_data,
- &pub));
- EXITIF (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_KEY_SET,
- &ks.purpose,
- &sig.eddsa_signature,
- &pub.eddsa_pub));
- return GNUNET_OK;
- EXITIF_exit:
-
- if (NULL != hash_context)
- GNUNET_CRYPTO_hash_context_abort (hash_context);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Callback used when downloading the reply to a /keys request
- * is complete.
- *
- * @param cls the `struct KeysRequest`
- * @param eh easy handle of the original request
- */
-static void
-keys_completed_cb (void *cls,
- CURL *eh)
-{
- struct KeysRequest *kr = cls;
- struct TALER_MINT_Handle *mint = kr->mint;
- json_t *resp_obj;
- long response_code;
- TALER_MINT_CertificationCallback cb;
-
- resp_obj = MAC_download_get_result (&kr->db,
- eh,
- &response_code);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received keys from URL `%s' with status %ld.\n",
- kr->url,
- response_code);
- switch (response_code) {
- case 0:
- break;
- case MHD_HTTP_OK:
- if ( (NULL == resp_obj) ||
- (GNUNET_OK !=
- decode_keys_json (resp_obj,
- &kr->mint->key_data)) )
- response_code = 0;
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- break;
- }
- if (NULL != resp_obj)
- json_decref (resp_obj);
-
- if (MHD_HTTP_OK != response_code)
- {
- mint->kr = NULL;
- free_keys_request (kr);
- mint->state = MHS_FAILED;
- /* notify application that we failed */
- if (NULL != (cb = mint->cert_cb))
- {
- mint->cert_cb = NULL;
- cb (mint->cert_cb_cls,
- NULL);
- }
- return;
- }
- mint->kr = NULL;
- free_keys_request (kr);
- mint->state = MHS_CERT;
- /* notify application about the key information */
- if (NULL != (cb = mint->cert_cb))
- {
- mint->cert_cb = NULL;
- cb (mint->cert_cb_cls,
- &mint->key_data);
- }
-}
-
-
-/* ********************* library internal API ********* */
-
-
-/**
- * Get the context of a mint.
- *
- * @param h the mint handle to query
- * @return ctx context to execute jobs in
- */
-struct TALER_MINT_Context *
-MAH_handle_to_context (struct TALER_MINT_Handle *h)
-{
- return h->ctx;
-}
-
-
-/**
- * Check if the handle is ready to process requests.
- *
- * @param h the mint handle to query
- * @return #GNUNET_YES if we are ready, #GNUNET_NO if not
- */
-int
-MAH_handle_is_ready (struct TALER_MINT_Handle *h)
-{
- return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Obtain the URL to use for an API request.
- *
- * @param h the mint handle to query
- * @param path Taler API path (i.e. "/reserve/withdraw")
- * @return the full URI to use with cURL
- */
-char *
-MAH_path_to_url (struct TALER_MINT_Handle *h,
- const char *path)
-{
- char *url;
-
- if ( ('/' == path[0]) &&
- (0 < strlen (h->url)) &&
- ('/' == h->url[strlen (h->url) - 1]) )
- path++; /* avoid generating URL with "//" from concat */
- GNUNET_asprintf (&url,
- "%s%s",
- h->url,
- path);
- return url;
-}
-
-
-/* ********************* public API ******************* */
-
-/**
- * Initialise a connection to the mint. Will connect to the
- * mint and obtain information about the mint's master public
- * key and the mint's auditor. The respective information will
- * be passed to the @a cert_cb once available, and all future
- * interactions with the mint will be checked to be signed
- * (where appropriate) by the respective master key.
- *
- * @param ctx the context
- * @param url HTTP base URL for the mint
- * @param cert_cb function to call with the mint's certification information
- * @param cert_cb_cls closure for @a cert_cb
- * @param ... list of additional arguments, terminated by #TALER_MINT_OPTION_END.
- * @return the mint handle; NULL upon error
- */
-struct TALER_MINT_Handle *
-TALER_MINT_connect (struct TALER_MINT_Context *ctx,
- const char *url,
- TALER_MINT_CertificationCallback cert_cb,
- void *cert_cb_cls,
- ...)
-{
- struct TALER_MINT_Handle *mint;
- struct KeysRequest *kr;
- CURL *c;
-
- mint = GNUNET_new (struct TALER_MINT_Handle);
- mint->ctx = ctx;
- mint->url = GNUNET_strdup (url);
- mint->cert_cb = cert_cb;
- mint->cert_cb_cls = cert_cb_cls;
- kr = GNUNET_new (struct KeysRequest);
- kr->mint = mint;
- kr->url = MAH_path_to_url (mint, "/keys");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting keys with URL `%s'.\n",
- kr->url);
- c = curl_easy_init ();
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (c,
- CURLOPT_VERBOSE,
- 0));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (c,
- CURLOPT_STDERR,
- stdout));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (c,
- CURLOPT_URL,
- kr->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (c,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (c,
- CURLOPT_WRITEDATA,
- &kr->db));
- kr->job = MAC_job_add (mint->ctx,
- c,
- GNUNET_NO,
- &keys_completed_cb,
- kr);
- mint->kr = kr;
- return mint;
-}
-
-
-/**
- * Disconnect from the mint
- *
- * @param mint the mint handle
- */
-void
-TALER_MINT_disconnect (struct TALER_MINT_Handle *mint)
-{
- unsigned int i;
-
- if (NULL != mint->kr)
- {
- MAC_job_cancel (mint->kr->job);
- free_keys_request (mint->kr);
- mint->kr = NULL;
- }
- GNUNET_array_grow (mint->key_data.sign_keys,
- mint->key_data.num_sign_keys,
- 0);
- for (i=0;i<mint->key_data.num_denom_keys;i++)
- GNUNET_CRYPTO_rsa_public_key_free (mint->key_data.denom_keys[i].key.rsa_public_key);
- GNUNET_array_grow (mint->key_data.denom_keys,
- mint->key_data.num_denom_keys,
- 0);
- GNUNET_array_grow (mint->key_data.auditors,
- mint->key_data.num_auditors,
- 0);
- GNUNET_free (mint->url);
- GNUNET_free (mint);
-}
-
-
-/**
- * Test if the given @a pub is a the current signing key from the mint
- * according to @a keys.
- *
- * @param keys the mint's key set
- * @param pub claimed current online signing key for the mint
- * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key
- */
-int
-TALER_MINT_test_signing_key (const struct TALER_MINT_Keys *keys,
- const struct TALER_MintPublicKeyP *pub)
-{
- struct GNUNET_TIME_Absolute now;
- unsigned int i;
-
- /* we will check using a tolerance of 1h for the time */
- now = GNUNET_TIME_absolute_get ();
- for (i=0;i<keys->num_sign_keys;i++)
- if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) &&
- (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) &&
- (0 == memcmp (pub,
- &keys->sign_keys[i].key,
- sizeof (struct TALER_MintPublicKeyP))) )
- return GNUNET_OK;
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Obtain the denomination key details from the mint.
- *
- * @param keys the mint's key set
- * @param pk public key of the denomination to lookup
- * @return details about the given denomination key, NULL if the key is
- * not found
- */
-const struct TALER_MINT_DenomPublicKey *
-TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys,
- const struct TALER_DenominationPublicKey *pk)
-{
- unsigned int i;
-
- for (i=0;i<keys->num_denom_keys;i++)
- if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key,
- keys->denom_keys[i].key.rsa_public_key))
- return &keys->denom_keys[i];
- return NULL;
-}
-
-
-/**
- * Obtain the denomination key details from the mint.
- *
- * @param keys the mint's key set
- * @param hc hash of the public key of the denomination to lookup
- * @return details about the given denomination key
- */
-const struct TALER_MINT_DenomPublicKey *
-TALER_MINT_get_denomination_key_by_hash (const struct TALER_MINT_Keys *keys,
- const struct GNUNET_HashCode *hc)
-{
- unsigned int i;
-
- for (i=0;i<keys->num_denom_keys;i++)
- if (0 == memcmp (hc,
- &keys->denom_keys[i].h_key,
- sizeof (struct GNUNET_HashCode)))
- return &keys->denom_keys[i];
- return NULL;
-}
-
-
-/**
- * Obtain the keys from the mint.
- *
- * @param mint the mint handle
- * @return the mint's key set
- */
-const struct TALER_MINT_Keys *
-TALER_MINT_get_keys (const struct TALER_MINT_Handle *mint)
-{
- return &mint->key_data;
-}
-
-
-/* end of mint_api_handle.c */
diff --git a/src/mint-lib/mint_api_handle.h b/src/mint-lib/mint_api_handle.h
deleted file mode 100644
index 0dae58db6..000000000
--- a/src/mint-lib/mint_api_handle.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_handle.h
- * @brief Internal interface to the handle part of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include "taler_mint_service.h"
-
-
-/**
- * Get the context of a mint.
- *
- * @param h the mint handle to query
- * @return ctx context to execute jobs in
- */
-struct TALER_MINT_Context *
-MAH_handle_to_context (struct TALER_MINT_Handle *h);
-
-
-/**
- * Check if the handle is ready to process requests.
- *
- * @param h the mint handle to query
- * @return #GNUNET_YES if we are ready, #GNUNET_NO if not
- */
-int
-MAH_handle_is_ready (struct TALER_MINT_Handle *h);
-
-
-/**
- * Obtain the URL to use for an API request.
- *
- * @param h the mint handle to query
- * @param path Taler API path (i.e. "/reserve/withdraw")
- * @return the full URI to use with cURL
- */
-char *
-MAH_path_to_url (struct TALER_MINT_Handle *h,
- const char *path);
-
-
-/* end of mint_api_handle.h */
diff --git a/src/mint-lib/mint_api_json.c b/src/mint-lib/mint_api_json.c
deleted file mode 100644
index 7de33e5eb..000000000
--- a/src/mint-lib/mint_api_json.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_json.c
- * @brief functions to parse incoming requests (JSON snippets)
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "mint_api_json.h"
-
-/**
- * Navigate and parse data in a JSON tree.
- *
- * @param root the JSON node to start the navigation at.
- * @param spec parse specification array
- * @return offset in @a spec where parsing failed, -1 on success (!)
- */
-static int
-parse_json (json_t *root,
- struct MAJ_Specification *spec)
-{
- int i;
- json_t *pos; /* what's our current position? */
-
- pos = root;
- for (i=0;MAJ_CMD_END != spec[i].cmd;i++)
- {
- pos = json_object_get (root,
- spec[i].field);
- if (NULL == pos)
- {
- GNUNET_break_op (0);
- return i;
- }
- switch (spec[i].cmd)
- {
- case MAJ_CMD_END:
- GNUNET_assert (0);
- return i;
- case MAJ_CMD_AMOUNT:
- if (GNUNET_OK !=
- TALER_json_to_amount (pos,
- spec[i].details.amount))
- {
- GNUNET_break_op (0);
- return i;
- }
- break;
- case MAJ_CMD_TIME_ABSOLUTE:
- if (GNUNET_OK !=
- TALER_json_to_abs (pos,
- spec[i].details.abs_time))
- {
- GNUNET_break_op (0);
- return i;
- }
- break;
-
- case MAJ_CMD_STRING:
- {
- const char *str;
-
- str = json_string_value (pos);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- return i;
- }
- *spec[i].details.strptr = str;
- }
- break;
-
- case MAJ_CMD_BINARY_FIXED:
- {
- const char *str;
- int res;
-
- str = json_string_value (pos);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- return i;
- }
- res = GNUNET_STRINGS_string_to_data (str, strlen (str),
- spec[i].details.fixed_data.dest,
- spec[i].details.fixed_data.dest_size);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- return i;
- }
- }
- break;
-
- case MAJ_CMD_BINARY_VARIABLE:
- {
- const char *str;
- size_t size;
- void *data;
- int res;
-
- str = json_string_value (pos);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- return i;
- }
- size = (strlen (str) * 5) / 8;
- if (size >= 1024)
- {
- GNUNET_break_op (0);
- return i;
- }
- data = GNUNET_malloc (size);
- res = GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- data,
- size);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- GNUNET_free (data);
- return i;
- }
- *spec[i].details.variable_data.dest_p = data;
- *spec[i].details.variable_data.dest_size_p = size;
- }
- break;
-
- case MAJ_CMD_RSA_PUBLIC_KEY:
- {
- size_t size;
- const char *str;
- int res;
- void *buf;
-
- str = json_string_value (pos);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- return i;
- }
- size = (strlen (str) * 5) / 8;
- buf = GNUNET_malloc (size);
- res = GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- buf,
- size);
- if (GNUNET_OK != res)
- {
- GNUNET_free (buf);
- GNUNET_break_op (0);
- return i;
- }
- *spec[i].details.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_decode (buf,
- size);
- GNUNET_free (buf);
- if (NULL == spec[i].details.rsa_public_key)
- {
- GNUNET_break_op (0);
- return i;
- }
- }
- break;
-
- case MAJ_CMD_RSA_SIGNATURE:
- {
- size_t size;
- const char *str;
- int res;
- void *buf;
-
- str = json_string_value (pos);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- return i;
- }
- size = (strlen (str) * 5) / 8;
- buf = GNUNET_malloc (size);
- res = GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- buf,
- size);
- if (GNUNET_OK != res)
- {
- GNUNET_free (buf);
- GNUNET_break_op (0);
- return i;
- }
- *spec[i].details.rsa_signature
- = GNUNET_CRYPTO_rsa_signature_decode (buf,
- size);
- GNUNET_free (buf);
- if (NULL == spec[i].details.rsa_signature)
- return i;
- }
- break;
-
- case MAJ_CMD_UINT16:
- {
- json_int_t val;
-
- if (! json_is_integer (pos))
- {
- GNUNET_break_op (0);
- return i;
- }
- val = json_integer_value (pos);
- if ( (0 > val) || (val > UINT16_MAX) )
- {
- GNUNET_break_op (0);
- return i;
- }
- *spec[i].details.u16 = (uint16_t) val;
- }
- break;
-
- case MAJ_CMD_UINT64:
- {
- json_int_t val;
-
- if (! json_is_integer (pos))
- {
- GNUNET_break_op (0);
- return i;
- }
- val = json_integer_value (pos);
- *spec[i].details.u64 = (uint64_t) val;
- }
- break;
-
- case MAJ_CMD_JSON_OBJECT:
- {
- if (! (json_is_object (pos) || json_is_array (pos)) )
- {
- GNUNET_break_op (0);
- return i;
- }
- json_incref (pos);
- *spec[i].details.obj = pos;
- }
- break;
-
- default:
- GNUNET_break (0);
- return i;
- }
- }
- return -1; /* all OK! */
-}
-
-
-/**
- * Free all elements allocated during a
- * #MAJ_parse_json() operation.
- *
- * @param spec specification of the parse operation
- * @param end number of elements in @a spec to process
- */
-static void
-parse_free (struct MAJ_Specification *spec,
- int end)
-{
- int i;
-
- for (i=0;i<end;i++)
- {
- switch (spec[i].cmd)
- {
- case MAJ_CMD_END:
- GNUNET_assert (0);
- return;
- case MAJ_CMD_AMOUNT:
- break;
- case MAJ_CMD_TIME_ABSOLUTE:
- break;
- case MAJ_CMD_BINARY_FIXED:
- break;
- case MAJ_CMD_STRING:
- break;
- case MAJ_CMD_BINARY_VARIABLE:
- GNUNET_free (*spec[i].details.variable_data.dest_p);
- *spec[i].details.variable_data.dest_p = NULL;
- *spec[i].details.variable_data.dest_size_p = 0;
- break;
- case MAJ_CMD_RSA_PUBLIC_KEY:
- GNUNET_CRYPTO_rsa_public_key_free (*spec[i].details.rsa_public_key);
- *spec[i].details.rsa_public_key = NULL;
- break;
- case MAJ_CMD_RSA_SIGNATURE:
- GNUNET_CRYPTO_rsa_signature_free (*spec[i].details.rsa_signature);
- *spec[i].details.rsa_signature = NULL;
- break;
- case MAJ_CMD_JSON_OBJECT:
- json_decref (*spec[i].details.obj);
- *spec[i].details.obj = NULL;
- break;
- default:
- GNUNET_break (0);
- break;
- }
- }
-}
-
-
-/**
- * Navigate and parse data in a JSON tree.
- *
- * @param root the JSON node to start the navigation at.
- * @param spec parse specification array
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-MAJ_parse_json (const json_t *root,
- struct MAJ_Specification *spec)
-{
- int ret;
-
- ret = parse_json ((json_t *) root,
- spec);
- if (-1 == ret)
- return GNUNET_OK;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "JSON field `%s` (%d) had unexpected value\n",
- spec[ret].field,
- ret);
- parse_free (spec, ret);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Free all elements allocated during a
- * #MAJ_parse_json() operation.
- *
- * @param spec specification of the parse operation
- */
-void
-MAJ_parse_free (struct MAJ_Specification *spec)
-{
- int i;
-
- for (i=0;MAJ_CMD_END != spec[i].cmd;i++) ;
- parse_free (spec, i);
-}
-
-
-/**
- * The expected field stores a string.
- *
- * @param name name of the JSON field
- * @param strptr where to store a pointer to the field
- */
-struct MAJ_Specification
-MAJ_spec_string (const char *name,
- const char **strptr)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_STRING,
- .field = name,
- .details.strptr = strptr
- };
- return ret;
-}
-
-
-/**
- * Specification for parsing an absolute time value.
- *
- * @param name name of the JSON field
- * @param at where to store the absolute time found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_absolute_time (const char *name,
- struct GNUNET_TIME_Absolute *at)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_TIME_ABSOLUTE,
- .field = name,
- .details.abs_time = at
- };
- return ret;
-}
-
-
-/**
- * Specification for parsing an amount value.
- *
- * @param name name of the JSON field
- * @param amount where to store the amount found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_amount (const char *name,
- struct TALER_Amount *amount)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_AMOUNT,
- .field = name,
- .details.amount = amount
- };
- return ret;
-}
-
-
-/**
- * 16-bit integer.
- *
- * @param name name of the JSON field
- * @param[out] u16 where to store the integer found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_uint16 (const char *name,
- uint16_t *u16)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_UINT16,
- .field = name,
- .details.u16 = u16
- };
- return ret;
-}
-
-
-/**
- * 64-bit integer.
- *
- * @param name name of the JSON field
- * @param[out] u64 where to store the integer found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_uint64 (const char *name,
- uint64_t *u64)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_UINT64,
- .field = name,
- .details.u64 = u64
- };
- return ret;
-}
-
-
-/**
- * JSON object.
- *
- * @param name name of the JSON field
- * @param[out] jsonp where to store the JSON found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_json (const char *name,
- json_t **jsonp)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_JSON_OBJECT,
- .field = name,
- .details.obj = jsonp
- };
- return ret;
-}
-
-
-/**
- * Specification for parsing an RSA public key.
- *
- * @param name name of the JSON field
- * @param pk where to store the RSA key found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_rsa_public_key (const char *name,
- struct GNUNET_CRYPTO_rsa_PublicKey **pk)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_RSA_PUBLIC_KEY,
- .field = name,
- .details.rsa_public_key = pk
- };
- return ret;
-}
-
-
-/**
- * Specification for parsing an RSA signature.
- *
- * @param name name of the JSON field
- * @param sig where to store the RSA signature found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_rsa_signature (const char *name,
- struct GNUNET_CRYPTO_rsa_Signature **sig)
-{
- struct MAJ_Specification ret =
- {
- .cmd = MAJ_CMD_RSA_SIGNATURE,
- .field = name,
- .details.rsa_signature = sig
- };
- return ret;
-}
-
-
-/* end of mint_api_json.c */
diff --git a/src/mint-lib/mint_api_json.h b/src/mint-lib/mint_api_json.h
deleted file mode 100644
index 6bc3a5572..000000000
--- a/src/mint-lib/mint_api_json.h
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_json.h
- * @brief functions to parse incoming requests (JSON snippets)
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_util.h"
-#include <jansson.h>
-
-
-/**
- * Enumeration with the various commands for the
- * #MAJ_parse_json interpreter.
- */
-enum MAJ_Command
-{
-
- /**
- * End of command list.
- */
- MAJ_CMD_END,
-
- /**
- * Parse amount at current position.
- */
- MAJ_CMD_AMOUNT,
-
- /**
- * Parse absolute time at current position.
- */
- MAJ_CMD_TIME_ABSOLUTE,
-
- /**
- * Parse fixed binary value at current position.
- */
- MAJ_CMD_BINARY_FIXED,
-
- /**
- * Parse variable-size binary value at current position.
- */
- MAJ_CMD_BINARY_VARIABLE,
-
- /**
- * Parse RSA public key at current position.
- */
- MAJ_CMD_RSA_PUBLIC_KEY,
-
- /**
- * Parse RSA signature at current position.
- */
- MAJ_CMD_RSA_SIGNATURE,
-
- /**
- * Parse `const char *` JSON string at current position.
- */
- MAJ_CMD_STRING,
-
- /**
- * Parse `uint16_t` integer at the current position.
- */
- MAJ_CMD_UINT16,
-
- /**
- * Parse `uint64_t` integer at the current position.
- */
- MAJ_CMD_UINT64,
-
- /**
- * Parse JSON object at the current position.
- */
- MAJ_CMD_JSON_OBJECT,
-
- /**
- * Parse ??? at current position.
- */
- MAJ_CMD_C
-
-};
-
-
-/**
- * @brief Entry in parser specification for #MAJ_parse_json.
- */
-struct MAJ_Specification
-{
-
- /**
- * Command to execute.
- */
- enum MAJ_Command cmd;
-
- /**
- * Name of the field to access.
- */
- const char *field;
-
- /**
- * Further details for the command.
- */
- union {
-
- /**
- * Where to store amount for #MAJ_CMD_AMOUNT.
- */
- struct TALER_Amount *amount;
-
- /**
- * Where to store time, for #MAJ_CMD_TIME_ABSOLUTE.
- */
- struct GNUNET_TIME_Absolute *abs_time;
-
- /**
- * Where to write binary data, for #MAJ_CMD_BINARY_FIXED.
- */
- struct {
- /**
- * Where to write the data.
- */
- void *dest;
-
- /**
- * How many bytes to write to @e dest.
- */
- size_t dest_size;
-
- } fixed_data;
-
- /**
- * Where to write binary data, for #MAJ_CMD_BINARY_VARIABLE.
- */
- struct {
- /**
- * Where to store the pointer with the data (is allocated).
- */
- void **dest_p;
-
- /**
- * Where to store the number of bytes allocated at `*dest`.
- */
- size_t *dest_size_p;
-
- } variable_data;
-
- /**
- * Where to store the RSA public key for #MAJ_CMD_RSA_PUBLIC_KEY
- */
- struct GNUNET_CRYPTO_rsa_PublicKey **rsa_public_key;
-
- /**
- * Where to store the RSA signature for #MAJ_CMD_RSA_SIGNATURE
- */
- struct GNUNET_CRYPTO_rsa_Signature **rsa_signature;
-
- /**
- * Details for #MAJ_CMD_EDDSA_SIGNATURE
- */
- struct {
-
- /**
- * Where to store the purpose.
- */
- struct GNUNET_CRYPTO_EccSignaturePurpose **purpose_p;
-
- /**
- * Key to verify the signature against.
- */
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key;
-
- } eddsa_signature;
-
- /**
- * Where to store a pointer to the string.
- */
- const char **strptr;
-
- /**
- * Where to store 16-bit integer.
- */
- uint16_t *u16;
-
- /**
- * Where to store 64-bit integer.
- */
- uint64_t *u64;
-
- /**
- * Where to store a JSON object.
- */
- json_t **obj;
-
- } details;
-
-};
-
-
-/**
- * Navigate and parse data in a JSON tree.
- *
- * @param root the JSON node to start the navigation at.
- * @param spec parse specification array
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-MAJ_parse_json (const json_t *root,
- struct MAJ_Specification *spec);
-
-
-/**
- * Free all elements allocated during a
- * #MAJ_parse_json() operation.
- *
- * @param spec specification of the parse operation
- */
-void
-MAJ_parse_free (struct MAJ_Specification *spec);
-
-
-/**
- * End of a parser specification.
- */
-#define MAJ_spec_end { .cmd = MAJ_CMD_END }
-
-/**
- * Fixed size object (in network byte order, encoded using Crockford
- * Base32hex encoding).
- *
- * @param name name of the JSON field
- * @param obj pointer where to write the data (type of `*obj` will determine size)
- */
-#define MAJ_spec_fixed_auto(name,obj) { .cmd = MAJ_CMD_BINARY_FIXED, .field = name, .details.fixed_data.dest = obj, .details.fixed_data.dest_size = sizeof (*obj) }
-
-
-/**
- * Variable size object (in network byte order, encoded using Crockford
- * Base32hex encoding).
- *
- * @param name name of the JSON field
- * @param obj pointer where to write the data (a `void **`)
- * @param size where to store the number of bytes allocated for @a obj (of type `size_t *`
- */
-#define MAJ_spec_varsize(name,obj,size) { .cmd = MAJ_CMD_BINARY_VARIABLE, .field = name, .details.variable_data.dest_p = obj, .details.variable_data.dest_size_p = size }
-
-
-/**
- * The expected field stores a string.
- *
- * @param name name of the JSON field
- * @param strptr where to store a pointer to the field
- */
-struct MAJ_Specification
-MAJ_spec_string (const char *name,
- const char **strptr);
-
-
-/**
- * Absolute time.
- *
- * @param name name of the JSON field
- * @param[out] at where to store the absolute time found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_absolute_time (const char *name,
- struct GNUNET_TIME_Absolute *at);
-
-
-/**
- * 16-bit integer.
- *
- * @param name name of the JSON field
- * @param[out] u16 where to store the integer found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_uint16 (const char *name,
- uint16_t *u16);
-
-
-/**
- * 64-bit integer.
- *
- * @param name name of the JSON field
- * @param[out] u64 where to store the integer found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_uint64 (const char *name,
- uint64_t *u64);
-
-
-/**
- * JSON object.
- *
- * @param name name of the JSON field
- * @param[out] jsonp where to store the JSON found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_json (const char *name,
- json_t **jsonp);
-
-
-/**
- * Specification for parsing an amount value.
- *
- * @param name name of the JSON field
- * @param amount where to store the amount under @a name
- */
-struct MAJ_Specification
-MAJ_spec_amount (const char *name,
- struct TALER_Amount *amount);
-
-
-/**
- * Specification for parsing an RSA public key.
- *
- * @param name name of the JSON field
- * @param pk where to store the RSA key found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_rsa_public_key (const char *name,
- struct GNUNET_CRYPTO_rsa_PublicKey **pk);
-
-
-/**
- * Specification for parsing an RSA signature.
- *
- * @param name name of the JSON field
- * @param sig where to store the RSA signature found under @a name
- */
-struct MAJ_Specification
-MAJ_spec_rsa_signature (const char *name,
- struct GNUNET_CRYPTO_rsa_Signature **sig);
-
-
-
-
-/* end of mint_api_json.h */
diff --git a/src/mint-lib/mint_api_refresh.c b/src/mint-lib/mint_api_refresh.c
deleted file mode 100644
index cea16b153..000000000
--- a/src/mint-lib/mint_api_refresh.c
+++ /dev/null
@@ -1,2061 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_refresh.c
- * @brief Implementation of the /refresh/melt+reveal requests of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_common.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/* ********************* /refresh/ common ***************************** */
-
-/* structures for committing refresh data to disk before doing the
- network interaction(s) */
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * Header of serialized information about a coin we are melting.
- */
-struct MeltedCoinP
-{
- /**
- * Private key of the coin.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * Amount this coin contributes to the melt, including fee.
- */
- struct TALER_AmountNBO melt_amount_with_fee;
-
- /**
- * The applicable fee for withdrawing a coin of this denomination
- */
- struct TALER_AmountNBO fee_melt;
-
- /**
- * The original value of the coin.
- */
- struct TALER_AmountNBO original_value;
-
- /**
- * Transfer private keys for each cut-and-choose dimension.
- */
- struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
-
- /**
- * Timestamp indicating when coins of this denomination become invalid.
- */
- struct GNUNET_TIME_AbsoluteNBO deposit_valid_until;
-
- /**
- * Size of the encoded public key that follows.
- */
- uint16_t pbuf_size;
-
- /**
- * Size of the encoded signature that follows.
- */
- uint16_t sbuf_size;
-
- /* Followed by serializations of:
- 1) struct TALER_DenominationPublicKey pub_key;
- 2) struct TALER_DenominationSignature sig;
- */
-};
-
-
-/**
- * Header for serializations of coin-specific information about the
- * fresh coins we generate during a melt.
- */
-struct FreshCoinP
-{
-
- /**
- * Private key of the coin.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * Size of the encoded blinding key that follows.
- */
- uint32_t bbuf_size;
-
- /* Followed by serialization of:
- - struct TALER_DenominationBlindingKey blinding_key;
- */
-
-};
-
-
-/**
- * Header of serialized data about a melt operation, suitable for
- * persisting it on disk.
- */
-struct MeltDataP
-{
-
- /**
- * Hash over the melting session.
- */
- struct GNUNET_HashCode melt_session_hash;
-
- /**
- * Link secret used to encrypt the @a coin_priv and the blinding
- * key in the linkage data for the respective cut-and-choose dimension.
- */
- struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA];
-
- /**
- * Number of coins we are melting, in NBO
- */
- uint16_t num_melted_coins GNUNET_PACKED;
-
- /**
- * Number of coins we are creating, in NBO
- */
- uint16_t num_fresh_coins GNUNET_PACKED;
-
- /* Followed by serializations of:
- 1) struct MeltedCoinP melted_coins[num_melted_coins];
- 2) struct TALER_MINT_DenomPublicKey fresh_pks[num_fresh_coins];
- 3) TALER_CNC_KAPPA times:
- 3a) struct FreshCoinP fresh_coins[num_fresh_coins];
- */
-};
-
-
-GNUNET_NETWORK_STRUCT_END
-
-
-/**
- * Information about a coin we are melting.
- */
-struct MeltedCoin
-{
- /**
- * Private key of the coin.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * Amount this coin contributes to the melt, including fee.
- */
- struct TALER_Amount melt_amount_with_fee;
-
- /**
- * The applicable fee for melting a coin of this denomination
- */
- struct TALER_Amount fee_melt;
-
- /**
- * The original value of the coin.
- */
- struct TALER_Amount original_value;
-
- /**
- * Transfer private keys for each cut-and-choose dimension.
- */
- struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
-
- /**
- * Timestamp indicating when coins of this denomination become invalid.
- */
- struct GNUNET_TIME_Absolute deposit_valid_until;
-
- /**
- * Denomination key of the original coin.
- */
- struct TALER_DenominationPublicKey pub_key;
-
- /**
- * Mint's signature over the coin.
- */
- struct TALER_DenominationSignature sig;
-
-};
-
-
-/**
- * Coin-specific information about the fresh coins we generate during
- * a melt.
- */
-struct FreshCoin
-{
-
- /**
- * Private key of the coin.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * Blinding key used for blinding during blind signing.
- */
- struct TALER_DenominationBlindingKey blinding_key;
-
-};
-
-
-/**
- * Melt data in non-serialized format for convenient processing.
- */
-struct MeltData
-{
-
- /**
- * Hash over the melting session.
- */
- struct GNUNET_HashCode melt_session_hash;
-
- /**
- * Link secrets for each cut-and-choose dimension.
- */
- struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA];
-
- /**
- * Number of coins we are melting
- */
- uint16_t num_melted_coins;
-
- /**
- * Number of coins we are creating
- */
- uint16_t num_fresh_coins;
-
- /**
- * Information about the melted coins in an array of length @e
- * num_melted_coins.
- */
- struct MeltedCoin *melted_coins;
-
- /**
- * Array of @e num_fresh_coins denomination keys for the coins to be
- * freshly minted.
- */
- struct TALER_DenominationPublicKey *fresh_pks;
-
- /**
- * Arrays of @e num_fresh_coins with information about the fresh
- * coins to be created, for each cut-and-choose dimension.
- */
- struct FreshCoin *fresh_coins[TALER_CNC_KAPPA];
-};
-
-
-/**
- * Free all information associated with a melted coin session.
- *
- * @param mc melted coin to release, the pointer itself is NOT
- * freed (as it is typically not allocated by itself)
- */
-static void
-free_melted_coin (struct MeltedCoin *mc)
-{
- if (NULL == mc)
- return;
- if (NULL != mc->pub_key.rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (mc->pub_key.rsa_public_key);
- if (NULL != mc->sig.rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (mc->sig.rsa_signature);
-}
-
-
-/**
- * Free all information associated with a fresh coin.
- *
- * @param fc fresh coin to release, the pointer itself is NOT
- * freed (as it is typically not allocated by itself)
- */
-static void
-free_fresh_coin (struct FreshCoin *fc)
-{
- if (NULL == fc)
- return;
- if (NULL != fc->blinding_key.rsa_blinding_key)
- GNUNET_CRYPTO_rsa_blinding_key_free (fc->blinding_key.rsa_blinding_key);
-}
-
-
-/**
- * Free all information associated with a melting session. Note
- * that we allow the melting session to be only partially initialized,
- * as we use this function also when freeing melt data that was not
- * fully initialized (i.e. due to failures in #deserialize_melt_data()).
- *
- * @param md melting data to release, the pointer itself is NOT
- * freed (as it is typically not allocated by itself)
- */
-static void
-free_melt_data (struct MeltData *md)
-{
- unsigned int i;
- unsigned int j;
-
- if (NULL != md->melted_coins)
- {
- for (i=0;i<md->num_melted_coins;i++)
- free_melted_coin (&md->melted_coins[i]);
- GNUNET_free (md->melted_coins);
- }
- if (NULL != md->fresh_pks)
- {
- for (i=0;i<md->num_fresh_coins;i++)
- if (NULL != md->fresh_pks[i].rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (md->fresh_pks[i].rsa_public_key);
- GNUNET_free (md->fresh_pks);
- }
-
- for (i=0;i<TALER_CNC_KAPPA;i++)
- {
- for (j=0;j<md->num_fresh_coins;j++)
- free_fresh_coin (&md->fresh_coins[i][j]);
- GNUNET_free (md->fresh_coins[i]);
- }
- /* Finally, clean up a bit...
- (NOTE: compilers might optimize this away, so this is
- not providing any strong assurances that the key material
- is purged.) */
- memset (md,
- 0,
- sizeof (struct MeltData));
-}
-
-
-/**
- * Serialize information about a coin we are melting.
- *
- * @param mc information to serialize
- * @param buf buffer to write data in, NULL to just compute
- * required size
- * @param off offeset at @a buf to use
- * @return number of bytes written to @a buf at @a off, or if
- * @a buf is NULL, number of bytes required; 0 on error
- */
-static size_t
-serialize_melted_coin (const struct MeltedCoin *mc,
- char *buf,
- size_t off)
-{
- struct MeltedCoinP mcp;
- unsigned int i;
- char *pbuf;
- size_t pbuf_size;
- char *sbuf;
- size_t sbuf_size;
-
- sbuf_size = GNUNET_CRYPTO_rsa_signature_encode (mc->sig.rsa_signature,
- &sbuf);
- pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (mc->pub_key.rsa_public_key,
- &pbuf);
- if (NULL == buf)
- {
- GNUNET_free (sbuf);
- GNUNET_free (pbuf);
- return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size;
- }
- if ( (sbuf_size > UINT16_MAX) ||
- (pbuf_size > UINT16_MAX) )
- {
- GNUNET_break (0);
- return 0;
- }
- mcp.coin_priv = mc->coin_priv;
- TALER_amount_hton (&mcp.melt_amount_with_fee,
- &mc->melt_amount_with_fee);
- TALER_amount_hton (&mcp.fee_melt,
- &mc->fee_melt);
- TALER_amount_hton (&mcp.original_value,
- &mc->original_value);
- for (i=0;i<TALER_CNC_KAPPA;i++)
- mcp.transfer_priv[i] = mc->transfer_priv[i];
- mcp.deposit_valid_until = GNUNET_TIME_absolute_hton (mc->deposit_valid_until);
- mcp.pbuf_size = htons ((uint16_t) pbuf_size);
- mcp.sbuf_size = htons ((uint16_t) sbuf_size);
- memcpy (&buf[off],
- &mcp,
- sizeof (struct MeltedCoinP));
- memcpy (&buf[off + sizeof (struct MeltedCoinP)],
- pbuf,
- pbuf_size);
- memcpy (&buf[off + sizeof (struct MeltedCoinP) + pbuf_size],
- sbuf,
- sbuf_size);
- GNUNET_free (sbuf);
- GNUNET_free (pbuf);
- return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size;
-}
-
-
-/**
- * Deserialize information about a coin we are melting.
- *
- * @param[out] mc information to deserialize
- * @param buf buffer to read data from
- * @param size number of bytes available at @a buf to use
- * @param[out] ok set to #GNUNET_NO to report errors
- * @return number of bytes read from @a buf, 0 on error
- */
-static size_t
-deserialize_melted_coin (struct MeltedCoin *mc,
- const char *buf,
- size_t size,
- int *ok)
-{
- struct MeltedCoinP mcp;
- unsigned int i;
- size_t pbuf_size;
- size_t sbuf_size;
- size_t off;
-
- if (size < sizeof (struct MeltedCoinP))
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- memcpy (&mcp,
- buf,
- sizeof (struct MeltedCoinP));
- pbuf_size = ntohs (mcp.pbuf_size);
- sbuf_size = ntohs (mcp.sbuf_size);
- if (size < sizeof (struct MeltedCoinP) + pbuf_size + sbuf_size)
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- off = sizeof (struct MeltedCoinP);
- mc->pub_key.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_decode (&buf[off],
- pbuf_size);
- off += pbuf_size;
- mc->sig.rsa_signature
- = GNUNET_CRYPTO_rsa_signature_decode (&buf[off],
- sbuf_size);
- off += sbuf_size;
- if ( (NULL == mc->pub_key.rsa_public_key) ||
- (NULL == mc->sig.rsa_signature) )
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
-
- mc->coin_priv = mcp.coin_priv;
- TALER_amount_ntoh (&mc->melt_amount_with_fee,
- &mcp.melt_amount_with_fee);
- TALER_amount_ntoh (&mc->fee_melt,
- &mcp.fee_melt);
- TALER_amount_ntoh (&mc->original_value,
- &mcp.original_value);
- for (i=0;i<TALER_CNC_KAPPA;i++)
- mc->transfer_priv[i] = mcp.transfer_priv[i];
- mc->deposit_valid_until = GNUNET_TIME_absolute_ntoh (mcp.deposit_valid_until);
- return off;
-}
-
-
-/**
- * Serialize information about a denomination key.
- *
- * @param dk information to serialize
- * @param buf buffer to write data in, NULL to just compute
- * required size
- * @param off offeset at @a buf to use
- * @return number of bytes written to @a buf at @a off, or if
- * @a buf is NULL, number of bytes required
- */
-static size_t
-serialize_denomination_key (const struct TALER_DenominationPublicKey *dk,
- char *buf,
- size_t off)
-{
- char *pbuf;
- size_t pbuf_size;
- uint32_t be;
-
- pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key,
- &pbuf);
- if (NULL == buf)
- {
- GNUNET_free (pbuf);
- return pbuf_size + sizeof (uint32_t);
- }
- be = htonl ((uint32_t) pbuf_size);
- memcpy (&buf[off],
- &be,
- sizeof (uint32_t));
- memcpy (&buf[off + sizeof (uint32_t)],
- pbuf,
- pbuf_size);
- GNUNET_free (pbuf);
- return pbuf_size + sizeof (uint32_t);
-}
-
-
-/**
- * Deserialize information about a denomination key.
- *
- * @param[out] dk information to deserialize
- * @param buf buffer to read data from
- * @param size number of bytes available at @a buf to use
- * @param[out] ok set to #GNUNET_NO to report errors
- * @return number of bytes read from @a buf, 0 on error
- */
-static size_t
-deserialize_denomination_key (struct TALER_DenominationPublicKey *dk,
- const char *buf,
- size_t size,
- int *ok)
-{
- size_t pbuf_size;
- uint32_t be;
-
- if (size < sizeof (uint32_t))
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- memcpy (&be,
- buf,
- sizeof (uint32_t));
- pbuf_size = ntohl (be);
- if (size < sizeof (uint32_t) + pbuf_size)
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- dk->rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (uint32_t)],
- pbuf_size);
-
- if (NULL == dk->rsa_public_key)
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- return sizeof (uint32_t) + pbuf_size;
-}
-
-
-/**
- * Serialize information about a fresh coin we are generating.
- *
- * @param fc information to serialize
- * @param buf buffer to write data in, NULL to just compute
- * required size
- * @param off offeset at @a buf to use
- * @return number of bytes written to @a buf at @a off, or if
- * @a buf is NULL, number of bytes required
- */
-static size_t
-serialize_fresh_coin (const struct FreshCoin *fc,
- char *buf,
- size_t off)
-{
- struct FreshCoinP fcp;
- char *bbuf;
- size_t bbuf_size;
-
- bbuf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (fc->blinding_key.rsa_blinding_key,
- &bbuf);
- if (NULL == buf)
- {
- GNUNET_free (bbuf);
- return sizeof (struct FreshCoinP) + bbuf_size;
- }
- fcp.coin_priv = fc->coin_priv;
- fcp.bbuf_size = htonl ((uint32_t) bbuf_size);
- memcpy (&buf[off],
- &fcp,
- sizeof (struct FreshCoinP));
- memcpy (&buf[off + sizeof (struct FreshCoinP)],
- bbuf,
- bbuf_size);
- GNUNET_free (bbuf);
- return sizeof (struct FreshCoinP) + bbuf_size;
-}
-
-
-/**
- * Deserialize information about a fresh coin we are generating.
- *
- * @param[out] fc information to deserialize
- * @param buf buffer to read data from
- * @param size number of bytes available at @a buf to use
- * @param[out] ok set to #GNUNET_NO to report errors
- * @return number of bytes read from @a buf, 0 on error
- */
-static size_t
-deserialize_fresh_coin (struct FreshCoin *fc,
- const char *buf,
- size_t size,
- int *ok)
-{
- struct FreshCoinP fcp;
- size_t bbuf_size;
-
- if (size < sizeof (struct FreshCoinP))
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- memcpy (&fcp,
- buf,
- sizeof (struct FreshCoinP));
- bbuf_size = ntohl (fcp.bbuf_size);
- if (size < sizeof (struct FreshCoinP) + bbuf_size)
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- fc->blinding_key.rsa_blinding_key
- = GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct FreshCoinP)],
- bbuf_size);
- if (NULL == fc->blinding_key.rsa_blinding_key)
- {
- GNUNET_break (0);
- *ok = GNUNET_NO;
- return 0;
- }
- fc->coin_priv = fcp.coin_priv;
- return sizeof (struct FreshCoinP) + bbuf_size;
-}
-
-
-/**
- * Serialize melt data.
- *
- * @param md data to serialize
- * @param[out] res_size size of buffer returned
- * @return serialized melt data
- */
-static char *
-serialize_melt_data (const struct MeltData *md,
- size_t *res_size)
-{
- size_t size;
- size_t asize;
- char *buf;
- unsigned int i;
- unsigned int j;
-
- size = 0;
- asize = (size_t) -1; /* make the compiler happy */
- buf = NULL;
- /* we do 2 iterations, #1 to determine total size, #2 to
- actually construct the buffer */
- do {
- if (0 == size)
- {
- size = sizeof (struct MeltDataP);
- }
- else
- {
- struct MeltDataP *mdp;
-
- buf = GNUNET_malloc (size);
- asize = size; /* just for invariant check later */
- size = sizeof (struct MeltDataP);
- mdp = (struct MeltDataP *) buf;
- mdp->melt_session_hash = md->melt_session_hash;
- for (i=0;i<TALER_CNC_KAPPA;i++)
- mdp->link_secrets[i] = md->link_secrets[i];
- mdp->num_melted_coins = htons (md->num_melted_coins);
- mdp->num_fresh_coins = htons (md->num_fresh_coins);
- }
- for (i=0;i<md->num_melted_coins;i++)
- size += serialize_melted_coin (&md->melted_coins[i],
- buf,
- size);
- for (i=0;i<md->num_fresh_coins;i++)
- size += serialize_denomination_key (&md->fresh_pks[i],
- buf,
- size);
- for (i=0;i<TALER_CNC_KAPPA;i++)
- for(j=0;j<md->num_fresh_coins;j++)
- size += serialize_fresh_coin (&md->fresh_coins[i][j],
- buf,
- size);
- } while (NULL == buf);
- GNUNET_assert (size == asize);
- *res_size = size;
- return buf;
-}
-
-
-/**
- * Deserialize melt data.
- *
- * @param buf serialized data
- * @param buf_size size of @a buf
- * @return deserialized melt data, NULL on error
- */
-static struct MeltData *
-deserialize_melt_data (const char *buf,
- size_t buf_size)
-{
- struct MeltData *md;
- struct MeltDataP mdp;
- unsigned int i;
- unsigned int j;
- size_t off;
- int ok;
-
- if (buf_size < sizeof (struct MeltDataP))
- return NULL;
- memcpy (&mdp,
- buf,
- sizeof (struct MeltDataP));
- md = GNUNET_new (struct MeltData);
- md->melt_session_hash = mdp.melt_session_hash;
- for (i=0;i<TALER_CNC_KAPPA;i++)
- md->link_secrets[i] = mdp.link_secrets[i];
- md->num_melted_coins = ntohs (mdp.num_melted_coins);
- md->num_fresh_coins = ntohs (mdp.num_fresh_coins);
- md->melted_coins = GNUNET_new_array (md->num_melted_coins,
- struct MeltedCoin);
- md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
- struct TALER_DenominationPublicKey);
- for (i=0;i<TALER_CNC_KAPPA;i++)
- md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins,
- struct FreshCoin);
- off = sizeof (struct MeltDataP);
- ok = GNUNET_YES;
- for (i=0;(i<md->num_melted_coins)&&(GNUNET_YES == ok);i++)
- off += deserialize_melted_coin (&md->melted_coins[i],
- &buf[off],
- buf_size - off,
- &ok);
- for (i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++)
- off += deserialize_denomination_key (&md->fresh_pks[i],
- &buf[off],
- buf_size - off,
- &ok);
-
- for (i=0;i<TALER_CNC_KAPPA;i++)
- for(j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++)
- off += deserialize_fresh_coin (&md->fresh_coins[i][j],
- &buf[off],
- buf_size - off,
- &ok);
- if (off != buf_size)
- {
- GNUNET_break (0);
- ok = GNUNET_NO;
- }
- if (GNUNET_YES != ok)
- {
- free_melt_data (md);
- GNUNET_free (md);
- return NULL;
- }
- return md;
-}
-
-
-/**
- * Setup information for a fresh coin.
- *
- * @param[out] fc value to initialize
- * @param pk denomination information for the fresh coin
- */
-static void
-setup_fresh_coin (struct FreshCoin *fc,
- const struct TALER_MINT_DenomPublicKey *pk)
-{
- struct GNUNET_CRYPTO_EddsaPrivateKey *epk;
- unsigned int len;
-
- epk = GNUNET_CRYPTO_eddsa_key_create ();
- fc->coin_priv.eddsa_priv = *epk;
- GNUNET_free (epk);
- len = GNUNET_CRYPTO_rsa_public_key_len (pk->key.rsa_public_key);
- fc->blinding_key.rsa_blinding_key
- = GNUNET_CRYPTO_rsa_blinding_key_create (len);
-}
-
-
-/**
- * Melt (partially spent) coins to obtain fresh coins that are
- * unlinkable to the original coin(s). Note that melting more
- * than one coin in a single request will make those coins linkable,
- * so the safest operation only melts one coin at a time.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, is operation does
- * not actually initiate the request. Instead, it generates a buffer
- * which the caller must store before proceeding with the actual call
- * to #TALER_MINT_refresh_melt() that will generate the request.
- *
- * This function does verify that the given request data is internally
- * consistent. However, the @a melts_sigs are only verified if
- * @a check_sigs is set to #GNUNET_YES, as this may be relatively
- * expensive and should be redundant.
- *
- * Aside from some non-trivial cryptographic operations that might
- * take a bit of CPU time to complete, this function returns
- * its result immediately and does not start any asynchronous
- * processing. This function is also thread-safe.
- *
- * @param num_melts number of coins that are being melted (typically 1)
- * @param melt_privs array of @a num_melts private keys of the coins to melt
- * @param melt_amounts array of @a num_melts amounts specifying how much
- * each coin will contribute to the melt (including fee)
- * @param melt_sigs array of @a num_melts signatures affirming the
- * validity of the public keys corresponding to the
- * @a melt_privs private keys
- * @param melt_pks array of @a num_melts denomination key information
- * records corresponding to the @a melt_sigs
- * validity of the keys
- * @param check_sigs verify the validity of the signatures of @a melt_sigs
- * @param fresh_pks_len length of the @a pks array
- * @param fresh_pks array of @a pks_len denominations of fresh coins to create
- * @param[out] res_size set to the size of the return value, or 0 on error
- * @return NULL
- * if the inputs are invalid (i.e. denomination key not with this mint).
- * Otherwise, pointer to a buffer of @a res_size to store persistently
- * before proceeding to #TALER_MINT_refresh_melt().
- * Non-null results should be freed using #GNUNET_free().
- */
-char *
-TALER_MINT_refresh_prepare (unsigned int num_melts,
- const struct TALER_CoinSpendPrivateKeyP *melt_privs,
- const struct TALER_Amount *melt_amounts,
- const struct TALER_DenominationSignature *melt_sigs,
- const struct TALER_MINT_DenomPublicKey *melt_pks,
- int check_sigs,
- unsigned int fresh_pks_len,
- const struct TALER_MINT_DenomPublicKey *fresh_pks,
- size_t *res_size)
-{
- struct MeltData md;
- char *buf;
- unsigned int i;
- unsigned int j;
- struct GNUNET_HashContext *hash_context;
-
- /* build up melt data structure */
- for (i=0;i<TALER_CNC_KAPPA;i++)
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
- &md.link_secrets[i],
- sizeof (struct TALER_LinkSecretP));
- md.num_melted_coins = num_melts;
- md.num_fresh_coins = fresh_pks_len;
- md.melted_coins = GNUNET_new_array (num_melts,
- struct MeltedCoin);
- for (i=0;i<num_melts;i++)
- {
- md.melted_coins[i].coin_priv = melt_privs[i];
- md.melted_coins[i].melt_amount_with_fee = melt_amounts[i];
- md.melted_coins[i].fee_melt = melt_pks[i].fee_refresh;
- md.melted_coins[i].original_value = melt_pks[i].value;
- for (j=0;j<TALER_CNC_KAPPA;j++)
- {
- struct GNUNET_CRYPTO_EcdhePrivateKey *tpk;
-
- tpk = GNUNET_CRYPTO_ecdhe_key_create ();
- md.melted_coins[i].transfer_priv[j].ecdhe_priv = *tpk;
- GNUNET_free (tpk);
- }
- md.melted_coins[i].deposit_valid_until
- = melt_pks[i].deposit_valid_until;
- md.melted_coins[i].pub_key.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_dup (melt_pks[i].key.rsa_public_key);
- md.melted_coins[i].sig.rsa_signature
- = GNUNET_CRYPTO_rsa_signature_dup (melt_sigs[i].rsa_signature);
- }
- md.fresh_pks = GNUNET_new_array (fresh_pks_len,
- struct TALER_DenominationPublicKey);
- for (i=0;i<fresh_pks_len;i++)
- md.fresh_pks[i].rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key);
- for (i=0;i<TALER_CNC_KAPPA;i++)
- {
- md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
- struct FreshCoin);
- for (j=0;j<fresh_pks_len;j++)
- setup_fresh_coin (&md.fresh_coins[i][j],
- &fresh_pks[j]);
- }
-
- /* now compute melt session hash */
- hash_context = GNUNET_CRYPTO_hash_context_start ();
- for (i=0;i<fresh_pks_len;i++)
- {
- char *buf;
- size_t buf_size;
-
- buf_size = GNUNET_CRYPTO_rsa_public_key_encode (fresh_pks[i].key.rsa_public_key,
- &buf);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- buf,
- buf_size);
- GNUNET_free (buf);
- }
- for (i=0;i<num_melts;i++)
- {
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_AmountNBO melt_amount;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&melt_privs[i].eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP));
- TALER_amount_hton (&melt_amount,
- &melt_amounts[i]);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &melt_amount,
- sizeof (struct TALER_AmountNBO));
-
- }
- for (i = 0; i < TALER_CNC_KAPPA; i++)
- {
- for (j = 0; j < fresh_pks_len; j++)
- {
- const struct FreshCoin *fc; /* coin this is about */
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_HashCode coin_hash;
- char *coin_ev; /* blinded message to be signed (in envelope) for each coin */
- size_t coin_ev_size;
- struct TALER_RefreshLinkDecrypted rld;
- struct TALER_RefreshLinkEncrypted *rle;
- char *link_enc; /* encrypted link data */
- size_t link_enc_size;
-
- fc = &md.fresh_coins[i][j];
- GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &coin_hash);
- coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash,
- fc->blinding_key.rsa_blinding_key,
- md.fresh_pks[j].rsa_public_key,
- &coin_ev);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- coin_ev,
- coin_ev_size);
- GNUNET_free (coin_ev);
-
- rld.coin_priv = fc->coin_priv;
- rld.blinding_key = fc->blinding_key;
- rle = TALER_refresh_encrypt (&rld,
- &md.link_secrets[i]);
- link_enc = TALER_refresh_link_encrypted_encode (rle,
- &link_enc_size);
-
- GNUNET_CRYPTO_hash_context_read (hash_context,
- link_enc,
- link_enc_size);
- GNUNET_free (link_enc);
- }
- }
- for (i = 0; i < TALER_CNC_KAPPA; i++)
- {
- for (j = 0; j < num_melts; j++)
- {
- struct TALER_RefreshCommitLinkP rcl;
- struct TALER_TransferSecretP trans_sec;
-
- GNUNET_CRYPTO_ecdhe_key_get_public (&md.melted_coins[j].transfer_priv[i].ecdhe_priv,
- &rcl.transfer_pub.ecdhe_pub);
- TALER_link_derive_transfer_secret (&melt_privs[j],
- &md.melted_coins[j].transfer_priv[i],
- &trans_sec);
- TALER_transfer_encrypt (&md.link_secrets[i],
- &trans_sec,
- &rcl.shared_secret_enc);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &rcl,
- sizeof (struct TALER_RefreshCommitLinkP));
- }
- }
-
- GNUNET_CRYPTO_hash_context_finish (hash_context,
- &md.melt_session_hash);
-
- /* finally, serialize everything */
- buf = serialize_melt_data (&md,
- res_size);
- free_melt_data (&md);
- return buf;
-}
-
-
-/* ********************* /refresh/melt ***************************** */
-
-
-/**
- * @brief A /refresh/melt Handle
- */
-struct TALER_MINT_RefreshMeltHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * JSON encoding of the request to POST.
- */
- char *json_enc;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with refresh melt failure results.
- */
- TALER_MINT_RefreshMeltCallback melt_cb;
-
- /**
- * Closure for @e result_cb and @e melt_failure_cb.
- */
- void *melt_cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Actual information about the melt operation.
- */
- struct MeltData *md;
-};
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * from the mint is valid.
- *
- * @param rmh melt handle
- * @param json json reply with the signature
- * @param[out] noreveal_index set to the noreveal index selected by the mint
- * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
- */
-static int
-verify_refresh_melt_signature_ok (struct TALER_MINT_RefreshMeltHandle *rmh,
- json_t *json,
- uint16_t *noreveal_index)
-{
- struct TALER_MintSignatureP mint_sig;
- struct TALER_MintPublicKeyP mint_pub;
- const struct TALER_MINT_Keys *key_state;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("mint_sig", &mint_sig),
- MAJ_spec_fixed_auto ("mint_pub", &mint_pub),
- MAJ_spec_uint16 ("noreveal_index", noreveal_index),
- MAJ_spec_end
- };
- struct TALER_RefreshMeltConfirmationPS confirm;
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* check that mint signing key is permitted */
- key_state = TALER_MINT_get_keys (rmh->mint);
- if (GNUNET_OK !=
- TALER_MINT_test_signing_key (key_state,
- &mint_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* check that noreveal index is in permitted range */
- if (TALER_CNC_KAPPA <= *noreveal_index)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* verify signature by mint */
- confirm.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_MELT);
- confirm.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
- confirm.session_hash = rmh->md->melt_session_hash;
- confirm.noreveal_index = htons (*noreveal_index);
- confirm.reserved = htons (0);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_MELT,
- &confirm.purpose,
- &mint_sig.eddsa_signature,
- &mint_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Verify that the signatures on the "403 FORBIDDEN" response from the
- * mint demonstrating customer double-spending are valid.
- *
- * @param rmh melt handle
- * @param json json reply with the signature(s) and transaction history
- * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
- */
-static int
-verify_refresh_melt_signature_forbidden (struct TALER_MINT_RefreshMeltHandle *rmh,
- json_t *json)
-{
- json_t *history;
- struct TALER_Amount original_value;
- struct TALER_Amount melt_value_with_fee;
- struct TALER_Amount total;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- unsigned int i;
- struct MAJ_Specification spec[] = {
- MAJ_spec_json ("history", &history),
- MAJ_spec_fixed_auto ("coin_pub", &coin_pub),
- MAJ_spec_amount ("original_value", &original_value),
- MAJ_spec_amount ("requested_value", &melt_value_with_fee),
- MAJ_spec_end
- };
- const struct MeltedCoin *mc;
-
- /* parse JSON reply */
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* Find out which coin was deemed problematic by the mint */
- mc = NULL;
- for (i=0;i<rmh->md->num_melted_coins;i++)
- {
- if (0 == TALER_amount_cmp (&melt_value_with_fee,
- &rmh->md->melted_coins[i].melt_amount_with_fee))
- {
- struct TALER_CoinSpendPublicKeyP mc_pub;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&rmh->md->melted_coins[i].coin_priv.eddsa_priv,
- &mc_pub.eddsa_pub);
- if (0 == memcmp (&mc_pub,
- &coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP)))
- {
- mc = &rmh->md->melted_coins[i];
- break;
- }
- }
- }
- if (NULL == mc)
- {
- /* coin not found in our original request */
- GNUNET_break_op (0);
- json_decref (history);
- return GNUNET_SYSERR;
- }
-
- /* check basic coin properties */
- if (0 != TALER_amount_cmp (&original_value,
- &mc->original_value))
- {
- /* We disagree on the value of the coin */
- GNUNET_break_op (0);
- json_decref (history);
- return GNUNET_SYSERR;
- }
- if (0 != TALER_amount_cmp (&melt_value_with_fee,
- &mc->melt_amount_with_fee))
- {
- /* We disagree on the value of the coin */
- GNUNET_break_op (0);
- json_decref (history);
- return GNUNET_SYSERR;
- }
-
- /* verify coin history */
- history = json_object_get (json,
- "history");
- if (GNUNET_OK !=
- TALER_MINT_verify_coin_history_ (original_value.currency,
- &coin_pub,
- history,
- &total))
- {
- GNUNET_break_op (0);
- json_decref (history);
- return GNUNET_SYSERR;
- }
- json_decref (history);
-
- /* check if melt operation was really too expensive given history */
- if (GNUNET_OK !=
- TALER_amount_add (&total,
- &total,
- &melt_value_with_fee))
- {
- /* clearly not OK if our transaction would have caused
- the overflow... */
- return GNUNET_OK;
- }
-
- if (0 >= TALER_amount_cmp (&total,
- &original_value))
- {
- /* transaction should have still fit */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- /* everything OK, valid proof of double-spending was provided */
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /refresh/melt request.
- *
- * @param cls the `struct TALER_MINT_RefreshMeltHandle`
- * @param eh the curl request handle
- */
-static void
-handle_refresh_melt_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_RefreshMeltHandle *rmh = cls;
- long response_code;
- json_t *json;
- uint16_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */
-
- rmh->job = NULL;
- json = MAC_download_get_result (&rmh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- if (GNUNET_OK !=
- verify_refresh_melt_signature_ok (rmh,
- json,
- &noreveal_index))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- if (NULL != rmh->melt_cb)
- {
- rmh->melt_cb (rmh->melt_cb_cls,
- response_code,
- noreveal_index,
- json);
- rmh->melt_cb = NULL;
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_FORBIDDEN:
- /* Double spending; check signatures on transaction history */
- if (GNUNET_OK !=
- verify_refresh_melt_signature_forbidden (rmh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- break;
- case MHD_HTTP_UNAUTHORIZED:
- /* Nothing really to verify, mint says one of the signatures is
- invalid; assuming we checked them, this should never happen, we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (NULL != rmh->melt_cb)
- rmh->melt_cb (rmh->melt_cb_cls,
- response_code,
- UINT16_MAX,
- json);
- json_decref (json);
- TALER_MINT_refresh_melt_cancel (rmh);
-}
-
-
-/**
- * Convert a coin to be melted to the respective JSON encoding.
- *
- * @param melt_session_hash session hash to use
- * @param mc coin to be melted
- * @return JSON encoding of the melting request
- */
-static json_t *
-melted_coin_to_json (const struct GNUNET_HashCode *melt_session_hash,
- const struct MeltedCoin *mc)
-{
- struct TALER_CoinSpendSignatureP confirm_sig;
- struct TALER_RefreshMeltCoinAffirmationPS melt;
-
- melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
- melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
- melt.session_hash = *melt_session_hash;
- TALER_amount_hton (&melt.amount_with_fee,
- &mc->melt_amount_with_fee);
- TALER_amount_hton (&melt.melt_fee,
- &mc->fee_melt);
- GNUNET_CRYPTO_eddsa_key_get_public (&mc->coin_priv.eddsa_priv,
- &melt.coin_pub.eddsa_pub);
- GNUNET_CRYPTO_eddsa_sign (&mc->coin_priv.eddsa_priv,
- &melt.purpose,
- &confirm_sig.eddsa_signature);
- return json_pack ("{s:o, s:o, s:o, s:o, s:o}",
- "coin_pub",
- TALER_json_from_data (&melt.coin_pub,
- sizeof (melt.coin_pub)),
- "denom_pub",
- TALER_json_from_rsa_public_key (mc->pub_key.rsa_public_key),
- "denom_sig",
- TALER_json_from_rsa_signature (mc->sig.rsa_signature),
- "confirm_sig",
- TALER_json_from_data (&confirm_sig,
- sizeof (confirm_sig)),
- "value_with_fee",
- TALER_json_from_amount (&mc->melt_amount_with_fee));
-}
-
-
-/**
- * Submit a melt request to the mint and get the mint's
- * response.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, the provided
- * argument should have been constructed using
- * #TALER_MINT_refresh_prepare and committed to persistent storage
- * prior to calling this function.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param refresh_data_length size of the @a refresh_data (returned
- * in the `res_size` argument from #TALER_MINT_refresh_prepare())
- * @param refresh_data the refresh data as returned from
- #TALER_MINT_refresh_prepare())
- * @param melt_cb the callback to call with the result
- * @param melt_cb_cls closure for @a melt_cb
- * @return a handle for this request; NULL if the argument was invalid.
- * In this case, neither callback will be called.
- */
-struct TALER_MINT_RefreshMeltHandle *
-TALER_MINT_refresh_melt (struct TALER_MINT_Handle *mint,
- size_t refresh_data_length,
- const char *refresh_data,
- TALER_MINT_RefreshMeltCallback melt_cb,
- void *melt_cb_cls)
-{
- json_t *melt_obj;
- json_t *new_denoms;
- json_t *melt_coins;
- json_t *coin_evs;
- json_t *transfer_pubs;
- json_t *secret_encs;
- json_t *link_encs;
- json_t *tmp;
- struct TALER_MINT_RefreshMeltHandle *rmh;
- CURL *eh;
- struct TALER_MINT_Context *ctx;
- struct MeltData *md;
- unsigned int i;
- unsigned int j;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- md = deserialize_melt_data (refresh_data,
- refresh_data_length);
- if (NULL == md)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- /* build JSON request, each of the 6 arrays first */
- new_denoms = json_array ();
- melt_coins = json_array ();
- coin_evs = json_array ();
- transfer_pubs = json_array ();
- secret_encs = json_array ();
- link_encs = json_array ();
- for (i=0;i<md->num_melted_coins;i++)
- {
- const struct MeltedCoin *mc = &md->melted_coins[i];
-
- /* now melt_coins */
- json_array_append (melt_coins,
- melted_coin_to_json (&md->melt_session_hash,
- mc));
- }
-
- /* now transfer_pubs */
- for (j=0;j<TALER_CNC_KAPPA;j++)
- {
- tmp = json_array ();
- for (i=0;i<md->num_melted_coins;i++)
- {
- const struct MeltedCoin *mc = &md->melted_coins[i];
- struct TALER_TransferPublicKeyP transfer_pub;
-
- GNUNET_CRYPTO_ecdhe_key_get_public (&mc->transfer_priv[j].ecdhe_priv,
- &transfer_pub.ecdhe_pub);
- json_array_append (tmp,
- TALER_json_from_data (&transfer_pub,
- sizeof (transfer_pub)));
- }
- json_array_append (transfer_pubs,
- tmp);
- }
-
- /* now secret_encs */
- for (j=0;j<TALER_CNC_KAPPA;j++)
- {
- tmp = json_array ();
- for (i=0;i<md->num_melted_coins;i++)
- {
- const struct MeltedCoin *mc = &md->melted_coins[i];
- struct TALER_EncryptedLinkSecretP els;
- struct TALER_TransferSecretP trans_sec;
-
- TALER_link_derive_transfer_secret (&mc->coin_priv,
- &mc->transfer_priv[j],
- &trans_sec);
- GNUNET_assert (GNUNET_OK ==
- TALER_transfer_encrypt (&md->link_secrets[j],
- &trans_sec,
- &els));
- json_array_append (tmp,
- TALER_json_from_data (&els,
- sizeof (els)));
- }
- json_array_append (secret_encs,
- tmp);
- }
-
- /* now new_denoms */
- for (i=0;i<md->num_fresh_coins;i++)
- {
- json_array_append (new_denoms,
- TALER_json_from_rsa_public_key
- (md->fresh_pks[i].rsa_public_key));
- }
-
- /* now link_encs */
- for (j=0;j<TALER_CNC_KAPPA;j++)
- {
- tmp = json_array ();
- for (i=0;i<md->num_fresh_coins;i++)
- {
- const struct FreshCoin *fc = &md->fresh_coins[j][i];
- struct TALER_RefreshLinkDecrypted rld;
- struct TALER_RefreshLinkEncrypted *rle;
- char *buf;
- size_t buf_len;
-
- rld.coin_priv = fc->coin_priv;
- rld.blinding_key = fc->blinding_key;
- rle = TALER_refresh_encrypt (&rld,
- &md->link_secrets[j]);
- GNUNET_assert (NULL != rle);
- buf = TALER_refresh_link_encrypted_encode (rle,
- &buf_len);
- GNUNET_assert (NULL != buf);
- json_array_append (tmp,
- TALER_json_from_data (buf,
- buf_len));
- GNUNET_free (buf);
- GNUNET_free (rle);
- }
- json_array_append (link_encs,
- tmp);
- }
-
- /* now coin_evs */
- for (j=0;j<TALER_CNC_KAPPA;j++)
- {
- tmp = json_array ();
- for (i=0;i<md->num_fresh_coins;i++)
- {
- const struct FreshCoin *fc = &md->fresh_coins[j][i];
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_HashCode coin_hash;
- char *coin_ev; /* blinded message to be signed (in envelope) for each coin */
- size_t coin_ev_size;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &coin_hash);
- coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash,
- fc->blinding_key.rsa_blinding_key,
- md->fresh_pks[i].rsa_public_key,
- &coin_ev);
- json_array_append (tmp,
- TALER_json_from_data (coin_ev,
- coin_ev_size));
- GNUNET_free (coin_ev);
- }
- json_array_append (coin_evs,
- tmp);
- }
-
- /* finally, assemble main JSON request from constitutent arrays */
- melt_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}",
- "new_denoms", new_denoms,
- "melt_coins", melt_coins,
- "coin_evs", coin_evs,
- "transfer_pubs", transfer_pubs,
- "secret_encs", secret_encs,
- "link_encs", link_encs);
-
- /* and now we can at last begin the actual request handling */
- rmh = GNUNET_new (struct TALER_MINT_RefreshMeltHandle);
- rmh->mint = mint;
- rmh->melt_cb = melt_cb;
- rmh->melt_cb_cls = melt_cb_cls;
- rmh->md = md;
- rmh->url = MAH_path_to_url (mint,
- "/refresh/melt");
-
- eh = curl_easy_init ();
- GNUNET_assert (NULL != (rmh->json_enc =
- json_dumps (melt_obj,
- JSON_COMPACT)));
- json_decref (melt_obj);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- rmh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDS,
- rmh->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDSIZE,
- strlen (rmh->json_enc)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &rmh->db));
- ctx = MAH_handle_to_context (mint);
- rmh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_refresh_melt_finished,
- rmh);
- return rmh;
-}
-
-
-/**
- * Cancel a refresh execute request. This function cannot be used
- * on a request handle if either callback was already invoked.
- *
- * @param rmh the refresh melt handle
- */
-void
-TALER_MINT_refresh_melt_cancel (struct TALER_MINT_RefreshMeltHandle *rmh)
-{
- if (NULL != rmh->job)
- {
- MAC_job_cancel (rmh->job);
- rmh->job = NULL;
- }
- GNUNET_free_non_null (rmh->db.buf);
- free_melt_data (rmh->md); /* does not free 'md' itself */
- GNUNET_free (rmh->md);
- GNUNET_free (rmh->url);
- GNUNET_free (rmh->json_enc);
- GNUNET_free (rmh);
-}
-
-
-/* ********************* /refresh/reveal ***************************** */
-
-
-/**
- * @brief A /refresh/reveal Handle
- */
-struct TALER_MINT_RefreshRevealHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * JSON encoding of the request to POST.
- */
- char *json_enc;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_RefreshRevealCallback reveal_cb;
-
- /**
- * Closure for @e reveal_cb.
- */
- void *reveal_cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Actual information about the melt operation.
- */
- struct MeltData *md;
-
- /**
- * The index selected by the mint in cut-and-choose to not be revealed.
- */
- uint16_t noreveal_index;
-
-};
-
-
-/**
- * We got a 200 OK response for the /refresh/reveal operation.
- * Extract the coin signatures and return them to the caller.
- * The signatures we get from the mint is for the blinded value.
- * Thus, we first must unblind them and then should verify their
- * validity.
- *
- * If everything checks out, we return the unblinded signatures
- * to the application via the callback.
- *
- * @param rrh operation handle
- * @param json reply from the mint
- * @param[out] coin_privs array of length `num_fresh_coins`, initialized to contain private keys
- * @param[out] sigs array of length `num_fresh_coins`, initialized to cointain RSA signatures
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static int
-refresh_reveal_ok (struct TALER_MINT_RefreshRevealHandle *rrh,
- json_t *json,
- struct TALER_CoinSpendPrivateKeyP *coin_privs,
- struct TALER_DenominationSignature *sigs)
-{
- unsigned int i;
- json_t *jsona;
- struct MAJ_Specification spec[] = {
- MAJ_spec_json ("ev_sigs", &jsona),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (! json_is_array (jsona))
- {
- /* We expected an array of coins */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (rrh->md->num_fresh_coins != json_array_size (jsona))
- {
- /* Number of coins generated does not match our expectation */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- for (i=0;i<rrh->md->num_fresh_coins;i++)
- {
- const struct FreshCoin *fc;
- struct TALER_DenominationPublicKey *pk;
- json_t *jsonai;
- struct GNUNET_CRYPTO_rsa_Signature *blind_sig;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_HashCode coin_hash;
-
- struct MAJ_Specification spec[] = {
- MAJ_spec_rsa_signature ("ev_sig", &blind_sig),
- MAJ_spec_end
- };
-
- fc = &rrh->md->fresh_coins[rrh->noreveal_index][i];
- pk = &rrh->md->fresh_pks[i];
- jsonai = json_array_get (jsona, i);
- GNUNET_assert (NULL != jsonai);
-
- if (GNUNET_OK !=
- MAJ_parse_json (jsonai,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* unblind the signature */
- sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
- fc->blinding_key.rsa_blinding_key,
- pk->rsa_public_key);
- GNUNET_CRYPTO_rsa_signature_free (blind_sig);
-
- /* verify the signature */
- GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &coin_hash);
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify (&coin_hash,
- sig,
- pk->rsa_public_key))
- {
- GNUNET_break_op (0);
- GNUNET_CRYPTO_rsa_signature_free (sig);
- return GNUNET_SYSERR;
- }
- coin_privs[i] = fc->coin_priv;
- sigs[i].rsa_signature = sig;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /refresh/reveal request.
- *
- * @param cls the `struct TALER_MINT_RefreshHandle`
- * @param eh the curl request handle
- */
-static void
-handle_refresh_reveal_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_RefreshRevealHandle *rrh = cls;
- long response_code;
- json_t *json;
-
- rrh->job = NULL;
- json = MAC_download_get_result (&rrh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- {
- struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins];
- struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
- unsigned int i;
- int ret;
-
- memset (sigs, 0, sizeof (sigs));
- ret = refresh_reveal_ok (rrh,
- json,
- coin_privs,
- sigs);
- if (GNUNET_OK != ret)
- {
- response_code = 0;
- }
- else
- {
- rrh->reveal_cb (rrh->reveal_cb_cls,
- MHD_HTTP_OK,
- rrh->md->num_fresh_coins,
- coin_privs,
- sigs,
- json);
- rrh->reveal_cb = NULL;
- }
- for (i=0;i<rrh->md->num_fresh_coins;i++)
- if (NULL != sigs[i].rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_CONFLICT:
- /* Nothing really to verify, mint says our reveal is inconsitent
- with our commitment, so either side is buggy; we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (NULL != rrh->reveal_cb)
- rrh->reveal_cb (rrh->reveal_cb_cls,
- response_code,
- 0, NULL, NULL,
- json);
- json_decref (json);
- TALER_MINT_refresh_reveal_cancel (rrh);
-}
-
-
-/**
- * Submit a /refresh/reval request to the mint and get the mint's
- * response.
- *
- * This API is typically used by a wallet. Note that to ensure that
- * no money is lost in case of hardware failures, the provided
- * arguments should have been committed to persistent storage
- * prior to calling this function.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param refresh_data_length size of the @a refresh_data (returned
- * in the `res_size` argument from #TALER_MINT_refresh_prepare())
- * @param refresh_data the refresh data as returned from
- #TALER_MINT_refresh_prepare())
- * @param noreveal_index response from the mint to the
- * #TALER_MINT_refresh_melt() invocation
- * @param reveal_cb the callback to call with the final result of the
- * refresh operation
- * @param reveal_cb_cls closure for the above callback
- * @return a handle for this request; NULL if the argument was invalid.
- * In this case, neither callback will be called.
- */
-struct TALER_MINT_RefreshRevealHandle *
-TALER_MINT_refresh_reveal (struct TALER_MINT_Handle *mint,
- size_t refresh_data_length,
- const char *refresh_data,
- uint16_t noreveal_index,
- TALER_MINT_RefreshRevealCallback reveal_cb,
- void *reveal_cb_cls)
-{
- struct TALER_MINT_RefreshRevealHandle *rrh;
- json_t *transfer_privs;
- json_t *reveal_obj;
- json_t *tmp;
- CURL *eh;
- struct TALER_MINT_Context *ctx;
- struct MeltData *md;
- unsigned int i;
- unsigned int j;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- md = deserialize_melt_data (refresh_data,
- refresh_data_length);
- if (NULL == md)
- {
- GNUNET_break (0);
- return NULL;
- }
- if (noreveal_index >= TALER_CNC_KAPPA)
- {
- /* We check this here, as it would be really bad to below just
- disclose all the transfer keys. Note that this error should
- have been caught way earlier when the mint replied, but maybe
- we had some internal corruption that changed the value... */
- GNUNET_break (0);
- return NULL;
- }
-
- /* build array of transfer private keys */
- transfer_privs = json_array ();
- for (j=0;j<TALER_CNC_KAPPA;j++)
- {
- if (j == noreveal_index)
- {
- /* This is crucial: exclude the transfer key for the
- noreval index! */
- continue;
- }
- tmp = json_array ();
- for (i=0;i<md->num_melted_coins;i++)
- {
- const struct MeltedCoin *mc = &md->melted_coins[i];
-
- json_array_append (tmp,
- TALER_json_from_data (&mc->transfer_priv[j],
- sizeof (struct TALER_TransferPrivateKeyP)));
- }
- json_array_append (transfer_privs,
- tmp);
- }
-
- /* build main JSON request */
- reveal_obj = json_pack ("{s:o, s:o}",
- "session_hash",
- TALER_json_from_data (&md->melt_session_hash,
- sizeof (struct GNUNET_HashCode)),
- "transfer_privs",
- transfer_privs);
-
- /* finally, we can actually issue the request */
- rrh = GNUNET_new (struct TALER_MINT_RefreshRevealHandle);
- rrh->mint = mint;
- rrh->noreveal_index = noreveal_index;
- rrh->reveal_cb = reveal_cb;
- rrh->reveal_cb_cls = reveal_cb_cls;
- rrh->md = md;
- rrh->url = MAH_path_to_url (rrh->mint,
- "/refresh/reveal");
-
- eh = curl_easy_init ();
- GNUNET_assert (NULL != (rrh->json_enc =
- json_dumps (reveal_obj,
- JSON_COMPACT)));
- json_decref (reveal_obj);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- rrh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDS,
- rrh->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDSIZE,
- strlen (rrh->json_enc)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &rrh->db));
- ctx = MAH_handle_to_context (rrh->mint);
- rrh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_refresh_reveal_finished,
- rrh);
- return rrh;
-}
-
-
-/**
- * Cancel a refresh reveal request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param rrh the refresh reval handle
- */
-void
-TALER_MINT_refresh_reveal_cancel (struct TALER_MINT_RefreshRevealHandle *rrh)
-{
- if (NULL != rrh->job)
- {
- MAC_job_cancel (rrh->job);
- rrh->job = NULL;
- }
- GNUNET_free_non_null (rrh->db.buf);
- GNUNET_free (rrh->url);
- GNUNET_free (rrh->json_enc);
- free_melt_data (rrh->md); /* does not free 'md' itself */
- GNUNET_free (rrh->md);
- GNUNET_free (rrh);
-}
-
-
-/* end of mint_api_refresh.c */
diff --git a/src/mint-lib/mint_api_refresh_link.c b/src/mint-lib/mint_api_refresh_link.c
deleted file mode 100644
index dcd2326ca..000000000
--- a/src/mint-lib/mint_api_refresh_link.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_refresh_link.c
- * @brief Implementation of the /refresh/link request of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * @brief A /refresh/link Handle
- */
-struct TALER_MINT_RefreshLinkHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_RefreshLinkCallback link_cb;
-
- /**
- * Closure for @e cb.
- */
- void *link_cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Private key of the coin, required to decode link information.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
-};
-
-
-/**
- * Parse the provided linkage data from the "200 OK" response
- * for one of the coins.
- *
- * @param rlh refresh link handle
- * @param json json reply with the data for one coin
- * @param trans_pub our transfer public key
- * @param secret_enc encrypted key to decrypt link data
- * @param[out] coin_priv where to return private coin key
- * @param[out] sig where to return private coin signature
- * @param[out] pub where to return the public key for the coin
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-parse_refresh_link_coin (const struct TALER_MINT_RefreshLinkHandle *rlh,
- json_t *json,
- const struct TALER_TransferPublicKeyP *trans_pub,
- const struct TALER_EncryptedLinkSecretP *secret_enc,
- struct TALER_CoinSpendPrivateKeyP *coin_priv,
- struct TALER_DenominationSignature *sig,
- struct TALER_DenominationPublicKey *pub)
-{
- void *link_enc;
- size_t link_enc_size;
- struct GNUNET_CRYPTO_rsa_Signature *bsig;
- struct GNUNET_CRYPTO_rsa_PublicKey *rpub;
- struct MAJ_Specification spec[] = {
- MAJ_spec_varsize ("link_enc", &link_enc, &link_enc_size),
- MAJ_spec_rsa_public_key ("denom_pub", &rpub),
- MAJ_spec_rsa_signature ("ev_sig", &bsig),
- MAJ_spec_end
- };
- struct TALER_RefreshLinkEncrypted *rle;
- struct TALER_RefreshLinkDecrypted *rld;
- struct TALER_LinkSecretP secret;
-
- /* parse reply */
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* decode and decrypt link data */
- rle = TALER_refresh_link_encrypted_decode (link_enc,
- link_enc_size);
- if (NULL == rle)
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_link_decrypt_secret2 (secret_enc,
- trans_pub,
- &rlh->coin_priv,
- &secret))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- rld = TALER_refresh_decrypt (rle,
- &secret);
- if (NULL == rld)
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
-
- /* extract coin and signature */
- *coin_priv = rld->coin_priv;
- sig->rsa_signature
- = GNUNET_CRYPTO_rsa_unblind (bsig,
- rld->blinding_key.rsa_blinding_key,
- rpub);
-
- /* clean up */
- GNUNET_free (rld);
- pub->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (rpub);
- MAJ_parse_free (spec);
- return GNUNET_OK;
-}
-
-
-/**
- * Parse the provided linkage data from the "200 OK" response
- * for one of the coins.
- *
- * @param[in,out] rlh refresh link handle (callback may be zero'ed out)
- * @param json json reply with the data for one coin
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
- json_t *json)
-{
- unsigned int session;
- unsigned int num_coins;
- int ret;
-
- if (! json_is_array (json))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- num_coins = 0;
- /* Theoretically, a coin may have been melted repeatedly
- into different sessions; so the response is an array
- which contains information by melting session. That
- array contains another array. However, our API returns
- a single 1d array, so we flatten the 2d array that is
- returned into a single array. Note that usually a coin
- is melted at most once, and so we'll only run this
- loop once for 'session=0' in most cases.
-
- num_coins tracks the size of the 1d array we return,
- whilst 'i' and 'session' track the 2d array. */
- for (session=0;session<json_array_size (json); session++)
- {
- json_t *jsona;
- struct MAJ_Specification spec[] = {
- MAJ_spec_json ("new_coins", &jsona),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json_array_get (json,
- session),
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (! json_is_array (jsona))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
-
- /* count all coins over all sessions */
- num_coins += json_array_size (jsona);
- MAJ_parse_free (spec);
- }
- /* Now that we know how big the 1d array is, allocate
- and fill it. */
- {
- unsigned int off_coin; /* index into 1d array */
- unsigned int i;
- struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins];
- struct TALER_DenominationSignature sigs[num_coins];
- struct TALER_DenominationPublicKey pubs[num_coins];
-
- memset (sigs, 0, sizeof (sigs));
- memset (pubs, 0, sizeof (pubs));
- off_coin = 0;
- for (session=0;session<json_array_size (json); session++)
- {
- json_t *jsona;
- struct TALER_TransferPublicKeyP trans_pub;
- struct TALER_EncryptedLinkSecretP secret_enc;
- struct MAJ_Specification spec[] = {
- MAJ_spec_json ("new_coins", &jsona),
- MAJ_spec_fixed_auto ("transfer_pub", &trans_pub),
- MAJ_spec_fixed_auto ("secret_enc", &secret_enc),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json_array_get (json,
- session),
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (! json_is_array (jsona))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
-
- /* decode all coins */
- for (i=0;i<json_array_size (jsona);i++)
- {
- if (GNUNET_OK !=
- parse_refresh_link_coin (rlh,
- json_array_get (jsona,
- i),
- &trans_pub,
- &secret_enc,
- &coin_privs[i+off_coin],
- &sigs[i+off_coin],
- &pubs[i+off_coin]))
- {
- GNUNET_break_op (0);
- break;
- }
- }
- /* check if we really got all, then invoke callback */
- off_coin += i;
- if (i != json_array_size (jsona))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- MAJ_parse_free (spec);
- break;
- }
- MAJ_parse_free (spec);
- } /* end of for (session) */
-
- if (off_coin == num_coins)
- {
- rlh->link_cb (rlh->link_cb_cls,
- MHD_HTTP_OK,
- num_coins,
- coin_privs,
- sigs,
- pubs,
- json);
- rlh->link_cb = NULL;
- ret = GNUNET_OK;
- }
- else
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- }
-
- /* clean up */
- for (i=0;i<off_coin;i++)
- {
- if (NULL != sigs[i].rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
- if (NULL != pubs[i].rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (pubs[i].rsa_public_key);
- }
- }
- return ret;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /refresh/link request.
- *
- * @param cls the `struct TALER_MINT_RefreshLinkHandle`
- * @param eh the curl request handle
- */
-static void
-handle_refresh_link_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_RefreshLinkHandle *rlh = cls;
- long response_code;
- json_t *json;
-
- rlh->job = NULL;
- json = MAC_download_get_result (&rlh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- if (GNUNET_OK !=
- parse_refresh_link_ok (rlh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, mint says this coin was not melted; we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (NULL != rlh->link_cb)
- rlh->link_cb (rlh->link_cb_cls,
- response_code,
- 0, NULL, NULL, NULL,
- json);
- json_decref (json);
- TALER_MINT_refresh_link_cancel (rlh);
-}
-
-
-/**
- * Submit a link request to the mint and get the mint's response.
- *
- * This API is typically not used by anyone, it is more a threat
- * against those trying to receive a funds transfer by abusing the
- * /refresh protocol.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param coin_priv private key to request link data for
- * @param link_cb the callback to call with the useful result of the
- * refresh operation the @a coin_priv was involved in (if any)
- * @param link_cb_cls closure for @a link_cb
- * @return a handle for this request
- */
-struct TALER_MINT_RefreshLinkHandle *
-TALER_MINT_refresh_link (struct TALER_MINT_Handle *mint,
- const struct TALER_CoinSpendPrivateKeyP *coin_priv,
- TALER_MINT_RefreshLinkCallback link_cb,
- void *link_cb_cls)
-{
- struct TALER_MINT_RefreshLinkHandle *rlh;
- CURL *eh;
- struct TALER_MINT_Context *ctx;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- char *pub_str;
- char *arg_str;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
-
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
- pub_str = GNUNET_STRINGS_data_to_string_alloc (&coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP));
- GNUNET_asprintf (&arg_str,
- "/refresh/link?coin_pub=%s",
- pub_str);
- GNUNET_free (pub_str);
-
- rlh = GNUNET_new (struct TALER_MINT_RefreshLinkHandle);
- rlh->mint = mint;
- rlh->link_cb = link_cb;
- rlh->link_cb_cls = link_cb_cls;
- rlh->coin_priv = *coin_priv;
- rlh->url = MAH_path_to_url (mint, arg_str);
- GNUNET_free (arg_str);
-
- eh = curl_easy_init ();
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- rlh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &rlh->db));
- ctx = MAH_handle_to_context (mint);
- rlh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_refresh_link_finished,
- rlh);
- return rlh;
-}
-
-
-/**
- * Cancel a refresh link request. This function cannot be used
- * on a request handle if the callback was already invoked.
- *
- * @param rlh the refresh link handle
- */
-void
-TALER_MINT_refresh_link_cancel (struct TALER_MINT_RefreshLinkHandle *rlh)
-{
- if (NULL != rlh->job)
- {
- MAC_job_cancel (rlh->job);
- rlh->job = NULL;
- }
- GNUNET_free_non_null (rlh->db.buf);
- GNUNET_free (rlh->url);
- GNUNET_free (rlh);
-}
-
-
-/* end of mint_api_refresh_link.c */
diff --git a/src/mint-lib/mint_api_reserve.c b/src/mint-lib/mint_api_reserve.c
deleted file mode 100644
index 1f8140cff..000000000
--- a/src/mint-lib/mint_api_reserve.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_reserve.c
- * @brief Implementation of the /reserve requests of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/* ********************** /reserve/status ********************** */
-
-/**
- * @brief A Withdraw Status Handle
- */
-struct TALER_MINT_ReserveStatusHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_ReserveStatusResultCallback cb;
-
- /**
- * Public key of the reserve we are querying.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
-};
-
-
-/**
- * Parse history given in JSON format and return it in binary
- * format.
- *
- * @param[in] history JSON array with the history
- * @param reserve_pub public key of the reserve to inspect
- * @param currency currency we expect the balance to be in
- * @param[out] balance final balance
- * @param history_length number of entries in @a history
- * @param[out] rhistory array of length @a history_length, set to the
- * parsed history entries
- * @return #GNUNET_OK if history was valid and @a rhistory and @a balance
- * were set,
- * #GNUNET_SYSERR if there was a protocol violation in @a history
- */
-static int
-parse_reserve_history (json_t *history,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const char *currency,
- struct TALER_Amount *balance,
- unsigned int history_length,
- struct TALER_MINT_ReserveHistory *rhistory)
-{
- struct GNUNET_HashCode uuid[history_length];
- unsigned int uuid_off;
- struct TALER_Amount total_in;
- struct TALER_Amount total_out;
- size_t off;
-
- TALER_amount_get_zero (currency,
- &total_in);
- TALER_amount_get_zero (currency,
- &total_out);
- uuid_off = 0;
- for (off=0;off<history_length;off++)
- {
- json_t *transaction;
- struct TALER_Amount amount;
- const char *type;
- struct MAJ_Specification hist_spec[] = {
- MAJ_spec_string ("type", &type),
- MAJ_spec_amount ("amount",
- &amount),
- /* 'wire' and 'signature' are optional depending on 'type'! */
- MAJ_spec_end
- };
-
- transaction = json_array_get (history,
- off);
- if (GNUNET_OK !=
- MAJ_parse_json (transaction,
- hist_spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- rhistory[off].amount = amount;
-
- if (0 == strcasecmp (type,
- "DEPOSIT"))
- {
- json_t *wire;
-
- rhistory[off].type = TALER_MINT_RTT_DEPOSIT;
- if (GNUNET_OK !=
- TALER_amount_add (&total_in,
- &total_in,
- &amount))
- {
- /* overflow in history already!? inconceivable! Bad mint! */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- wire = json_object_get (transaction,
- "wire");
- /* check 'wire' is a JSON object (no need to check wireformat,
- but we do at least expect "some" JSON object here) */
- if ( (NULL == wire) ||
- (! json_is_object (wire)) )
- {
- /* not even a JSON 'wire' specification, not acceptable */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- rhistory[off].details.wire_in_details = wire;
- /* end type==DEPOSIT */
- }
- else if (0 == strcasecmp (type,
- "WITHDRAW"))
- {
- struct TALER_ReserveSignatureP sig;
- struct TALER_WithdrawRequestPS withdraw_purpose;
- struct TALER_Amount amount_from_purpose;
- struct MAJ_Specification withdraw_spec[] = {
- MAJ_spec_fixed_auto ("signature",
- &sig),
- MAJ_spec_fixed_auto ("details",
- &withdraw_purpose),
- MAJ_spec_end
- };
- unsigned int i;
-
- rhistory[off].type = TALER_MINT_RTT_WITHDRAWAL;
- if (GNUNET_OK !=
- MAJ_parse_json (transaction,
- withdraw_spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* Check that the signature is a valid withdraw request */
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
- &withdraw_purpose.purpose,
- &sig.eddsa_signature,
- &reserve_pub->eddsa_pub))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (withdraw_spec);
- return GNUNET_SYSERR;
- }
- TALER_amount_ntoh (&amount_from_purpose,
- &withdraw_purpose.amount_with_fee);
- if (0 != TALER_amount_cmp (&amount,
- &amount_from_purpose))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (withdraw_spec);
- return GNUNET_SYSERR;
- }
- rhistory[off].details.out_authorization_sig = json_object_get (transaction,
- "signature");
- /* Check check that the same withdraw transaction
- isn't listed twice by the mint. We use the
- "uuid" array to remember the hashes of all
- purposes, and compare the hashes to find
- duplicates. */
- GNUNET_CRYPTO_hash (&withdraw_purpose,
- ntohl (withdraw_purpose.purpose.size),
- &uuid[uuid_off]);
- for (i=0;i<uuid_off;i++)
- {
- if (0 == memcmp (&uuid[uuid_off],
- &uuid[i],
- sizeof (struct GNUNET_HashCode)))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (withdraw_spec);
- return GNUNET_SYSERR;
- }
- }
- uuid_off++;
-
- if (GNUNET_OK !=
- TALER_amount_add (&total_out,
- &total_out,
- &amount))
- {
- /* overflow in history already!? inconceivable! Bad mint! */
- GNUNET_break_op (0);
- MAJ_parse_free (withdraw_spec);
- return GNUNET_SYSERR;
- }
- /* end type==WITHDRAW */
- }
- else
- {
- /* unexpected 'type', protocol incompatibility, complain! */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
-
- /* check balance = total_in - total_out < withdraw-amount */
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (balance,
- &total_in,
- &total_out))
- {
- /* total_in < total_out, why did the mint ever allow this!? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /reserve/status request.
- *
- * @param cls the `struct TALER_MINT_ReserveStatusHandle`
- * @param eh curl handle of the request that finished
- */
-static void
-handle_reserve_status_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_ReserveStatusHandle *wsh = cls;
- long response_code;
- json_t *json;
-
- wsh->job = NULL;
- json = MAC_download_get_result (&wsh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- {
- /* TODO: move into separate function... */
- json_t *history;
- unsigned int len;
- struct TALER_Amount balance;
- struct TALER_Amount balance_from_history;
- struct MAJ_Specification spec[] = {
- MAJ_spec_amount ("balance", &balance),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- history = json_object_get (json,
- "history");
- if (NULL == history)
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- len = json_array_size (history);
- {
- struct TALER_MINT_ReserveHistory rhistory[len];
-
- if (GNUNET_OK !=
- parse_reserve_history (history,
- &wsh->reserve_pub,
- balance.currency,
- &balance_from_history,
- len,
- rhistory))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- if (0 !=
- TALER_amount_cmp (&balance_from_history,
- &balance))
- {
- /* mint cannot add up balances!? */
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- wsh->cb (wsh->cb_cls,
- response_code,
- json,
- &balance,
- len,
- rhistory);
- wsh->cb = NULL;
- }
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (NULL != wsh->cb)
- wsh->cb (wsh->cb_cls,
- response_code,
- json,
- NULL,
- 0, NULL);
- json_decref (json);
- TALER_MINT_reserve_status_cancel (wsh);
-}
-
-
-/**
- * Submit a request to obtain the transaction history of a reserve
- * from the mint. Note that while we return the full response to the
- * caller for further processing, we do already verify that the
- * response is well-formed (i.e. that signatures included in the
- * response are all valid and add up to the balance). If the mint's
- * reply is not well-formed, we return an HTTP status code of zero to
- * @a cb.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param reserve_pub public key of the reserve to inspect
- * @param cb the callback to call when a reply for this request is available
- * @param cb_cls closure for the above callback
- * @return a handle for this request; NULL if the inputs are invalid (i.e.
- * signatures fail to verify). In this case, the callback is not called.
- */
-struct TALER_MINT_ReserveStatusHandle *
-TALER_MINT_reserve_status (struct TALER_MINT_Handle *mint,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- TALER_MINT_ReserveStatusResultCallback cb,
- void *cb_cls)
-{
- struct TALER_MINT_ReserveStatusHandle *wsh;
- struct TALER_MINT_Context *ctx;
- CURL *eh;
- char *pub_str;
- char *arg_str;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- pub_str = GNUNET_STRINGS_data_to_string_alloc (reserve_pub,
- sizeof (struct TALER_ReservePublicKeyP));
- GNUNET_asprintf (&arg_str,
- "/reserve/status?reserve_pub=%s",
- pub_str);
- GNUNET_free (pub_str);
- wsh = GNUNET_new (struct TALER_MINT_ReserveStatusHandle);
- wsh->mint = mint;
- wsh->cb = cb;
- wsh->cb_cls = cb_cls;
- wsh->reserve_pub = *reserve_pub;
- wsh->url = MAH_path_to_url (mint,
- arg_str);
- GNUNET_free (arg_str);
-
- eh = curl_easy_init ();
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- wsh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &wsh->db));
- ctx = MAH_handle_to_context (mint);
- wsh->job = MAC_job_add (ctx,
- eh,
- GNUNET_NO,
- &handle_reserve_status_finished,
- wsh);
- return wsh;
-}
-
-
-/**
- * Cancel a withdraw status request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param wsh the withdraw status request handle
- */
-void
-TALER_MINT_reserve_status_cancel (struct TALER_MINT_ReserveStatusHandle *wsh)
-{
- if (NULL != wsh->job)
- {
- MAC_job_cancel (wsh->job);
- wsh->job = NULL;
- }
- GNUNET_free_non_null (wsh->db.buf);
- GNUNET_free (wsh->url);
- GNUNET_free (wsh);
-}
-
-
-/* ********************** /reserve/withdraw ********************** */
-
-/**
- * @brief A Withdraw Sign Handle
- */
-struct TALER_MINT_ReserveWithdrawHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * JSON encoding of the request to POST.
- */
- char *json_enc;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_ReserveWithdrawResultCallback cb;
-
- /**
- * Key used to blind the value.
- */
- const struct TALER_DenominationBlindingKey *blinding_key;
-
- /**
- * Denomination key we are withdrawing.
- */
- const struct TALER_MINT_DenomPublicKey *pk;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Hash of the public key of the coin we are signing.
- */
- struct GNUNET_HashCode c_hash;
-
- /**
- * Public key of the reserve we are withdrawing from.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
-};
-
-
-/**
- * We got a 200 OK response for the /reserve/withdraw operation.
- * Extract the coin's signature and return it to the caller.
- * The signature we get from the mint is for the blinded value.
- * Thus, we first must unblind it and then should verify its
- * validity against our coin's hash.
- *
- * If everything checks out, we return the unblinded signature
- * to the application via the callback.
- *
- * @param wsh operation handle
- * @param json reply from the mint
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static int
-reserve_withdraw_ok (struct TALER_MINT_ReserveWithdrawHandle *wsh,
- json_t *json)
-{
- struct GNUNET_CRYPTO_rsa_Signature *blind_sig;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
- struct TALER_DenominationSignature dsig;
- struct MAJ_Specification spec[] = {
- MAJ_spec_rsa_signature ("ev_sig", &blind_sig),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- sig = GNUNET_CRYPTO_rsa_unblind (blind_sig,
- wsh->blinding_key->rsa_blinding_key,
- wsh->pk->key.rsa_public_key);
- GNUNET_CRYPTO_rsa_signature_free (blind_sig);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify (&wsh->c_hash,
- sig,
- wsh->pk->key.rsa_public_key))
- {
- GNUNET_break_op (0);
- GNUNET_CRYPTO_rsa_signature_free (sig);
- return GNUNET_SYSERR;
- }
- /* signature is valid, return it to the application */
- dsig.rsa_signature = sig;
- wsh->cb (wsh->cb_cls,
- MHD_HTTP_OK,
- &dsig,
- json);
- /* make sure callback isn't called again after return */
- wsh->cb = NULL;
- GNUNET_CRYPTO_rsa_signature_free (sig);
- return GNUNET_OK;
-}
-
-
-/**
- * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation.
- * Check the signatures on the withdraw transactions in the provided
- * history and that the balances add up. We don't do anything directly
- * with the information, as the JSON will be returned to the application.
- * However, our job is ensuring that the mint followed the protocol, and
- * this in particular means checking all of the signatures in the history.
- *
- * @param wsh operation handle
- * @param json reply from the mint
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static int
-reserve_withdraw_payment_required (struct TALER_MINT_ReserveWithdrawHandle *wsh,
- json_t *json)
-{
- struct TALER_Amount balance;
- struct TALER_Amount balance_from_history;
- struct TALER_Amount requested_amount;
- json_t *history;
- size_t len;
- struct MAJ_Specification spec[] = {
- MAJ_spec_amount ("balance", &balance),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- history = json_object_get (json,
- "history");
- if (NULL == history)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* go over transaction history and compute
- total incoming and outgoing amounts */
- len = json_array_size (history);
- {
- struct TALER_MINT_ReserveHistory rhistory[len];
-
- if (GNUNET_OK !=
- parse_reserve_history (history,
- &wsh->reserve_pub,
- balance.currency,
- &balance_from_history,
- len,
- rhistory))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
-
- if (0 !=
- TALER_amount_cmp (&balance_from_history,
- &balance))
- {
- /* mint cannot add up balances!? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* Compute how much we expected to charge to the reserve */
- if (GNUNET_OK !=
- TALER_amount_add (&requested_amount,
- &wsh->pk->value,
- &wsh->pk->fee_withdraw))
- {
- /* Overflow here? Very strange, our CPU must be fried... */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* Check that funds were really insufficient */
- if (0 >= TALER_amount_cmp (&requested_amount,
- &balance))
- {
- /* Requested amount is smaller or equal to reported balance,
- so this should not have failed. */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /reserve/withdraw request.
- *
- * @param cls the `struct TALER_MINT_ReserveWithdrawHandle`
- * @param eh curl handle of the request that finished
- */
-static void
-handle_reserve_withdraw_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_ReserveWithdrawHandle *wsh = cls;
- long response_code;
- json_t *json;
-
- wsh->job = NULL;
- json = MAC_download_get_result (&wsh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- if (GNUNET_OK !=
- reserve_withdraw_ok (wsh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_PAYMENT_REQUIRED:
- /* The mint says that the reserve has insufficient funds;
- check the signatures in the history... */
- if (GNUNET_OK !=
- reserve_withdraw_payment_required (wsh,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- }
- break;
- case MHD_HTTP_UNAUTHORIZED:
- GNUNET_break (0);
- /* Nothing really to verify, mint says one of the signatures is
- invalid; as we checked them, this should never happen, we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, the mint basically just says
- that it doesn't know this reserve. Can happen if we
- query before the wire transfer went through.
- We should simply pass the JSON reply to the application. */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (NULL != wsh->cb)
- wsh->cb (wsh->cb_cls,
- response_code,
- NULL,
- json);
- json_decref (json);
- TALER_MINT_reserve_withdraw_cancel (wsh);
-}
-
-
-/**
- * Withdraw a coin from the mint using a /reserve/withdraw request. Note
- * that to ensure that no money is lost in case of hardware failures,
- * the caller must have committed (most of) the arguments to disk
- * before calling, and be ready to repeat the request with the same
- * arguments in case of failures.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_priv private key of the reserve to withdraw from
- * @param coin_priv where to store the coin's private key,
- * caller must have committed this value to disk before the call (with @a pk)
- * @param blinding_key where to store the coin's blinding key
- * caller must have committed this value to disk before the call (with @a pk)
- * @param res_cb the callback to call when the final result for this request is available
- * @param res_cb_cls closure for the above callback
- * @return #GNUNET_OK on success, #GNUNET_SYSERR
- * if the inputs are invalid (i.e. denomination key not with this mint).
- * In this case, the callback is not called.
- */
-struct TALER_MINT_ReserveWithdrawHandle *
-TALER_MINT_reserve_withdraw (struct TALER_MINT_Handle *mint,
- const struct TALER_MINT_DenomPublicKey *pk,
- const struct TALER_ReservePrivateKeyP *reserve_priv,
- const struct TALER_CoinSpendPrivateKeyP *coin_priv,
- const struct TALER_DenominationBlindingKey *blinding_key,
- TALER_MINT_ReserveWithdrawResultCallback res_cb,
- void *res_cb_cls)
-{
- struct TALER_MINT_ReserveWithdrawHandle *wsh;
- struct TALER_WithdrawRequestPS req;
- struct TALER_ReserveSignatureP reserve_sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_MINT_Context *ctx;
- struct TALER_Amount amount_with_fee;
- char *coin_ev;
- size_t coin_ev_size;
- json_t *withdraw_obj;
- CURL *eh;
-
- wsh = GNUNET_new (struct TALER_MINT_ReserveWithdrawHandle);
- wsh->mint = mint;
- wsh->cb = res_cb;
- wsh->cb_cls = res_cb_cls;
- wsh->pk = pk;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &wsh->c_hash);
- coin_ev_size = GNUNET_CRYPTO_rsa_blind (&wsh->c_hash,
- blinding_key->rsa_blinding_key,
- pk->key.rsa_public_key,
- &coin_ev);
- GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
- &wsh->reserve_pub.eddsa_pub);
- req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
- req.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
- req.reserve_pub = wsh->reserve_pub;
- if (GNUNET_OK !=
- TALER_amount_add (&amount_with_fee,
- &pk->fee_withdraw,
- &pk->value))
- {
- /* mint gave us denomination keys that overflow like this!? */
- GNUNET_break_op (0);
- GNUNET_free (coin_ev);
- GNUNET_free (wsh);
- return NULL;
- }
- TALER_amount_hton (&req.amount_with_fee,
- &amount_with_fee);
- TALER_amount_hton (&req.withdraw_fee,
- &pk->fee_withdraw);
- GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
- &req.h_denomination_pub);
- GNUNET_CRYPTO_hash (coin_ev,
- coin_ev_size,
- &req.h_coin_envelope);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
- &req.purpose,
- &reserve_sig.eddsa_signature));
- withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub and coin_ev */
- " s:o, s:o}",/* reserve_pub and reserve_sig */
- "denom_pub", TALER_json_from_rsa_public_key (pk->key.rsa_public_key),
- "coin_ev", TALER_json_from_data (coin_ev,
- coin_ev_size),
- "reserve_pub", TALER_json_from_data (&wsh->reserve_pub,
- sizeof (struct TALER_ReservePublicKeyP)),
- "reserve_sig", TALER_json_from_data (&reserve_sig,
- sizeof (reserve_sig)));
- GNUNET_free (coin_ev);
-
- wsh->blinding_key = blinding_key;
- wsh->url = MAH_path_to_url (mint, "/reserve/withdraw");
-
- eh = curl_easy_init ();
- GNUNET_assert (NULL != (wsh->json_enc =
- json_dumps (withdraw_obj,
- JSON_COMPACT)));
- json_decref (withdraw_obj);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- wsh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDS,
- wsh->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_POSTFIELDSIZE,
- strlen (wsh->json_enc)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &wsh->db));
- ctx = MAH_handle_to_context (mint);
- wsh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_reserve_withdraw_finished,
- wsh);
- return wsh;
-}
-
-
-/**
- * Cancel a withdraw status request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param sign the withdraw sign request handle
- */
-void
-TALER_MINT_reserve_withdraw_cancel (struct TALER_MINT_ReserveWithdrawHandle *sign)
-{
- if (NULL != sign->job)
- {
- MAC_job_cancel (sign->job);
- sign->job = NULL;
- }
- GNUNET_free_non_null (sign->db.buf);
- GNUNET_free (sign->url);
- GNUNET_free (sign->json_enc);
- GNUNET_free (sign);
-}
-
-
-/* end of mint_api_reserve.c */
diff --git a/src/mint-lib/mint_api_wire.c b/src/mint-lib/mint_api_wire.c
deleted file mode 100644
index 0947354ad..000000000
--- a/src/mint-lib/mint_api_wire.c
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_wire.c
- * @brief Implementation of the /wire request of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_common.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * @brief A Wire Handle
- */
-struct TALER_MINT_WireHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_WireResultCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
- /**
- * Set to the "methods" JSON array returned by the
- * /wire request.
- */
- json_t *methods;
-
- /**
- * Current iteration offset in the @e methods array.
- */
- unsigned int methods_off;
-
-};
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * for /wire/sepa from the mint is valid.
- *
- * @param wh wire handle
- * @param json json reply with the signature
- * @return #GNUNET_SYSERR if @a json is invalid,
- * #GNUNET_NO if the method is unknown,
- * #GNUNET_OK if the json is valid
- */
-static int
-verify_wire_sepa_signature_ok (const struct TALER_MINT_WireHandle *wh,
- json_t *json)
-{
- struct TALER_MasterSignatureP mint_sig;
- struct TALER_MasterWireSepaDetailsPS mp;
- const char *receiver_name;
- const char *iban;
- const char *bic;
- const struct TALER_MINT_Keys *key_state;
- struct GNUNET_HashContext *hc;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("sig", &mint_sig),
- MAJ_spec_string ("receiver_name", &receiver_name),
- MAJ_spec_string ("iban", &iban),
- MAJ_spec_string ("bic", &bic),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- key_state = TALER_MINT_get_keys (wh->mint);
- mp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
- mp.purpose.size = htonl (sizeof (struct TALER_MasterWireSepaDetailsPS));
- hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc,
- receiver_name,
- strlen (receiver_name) + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- iban,
- strlen (iban) + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- bic,
- strlen (bic) + 1);
- GNUNET_CRYPTO_hash_context_finish (hc,
- &mp.h_sepa_details);
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
- &mp.purpose,
- &mint_sig.eddsa_signature,
- &key_state->master_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return GNUNET_SYSERR;
- }
- MAJ_parse_free (spec);
- return GNUNET_OK;
-}
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * for /wire/METHOD from the mint is valid.
- *
- * @param wh wire handle with key material
- * @param method method to verify the reply for
- * @param json json reply with the signature
- * @return #GNUNET_SYSERR if @a json is invalid,
- * #GNUNET_NO if the method is unknown,
- * #GNUNET_OK if the json is valid
- */
-static int
-verify_wire_method_signature_ok (const struct TALER_MINT_WireHandle *wh,
- const char *method,
- json_t *json)
-{
- struct
- {
- /**
- * Name fo the method.
- */
- const char *method;
-
- /**
- * Handler to invoke to verify signature.
- *
- * @param wh wire handle with key material
- * @param json json reply with signature to verify
- */
- int (*handler)(const struct TALER_MINT_WireHandle *wh,
- json_t *json);
- } handlers[] = {
- { "sepa", &verify_wire_sepa_signature_ok },
- { NULL, NULL }
- };
- unsigned int i;
-
- for (i=0;NULL != handlers[i].method; i++)
- if (0 == strcasecmp (handlers[i].method,
- method))
- return handlers[i].handler (wh,
- json);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Wire transfer method `%s' not supported\n",
- method);
- return GNUNET_NO;
-}
-
-
-/**
- * Perform the next /wire/method request or signal
- * the end of the iteration.
- *
- * @param wh the wire handle
- * @return a handle for this request
- */
-static void
-request_wire_method (struct TALER_MINT_WireHandle *wh);
-
-
-/**
- * Function called when we're done processing the
- * HTTP /wire/METHOD request.
- *
- * @param cls the `struct TALER_MINT_WireHandle`
- * @param eh the curl request handle
- */
-static void
-handle_wire_method_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_WireHandle *wh = cls;
- long response_code;
- json_t *json;
-
- wh->job = NULL;
- json = MAC_download_get_result (&wh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- {
- const char *method;
-
- method = json_string_value (json_array_get (wh->methods,
- wh->methods_off - 1));
- if (GNUNET_OK !=
- verify_wire_method_signature_ok (wh,
- method,
- json))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- break;
- }
- case MHD_HTTP_FOUND:
- /* /wire/test returns a 302 redirect, we should just give
- this information back to the callback below */
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (0 == response_code)
- {
- /* signal end of iteration */
- wh->cb (wh->cb_cls,
- 0,
- NULL,
- NULL);
- json_decref (json);
- TALER_MINT_wire_cancel (wh);
- return;
- }
- /* pass on successful reply */
- wh->cb (wh->cb_cls,
- response_code,
- json_string_value (json_array_get (wh->methods,
- wh->methods_off-1)),
- json);
- /* trigger request for the next /wire/method */
- request_wire_method (wh);
-}
-
-
-/**
- * Perform the next /wire/method request or signal
- * the end of the iteration.
- *
- * @param wh the wire handle
- * @return a handle for this request
- */
-static void
-request_wire_method (struct TALER_MINT_WireHandle *wh)
-{
- struct TALER_MINT_Context *ctx;
- CURL *eh;
- char *path;
-
- if (json_array_size (wh->methods) <= wh->methods_off)
- {
- /* we are done, signal end of iteration */
- wh->cb (wh->cb_cls,
- 0,
- NULL,
- NULL);
- TALER_MINT_wire_cancel (wh);
- return;
- }
- GNUNET_free_non_null (wh->db.buf);
- wh->db.buf = NULL;
- wh->db.buf_size = 0;
- wh->db.eno = 0;
- GNUNET_free_non_null (wh->url);
- GNUNET_asprintf (&path,
- "/wire/%s",
- json_string_value (json_array_get (wh->methods,
- wh->methods_off++)));
- wh->url = MAH_path_to_url (wh->mint,
- path);
- GNUNET_free (path);
-
- eh = curl_easy_init ();
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- wh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &wh->db));
- /* The default is 'disabled', but let's be sure */
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_FOLLOWLOCATION,
- (long) 0));
- ctx = MAH_handle_to_context (wh->mint);
- wh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_wire_method_finished,
- wh);
- TALER_MINT_perform (ctx);
-}
-
-
-/**
- * Verify that the signature on the "200 OK" response
- * for /wire from the mint is valid.
- *
- * @param wh wire handle
- * @param json json reply with the signature
- * @return NULL if @a json is invalid, otherwise the
- * "methods" array (with an RC of 1)
- */
-static json_t *
-verify_wire_signature_ok (const struct TALER_MINT_WireHandle *wh,
- json_t *json)
-{
- struct TALER_MintSignatureP mint_sig;
- struct TALER_MintPublicKeyP mint_pub;
- struct TALER_MintWireSupportMethodsPS mp;
- json_t *methods;
- const struct TALER_MINT_Keys *key_state;
- struct GNUNET_HashContext *hc;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("sig", &mint_sig),
- MAJ_spec_fixed_auto ("pub", &mint_pub),
- MAJ_spec_json ("methods", &methods),
- MAJ_spec_end
- };
- unsigned int i;
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- return NULL;
- }
- if (! json_is_array (methods))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return NULL;
- }
-
- key_state = TALER_MINT_get_keys (wh->mint);
- if (GNUNET_OK !=
- TALER_MINT_test_signing_key (key_state,
- &mint_pub))
- {
- GNUNET_break_op (0);
- return NULL;
- }
- hc = GNUNET_CRYPTO_hash_context_start ();
- for (i=0;i<json_array_size (methods);i++)
- {
- const json_t *element = json_array_get (methods, i);
- const char *method;
-
- if (! json_is_string (element))
- {
- GNUNET_CRYPTO_hash_context_abort (hc);
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return NULL;
- }
- method = json_string_value (element);
- GNUNET_CRYPTO_hash_context_read (hc,
- method,
- strlen (method) + 1);
- }
- mp.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES);
- mp.purpose.size = htonl (sizeof (struct TALER_MintWireSupportMethodsPS));
- GNUNET_CRYPTO_hash_context_finish (hc,
- &mp.h_wire_types);
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_WIRE_TYPES,
- &mp.purpose,
- &mint_sig.eddsa_signature,
- &mint_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- MAJ_parse_free (spec);
- return NULL;
- }
- return methods;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /wire request.
- *
- * @param cls the `struct TALER_MINT_WireHandle`
- * @param eh the curl request handle
- */
-static void
-handle_wire_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_WireHandle *wh = cls;
- long response_code;
- json_t *json;
-
- wh->job = NULL;
- json = MAC_download_get_result (&wh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- {
- json_t *methods;
-
- if (NULL ==
- (methods = verify_wire_signature_ok (wh,
- json)))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- wh->methods = methods;
- request_wire_method (wh);
- return;
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- if (0 != response_code)
- {
- /* pass on successful reply */
- wh->cb (wh->cb_cls,
- response_code,
- NULL,
- json);
- }
- /* signal end of iteration */
- wh->cb (wh->cb_cls,
- 0,
- NULL,
- NULL);
- if (NULL != json)
- json_decref (json);
- TALER_MINT_wire_cancel (wh);
-}
-
-
-/**
- * Obtain information about a mint's wire instructions.
- * A mint may provide wire instructions for creating
- * a reserve. The wire instructions also indicate
- * which wire formats merchants may use with the mint.
- * This API is typically used by a wallet for wiring
- * funds, and possibly by a merchant to determine
- * supported wire formats.
- *
- * Note that while we return the (main) response verbatim to the
- * caller for further processing, we do already verify that the
- * response is well-formed (i.e. that signatures included in the
- * response are all valid). If the mint's reply is not well-formed,
- * we return an HTTP status code of zero to @a cb.
- *
- * @param mint the mint handle; the mint must be ready to operate
- * @param wire_cb the callback to call when a reply for this request is available
- * @param wire_cb_cls closure for the above callback
- * @return a handle for this request
- */
-struct TALER_MINT_WireHandle *
-TALER_MINT_wire (struct TALER_MINT_Handle *mint,
- TALER_MINT_WireResultCallback wire_cb,
- void *wire_cb_cls)
-{
- struct TALER_MINT_WireHandle *wh;
- struct TALER_MINT_Context *ctx;
- CURL *eh;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
- wh = GNUNET_new (struct TALER_MINT_WireHandle);
- wh->mint = mint;
- wh->cb = wire_cb;
- wh->cb_cls = wire_cb_cls;
- wh->url = MAH_path_to_url (mint, "/wire");
-
- eh = curl_easy_init ();
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- wh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &wh->db));
- ctx = MAH_handle_to_context (mint);
- wh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_wire_finished,
- wh);
- return wh;
-}
-
-
-/**
- * Cancel a wire information request. This function cannot be used
- * on a request handle if a response is already served for it.
- *
- * @param wh the wire information request handle
- */
-void
-TALER_MINT_wire_cancel (struct TALER_MINT_WireHandle *wh)
-{
- if (NULL != wh->job)
- {
- MAC_job_cancel (wh->job);
- wh->job = NULL;
- }
- if (NULL != wh->methods)
- {
- json_decref (wh->methods);
- wh->methods = NULL;
- }
- GNUNET_free_non_null (wh->db.buf);
- GNUNET_free (wh->url);
- GNUNET_free (wh);
-}
-
-
-/* end of mint_api_wire.c */
diff --git a/src/mint-lib/mint_api_wire_deposits.c b/src/mint-lib/mint_api_wire_deposits.c
deleted file mode 100644
index f71c5b696..000000000
--- a/src/mint-lib/mint_api_wire_deposits.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api_wire_deposits.c
- * @brief Implementation of the /wire/deposits request of the mint's HTTP API
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <microhttpd.h> /* just for HTTP status codes */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "mint_api_common.h"
-#include "mint_api_json.h"
-#include "mint_api_context.h"
-#include "mint_api_handle.h"
-#include "taler_signatures.h"
-
-
-/**
- * @brief A /wire/deposits Handle
- */
-struct TALER_MINT_WireDepositsHandle
-{
-
- /**
- * The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct MAC_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MINT_WireDepositsCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Download buffer
- */
- struct MAC_DownloadBuffer db;
-
-};
-
-
-/**
- * Function called when we're done processing the
- * HTTP /wire/deposits request.
- *
- * @param cls the `struct TALER_MINT_WireDepositsHandle`
- * @param eh the curl request handle
- */
-static void
-handle_wire_deposits_finished (void *cls,
- CURL *eh)
-{
- struct TALER_MINT_WireDepositsHandle *wdh = cls;
- long response_code;
- json_t *json;
-
- wdh->job = NULL;
- json = MAC_download_get_result (&wdh->db,
- eh,
- &response_code);
- switch (response_code)
- {
- case 0:
- break;
- case MHD_HTTP_OK:
- {
- json_t *details_j;
- struct GNUNET_HashCode h_wire;
- struct TALER_Amount total_amount;
- struct TALER_MerchantPublicKeyP merchant_pub;
- unsigned int num_details;
- struct MAJ_Specification spec[] = {
- MAJ_spec_fixed_auto ("H_wire", &h_wire),
- MAJ_spec_fixed_auto ("merchant_pub", &merchant_pub),
- MAJ_spec_amount ("total_amount", &total_amount),
- MAJ_spec_json ("details", &details_j),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (json,
- spec))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- num_details = json_array_size (details_j);
- {
- struct TALER_WireDepositDetails details[num_details];
- unsigned int i;
-
- for (i=0;i<num_details;i++)
- {
- struct TALER_WireDepositDetails *detail = &details[i];
- struct json_t *detail_j = json_array_get (details_j, i);
- struct MAJ_Specification spec_detail[] = {
- MAJ_spec_fixed_auto ("H_contract", &detail->h_contract),
- MAJ_spec_amount ("deposit_value", &detail->coin_value),
- MAJ_spec_amount ("deposit_fee", &detail->coin_fee),
- MAJ_spec_uint64 ("transaction_id", &detail->transaction_id),
- MAJ_spec_fixed_auto ("coin_pub", &detail->coin_pub),
- MAJ_spec_end
- };
-
- if (GNUNET_OK !=
- MAJ_parse_json (detail_j,
- spec_detail))
- {
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- }
- if (0 == response_code)
- break;
- wdh->cb (wdh->cb_cls,
- response_code,
- json,
- &h_wire,
- &total_amount,
- num_details,
- details);
- json_decref (json);
- TALER_MINT_wire_deposits_cancel (wdh);
- return;
- }
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* This should never happen, either us or the mint is buggy
- (or API version conflict); just pass JSON reply to the application */
- break;
- case MHD_HTTP_UNAUTHORIZED:
- /* Nothing really to verify, mint says one of the signatures is
- invalid; as we checked them, this should never happen, we
- should pass the JSON reply to the application */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* Mint does not know about transaction;
- we should pass the reply to the application */
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- break;
- default:
- /* unexpected response code */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u\n",
- response_code);
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- wdh->cb (wdh->cb_cls,
- response_code,
- json,
- NULL, NULL, 0, NULL);
- json_decref (json);
- TALER_MINT_wire_deposits_cancel (wdh);
-}
-
-
-/**
- * Query the mint about which transactions were combined
- * to create a wire transfer.
- *
- * @param mint mint to query
- * @param wtid raw wire transfer identifier to get information about
- * @param cb callback to call
- * @param cb_cls closure for @a cb
- * @return handle to cancel operation
- */
-struct TALER_MINT_WireDepositsHandle *
-TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MINT_WireDepositsCallback cb,
- void *cb_cls)
-{
- struct TALER_MINT_WireDepositsHandle *wdh;
- struct TALER_MINT_Context *ctx;
- char *buf;
- char *path;
- CURL *eh;
-
- if (GNUNET_YES !=
- MAH_handle_is_ready (mint))
- {
- GNUNET_break (0);
- return NULL;
- }
-
- wdh = GNUNET_new (struct TALER_MINT_WireDepositsHandle);
- wdh->mint = mint;
- wdh->cb = cb;
- wdh->cb_cls = cb_cls;
-
- buf = GNUNET_STRINGS_data_to_string_alloc (wtid,
- sizeof (struct TALER_WireTransferIdentifierRawP));
- GNUNET_asprintf (&path,
- "/wire/deposits?wtid=%s",
- buf);
- wdh->url = MAH_path_to_url (wdh->mint,
- path);
- GNUNET_free (buf);
- GNUNET_free (path);
-
- eh = curl_easy_init ();
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_URL,
- wdh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEFUNCTION,
- &MAC_download_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_WRITEDATA,
- &wdh->db));
- ctx = MAH_handle_to_context (mint);
- wdh->job = MAC_job_add (ctx,
- eh,
- GNUNET_YES,
- &handle_wire_deposits_finished,
- wdh);
- return wdh;
-}
-
-
-/**
- * Cancel wire deposits request. This function cannot be used on a request
- * handle if a response is already served for it.
- *
- * @param wdh the wire deposits request handle
- */
-void
-TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh)
-{
- if (NULL != wdh->job)
- {
- MAC_job_cancel (wdh->job);
- wdh->job = NULL;
- }
- GNUNET_free_non_null (wdh->db.buf);
- GNUNET_free (wdh->url);
- GNUNET_free (wdh);
-}
-
-
-/* end of mint_api_wire_deposits.c */
diff --git a/src/mint-lib/test-mint-home/config/mint-common.conf b/src/mint-lib/test-mint-home/config/mint-common.conf
deleted file mode 100644
index b2b948268..000000000
--- a/src/mint-lib/test-mint-home/config/mint-common.conf
+++ /dev/null
@@ -1,30 +0,0 @@
-[mint]
-# Currency supported by the mint (can only be one)
-CURRENCY = EUR
-
-# Wire format supported by the mint
-# We use 'test' for testing of the actual
-# coin operations, and 'sepa' to test SEPA-specific routines.
-WIREFORMAT = test sepa
-
-# HTTP port the mint listens to
-PORT = 8081
-
-# Master public key used to sign the mint's various keys
-MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# How to access our database
-DB = postgres
-
-# Is this is a testcase, use transient DB actions?
-TESTRUN = YES
-
-[mintdb-postgres]
-
-DB_CONN_STR = "postgres:///talercheck"
-
-[mint-wire-sepa]
-SEPA_RESPONSE_FILE = "test-mint-home/sepa.json"
-
-[mint-wire-test]
-REDIRECT_URL = "http://www.taler.net/"
diff --git a/src/mint-lib/test-mint-home/config/mint-keyup.conf b/src/mint-lib/test-mint-home/config/mint-keyup.conf
deleted file mode 100644
index 8ad1f3bb2..000000000
--- a/src/mint-lib/test-mint-home/config/mint-keyup.conf
+++ /dev/null
@@ -1,86 +0,0 @@
-[mint_keys]
-
-# how long is one signkey valid?
-signkey_duration = 4 weeks
-
-# how long are the signatures with the signkey valid?
-legal_duration = 2 years
-
-# how long do we generate denomination and signing keys
-# ahead of time?
-lookahead_sign = 32 weeks 1 day
-
-# how long do we provide to clients denomination and signing keys
-# ahead of time?
-lookahead_provide = 4 weeks 1 day
-
-
-# Coin definitions are detected because the section
-# name begins with "coin_". The rest of the
-# name is free, but of course following the convention
-# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense.
-[coin_eur_ct_1]
-value = EUR:0.01
-duration_overlap = 5 minutes
-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
-rsa_keysize = 1024
-
-[coin_eur_ct_10]
-value = EUR:0.10
-duration_overlap = 5 minutes
-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
-rsa_keysize = 1024
-
-[coin_eur_1]
-value = EUR:1
-duration_overlap = 5 minutes
-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
-rsa_keysize = 1024
-
-[coin_eur_5]
-value = EUR:5
-duration_overlap = 5 minutes
-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
-rsa_keysize = 1024
-
-[coin_eur_10]
-value = EUR:10
-duration_overlap = 5 minutes
-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
-rsa_keysize = 1024
-
-[coin_eur_1000]
-value = EUR:1000
-duration_overlap = 5 minutes
-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
-rsa_keysize = 2048
diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c
deleted file mode 100644
index b243cc2cf..000000000
--- a/src/mint-lib/test_mint_api.c
+++ /dev/null
@@ -1,2599 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint/test_mint_api.c
- * @brief testcase to test mint's HTTP API interface
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_mint_service.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-
-/**
- * Is the configuration file is set to include wire format 'test'?
- */
-#define WIRE_TEST 1
-
-/**
- * Is the configuration file is set to include wire format 'sepa'?
- */
-#define WIRE_SEPA 1
-
-/**
- * Main execution context for the main loop.
- */
-static struct TALER_MINT_Context *ctx;
-
-/**
- * Handle to access the mint.
- */
-static struct TALER_MINT_Handle *mint;
-
-/**
- * Task run on shutdown.
- */
-static struct GNUNET_SCHEDULER_Task *shutdown_task;
-
-/**
- * Task that runs the main event loop.
- */
-static struct GNUNET_SCHEDULER_Task *ctx_task;
-
-/**
- * Result of the testcases, #GNUNET_OK on success
- */
-static int result;
-
-
-/**
- * Opcodes for the interpreter.
- */
-enum OpCode
-{
- /**
- * Termination code, stops the interpreter loop (with success).
- */
- OC_END = 0,
-
- /**
- * Add funds to a reserve by (faking) incoming wire transfer.
- */
- OC_ADMIN_ADD_INCOMING,
-
- /**
- * Check status of a reserve.
- */
- OC_WITHDRAW_STATUS,
-
- /**
- * Withdraw a coin from a reserve.
- */
- OC_WITHDRAW_SIGN,
-
- /**
- * Deposit a coin (pay with it).
- */
- OC_DEPOSIT,
-
- /**
- * Melt a (set of) coins.
- */
- OC_REFRESH_MELT,
-
- /**
- * Complete melting session by withdrawing melted coins.
- */
- OC_REFRESH_REVEAL,
-
- /**
- * Verify mint's /refresh/link by linking original private key to
- * results from #OC_REFRESH_REVEAL step.
- */
- OC_REFRESH_LINK,
-
- /**
- * Verify the mint's /wire-method.
- */
- OC_WIRE,
-
- /**
- * Verify mint's /wire/deposits method.
- */
- OC_WIRE_DEPOSITS,
-
- /**
- * Verify mint's /deposit/wtid method.
- */
- OC_DEPOSIT_WTID
-
-};
-
-
-/**
- * Structure specifying details about a coin to be melted.
- * Used in a NULL-terminated array as part of command
- * specification.
- */
-struct MeltDetails
-{
-
- /**
- * Amount to melt (including fee).
- */
- const char *amount;
-
- /**
- * Reference to reserve_withdraw operations for coin to
- * be used for the /refresh/melt operation.
- */
- const char *coin_ref;
-
-};
-
-
-/**
- * Information about a fresh coin generated by the refresh operation.
- */
-struct FreshCoin
-{
-
- /**
- * If @e amount is NULL, this specifies the denomination key to
- * use. Otherwise, this will be set (by the interpreter) to the
- * denomination PK matching @e amount.
- */
- const struct TALER_MINT_DenomPublicKey *pk;
-
- /**
- * Set (by the interpreter) to the mint's signature over the
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Set (by the interpreter) to the coin's private key.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
-};
-
-
-/**
- * Details for a mint operation to execute.
- */
-struct Command
-{
- /**
- * Opcode of the command.
- */
- enum OpCode oc;
-
- /**
- * Label for the command, can be NULL.
- */
- const char *label;
-
- /**
- * Which response code do we expect for this command?
- */
- unsigned int expected_response_code;
-
- /**
- * Details about the command.
- */
- union
- {
-
- /**
- * Information for a #OC_ADMIN_ADD_INCOMING command.
- */
- struct
- {
-
- /**
- * Label to another admin_add_incoming command if we
- * should deposit into an existing reserve, NULL if
- * a fresh reserve should be created.
- */
- const char *reserve_reference;
-
- /**
- * String describing the amount to add to the reserve.
- */
- const char *amount;
-
- /**
- * Wire details (JSON).
- */
- const char *wire;
-
- /**
- * Set (by the interpreter) to the reserve's private key
- * we used to fill the reserve.
- */
- struct TALER_ReservePrivateKeyP reserve_priv;
-
- /**
- * Set to the API's handle during the operation.
- */
- struct TALER_MINT_AdminAddIncomingHandle *aih;
-
- } admin_add_incoming;
-
- /**
- * Information for a #OC_WITHDRAW_STATUS command.
- */
- struct
- {
-
- /**
- * Label to the #OC_ADMIN_ADD_INCOMING command which
- * created the reserve.
- */
- const char *reserve_reference;
-
- /**
- * Set to the API's handle during the operation.
- */
- struct TALER_MINT_ReserveStatusHandle *wsh;
-
- /**
- * Expected reserve balance.
- */
- const char *expected_balance;
-
- } reserve_status;
-
- /**
- * Information for a #OC_WITHDRAW_SIGN command.
- */
- struct
- {
-
- /**
- * Which reserve should we withdraw from?
- */
- const char *reserve_reference;
-
- /**
- * String describing the denomination value we should withdraw.
- * A corresponding denomination key must exist in the mint's
- * offerings. Can be NULL if @e pk is set instead.
- */
- const char *amount;
-
- /**
- * If @e amount is NULL, this specifies the denomination key to
- * use. Otherwise, this will be set (by the interpreter) to the
- * denomination PK matching @e amount.
- */
- const struct TALER_MINT_DenomPublicKey *pk;
-
- /**
- * Set (by the interpreter) to the mint's signature over the
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Set (by the interpreter) to the coin's private key.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * Blinding key used for the operation.
- */
- struct TALER_DenominationBlindingKey blinding_key;
-
- /**
- * Withdraw handle (while operation is running).
- */
- struct TALER_MINT_ReserveWithdrawHandle *wsh;
-
- } reserve_withdraw;
-
- /**
- * Information for a #OC_DEPOSIT command.
- */
- struct
- {
-
- /**
- * Amount to deposit.
- */
- const char *amount;
-
- /**
- * Reference to a reserve_withdraw operation for a coin to
- * be used for the /deposit operation.
- */
- const char *coin_ref;
-
- /**
- * If this @e coin_ref refers to an operation that generated
- * an array of coins, this value determines which coin to use.
- */
- unsigned int coin_idx;
-
- /**
- * JSON string describing the merchant's "wire details".
- */
- const char *wire_details;
-
- /**
- * JSON string describing the contract between the two parties.
- */
- const char *contract;
-
- /**
- * Transaction ID to use.
- */
- uint64_t transaction_id;
-
- /**
- * Relative time (to add to 'now') to compute the refund deadline.
- * Zero for no refunds.
- */
- struct GNUNET_TIME_Relative refund_deadline;
-
- /**
- * Set (by the interpreter) to a fresh private key of the merchant,
- * if @e refund_deadline is non-zero.
- */
- struct TALER_MerchantPrivateKeyP merchant_priv;
-
- /**
- * Deposit handle while operation is running.
- */
- struct TALER_MINT_DepositHandle *dh;
-
- } deposit;
-
- /**
- * Information for a #OC_REFRESH_MELT command.
- */
- struct
- {
-
- /**
- * Information about coins to be melted.
- */
- struct MeltDetails *melted_coins;
-
- /**
- * Denominations of the fresh coins to withdraw.
- */
- const char **fresh_amounts;
-
- /**
- * Array of the public keys corresponding to
- * the @e fresh_amounts, set by the interpreter.
- */
- const struct TALER_MINT_DenomPublicKey **fresh_pks;
-
- /**
- * Melt handle while operation is running.
- */
- struct TALER_MINT_RefreshMeltHandle *rmh;
-
- /**
- * Data used in the refresh operation, set by the interpreter.
- */
- char *refresh_data;
-
- /**
- * Number of bytes in @e refresh_data, set by the interpreter.
- */
- size_t refresh_data_length;
-
- /**
- * Set by the interpreter (upon completion) to the noreveal
- * index selected by the mint.
- */
- uint16_t noreveal_index;
-
- } refresh_melt;
-
- /**
- * Information for a #OC_REFRESH_REVEAL command.
- */
- struct
- {
-
- /**
- * Melt operation this is the matching reveal for.
- */
- const char *melt_ref;
-
- /**
- * Reveal handle while operation is running.
- */
- struct TALER_MINT_RefreshRevealHandle *rrh;
-
- /**
- * Number of fresh coins withdrawn, set by the interpreter.
- * Length of the @e fresh_coins array.
- */
- unsigned int num_fresh_coins;
-
- /**
- * Information about coins withdrawn, set by the interpreter.
- */
- struct FreshCoin *fresh_coins;
-
- } refresh_reveal;
-
- /**
- * Information for a #OC_REFRESH_LINK command.
- */
- struct
- {
-
- /**
- * Reveal operation this is the matching link for.
- */
- const char *reveal_ref;
-
- /**
- * Link handle while operation is running.
- */
- struct TALER_MINT_RefreshLinkHandle *rlh;
-
- /**
- * Which of the melted coins should be used for the linkage?
- */
- unsigned int coin_idx;
-
- } refresh_link;
-
- /**
- * Information for the /wire command.
- */
- struct {
-
- /**
- * Handle to the wire request.
- */
- struct TALER_MINT_WireHandle *wh;
-
- /**
- * Format we expect to see, others will be *ignored*.
- */
- const char *format;
-
- } wire;
-
- /**
- * Information for the /wire/deposits's command.
- */
- struct {
-
- /**
- * Handle to the wire deposits request.
- */
- struct TALER_MINT_WireDepositsHandle *wdh;
-
- /**
- * Reference to a /deposit/wtid command. If set, we use the
- * WTID from that command.
- */
- const char *wtid_ref;
-
- /**
- * WTID to use (used if @e wtid_ref is NULL).
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /* TODO: may want to add list of deposits we expected
- to see aggregated here in the future. */
-
- } wire_deposits;
-
- /**
- * Information for the /deposit/wtid command.
- */
- struct {
-
- /**
- * Handle to the deposit wtid request.
- */
- struct TALER_MINT_DepositWtidHandle *dwh;
-
- /**
- * Which /deposit operation should we obtain WTID data for?
- */
- const char *deposit_ref;
-
- /**
- * What is the expected total amount? Only used if
- * @e expected_response_code was #MHD_HTTP_OK.
- */
- struct TALER_Amount total_amount_expected;
-
- /**
- * Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- } deposit_wtid;
-
- } details;
-
-};
-
-
-/**
- * State of the interpreter loop.
- */
-struct InterpreterState
-{
- /**
- * Keys from the mint.
- */
- const struct TALER_MINT_Keys *keys;
-
- /**
- * Commands the interpreter will run.
- */
- struct Command *commands;
-
- /**
- * Interpreter task (if one is scheduled).
- */
- struct GNUNET_SCHEDULER_Task *task;
-
- /**
- * Instruction pointer. Tells #interpreter_run() which
- * instruction to run next.
- */
- unsigned int ip;
-
-};
-
-
-/**
- * Task that runs the context's event loop with the GNUnet scheduler.
- *
- * @param cls unused
- * @param tc scheduler context (unused)
- */
-static void
-context_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Run the context task, the working set has changed.
- */
-static void
-trigger_context_task ()
-{
- GNUNET_SCHEDULER_cancel (ctx_task);
- ctx_task = GNUNET_SCHEDULER_add_now (&context_task,
- NULL);
-}
-
-
-/**
- * The testcase failed, return with an error code.
- *
- * @param is interpreter state to clean up
- */
-static void
-fail (struct InterpreterState *is)
-{
- result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Find a command by label.
- *
- * @param is interpreter state to search
- * @param label label to look for
- * @return NULL if command was not found
- */
-static const struct Command *
-find_command (const struct InterpreterState *is,
- const char *label)
-{
- unsigned int i;
- const struct Command *cmd;
-
- if (NULL == label)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Attempt to lookup command for empty label\n");
- return NULL;
- }
- for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
- if ( (NULL != cmd->label) &&
- (0 == strcmp (cmd->label,
- label)) )
- return cmd;
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command not found: %s\n",
- label);
- return NULL;
-}
-
-
-/**
- * Run the main interpreter loop that performs mint operations.
- *
- * @param cls contains the `struct InterpreterState`
- * @param tc scheduler context
- */
-static void
-interpreter_run (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Function called upon completion of our /admin/add/incoming request.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-static void
-add_incoming_cb (void *cls,
- unsigned int http_status,
- json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.admin_add_incoming.aih = NULL;
- if (MHD_HTTP_OK != http_status)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Check if the given historic event @a h corresponds to the given
- * command @a cmd.
- *
- * @param h event in history
- * @param cmd an #OC_ADMIN_ADD_INCOMING command
- * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
- */
-static int
-compare_admin_add_incoming_history (const struct TALER_MINT_ReserveHistory *h,
- const struct Command *cmd)
-{
- struct TALER_Amount amount;
-
- if (TALER_MINT_RTT_DEPOSIT != h->type)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
- &amount));
- if (0 != TALER_amount_cmp (&amount,
- &h->amount))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Check if the given historic event @a h corresponds to the given
- * command @a cmd.
- *
- * @param h event in history
- * @param cmd an #OC_WITHDRAW_SIGN command
- * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
- */
-static int
-compare_reserve_withdraw_history (const struct TALER_MINT_ReserveHistory *h,
- const struct Command *cmd)
-{
- struct TALER_Amount amount;
- struct TALER_Amount amount_with_fee;
-
- if (TALER_MINT_RTT_WITHDRAWAL != h->type)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
- &amount));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_add (&amount_with_fee,
- &amount,
- &cmd->details.reserve_withdraw.pk->fee_withdraw));
- if (0 != TALER_amount_cmp (&amount_with_fee,
- &h->amount))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called with the result of a /reserve/status request.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param[in] json original response in JSON format (useful only for diagnostics)
- * @param balance current balance in the reserve, NULL on error
- * @param history_length number of entries in the transaction history, 0 on error
- * @param history detailed transaction history, NULL on error
- */
-static void
-reserve_status_cb (void *cls,
- unsigned int http_status,
- json_t *json,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_MINT_ReserveHistory *history)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- struct Command *rel;
- unsigned int i;
- unsigned int j;
- struct TALER_Amount amount;
-
- cmd->details.reserve_status.wsh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- GNUNET_break (0);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- /* FIXME: note that history events may come in a different
- order than the commands. However, for now this works... */
- j = 0;
- for (i=0;i<is->ip;i++)
- {
- switch ((rel = &is->commands[i])->oc)
- {
- case OC_ADMIN_ADD_INCOMING:
- if ( ( (NULL != rel->label) &&
- (0 == strcmp (cmd->details.reserve_status.reserve_reference,
- rel->label) ) ) ||
- ( (NULL != rel->details.admin_add_incoming.reserve_reference) &&
- (0 == strcmp (cmd->details.reserve_status.reserve_reference,
- rel->details.admin_add_incoming.reserve_reference) ) ) )
- {
- if (GNUNET_OK !=
- compare_admin_add_incoming_history (&history[j],
- rel))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- j++;
- }
- break;
- case OC_WITHDRAW_SIGN:
- if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
- rel->details.reserve_withdraw.reserve_reference))
- {
- if (GNUNET_OK !=
- compare_reserve_withdraw_history (&history[j],
- rel))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- j++;
- }
- break;
- default:
- /* unreleated, just skip */
- break;
- }
- }
- if (j != history_length)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- if (NULL != cmd->details.reserve_status.expected_balance)
- {
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (cmd->details.reserve_status.expected_balance,
- &amount));
- if (0 != TALER_amount_cmp (&amount,
- balance))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- }
- break;
- default:
- /* Unsupported status code (by test harness) */
- GNUNET_break (0);
- break;
- }
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Function called upon completion of our /reserve/withdraw request.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param sig signature over the coin, NULL on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-static void
-reserve_withdraw_cb (void *cls,
- unsigned int http_status,
- const struct TALER_DenominationSignature *sig,
- json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.reserve_withdraw.wsh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (full_response, stderr, 0);
- GNUNET_break (0);
- fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- if (NULL == sig)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- cmd->details.reserve_withdraw.sig.rsa_signature
- = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
- break;
- case MHD_HTTP_PAYMENT_REQUIRED:
- /* nothing to check */
- break;
- default:
- /* Unsupported status code (by test harness) */
- GNUNET_break (0);
- break;
- }
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Function called with the result of a /deposit operation.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param obj the received JSON reply, should be kept as proof (and, in case of errors,
- * be forwarded to the customer)
- */
-static void
-deposit_cb (void *cls,
- unsigned int http_status,
- json_t *obj)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.deposit.dh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (obj, stderr, 0);
- fail (is);
- return;
- }
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Function called with the result of the /refresh/melt operation.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param noreveal_index choice by the mint in the cut-and-choose protocol,
- * UINT16_MAX on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-static void
-melt_cb (void *cls,
- unsigned int http_status,
- uint16_t noreveal_index,
- json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.refresh_melt.rmh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (full_response, stderr, 0);
- fail (is);
- return;
- }
- cmd->details.refresh_melt.noreveal_index = noreveal_index;
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Function called with the result of the /refresh/reveal operation.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
- * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
- * @param sigs array of signature over @a num_coins coins, NULL on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-static void
-reveal_cb (void *cls,
- unsigned int http_status,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
- unsigned int i;
-
- cmd->details.refresh_reveal.rrh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (full_response, stderr, 0);
- fail (is);
- return;
- }
- ref = find_command (is,
- cmd->details.refresh_reveal.melt_ref);
- cmd->details.refresh_reveal.num_fresh_coins = num_coins;
- switch (http_status)
- {
- case MHD_HTTP_OK:
- cmd->details.refresh_reveal.fresh_coins
- = GNUNET_new_array (num_coins,
- struct FreshCoin);
- for (i=0;i<num_coins;i++)
- {
- struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i];
-
- fc->pk = ref->details.refresh_melt.fresh_pks[i];
- fc->coin_priv = coin_privs[i];
- fc->sig.rsa_signature
- = GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature);
- }
- break;
- default:
- break;
- }
-
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Function called with the result of a /refresh/link operation.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
- * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
- * @param sigs array of signature over @a num_coins coins, NULL on error
- * @param pubs array of public keys for the @a sigs, NULL on error
- * @param full_response full response from the mint (for logging, in case of errors)
- */
-static void
-link_cb (void *cls,
- unsigned int http_status,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_DenominationPublicKey *pubs,
- json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
- unsigned int i;
- unsigned int j;
- unsigned int found;
-
- cmd->details.refresh_link.rlh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (full_response, stderr, 0);
- fail (is);
- return;
- }
- ref = find_command (is,
- cmd->details.refresh_link.reveal_ref);
- switch (http_status)
- {
- case MHD_HTTP_OK:
- /* check that number of coins returned matches */
- if (num_coins != ref->details.refresh_reveal.num_fresh_coins)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- /* check that the coins match */
- for (i=0;i<num_coins;i++)
- for (j=i+1;j<num_coins;j++)
- if (0 == memcmp (&coin_privs[i],
- &coin_privs[j],
- sizeof (struct TALER_CoinSpendPrivateKeyP)))
- GNUNET_break (0);
- /* Note: coins might be legitimately permutated in here... */
- found = 0;
- for (i=0;i<num_coins;i++)
- for (j=0;j<num_coins;j++)
- {
- const struct FreshCoin *fc;
-
- fc = &ref->details.refresh_reveal.fresh_coins[j];
- if ( (0 == memcmp (&coin_privs[i],
- &fc->coin_priv,
- sizeof (struct TALER_CoinSpendPrivateKeyP))) &&
- (0 == GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature,
- sigs[i].rsa_signature)) &&
- (0 == GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key,
- pubs[i].rsa_public_key)) )
- {
- found++;
- break;
- }
- }
- if (found != num_coins)
- {
- fprintf (stderr,
- "Only %u/%u coins match expectations\n",
- found,
- num_coins);
- GNUNET_break (0);
- fail (is);
- return;
- }
- break;
- default:
- break;
- }
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Find denomination key matching the given amount.
- *
- * @param keys array of keys to search
- * @param amount coin value to look for
- * @return NULL if no matching key was found
- */
-static const struct TALER_MINT_DenomPublicKey *
-find_pk (const struct TALER_MINT_Keys *keys,
- const struct TALER_Amount *amount)
-{
- unsigned int i;
- struct GNUNET_TIME_Absolute now;
- struct TALER_MINT_DenomPublicKey *pk;
- char *str;
-
- now = GNUNET_TIME_absolute_get ();
- for (i=0;i<keys->num_denom_keys;i++)
- {
- pk = &keys->denom_keys[i];
- if ( (0 == TALER_amount_cmp (amount,
- &pk->value)) &&
- (now.abs_value_us >= pk->valid_from.abs_value_us) &&
- (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) )
- return pk;
- }
- /* do 2nd pass to check if expiration times are to blame for failure */
- str = TALER_amount_to_string (amount);
- for (i=0;i<keys->num_denom_keys;i++)
- {
- pk = &keys->denom_keys[i];
- if ( (0 == TALER_amount_cmp (amount,
- &pk->value)) &&
- ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
- (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n",
- str,
- now.abs_value_us,
- pk->valid_from.abs_value_us,
- pk->withdraw_valid_until.abs_value_us);
- GNUNET_free (str);
- return NULL;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No denomination key for amount %s found\n",
- str);
- GNUNET_free (str);
- return NULL;
-}
-
-
-/**
- * Callbacks called with the result(s) of a
- * wire format inquiry request to the mint.
- *
- * The callback is invoked multiple times, once for each supported @a
- * method. Finally, it is invoked one more time with cls/0/NULL/NULL
- * to indicate the end of the iteration. If any request fails to
- * generate a valid response from the mint, @a http_status will also
- * be zero and the iteration will also end. Thus, the iteration
- * always ends with a final call with an @a http_status of 0. If the
- * @a http_status is already 0 on the first call, then the response to
- * the /wire request was invalid. Later, clients can tell the
- * difference between @a http_status of 0 indicating a failed
- * /wire/method request and a regular end of the iteration by @a
- * method being non-NULL. If the mint simply correctly asserts that
- * it does not support any methods, @a method will be NULL but the @a
- * http_status will be #MHD_HTTP_OK for the first call (followed by a
- * cls/0/NULL/NULL call to signal the end of the iteration).
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param method wire format method supported, i.e. "test" or "sepa", or NULL
- * if already the /wire request failed.
- * @param obj the received JSON reply, if successful this should be the wire
- * format details as provided by /wire/METHOD/, or NULL if the
- * reply was not in JSON format (in this case, the client might
- * want to do an HTTP request to /wire/METHOD/ with a browser to
- * provide more information to the user about the @a method).
- */
-static void
-wire_cb (void *cls,
- unsigned int http_status,
- const char *method,
- json_t *obj)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- if (0 == http_status)
- {
- /* 0 always signals the end of the iteration */
- cmd->details.wire.wh = NULL;
- }
- else if ( (NULL != method) &&
- (0 != strcasecmp (method,
- cmd->details.wire.format)) )
- {
- /* not the method we care about, skip */
- return;
- }
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s/%s\n",
- http_status,
- cmd->label,
- method);
- json_dumpf (obj, stderr, 0);
- fail (is);
- return;
- }
- if (0 == http_status)
- {
- /* end of iteration, move to next command */
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
- return;
- }
- /* For now, we only support to be called only once
- with a "positive" result; so we switch to an
- expected value of 0 for the 2nd iteration */
- cmd->expected_response_code = 0;
-}
-
-
-/**
- * Function called with detailed wire transfer data, including all
- * of the coin transactions that were combined into the wire transfer.
- *
- * @param cls closure
- * @param http_status HTTP status code we got, 0 on mint protocol violation
- * @param json original json reply (may include signatures, those have then been
- * validated already)
- * @param wtid extracted wire transfer identifier, or NULL if the mint could
- * not provide any (set only if @a http_status is #MHD_HTTP_OK)
- * @param total_amount total amount of the wire transfer, or NULL if the mint could
- * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
- * @param details_length length of the @a details array
- * @param details array with details about the combined transactions
- */
-static void
-wire_deposits_cb (void *cls,
- unsigned int http_status,
- json_t *json,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_Amount *total_amount,
- unsigned int details_length,
- const struct TALER_WireDepositDetails *details)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
-
- cmd->details.wire_deposits.wdh = NULL;
- ref = find_command (is,
- cmd->details.wire_deposits.wtid_ref);
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- if (0 != TALER_amount_cmp (total_amount,
- &ref->details.deposit_wtid.total_amount_expected))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount missmatch to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- if (NULL != ref->details.deposit_wtid.deposit_ref)
- {
- const struct Command *dep;
- struct GNUNET_HashCode hw;
-
- dep = find_command (is,
- ref->details.deposit_wtid.deposit_ref);
- GNUNET_CRYPTO_hash (dep->details.deposit.wire_details,
- strlen (dep->details.deposit.wire_details),
- &hw);
- if (0 != memcmp (&hw,
- h_wire,
- sizeof (struct GNUNET_HashCode)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire hash missmatch to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- }
- break;
- default:
- break;
- }
-
- /* move to next command */
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Function called with detailed wire transfer data.
- *
- * @param cls closure
- * @param http_status HTTP status code we got, 0 on mint protocol violation
- * @param json original json reply (may include signatures, those have then been
- * validated already)
- * @param wtid wire transfer identifier used by the mint, NULL if mint did not
- * yet execute the transaction
- * @param execution_time actual or planned execution time for the wire transfer
- * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
- * @param total_amount total amount of the wire transfer, or NULL if the mint could
- * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
- */
-static void
-deposit_wtid_cb (void *cls,
- unsigned int http_status,
- json_t *json,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_Amount *coin_contribution)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.deposit_wtid.dwh = NULL;
- if (cmd->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s\n",
- http_status,
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- cmd->details.deposit_wtid.wtid = *wtid;
- break;
- default:
- break;
- }
-
- /* move to next command */
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Run the main interpreter loop that performs mint operations.
- *
- * @param cls contains the `struct InterpreterState`
- * @param tc scheduler context
- */
-static void
-interpreter_run (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount;
- struct GNUNET_TIME_Absolute execution_date;
- json_t *wire;
-
- is->task = NULL;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- fprintf (stderr,
- "Test aborted by shutdown request\n");
- fail (is);
- return;
- }
- switch (cmd->oc)
- {
- case OC_END:
- result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown ();
- return;
- case OC_ADMIN_ADD_INCOMING:
- if (NULL !=
- cmd->details.admin_add_incoming.reserve_reference)
- {
- ref = find_command (is,
- cmd->details.admin_add_incoming.reserve_reference);
- GNUNET_assert (NULL != ref);
- GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
- cmd->details.admin_add_incoming.reserve_priv
- = ref->details.admin_add_incoming.reserve_priv;
- }
- else
- {
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
- priv = GNUNET_CRYPTO_eddsa_key_create ();
- cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv;
- GNUNET_free (priv);
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv,
- &reserve_pub.eddsa_pub);
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
- &amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- cmd->details.admin_add_incoming.amount,
- is->ip);
- fail (is);
- return;
- }
- wire = json_loads (cmd->details.admin_add_incoming.wire,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == wire)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse wire details `%s' at %u\n",
- cmd->details.admin_add_incoming.wire,
- is->ip);
- fail (is);
- return;
- }
- execution_date = GNUNET_TIME_absolute_get ();
- TALER_round_abs_time (&execution_date);
- cmd->details.admin_add_incoming.aih
- = TALER_MINT_admin_add_incoming (mint,
- &reserve_pub,
- &amount,
- execution_date,
- wire,
- &add_incoming_cb,
- is);
- if (NULL == cmd->details.admin_add_incoming.aih)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- trigger_context_task ();
- return;
- case OC_WITHDRAW_STATUS:
- GNUNET_assert (NULL !=
- cmd->details.reserve_status.reserve_reference);
- ref = find_command (is,
- cmd->details.reserve_status.reserve_reference);
- GNUNET_assert (NULL != ref);
- GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
- GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv,
- &reserve_pub.eddsa_pub);
- cmd->details.reserve_status.wsh
- = TALER_MINT_reserve_status (mint,
- &reserve_pub,
- &reserve_status_cb,
- is);
- trigger_context_task ();
- return;
- case OC_WITHDRAW_SIGN:
- GNUNET_assert (NULL !=
- cmd->details.reserve_withdraw.reserve_reference);
- ref = find_command (is,
- cmd->details.reserve_withdraw.reserve_reference);
- GNUNET_assert (NULL != ref);
- GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
- if (NULL != cmd->details.reserve_withdraw.amount)
- {
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
- &amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- cmd->details.reserve_withdraw.amount,
- is->ip);
- fail (is);
- return;
- }
- cmd->details.reserve_withdraw.pk = find_pk (is->keys,
- &amount);
- }
- if (NULL == cmd->details.reserve_withdraw.pk)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to determine denomination key at %u\n",
- is->ip);
- fail (is);
- return;
- }
-
- /* create coin's private key */
- {
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
- priv = GNUNET_CRYPTO_eddsa_key_create ();
- cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv;
- GNUNET_free (priv);
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.reserve_withdraw.coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key
- = GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.reserve_withdraw.pk->key.rsa_public_key));
- cmd->details.reserve_withdraw.wsh
- = TALER_MINT_reserve_withdraw (mint,
- cmd->details.reserve_withdraw.pk,
- &ref->details.admin_add_incoming.reserve_priv,
- &cmd->details.reserve_withdraw.coin_priv,
- &cmd->details.reserve_withdraw.blinding_key,
- &reserve_withdraw_cb,
- is);
- if (NULL == cmd->details.reserve_withdraw.wsh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- trigger_context_task ();
- return;
- case OC_DEPOSIT:
- {
- struct GNUNET_HashCode h_contract;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- const struct TALER_MINT_DenomPublicKey *coin_pk;
- const struct TALER_DenominationSignature *coin_pk_sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct GNUNET_TIME_Absolute refund_deadline;
- struct GNUNET_TIME_Absolute wire_deadline;
- struct GNUNET_TIME_Absolute timestamp;
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
- struct TALER_MerchantPublicKeyP merchant_pub;
- json_t *contract;
- json_t *wire;
-
- GNUNET_assert (NULL !=
- cmd->details.deposit.coin_ref);
- ref = find_command (is,
- cmd->details.deposit.coin_ref);
- GNUNET_assert (NULL != ref);
- switch (ref->oc)
- {
- case OC_WITHDRAW_SIGN:
- coin_priv = &ref->details.reserve_withdraw.coin_priv;
- coin_pk = ref->details.reserve_withdraw.pk;
- coin_pk_sig = &ref->details.reserve_withdraw.sig;
- break;
- case OC_REFRESH_REVEAL:
- {
- const struct FreshCoin *fc;
- unsigned int idx;
-
- idx = cmd->details.deposit.coin_idx;
- GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins);
- fc = &ref->details.refresh_reveal.fresh_coins[idx];
-
- coin_priv = &fc->coin_priv;
- coin_pk = fc->pk;
- coin_pk_sig = &fc->sig;
- }
- break;
- default:
- GNUNET_assert (0);
- }
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.deposit.amount,
- &amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- cmd->details.deposit.amount,
- is->ip);
- fail (is);
- return;
- }
- contract = json_loads (cmd->details.deposit.contract,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == contract)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse contract details `%s' at %u/%s\n",
- cmd->details.deposit.contract,
- is->ip,
- cmd->label);
- fail (is);
- return;
- }
- TALER_hash_json (contract,
- &h_contract);
- wire = json_loads (cmd->details.deposit.wire_details,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == wire)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse wire details `%s' at %u/%s\n",
- cmd->details.deposit.wire_details,
- is->ip,
- cmd->label);
- fail (is);
- return;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
-
- priv = GNUNET_CRYPTO_eddsa_key_create ();
- cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
- GNUNET_free (priv);
- if (0 != cmd->details.deposit.refund_deadline.rel_value_us)
- {
- refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline);
- }
- else
- {
- refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
- &merchant_pub.eddsa_pub);
-
- wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
- timestamp = GNUNET_TIME_absolute_get ();
- TALER_round_abs_time (&timestamp);
- {
- struct TALER_DepositRequestPS dr;
-
- memset (&dr, 0, sizeof (dr));
- dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
- dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
- dr.h_contract = h_contract;
- TALER_hash_json (wire,
- &dr.h_wire);
- dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
- dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
- dr.transaction_id = GNUNET_htonll (cmd->details.deposit.transaction_id);
- TALER_amount_hton (&dr.amount_with_fee,
- &amount);
- TALER_amount_hton (&dr.deposit_fee,
- &coin_pk->fee_deposit);
- dr.merchant = merchant_pub;
- dr.coin_pub = coin_pub;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
- &dr.purpose,
- &coin_sig.eddsa_signature));
- }
- cmd->details.deposit.dh
- = TALER_MINT_deposit (mint,
- &amount,
- wire_deadline,
- wire,
- &h_contract,
- &coin_pub,
- coin_pk_sig,
- &coin_pk->key,
- timestamp,
- cmd->details.deposit.transaction_id,
- &merchant_pub,
- refund_deadline,
- &coin_sig,
- &deposit_cb,
- is);
- if (NULL == cmd->details.deposit.dh)
- {
- GNUNET_break (0);
- json_decref (wire);
- fail (is);
- return;
- }
- json_decref (wire);
- trigger_context_task ();
- return;
- }
- case OC_REFRESH_MELT:
- {
- unsigned int num_melted_coins;
- unsigned int num_fresh_coins;
-
- cmd->details.refresh_melt.noreveal_index = UINT16_MAX;
- for (num_melted_coins=0;
- NULL != cmd->details.refresh_melt.melted_coins[num_melted_coins].amount;
- num_melted_coins++) ;
- for (num_fresh_coins=0;
- NULL != cmd->details.refresh_melt.fresh_amounts[num_fresh_coins];
- num_fresh_coins++) ;
-
- cmd->details.refresh_melt.fresh_pks
- = GNUNET_new_array (num_fresh_coins,
- const struct TALER_MINT_DenomPublicKey *);
- {
- struct TALER_CoinSpendPrivateKeyP melt_privs[num_melted_coins];
- struct TALER_Amount melt_amounts[num_melted_coins];
- struct TALER_DenominationSignature melt_sigs[num_melted_coins];
- struct TALER_MINT_DenomPublicKey melt_pks[num_melted_coins];
- struct TALER_MINT_DenomPublicKey fresh_pks[num_fresh_coins];
- unsigned int i;
-
- for (i=0;i<num_melted_coins;i++)
- {
- const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coins[i];
- ref = find_command (is,
- md->coin_ref);
- GNUNET_assert (NULL != ref);
- GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
-
- melt_privs[i] = ref->details.reserve_withdraw.coin_priv;
- if (GNUNET_OK !=
- TALER_string_to_amount (md->amount,
- &melt_amounts[i]))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- md->amount,
- is->ip);
- fail (is);
- return;
- }
- melt_sigs[i] = ref->details.reserve_withdraw.sig;
- melt_pks[i] = *ref->details.reserve_withdraw.pk;
- }
- for (i=0;i<num_fresh_coins;i++)
- {
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.refresh_melt.fresh_amounts[i],
- &amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- cmd->details.reserve_withdraw.amount,
- is->ip);
- fail (is);
- return;
- }
- cmd->details.refresh_melt.fresh_pks[i]
- = find_pk (is->keys,
- &amount);
- fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i];
- }
- cmd->details.refresh_melt.refresh_data
- = TALER_MINT_refresh_prepare (num_melted_coins,
- melt_privs,
- melt_amounts,
- melt_sigs,
- melt_pks,
- GNUNET_YES,
- num_fresh_coins,
- fresh_pks,
- &cmd->details.refresh_melt.refresh_data_length);
- if (NULL == cmd->details.refresh_melt.refresh_data)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- cmd->details.refresh_melt.rmh
- = TALER_MINT_refresh_melt (mint,
- cmd->details.refresh_melt.refresh_data_length,
- cmd->details.refresh_melt.refresh_data,
- &melt_cb,
- is);
- if (NULL == cmd->details.refresh_melt.rmh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- }
- }
- trigger_context_task ();
- return;
- case OC_REFRESH_REVEAL:
- ref = find_command (is,
- cmd->details.refresh_reveal.melt_ref);
- cmd->details.refresh_reveal.rrh
- = TALER_MINT_refresh_reveal (mint,
- ref->details.refresh_melt.refresh_data_length,
- ref->details.refresh_melt.refresh_data,
- ref->details.refresh_melt.noreveal_index,
- &reveal_cb,
- is);
- if (NULL == cmd->details.refresh_reveal.rrh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- trigger_context_task ();
- return;
- case OC_REFRESH_LINK:
- /* find reveal command */
- ref = find_command (is,
- cmd->details.refresh_link.reveal_ref);
- /* find melt command */
- ref = find_command (is,
- ref->details.refresh_reveal.melt_ref);
- /* find reserve_withdraw command */
- {
- unsigned int idx;
- const struct MeltDetails *md;
- unsigned int num_melted_coins;
-
- for (num_melted_coins=0;
- NULL != ref->details.refresh_melt.melted_coins[num_melted_coins].amount;
- num_melted_coins++) ;
- idx = cmd->details.refresh_link.coin_idx;
- GNUNET_assert (idx < num_melted_coins);
- md = &ref->details.refresh_melt.melted_coins[idx];
- ref = find_command (is,
- md->coin_ref);
- }
- GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
- /* finally, use private key from withdraw sign command */
- cmd->details.refresh_link.rlh
- = TALER_MINT_refresh_link (mint,
- &ref->details.reserve_withdraw.coin_priv,
- &link_cb,
- is);
- if (NULL == cmd->details.refresh_link.rlh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- trigger_context_task ();
- return;
- case OC_WIRE:
- cmd->details.wire.wh = TALER_MINT_wire (mint,
- &wire_cb,
- is);
- trigger_context_task ();
- return;
- case OC_WIRE_DEPOSITS:
- if (NULL != cmd->details.wire_deposits.wtid_ref)
- {
- ref = find_command (is,
- cmd->details.wire_deposits.wtid_ref);
- GNUNET_assert (NULL != ref);
- cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
- }
- cmd->details.wire_deposits.wdh
- = TALER_MINT_wire_deposits (mint,
- &cmd->details.wire_deposits.wtid,
- &wire_deposits_cb,
- is);
- trigger_context_task ();
- return;
- case OC_DEPOSIT_WTID:
- {
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_contract;
- json_t *wire;
- json_t *contract;
- const struct Command *coin;
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- ref = find_command (is,
- cmd->details.deposit_wtid.deposit_ref);
- GNUNET_assert (NULL != ref);
- coin = find_command (is,
- ref->details.deposit.coin_ref);
- GNUNET_assert (NULL != coin);
- switch (coin->oc)
- {
- case OC_WITHDRAW_SIGN:
- GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- break;
- case OC_REFRESH_REVEAL:
- {
- const struct FreshCoin *fc;
- unsigned int idx;
-
- idx = ref->details.deposit.coin_idx;
- GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
- fc = &coin->details.refresh_reveal.fresh_coins[idx];
-
- GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- }
- break;
- default:
- GNUNET_assert (0);
- }
-
- wire = json_loads (ref->details.deposit.wire_details,
- JSON_REJECT_DUPLICATES,
- NULL);
- GNUNET_assert (NULL != wire);
- TALER_hash_json (wire,
- &h_wire);
- json_decref (wire);
- contract = json_loads (ref->details.deposit.contract,
- JSON_REJECT_DUPLICATES,
- NULL);
- GNUNET_assert (NULL != contract);
- TALER_hash_json (contract,
- &h_contract);
- json_decref (contract);
- cmd->details.deposit_wtid.dwh
- = TALER_MINT_deposit_wtid (mint,
- &ref->details.deposit.merchant_priv,
- &h_wire,
- &h_contract,
- &coin_pub,
- ref->details.deposit.transaction_id,
- &deposit_wtid_cb,
- is);
- trigger_context_task ();
- }
- return;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown instruction %d at %u (%s)\n",
- cmd->oc,
- is->ip,
- cmd->label);
- fail (is);
- return;
- }
-}
-
-
-/**
- * Function run when the test terminates (good or bad).
- * Cleans up our state.
- *
- * @param cls the interpreter state.
- * @param tc unused
- */
-static void
-do_shutdown (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd;
- unsigned int i;
-
- shutdown_task = NULL;
- for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
- {
- switch (cmd->oc)
- {
- case OC_END:
- GNUNET_assert (0);
- break;
- case OC_ADMIN_ADD_INCOMING:
- if (NULL != cmd->details.admin_add_incoming.aih)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_admin_add_incoming_cancel (cmd->details.admin_add_incoming.aih);
- cmd->details.admin_add_incoming.aih = NULL;
- }
- break;
- case OC_WITHDRAW_STATUS:
- if (NULL != cmd->details.reserve_status.wsh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_reserve_status_cancel (cmd->details.reserve_status.wsh);
- cmd->details.reserve_status.wsh = NULL;
- }
- break;
- case OC_WITHDRAW_SIGN:
- if (NULL != cmd->details.reserve_withdraw.wsh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_reserve_withdraw_cancel (cmd->details.reserve_withdraw.wsh);
- cmd->details.reserve_withdraw.wsh = NULL;
- }
- if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature)
- {
- GNUNET_CRYPTO_rsa_signature_free (cmd->details.reserve_withdraw.sig.rsa_signature);
- cmd->details.reserve_withdraw.sig.rsa_signature = NULL;
- }
- if (NULL != cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key)
- {
- GNUNET_CRYPTO_rsa_blinding_key_free (cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key);
- cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key = NULL;
- }
- break;
- case OC_DEPOSIT:
- if (NULL != cmd->details.deposit.dh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_deposit_cancel (cmd->details.deposit.dh);
- cmd->details.deposit.dh = NULL;
- }
- break;
- case OC_REFRESH_MELT:
- if (NULL != cmd->details.refresh_melt.rmh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_refresh_melt_cancel (cmd->details.refresh_melt.rmh);
- cmd->details.refresh_melt.rmh = NULL;
- }
- GNUNET_free_non_null (cmd->details.refresh_melt.fresh_pks);
- cmd->details.refresh_melt.fresh_pks = NULL;
- GNUNET_free_non_null (cmd->details.refresh_melt.refresh_data);
- cmd->details.refresh_melt.refresh_data = NULL;
- cmd->details.refresh_melt.refresh_data_length = 0;
- break;
- case OC_REFRESH_REVEAL:
- if (NULL != cmd->details.refresh_reveal.rrh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_refresh_reveal_cancel (cmd->details.refresh_reveal.rrh);
- cmd->details.refresh_reveal.rrh = NULL;
- }
- {
- unsigned int j;
- struct FreshCoin *fresh_coins;
-
- fresh_coins = cmd->details.refresh_reveal.fresh_coins;
- for (j=0;j<cmd->details.refresh_reveal.num_fresh_coins;j++)
- GNUNET_CRYPTO_rsa_signature_free (fresh_coins[j].sig.rsa_signature);
- }
- GNUNET_free_non_null (cmd->details.refresh_reveal.fresh_coins);
- cmd->details.refresh_reveal.fresh_coins = NULL;
- cmd->details.refresh_reveal.num_fresh_coins = 0;
- break;
- case OC_REFRESH_LINK:
- if (NULL != cmd->details.refresh_link.rlh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_refresh_link_cancel (cmd->details.refresh_link.rlh);
- cmd->details.refresh_link.rlh = NULL;
- }
- break;
- case OC_WIRE:
- if (NULL != cmd->details.wire.wh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_wire_cancel (cmd->details.wire.wh);
- cmd->details.wire.wh = NULL;
- }
- break;
- case OC_WIRE_DEPOSITS:
- if (NULL != cmd->details.wire_deposits.wdh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_wire_deposits_cancel (cmd->details.wire_deposits.wdh);
- cmd->details.wire_deposits.wdh = NULL;
- }
- break;
- case OC_DEPOSIT_WTID:
- if (NULL != cmd->details.deposit_wtid.dwh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_MINT_deposit_wtid_cancel (cmd->details.deposit_wtid.dwh);
- cmd->details.deposit_wtid.dwh = NULL;
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown instruction %d at %u (%s)\n",
- cmd->oc,
- i,
- cmd->label);
- break;
- }
- }
- if (NULL != is->task)
- {
- GNUNET_SCHEDULER_cancel (is->task);
- is->task = NULL;
- }
- GNUNET_free (is);
- if (NULL != ctx_task)
- {
- GNUNET_SCHEDULER_cancel (ctx_task);
- ctx_task = NULL;
- }
- if (NULL != mint)
- {
- TALER_MINT_disconnect (mint);
- mint = NULL;
- }
- if (NULL != ctx)
- {
- TALER_MINT_fini (ctx);
- ctx = NULL;
- }
-}
-
-
-/**
- * Functions of this type are called to provide the retrieved signing and
- * denomination keys of the mint. No TALER_MINT_*() functions should be called
- * in this callback.
- *
- * @param cls closure
- * @param keys information about keys of the mint
- */
-static void
-cert_cb (void *cls,
- const struct TALER_MINT_Keys *keys)
-{
- struct InterpreterState *is = cls;
-
- /* check that keys is OK */
-#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); GNUNET_SCHEDULER_shutdown(); return; } while (0)
- ERR (NULL == keys);
- ERR (0 == keys->num_sign_keys);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Read %u signing keys\n",
- keys->num_sign_keys);
- ERR (0 == keys->num_denom_keys);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Read %u denomination keys\n",
- keys->num_denom_keys);
-#undef ERR
-
- /* run actual tests via interpreter-loop */
- is->keys = keys;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Task that runs the context's event loop with the GNUnet scheduler.
- *
- * @param cls unused
- * @param tc scheduler context (unused)
- */
-static void
-context_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- long timeout;
- int max_fd;
- fd_set read_fd_set;
- fd_set write_fd_set;
- fd_set except_fd_set;
- struct GNUNET_NETWORK_FDSet *rs;
- struct GNUNET_NETWORK_FDSet *ws;
- struct GNUNET_TIME_Relative delay;
-
- ctx_task = NULL;
- TALER_MINT_perform (ctx);
- max_fd = -1;
- timeout = -1;
- FD_ZERO (&read_fd_set);
- FD_ZERO (&write_fd_set);
- FD_ZERO (&except_fd_set);
- TALER_MINT_get_select_info (ctx,
- &read_fd_set,
- &write_fd_set,
- &except_fd_set,
- &max_fd,
- &timeout);
- if (timeout >= 0)
- delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
- timeout);
- else
- delay = GNUNET_TIME_UNIT_FOREVER_REL;
- rs = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_copy_native (rs,
- &read_fd_set,
- max_fd + 1);
- ws = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_copy_native (ws,
- &write_fd_set,
- max_fd + 1);
- ctx_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- delay,
- rs,
- ws,
- &context_task,
- cls);
- GNUNET_NETWORK_fdset_destroy (rs);
- GNUNET_NETWORK_fdset_destroy (ws);
-}
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param config configuration
- */
-static void
-run (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct InterpreterState *is;
- static struct MeltDetails melt_coins_1[] = {
- { .amount = "EUR:4",
- .coin_ref = "refresh-withdraw-coin-1" },
- { NULL, NULL }
- };
- static const char *melt_fresh_amounts_1[] = {
- "EUR:1",
- "EUR:1",
- "EUR:1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.1",
- "EUR:0.01",
- "EUR:0.01",
- "EUR:0.01",
- "EUR:0.01",
- "EUR:0.01",
- "EUR:0.01",
- /* with 0.01 withdraw fees (except for 1ct coins),
- this totals up to exactly EUR:3.97, and with
- the 0.03 refresh fee, to EUR:4.0*/
- NULL
- };
- static struct Command commands[] =
- {
- /* *************** start of /wire testing ************** */
-
-#if WIRE_TEST
- { .oc = OC_WIRE,
- .label = "wire-test",
- /* /wire/test replies with a 302 redirect */
- .expected_response_code = MHD_HTTP_FOUND,
- .details.wire.format = "test" },
-#endif
-#if WIRE_SEPA
- { .oc = OC_WIRE,
- .label = "wire-sepa",
- /* /wire/sepa replies with a 200 redirect */
- .expected_response_code = MHD_HTTP_OK,
- .details.wire.format = "sepa" },
-#endif
- /* *************** end of /wire testing ************** */
-
-#if WIRE_TEST
- /* None of this works if 'test' is not allowed as we do
- /admin/add/incoming with format 'test' */
-
- /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "create-reserve-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":42 }",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "withdraw-coin-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "create-reserve-1",
- .details.reserve_withdraw.amount = "EUR:5" },
- /* Check that deposit and withdraw operation are in history, and
- that the balance is now at zero */
- { .oc = OC_WITHDRAW_STATUS,
- .label = "withdraw-status-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_status.reserve_reference = "create-reserve-1",
- .details.reserve_status.expected_balance = "EUR:0" },
- /* Try to deposit the 5 EUR coin (in full) */
- { .oc = OC_DEPOSIT,
- .label = "deposit-simple",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:5",
- .details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
- .details.deposit.transaction_id = 1 },
-
- /* Try to overdraw funds ... */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "withdraw-coin-2",
- .expected_response_code = MHD_HTTP_PAYMENT_REQUIRED,
- .details.reserve_withdraw.reserve_reference = "create-reserve-1",
- .details.reserve_withdraw.amount = "EUR:5" },
-
- /* Try to double-spend the 5 EUR coin with different wire details */
- { .oc = OC_DEPOSIT,
- .label = "deposit-double-1",
- .expected_response_code = MHD_HTTP_FORBIDDEN,
- .details.deposit.amount = "EUR:5",
- .details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":43 }",
- .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
- .details.deposit.transaction_id = 1 },
- /* Try to double-spend the 5 EUR coin at the same merchant (but different
- transaction ID) */
- { .oc = OC_DEPOSIT,
- .label = "deposit-double-2",
- .expected_response_code = MHD_HTTP_FORBIDDEN,
- .details.deposit.amount = "EUR:5",
- .details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
- .details.deposit.transaction_id = 2 },
- /* Try to double-spend the 5 EUR coin at the same merchant (but different
- contract) */
- { .oc = OC_DEPOSIT,
- .label = "deposit-double-3",
- .expected_response_code = MHD_HTTP_FORBIDDEN,
- .details.deposit.amount = "EUR:5",
- .details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }",
- .details.deposit.transaction_id = 1 },
-
- /* ***************** /refresh testing ******************** */
-
- /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "refresh-create-reserve-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":424 }",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "refresh-withdraw-coin-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "refresh-create-reserve-1",
- .details.reserve_withdraw.amount = "EUR:5" },
- /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
- (merchant would receive EUR:0.99 due to 1 ct deposit fee) */
- { .oc = OC_DEPOSIT,
- .label = "refresh-deposit-partial",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:1",
- .details.deposit.coin_ref = "refresh-withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }",
- .details.deposit.transaction_id = 42421 },
-
- /* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
-
- { .oc = OC_REFRESH_MELT,
- .label = "refresh-melt-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.refresh_melt.melted_coins = melt_coins_1,
- .details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
-
-
- /* Complete (successful) melt operation, and withdraw the coins */
- { .oc = OC_REFRESH_REVEAL,
- .label = "refresh-reveal-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.refresh_reveal.melt_ref = "refresh-melt-1" },
-
- /* Test that /refresh/link works */
- { .oc = OC_REFRESH_LINK,
- .label = "refresh-link-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.refresh_link.reveal_ref = "refresh-reveal-1" },
-
-
- /* Test successfully spending coins from the refresh operation:
- first EUR:1 */
- { .oc = OC_DEPOSIT,
- .label = "refresh-deposit-refreshed-1a",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:1",
- .details.deposit.coin_ref = "refresh-reveal-1",
- .details.deposit.coin_idx = 0,
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
- .details.deposit.transaction_id = 2 },
-
- /* Test successfully spending coins from the refresh operation:
- finally EUR:0.1 */
- { .oc = OC_DEPOSIT,
- .label = "refresh-deposit-refreshed-1b",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:0.1",
- .details.deposit.coin_ref = "refresh-reveal-1",
- .details.deposit.coin_idx = 4,
- .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
- .details.deposit.transaction_id = 2 },
-
- /* Test running a failing melt operation (same operation again must fail) */
- { .oc = OC_REFRESH_MELT,
- .label = "refresh-melt-failing",
- .expected_response_code = MHD_HTTP_FORBIDDEN,
- .details.refresh_melt.melted_coins = melt_coins_1,
- .details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
-
- // FIXME: also test with coin that was already melted
- // (signature differs from coin that was deposited...)
- /* *************** end of /refresh testing ************** */
-
- /* ************** Test tracking API ******************** */
- /* Try resolving a deposit's WTID, as we never triggered
- execution of transactions, the answer should be that
- the mint knows about the deposit, but has no WTID yet. */
- { .oc = OC_DEPOSIT_WTID,
- .label = "deposit-wtid-found",
- .expected_response_code = MHD_HTTP_ACCEPTED,
- .details.deposit_wtid.deposit_ref = "deposit-simple" },
- /* Try resolving a deposit's WTID for a failed deposit.
- As the deposit failed, the answer should be that
- the mint does NOT know about the deposit. */
- { .oc = OC_DEPOSIT_WTID,
- .label = "deposit-wtid-failing",
- .expected_response_code = MHD_HTTP_NOT_FOUND,
- .details.deposit_wtid.deposit_ref = "deposit-double-2" },
- /* Try resolving an undefined (all zeros) WTID; this
- should fail as obviously the mint didn't use that
- WTID value for any transaction. */
- { .oc = OC_WIRE_DEPOSITS,
- .label = "wire-deposit-failing",
- .expected_response_code = MHD_HTTP_NOT_FOUND },
-
- /* TODO: trigger aggregation logic and then check the
- cases where tracking succeeds! */
-
- /* ************** End of tracking API testing************* */
-
-
-#endif
-
- { .oc = OC_END }
- };
-
- is = GNUNET_new (struct InterpreterState);
- is->commands = commands;
-
- ctx = TALER_MINT_init ();
- GNUNET_assert (NULL != ctx);
- ctx_task = GNUNET_SCHEDULER_add_now (&context_task,
- ctx);
- mint = TALER_MINT_connect (ctx,
- "http://localhost:8081",
- &cert_cb, is,
- TALER_MINT_OPTION_END);
- GNUNET_assert (NULL != mint);
- shutdown_task
- = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 150),
- &do_shutdown, is);
-}
-
-
-/**
- * Main function for the testcase for the mint API.
- *
- * @param argc expected to be 1
- * @param argv expected to only contain the program name
- */
-int
-main (int argc,
- char * const *argv)
-{
- struct GNUNET_OS_Process *proc;
- struct GNUNET_OS_Process *mintd;
-
- GNUNET_log_setup ("test-mint-api",
- "WARNING",
- NULL);
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-mint-keyup",
- "taler-mint-keyup",
- "-d", "test-mint-home",
- "-m", "test-mint-home/master.priv",
- NULL);
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
- mintd = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-mint-httpd",
- "taler-mint-httpd",
- "-d", "test-mint-home",
- NULL);
- /* give child time to start and bind against the socket */
- fprintf (stderr, "Waiting for taler-mint-httpd to be ready");
- do
- {
- fprintf (stderr, ".");
- sleep (1);
- }
- while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
- fprintf (stderr, "\n");
- result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_run (&run, NULL);
- GNUNET_OS_process_kill (mintd,
- SIGTERM);
- GNUNET_OS_process_wait (mintd);
- GNUNET_OS_process_destroy (mintd);
- return (GNUNET_OK == result) ? 0 : 1;
-}
-
-/* end of test_mint_api.c */
diff --git a/src/mint-tools/Makefile.am b/src/mint-tools/Makefile.am
deleted file mode 100644
index 94b8fb391..000000000
--- a/src/mint-tools/Makefile.am
+++ /dev/null
@@ -1,81 +0,0 @@
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
-if USE_COVERAGE
- AM_CFLAGS = --coverage -O0
- XLIB = -lgcov
-endif
-
-bin_PROGRAMS = \
- taler-auditor-sign \
- taler-mint-keyup \
- taler-mint-keycheck \
- taler-mint-reservemod \
- taler-mint-sepa \
- taler-mint-dbinit
-
-taler_mint_keyup_SOURCES = \
- taler-mint-keyup.c
-taler_mint_keyup_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/pq/libtalerpq.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -lgnunetutil $(XLIB)
-taler_mint_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS)
-
-taler_auditor_sign_SOURCES = \
- taler-auditor-sign.c
-taler_auditor_sign_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -lgnunetutil $(XLIB)
-
-
-taler_mint_sepa_SOURCES = \
- taler-mint-sepa.c
-taler_mint_sepa_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetutil -ljansson $(XLIB)
-taler_mint_sepa_LDFLAGS = $(POSTGRESQL_LDFLAGS)
-
-taler_mint_keycheck_SOURCES = \
- taler-mint-keycheck.c
-taler_mint_keycheck_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -lgnunetutil $(XLIB)
-taler_mint_keycheck_LDFLAGS = $(POSTGRESQL_LDFLAGS)
-
-taler_mint_reservemod_SOURCES = \
- taler-mint-reservemod.c
-taler_mint_reservemod_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/pq/libtalerpq.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -lgnunetutil -ljansson $(XLIB)
-taler_mint_reservemod_LDFLAGS = \
- $(POSTGRESQL_LDFLAGS)
-taler_mint_reservemod_CPPFLAGS = \
- -I$(top_srcdir)/src/include \
- -I$(top_srcdir)/src/pq/ \
- $(POSTGRESQL_CPPFLAGS)
-
-taler_mint_dbinit_SOURCES = \
- taler-mint-dbinit.c
-taler_mint_dbinit_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/pq/libtalerpq.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -lgnunetutil $(XLIB)
-taler_mint_dbinit_LDFLAGS = \
- $(POSTGRESQL_LDFLAGS)
-taler_mint_dbinit_CPPFLAGS = \
- -I$(top_srcdir)/src/include \
- -I$(top_srcdir)/src/pq/ \
- $(POSTGRESQL_CPPFLAGS)
diff --git a/src/mint-tools/taler-auditor-sign.c b/src/mint-tools/taler-auditor-sign.c
deleted file mode 100644
index 7e6d3b12a..000000000
--- a/src/mint-tools/taler-auditor-sign.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-auditor-sign.c
- * @brief Tool used by the auditor to sign the mint's master key and the
- * denomination key(s).
- * @author Christian Grothoff
- */
-#include <platform.h>
-#include "taler_mintdb_lib.h"
-
-
-/**
- * Are we running in verbose mode?
- */
-static int verbose;
-
-/**
- * Filename of the auditor's private key.
- */
-static char *auditor_key_file;
-
-/**
- * Mint's public key (in Crockford base32 encoding).
- */
-static char *mint_public_key;
-
-/**
- * File with the Mint's denomination keys to sign, itself
- * signed by the Mint's public key.
- */
-static char *mint_request_file;
-
-/**
- * Where should we write the auditor's signature?
- */
-static char *output_file;
-
-/**
- * Master public key of the mint.
- */
-static struct TALER_MasterPublicKeyP master_public_key;
-
-
-/**
- * Print denomination key details for diagnostics.
- *
- * @param dk denomination key to print
- */
-static void
-print_dk (const struct TALER_DenominationKeyValidityPS *dk)
-{
- struct TALER_Amount a;
- char *s;
-
- fprintf (stdout,
- "Denomination key hash: %s\n",
- GNUNET_h2s_full (&dk->denom_hash));
- TALER_amount_ntoh (&a,
- &dk->value);
- fprintf (stdout,
- "Value: %s\n",
- s = TALER_amount_to_string (&a));
- GNUNET_free (s);
- TALER_amount_ntoh (&a,
- &dk->fee_withdraw);
- fprintf (stdout,
- "Withdraw fee: %s\n",
- s = TALER_amount_to_string (&a));
- GNUNET_free (s);
- TALER_amount_ntoh (&a,
- &dk->fee_deposit);
- fprintf (stdout,
- "Deposit fee: %s\n",
- s = TALER_amount_to_string (&a));
- GNUNET_free (s);
- TALER_amount_ntoh (&a,
- &dk->fee_refresh);
- fprintf (stdout,
- "Refresh fee: %s\n",
- s = TALER_amount_to_string (&a));
- GNUNET_free (s);
-
- fprintf (stdout,
- "Validity start time: %s\n",
- GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->start)));
- fprintf (stdout,
- "Withdraw end time: %s\n",
- GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_withdraw)));
- fprintf (stdout,
- "Deposit end time: %s\n",
- GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_spend)));
- fprintf (stdout,
- "Legal dispute end time: %s\n",
- GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_legal)));
-
- fprintf (stdout,
- "\n");
-}
-
-
-/**
- * The main function of the taler-auditor-sign tool. This tool is used
- * to sign a mint's master and denomination keys, affirming that the
- * auditor is aware of them and will validate the mint's database with
- * respect to these keys.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc,
- char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'a', "auditor-key", "FILE",
- "file containing the private key of the auditor", 1,
- &GNUNET_GETOPT_set_filename, &auditor_key_file},
- TALER_GETOPT_OPTION_HELP ("Private key of the auditor to use for signing"),
- {'m', "mint-key", "KEY",
- "public key of the mint (Crockford base32 encoded)", 1,
- &GNUNET_GETOPT_set_filename, &mint_public_key},
- {'r', "mint-request", "FILE",
- "set of keys the mint requested the auditor to sign", 1,
- &GNUNET_GETOPT_set_string, &mint_request_file},
- {'o', "output", "FILE",
- "where to write our signature", 1,
- &GNUNET_GETOPT_set_string, &output_file},
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
- GNUNET_GETOPT_OPTION_END
- };
- struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
- struct TALER_AuditorSignatureP *sigs;
- struct TALER_AuditorPublicKeyP apub;
- struct GNUNET_DISK_FileHandle *fh;
- struct TALER_DenominationKeyValidityPS *dks;
- unsigned int dks_len;
- struct TALER_MintKeyValidityPS kv;
- off_t in_size;
- unsigned int i;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-keyup",
- "WARNING",
- NULL));
- if (GNUNET_GETOPT_run ("taler-mint-keyup",
- options,
- argc, argv) < 0)
- return 1;
- if (NULL == auditor_key_file)
- {
- fprintf (stderr,
- "Auditor key file not given\n");
- return 1;
- }
- eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (auditor_key_file);
- if (NULL == eddsa_priv)
- {
- fprintf (stderr,
- "Failed to initialize auditor key from file `%s'\n",
- auditor_key_file);
- return 1;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (eddsa_priv,
- &apub.eddsa_pub);
- if (NULL == mint_public_key)
- {
- fprintf (stderr,
- "Mint public key not given\n");
- GNUNET_free (eddsa_priv);
- return 1;
- }
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (mint_public_key,
- strlen (mint_public_key),
- &master_public_key,
- sizeof (master_public_key)))
- {
- fprintf (stderr,
- "Public key `%s' malformed\n",
- mint_public_key);
- GNUNET_free (eddsa_priv);
- return 1;
- }
- if (NULL == mint_request_file)
- {
- fprintf (stderr,
- "Mint signing request not given\n");
- GNUNET_free (eddsa_priv);
- return 1;
- }
- fh = GNUNET_DISK_file_open (mint_request_file,
- GNUNET_DISK_OPEN_READ,
- GNUNET_DISK_PERM_NONE);
- if (NULL == fh)
- {
- fprintf (stderr,
- "Failed to open file `%s': %s\n",
- mint_request_file,
- STRERROR (errno));
- GNUNET_free (eddsa_priv);
- return 1;
- }
- if (GNUNET_OK !=
- GNUNET_DISK_file_handle_size (fh,
- &in_size))
- {
- fprintf (stderr,
- "Failed to obtain input file size `%s': %s\n",
- mint_request_file,
- STRERROR (errno));
- GNUNET_DISK_file_close (fh);
- GNUNET_free (eddsa_priv);
- return 1;
- }
- if (0 != (in_size % sizeof (struct TALER_DenominationKeyValidityPS)))
- {
- fprintf (stderr,
- "Input file size of file `%s' is invalid\n",
- mint_request_file);
- GNUNET_DISK_file_close (fh);
- GNUNET_free (eddsa_priv);
- return 1;
- }
- dks_len = in_size / sizeof (struct TALER_DenominationKeyValidityPS);
- kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_MINT_KEYS);
- kv.purpose.size = htonl (sizeof (struct TALER_MintKeyValidityPS));
- kv.master = master_public_key;
- dks = GNUNET_new_array (dks_len,
- struct TALER_DenominationKeyValidityPS);
- sigs = GNUNET_new_array (dks_len,
- struct TALER_AuditorSignatureP);
- if (in_size !=
- GNUNET_DISK_file_read (fh,
- dks,
- in_size))
- {
- fprintf (stderr,
- "Failed to read input file `%s': %s\n",
- mint_request_file,
- STRERROR (errno));
- GNUNET_DISK_file_close (fh);
- GNUNET_free (sigs);
- GNUNET_free (dks);
- GNUNET_free (eddsa_priv);
- return 1;
- }
- GNUNET_DISK_file_close (fh);
- for (i=0;i<dks_len;i++)
- {
- struct TALER_DenominationKeyValidityPS *dk = &dks[i];
-
- if (verbose)
- print_dk (dk);
- kv.start = dk->start;
- kv.expire_withdraw = dk->expire_withdraw;
- kv.expire_spend = dk->expire_spend;
- kv.expire_legal = dk->expire_legal;
- kv.value = dk->value;
- kv.fee_withdraw = dk->fee_withdraw;
- kv.fee_deposit = dk->fee_deposit;
- kv.fee_refresh = dk->fee_refresh;
- kv.denom_hash = dk->denom_hash;
-
- /* Finally sign ... */
- GNUNET_CRYPTO_eddsa_sign (eddsa_priv,
- &kv.purpose,
- &sigs[i].eddsa_sig);
-
-
- }
-
- if (NULL == output_file)
- {
- fprintf (stderr,
- "Output file not given\n");
- GNUNET_free (dks);
- GNUNET_free (sigs);
- GNUNET_free (eddsa_priv);
- return 1;
- }
-
- /* write result to disk */
- if (GNUNET_OK !=
- TALER_MINTDB_auditor_write (output_file,
- &apub,
- sigs,
- &master_public_key,
- dks_len,
- dks))
- {
- fprintf (stderr,
- "Failed to write to file `%s': %s\n",
- output_file,
- STRERROR (errno));
- GNUNET_free (sigs);
- GNUNET_free (dks);
- return 1;
- }
- GNUNET_free (sigs);
- GNUNET_free (dks);
- GNUNET_free (eddsa_priv);
- return 0;
-}
-
-/* end of taler-auditor-sign.c */
diff --git a/src/mint-tools/taler-mint-dbinit.c b/src/mint-tools/taler-mint-dbinit.c
deleted file mode 100644
index 2d9f77764..000000000
--- a/src/mint-tools/taler-mint-dbinit.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-tools/taler-mint-dbinit.c
- * @brief Create tables for the mint database.
- * @author Florian Dold
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <libpq-fe.h>
-#include "taler_mintdb_plugin.h"
-
-/**
- * Mint directory with the keys.
- */
-static char *mint_base_dir;
-
-/**
- * Our configuration.
- */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Our DB plugin.
- */
-static struct TALER_MINTDB_Plugin *plugin;
-
-
-/**
- * The main function of the database initialization tool.
- * Used to initialize the Taler Mint's database.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc,
- char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'d', "mint-dir", "DIR",
- "mint directory", 1,
- &GNUNET_GETOPT_set_filename, &mint_base_dir},
- GNUNET_GETOPT_OPTION_HELP ("Initialize Taler Mint database"),
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
-
- if (GNUNET_GETOPT_run ("taler-mint-dbinit",
- options,
- argc, argv) < 0)
- return 1;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-dbinit",
- "INFO",
- NULL));
- if (NULL == mint_base_dir)
- {
- fprintf (stderr,
- "Mint base directory not given.\n");
- return 1;
- }
- cfg = TALER_config_load (mint_base_dir);
- if (NULL == cfg)
- {
- fprintf (stderr,
- "Failed to load mint configuration.\n");
- return 1;
- }
- if (NULL ==
- (plugin = TALER_MINTDB_plugin_load (cfg)))
- {
- fprintf (stderr,
- "Failed to initialize database plugin.\n");
- return 1;
- }
- if (GNUNET_OK !=
- plugin->create_tables (plugin->cls,
- GNUNET_NO))
- {
- fprintf (stderr,
- "Failed to initialize database.\n");
- TALER_MINTDB_plugin_unload (plugin);
- return 1;
- }
- TALER_MINTDB_plugin_unload (plugin);
- return 0;
-}
-
-/* end of taler-mint-dbinit.c */
diff --git a/src/mint-tools/taler-mint-keycheck.c b/src/mint-tools/taler-mint-keycheck.c
deleted file mode 100644
index 4fa2707f8..000000000
--- a/src/mint-tools/taler-mint-keycheck.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-keycheck.c
- * @brief Check mint keys for validity. Reads the signing and denomination
- * keys from the mint directory and checks to make sure they are
- * well-formed. This is purely a diagnostic tool.
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include <platform.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mintdb_lib.h"
-
-/**
- * Mint directory with the keys.
- */
-static char *mint_directory;
-
-/**
- * Our configuration.
- */
-static struct GNUNET_CONFIGURATION_Handle *kcfg;
-
-
-/**
- * Function called on each signing key.
- *
- * @param cls closure (NULL)
- * @param filename name of the file the key came from
- * @param ski the sign key
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-signkeys_iter (void *cls,
- const char *filename,
- const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Iterating over key `%s' for start time %s\n",
- filename,
- GNUNET_STRINGS_absolute_time_to_string
- (GNUNET_TIME_absolute_ntoh (ski->issue.start)));
-
- if (ntohl (ski->issue.purpose.size) !=
- (sizeof (struct TALER_MintSigningKeyValidityPS) -
- offsetof (struct TALER_MintSigningKeyValidityPS,
- purpose)))
- {
- fprintf (stderr,
- "Signing key `%s' has invalid purpose size\n",
- filename);
- return GNUNET_SYSERR;
- }
- if ( (0 != GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us % 1000000) ||
- (0 != GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us % 1000000) ||
- (0 != GNUNET_TIME_absolute_ntoh (ski->issue.end).abs_value_us % 1000000) )
- {
- fprintf (stderr,
- "Timestamps are not multiples of a round second\n");
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
- &ski->issue.purpose,
- &ski->issue.signature.eddsa_signature,
- &ski->issue.master_public_key.eddsa_pub))
- {
- fprintf (stderr,
- "Signing key `%s' has invalid signature\n",
- filename);
- return GNUNET_SYSERR;
- }
- printf ("Signing key `%s' valid\n",
- filename);
- return GNUNET_OK;
-}
-
-
-/**
- * Check signing keys.
- *
- * @return #GNUNET_OK if the keys are OK
- * #GNUNET_NO if not
- */
-static int
-mint_signkeys_check ()
-{
- if (0 > TALER_MINTDB_signing_keys_iterate (mint_directory,
- &signkeys_iter,
- NULL))
- return GNUNET_NO;
- return GNUNET_OK;
-}
-
-
-/**
- * Function called on each denomination key.
- *
- * @param cls closure (NULL)
- * @param dki the denomination key
- * @param alias coin alias
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-denomkeys_iter (void *cls,
- const char *alias,
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- struct GNUNET_HashCode hc;
-
- if (ntohl (dki->issue.properties.purpose.size) !=
- sizeof (struct TALER_DenominationKeyValidityPS))
- {
- fprintf (stderr,
- "Denomination key for `%s' has invalid purpose size\n",
- alias);
- return GNUNET_SYSERR;
- }
-
- if ( (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us % 1000000) ||
- (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us % 1000000) ||
- (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_legal).abs_value_us % 1000000) ||
- (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us % 1000000) )
- {
- fprintf (stderr,
- "Timestamps are not multiples of a round second\n");
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
- &dki->issue.properties.purpose,
- &dki->issue.signature.eddsa_signature,
- &dki->issue.properties.master.eddsa_pub))
- {
- fprintf (stderr,
- "Denomination key for `%s' has invalid signature\n",
- alias);
- return GNUNET_SYSERR;
- }
- GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
- &hc);
- if (0 != memcmp (&hc,
- &dki->issue.properties.denom_hash,
- sizeof (struct GNUNET_HashCode)))
- {
- fprintf (stderr,
- "Public key for `%s' does not match signature\n",
- alias);
- return GNUNET_SYSERR;
- }
- printf ("Denomination key `%s' is valid\n",
- alias);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Check denomination keys.
- *
- * @return #GNUNET_OK if the keys are OK
- * #GNUNET_NO if not
- */
-static int
-mint_denomkeys_check ()
-{
- if (0 > TALER_MINTDB_denomination_keys_iterate (mint_directory,
- &denomkeys_iter,
- NULL))
- return GNUNET_NO;
- return GNUNET_OK;
-}
-
-
-/**
- * The main function of the keyup tool
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc, char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keycheck OPTIONS"),
- {'d', "directory", "DIRECTORY",
- "mint directory with keys to check", 1,
- &GNUNET_GETOPT_set_filename, &mint_directory},
- GNUNET_GETOPT_OPTION_END
- };
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-keycheck",
- "WARNING",
- NULL));
-
- if (GNUNET_GETOPT_run ("taler-mint-keycheck",
- options,
- argc, argv) < 0)
- return 1;
- if (NULL == mint_directory)
- {
- fprintf (stderr,
- "Mint directory not given\n");
- return 1;
- }
-
- kcfg = TALER_config_load (mint_directory);
- if (NULL == kcfg)
- {
- fprintf (stderr,
- "Failed to load mint configuration\n");
- return 1;
- }
- if ( (GNUNET_OK != mint_signkeys_check ()) ||
- (GNUNET_OK != mint_denomkeys_check ()) )
- {
- GNUNET_CONFIGURATION_destroy (kcfg);
- return 1;
- }
- GNUNET_CONFIGURATION_destroy (kcfg);
- return 0;
-}
-
-/* end of taler-mint-keycheck.c */
diff --git a/src/mint-tools/taler-mint-keyup.c b/src/mint-tools/taler-mint-keyup.c
deleted file mode 100644
index b82554b94..000000000
--- a/src/mint-tools/taler-mint-keyup.c
+++ /dev/null
@@ -1,1039 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-keyup.c
- * @brief Update the mint's keys for coins and signatures,
- * using the mint's offline master key.
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include <platform.h>
-#include "taler_mintdb_lib.h"
-
-/**
- * When generating filenames from a cryptographic hash, we do not use
- * all 512 bits but cut off after this number of characters (in
- * base32-encoding). Base32 is 5 bit per character, and given that we
- * have very few coin types we hash, at 100 bits the chance of
- * collision (by accident over tiny set -- birthday paradox does not
- * apply here!) is negligible.
- */
-#define HASH_CUTOFF 20
-
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * Struct with all of the key information for a kind of coin. Hashed
- * to generate a unique directory name per coin type.
- */
-struct CoinTypeNBOP
-{
- /**
- * How long are the signatures legally valid?
- */
- struct GNUNET_TIME_RelativeNBO duration_legal;
-
- /**
- * How long can the coin be spend?
- */
- struct GNUNET_TIME_RelativeNBO duration_spend;
-
- /**
- * How long can the coin be withdrawn (generated)?
- */
- struct GNUNET_TIME_RelativeNBO duration_withdraw;
-
- /**
- * What is the value of the coin?
- */
- struct TALER_AmountNBO value;
-
- /**
- * What is the fee charged for withdrawl?
- */
- struct TALER_AmountNBO fee_withdraw;
-
- /**
- * What is the fee charged for deposits?
- */
- struct TALER_AmountNBO fee_deposit;
-
- /**
- * What is the fee charged for melting?
- */
- struct TALER_AmountNBO fee_refresh;
-
- /**
- * Key size in NBO.
- */
- uint32_t rsa_keysize;
-};
-
-GNUNET_NETWORK_STRUCT_END
-
-/**
- * Set of all of the parameters that chracterize a coin.
- */
-struct CoinTypeParams
-{
-
- /**
- * How long are the signatures legally valid? Should be
- * significantly larger than @e duration_spend (i.e. years).
- */
- struct GNUNET_TIME_Relative duration_legal;
-
-
- /**
- * How long can the coin be spend? Should be significantly
- * larger than @e duration_withdraw (i.e. years).
- */
- struct GNUNET_TIME_Relative duration_spend;
-
- /**
- * How long can the coin be withdrawn (generated)? Should be small
- * enough to limit how many coins will be signed into existence with
- * the same key, but large enough to still provide a reasonable
- * anonymity set.
- */
- struct GNUNET_TIME_Relative duration_withdraw;
-
- /**
- * How much should coin creation (@e duration_withdraw) duration
- * overlap with the next coin? Basically, the starting time of two
- * coins is always @e duration_withdraw - @e duration_overlap apart.
- */
- struct GNUNET_TIME_Relative duration_overlap;
-
- /**
- * What is the value of the coin?
- */
- struct TALER_Amount value;
-
- /**
- * What is the fee charged for withdrawl?
- */
- struct TALER_Amount fee_withdraw;
-
- /**
- * What is the fee charged for deposits?
- */
- struct TALER_Amount fee_deposit;
-
- /**
- * What is the fee charged for melting?
- */
- struct TALER_Amount fee_refresh;
-
- /**
- * Time at which this coin is supposed to become valid.
- */
- struct GNUNET_TIME_Absolute anchor;
-
- /**
- * Length of the RSA key in bits.
- */
- uint32_t rsa_keysize;
-};
-
-
-/**
- * Filename of the master private key.
- */
-static char *masterkeyfile;
-
-/**
- * Filename where to write denomination key signing
- * requests for the auditor (optional, can be NULL).
- */
-static char *auditorrequestfile;
-
-/**
- * Handle for writing the output for the auditor.
- */
-static FILE *auditor_output_file;
-
-/**
- * Director of the mint, containing the keys.
- */
-static char *mint_directory;
-
-/**
- * Time to pretend when the key update is executed.
- */
-static char *pretend_time_str;
-
-/**
- * Handle to the mint's configuration
- */
-static struct GNUNET_CONFIGURATION_Handle *kcfg;
-
-/**
- * Time when the key update is executed. Either the actual current time, or a
- * pretended time.
- */
-static struct GNUNET_TIME_Absolute now;
-
-/**
- * Master private key of the mint.
- */
-static struct TALER_MasterPrivateKeyP master_priv;
-
-/**
- * Master public key of the mint.
- */
-static struct TALER_MasterPublicKeyP master_public_key;
-
-/**
- * Until what time do we provide keys?
- */
-static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
-
-
-/**
- * Obtain the name of the directory we use to store signing
- * keys created at time @a start.
- *
- * @param start time at which we create the signing key
- * @return name of the directory we should use, basically "$MINTDIR/$TIME/";
- * (valid until next call to this function)
- */
-static const char *
-get_signkey_file (struct GNUNET_TIME_Absolute start)
-{
- static char dir[4096];
-
- GNUNET_snprintf (dir,
- sizeof (dir),
- "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_SIGNING_KEYS DIR_SEPARATOR_STR "%llu",
- mint_directory,
- (unsigned long long) start.abs_value_us);
- return dir;
-}
-
-
-/**
- * Hash the data defining the coin type. Exclude information that may
- * not be the same for all instances of the coin type (i.e. the
- * anchor, overlap).
- *
- * @param p coin parameters to convert to a hash
- * @param[out] hash set to the hash matching @a p
- */
-static void
-hash_coin_type (const struct CoinTypeParams *p,
- struct GNUNET_HashCode *hash)
-{
- struct CoinTypeNBOP p_nbo;
-
- memset (&p_nbo,
- 0,
- sizeof (struct CoinTypeNBOP));
- p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
- p_nbo.duration_legal = GNUNET_TIME_relative_hton (p->duration_legal);
- p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
- TALER_amount_hton (&p_nbo.value,
- &p->value);
- TALER_amount_hton (&p_nbo.fee_withdraw,
- &p->fee_withdraw);
- TALER_amount_hton (&p_nbo.fee_deposit,
- &p->fee_deposit);
- TALER_amount_hton (&p_nbo.fee_refresh,
- &p->fee_refresh);
- p_nbo.rsa_keysize = htonl (p->rsa_keysize);
- GNUNET_CRYPTO_hash (&p_nbo,
- sizeof (struct CoinTypeNBOP),
- hash);
-}
-
-
-/**
- * Obtain the name of the directory we should use to store coins of
- * the given type. The directory name has the format
- * "$MINTDIR/$VALUE/$HASH/" where "$VALUE" represents the value of the
- * coin and "$HASH" encodes all of the coin's parameters, generating a
- * unique string for each type of coin. Note that the "$HASH"
- * includes neither the absolute creation time nor the key of the
- * coin, thus the files in the subdirectory really just refer to the
- * same type of coins, not the same coin.
- *
- * @param p coin parameters to convert to a directory name
- * @return directory name (valid until next call to this function)
- */
-static const char *
-get_cointype_dir (const struct CoinTypeParams *p)
-{
- static char dir[4096];
- struct GNUNET_HashCode hash;
- char *hash_str;
- char *val_str;
- size_t i;
-
- hash_coin_type (p, &hash);
- hash_str = GNUNET_STRINGS_data_to_string_alloc (&hash,
- sizeof (struct GNUNET_HashCode));
- GNUNET_assert (NULL != hash_str);
- GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
- hash_str[HASH_CUTOFF] = 0;
-
- val_str = TALER_amount_to_string (&p->value);
- for (i = 0; i < strlen (val_str); i++)
- if ( (':' == val_str[i]) ||
- ('.' == val_str[i]) )
- val_str[i] = '_';
-
- GNUNET_snprintf (dir,
- sizeof (dir),
- "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR "%s-%s",
- mint_directory,
- val_str,
- hash_str);
- GNUNET_free (hash_str);
- GNUNET_free (val_str);
- return dir;
-}
-
-
-/**
- * Obtain the name of the file we would use to store the key
- * information for a coin of the given type @a p and validity
- * start time @a start
- *
- * @param p parameters for the coin
- * @param start when would the coin begin to be issued
- * @return name of the file to use for this coin
- * (valid until next call to this function)
- */
-static const char *
-get_cointype_file (const struct CoinTypeParams *p,
- struct GNUNET_TIME_Absolute start)
-{
- static char filename[4096];
- const char *dir;
-
- dir = get_cointype_dir (p);
- GNUNET_snprintf (filename,
- sizeof (filename),
- "%s" DIR_SEPARATOR_STR "%llu",
- dir,
- (unsigned long long) start.abs_value_us);
- return filename;
-}
-
-
-/**
- * Get the latest key file from a past run of the key generation
- * tool. Used to calculate the starting time for the keys we
- * generate during this invocation. This function is used to
- * handle both signing keys and coin keys, as in both cases
- * the filenames correspond to the timestamps we need.
- *
- * @param cls closure, a `struct GNUNET_TIME_Absolute *`, updated
- * to contain the highest timestamp (below #now)
- * that was found
- * @param filename complete filename (absolute path)
- * @return #GNUNET_OK (to continue to iterate)
- */
-static int
-get_anchor_iter (void *cls,
- const char *filename)
-{
- struct GNUNET_TIME_Absolute *anchor = cls;
- struct GNUNET_TIME_Absolute stamp;
- const char *base;
- char *end = NULL;
-
- base = GNUNET_STRINGS_get_short_name (filename);
- stamp.abs_value_us = strtol (base,
- &end,
- 10);
- if ((NULL == end) || (0 != *end))
- {
- fprintf(stderr,
- "Ignoring unexpected file `%s'.\n",
- filename);
- return GNUNET_OK;
- }
- *anchor = GNUNET_TIME_absolute_max (stamp,
- *anchor);
- return GNUNET_OK;
-}
-
-
-/**
- * Get the timestamp where the first new key should be generated.
- * Relies on correctly named key files (as we do not parse them,
- * but just look at the filenames to "guess" at their contents).
- *
- * @param dir directory that should contain the existing keys
- * @param duration how long is one key valid (for signing)?
- * @param overlap what's the overlap between the keys validity period?
- * @param[out] anchor the timestamp where the first new key should be generated
- */
-static void
-get_anchor (const char *dir,
- struct GNUNET_TIME_Relative duration,
- struct GNUNET_TIME_Relative overlap,
- struct GNUNET_TIME_Absolute *anchor)
-{
- GNUNET_assert (0 == duration.rel_value_us % 1000000);
- GNUNET_assert (0 == overlap.rel_value_us % 1000000);
- if (GNUNET_YES !=
- GNUNET_DISK_directory_test (dir,
- GNUNET_YES))
- {
- *anchor = now;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "No existing keys found, starting with fresh key set.\n");
- return;
- }
- *anchor = GNUNET_TIME_UNIT_ZERO_ABS;
- if (-1 ==
- GNUNET_DISK_directory_scan (dir,
- &get_anchor_iter,
- anchor))
- {
- *anchor = now;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "No existing keys found, starting with fresh key set.\n");
- return;
- }
-
- if ((GNUNET_TIME_absolute_add (*anchor,
- duration)).abs_value_us < now.abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Existing keys are way too old, starting with fresh key set.\n");
- *anchor = now;
- }
- else if (anchor->abs_value_us != now.abs_value_us)
- {
- /* Real starting time is the last start time + duration - overlap */
- *anchor = GNUNET_TIME_absolute_add (*anchor,
- duration);
- *anchor = GNUNET_TIME_absolute_subtract (*anchor,
- overlap);
- }
- /* anchor is now the stamp where we need to create a new key */
-}
-
-
-/**
- * Create a mint signing key (for signing mint messages, not for coins)
- * and assert its correctness by signing it with the master key.
- *
- * @param start start time of the validity period for the key
- * @param duration how long should the key be valid
- * @param end when do all signatures by this key expire
- * @param[out] pi set to the signing key information
- */
-static void
-create_signkey_issue_priv (struct GNUNET_TIME_Absolute start,
- struct GNUNET_TIME_Relative duration,
- struct GNUNET_TIME_Absolute end,
- struct TALER_MINTDB_PrivateSigningKeyInformationP *pi)
-{
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
- struct TALER_MintSigningKeyValidityPS *issue = &pi->issue;
-
- priv = GNUNET_CRYPTO_eddsa_key_create ();
- pi->signkey_priv.eddsa_priv = *priv;
- GNUNET_free (priv);
- issue->master_public_key = master_public_key;
- issue->start = GNUNET_TIME_absolute_hton (start);
- issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start,
- duration));
- issue->end = GNUNET_TIME_absolute_hton (end);
- GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv.eddsa_priv,
- &issue->signkey_pub.eddsa_pub);
- issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
- issue->purpose.size = htonl (sizeof (struct TALER_MintSigningKeyValidityPS) -
- offsetof (struct TALER_MintSigningKeyValidityPS,
- purpose));
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
- &issue->purpose,
- &issue->signature.eddsa_signature));
-}
-
-
-/**
- * Generate signing keys starting from the last key found to
- * the lookahead time.
- *
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-mint_keys_update_signkeys ()
-{
- struct GNUNET_TIME_Relative signkey_duration;
- struct GNUNET_TIME_Relative legal_duration;
- struct GNUNET_TIME_Absolute anchor;
- char *signkey_dir;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- "mint_keys",
- "signkey_duration",
- &signkey_duration))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint_keys",
- "signkey_duration");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- "mint_keys",
- "legal_duration",
- &legal_duration))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "mint_keys",
- "legal_duration",
- "fails to specify valid timeframe");
- return GNUNET_SYSERR;
- }
- if (signkey_duration.rel_value_us > legal_duration.rel_value_us)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "mint_keys",
- "legal_duration",
- "must be longer than signkey_duration");
- return GNUNET_SYSERR;
- }
- TALER_round_rel_time (&signkey_duration);
- GNUNET_asprintf (&signkey_dir,
- "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_SIGNING_KEYS,
- mint_directory);
- /* make sure the directory exists */
- if (GNUNET_OK !=
- GNUNET_DISK_directory_create (signkey_dir))
- {
- fprintf (stderr,
- "Failed to create signing key directory\n");
- return GNUNET_SYSERR;
- }
-
- get_anchor (signkey_dir,
- signkey_duration,
- GNUNET_TIME_UNIT_ZERO /* no overlap for signing keys */,
- &anchor);
-
- while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
- {
- const char *skf;
- struct TALER_MINTDB_PrivateSigningKeyInformationP signkey_issue;
- ssize_t nwrite;
- struct GNUNET_TIME_Absolute end;
-
- skf = get_signkey_file (anchor);
- end = GNUNET_TIME_absolute_add (anchor,
- legal_duration);
- GNUNET_break (GNUNET_YES !=
- GNUNET_DISK_file_test (skf));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Generating signing key for %s.\n",
- GNUNET_STRINGS_absolute_time_to_string (anchor));
- create_signkey_issue_priv (anchor,
- signkey_duration,
- end,
- &signkey_issue);
- nwrite = GNUNET_DISK_fn_write (skf,
- &signkey_issue,
- sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP),
- GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ);
- if (sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP) != nwrite)
- {
- fprintf (stderr,
- "Failed to write to file `%s': %s\n",
- skf,
- STRERROR (errno));
- return GNUNET_SYSERR;
- }
- anchor = GNUNET_TIME_absolute_add (anchor,
- signkey_duration);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Parse configuration for coin type parameters. Also determines
- * our anchor by looking at the existing coins of the same type.
- *
- * @param ct section in the configuration file giving the coin type parameters
- * @param[out] params set to the coin parameters from the configuration
- * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
- */
-static int
-get_cointype_params (const char *ct,
- struct CoinTypeParams *params)
-{
- const char *dir;
- unsigned long long rsa_keysize;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- ct,
- "duration_withdraw",
- &params->duration_withdraw))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "duration_withdraw");
- return GNUNET_SYSERR;
- }
- TALER_round_rel_time (&params->duration_withdraw);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- ct,
- "duration_spend",
- &params->duration_spend))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "duration_spend");
- return GNUNET_SYSERR;
- }
- TALER_round_rel_time (&params->duration_spend);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- ct,
- "duration_legal",
- &params->duration_legal))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "duration_legal");
- return GNUNET_SYSERR;
- }
- TALER_round_rel_time (&params->duration_legal);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- ct,
- "duration_overlap",
- &params->duration_overlap))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "mint_denom_duration_overlap");
- return GNUNET_SYSERR;
- }
- TALER_round_rel_time (&params->duration_overlap);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (kcfg,
- ct,
- "rsa_keysize",
- &rsa_keysize))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "rsa_keysize");
- return GNUNET_SYSERR;
- }
- if ( (rsa_keysize > 4 * 2048) ||
- (rsa_keysize < 1024) )
- {
- fprintf (stderr,
- "Given RSA keysize %llu outside of permitted range\n",
- rsa_keysize);
- return GNUNET_SYSERR;
- }
- params->rsa_keysize = (unsigned int) rsa_keysize;
- if (GNUNET_OK !=
- TALER_config_get_denom (kcfg,
- ct,
- "value",
- &params->value))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "value");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_config_get_denom (kcfg,
- ct,
- "fee_withdraw",
- &params->fee_withdraw))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "fee_withdraw");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_config_get_denom (kcfg,
- ct,
- "fee_deposit",
- &params->fee_deposit))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "fee_deposit");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_config_get_denom (kcfg,
- ct,
- "fee_refresh",
- &params->fee_refresh))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- ct,
- "fee_refresh");
- return GNUNET_SYSERR;
- }
-
- dir = get_cointype_dir (params);
- get_anchor (dir,
- params->duration_withdraw,
- params->duration_overlap,
- &params->anchor);
- return GNUNET_OK;
-}
-
-
-/**
- * Initialize the private and public key information structure for
- * signing coins into existence. Generates the private signing key
- * and signes it together with the coin's meta data using the master
- * signing key.
- *
- * @param params parameters used to initialize the @a dki
- * @param[out] dki initialized according to @a params
- */
-static void
-create_denomkey_issue (const struct CoinTypeParams *params,
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- dki->denom_priv.rsa_private_key
- = GNUNET_CRYPTO_rsa_private_key_create (params->rsa_keysize);
- GNUNET_assert (NULL != dki->denom_priv.rsa_private_key);
- dki->denom_pub.rsa_public_key
- = GNUNET_CRYPTO_rsa_private_key_get_public (dki->denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
- &dki->issue.properties.denom_hash);
- dki->issue.properties.master = master_public_key;
- dki->issue.properties.start = GNUNET_TIME_absolute_hton (params->anchor);
- dki->issue.properties.expire_withdraw =
- GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
- params->duration_withdraw));
- dki->issue.properties.expire_spend =
- GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
- params->duration_spend));
- dki->issue.properties.expire_legal =
- GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
- params->duration_legal));
- TALER_amount_hton (&dki->issue.properties.value,
- &params->value);
- TALER_amount_hton (&dki->issue.properties.fee_withdraw,
- &params->fee_withdraw);
- TALER_amount_hton (&dki->issue.properties.fee_deposit,
- &params->fee_deposit);
- TALER_amount_hton (&dki->issue.properties.fee_refresh,
- &params->fee_refresh);
- dki->issue.properties.purpose.purpose
- = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
- dki->issue.properties.purpose.size
- = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
- &dki->issue.properties.purpose,
- &dki->issue.signature.eddsa_signature));
-}
-
-
-/**
- * Generate new coin signing keys for the coin type of the given @a
- * coin_alias.
- *
- * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure
- * @param coin_alias name of the coin's section in the configuration
- */
-static void
-mint_keys_update_cointype (void *cls,
- const char *coin_alias)
-{
- int *ret = cls;
- struct CoinTypeParams p;
- const char *dkf;
- struct TALER_MINTDB_DenominationKeyIssueInformation denomkey_issue;
-
- if (0 != strncasecmp (coin_alias,
- "coin_",
- strlen ("coin_")))
- return; /* not a coin definition */
- if (GNUNET_OK !=
- get_cointype_params (coin_alias,
- &p))
- {
- *ret = GNUNET_SYSERR;
- return;
- }
- if (GNUNET_OK !=
- GNUNET_DISK_directory_create (get_cointype_dir (&p)))
- {
- *ret = GNUNET_SYSERR;
- return;
- }
-
- while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
- {
- dkf = get_cointype_file (&p,
- p.anchor);
- GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Generating denomination key for type `%s', start %s at %s\n",
- coin_alias,
- GNUNET_STRINGS_absolute_time_to_string (p.anchor),
- dkf);
- create_denomkey_issue (&p,
- &denomkey_issue);
- if (GNUNET_OK !=
- TALER_MINTDB_denomination_key_write (dkf,
- &denomkey_issue))
- {
- fprintf (stderr,
- "Failed to write denomination key information to file `%s'.\n",
- dkf);
- *ret = GNUNET_SYSERR;
- GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
- return;
- }
- if ( (NULL != auditor_output_file) &&
- (sizeof (denomkey_issue.issue.properties) !=
- fwrite (&denomkey_issue.issue.properties,
- sizeof (struct TALER_DenominationKeyValidityPS),
- 1,
- auditor_output_file)) )
- {
- fprintf (stderr,
- "Failed to write denomination key information to %s: %s\n",
- auditorrequestfile,
- STRERROR (errno));
- *ret = GNUNET_SYSERR;
- return;
- }
- GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
- p.anchor = GNUNET_TIME_absolute_add (p.anchor,
- p.duration_spend);
- p.anchor = GNUNET_TIME_absolute_subtract (p.anchor,
- p.duration_overlap);
- }
-}
-
-
-/**
- * Update all of the denomination keys of the mint.
- *
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-mint_keys_update_denomkeys ()
-{
- int ok;
-
- ok = GNUNET_OK;
- GNUNET_CONFIGURATION_iterate_sections (kcfg,
- &mint_keys_update_cointype,
- &ok);
- return ok;
-}
-
-
-/**
- * The main function of the taler-mint-keyup tool. This tool is used
- * to create the signing and denomination keys for the mint. It uses
- * the long-term offline private key and writes the (additional) key
- * files to the respective mint directory (from where they can then be
- * copied to the online server). Note that we need (at least) the
- * most recent generated previous keys so as to align the validity
- * periods.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc,
- char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'d', "mint-dir", "DIR",
- "mint directory with keys to update", 1,
- &GNUNET_GETOPT_set_filename, &mint_directory},
- TALER_GETOPT_OPTION_HELP ("Setup signing and denomination keys for a Taler mint"),
- {'m', "master-key", "FILE",
- "master key file (private key)", 1,
- &GNUNET_GETOPT_set_filename, &masterkeyfile},
- {'o', "output", "FILE",
- "auditor denomination key signing request file to create", 1,
- &GNUNET_GETOPT_set_filename, &auditorrequestfile},
- {'t', "time", "TIMESTAMP",
- "pretend it is a different time for the update", 0,
- &GNUNET_GETOPT_set_string, &pretend_time_str},
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- struct GNUNET_TIME_Relative lookahead_sign;
- struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-keyup",
- "WARNING",
- NULL));
-
- if (GNUNET_GETOPT_run ("taler-mint-keyup",
- options,
- argc, argv) < 0)
- return 1;
- if (NULL == mint_directory)
- {
- fprintf (stderr,
- "Mint directory not given\n");
- return 1;
- }
- if (NULL != pretend_time_str)
- {
- if (GNUNET_OK !=
- GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str,
- &now))
- {
- fprintf (stderr,
- "timestamp `%s' invalid\n",
- pretend_time_str);
- return 1;
- }
- }
- else
- {
- now = GNUNET_TIME_absolute_get ();
- }
- TALER_round_abs_time (&now);
-
- kcfg = TALER_config_load (mint_directory);
- if (NULL == kcfg)
- {
- fprintf (stderr,
- "Failed to load mint configuration\n");
- return 1;
- }
- if (NULL == masterkeyfile)
- {
- fprintf (stderr,
- "Master key file not given\n");
- return 1;
- }
- eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
- if (NULL == eddsa_priv)
- {
- fprintf (stderr,
- "Failed to initialize master key from file `%s'\n",
- masterkeyfile);
- return 1;
- }
- master_priv.eddsa_priv = *eddsa_priv;
- GNUNET_free (eddsa_priv);
- GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
- &master_public_key.eddsa_pub);
-
- if (NULL != auditorrequestfile)
- {
- auditor_output_file = FOPEN (auditorrequestfile,
- "w");
- if (NULL == auditor_output_file)
- {
- fprintf (stderr,
- "Failed to open `%s' for writing: %s\n",
- auditorrequestfile,
- STRERROR (errno));
- return 1;
- }
- }
-
- /* check if key from file matches the one from the configuration */
- {
- struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_data (kcfg,
- "mint",
- "master_public_key",
- &master_public_key_from_cfg,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "master_public_key");
- return 1;
- }
- if (0 !=
- memcmp (&master_public_key,
- &master_public_key_from_cfg,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "master_public_key",
- _("does not match with private key"));
- return 1;
- }
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- "mint_keys",
- "lookahead_sign",
- &lookahead_sign))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint_keys",
- "lookahead_sign");
- return GNUNET_SYSERR;
- }
- if (0 == lookahead_sign.rel_value_us)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "mint_keys",
- "lookahead_sign",
- _("must not be zero"));
- return GNUNET_SYSERR;
- }
- TALER_round_rel_time (&lookahead_sign);
- lookahead_sign_stamp = GNUNET_TIME_absolute_add (now,
- lookahead_sign);
-
-
- /* finally, do actual work */
- if (GNUNET_OK != mint_keys_update_signkeys ())
- return 1;
-
- if (GNUNET_OK != mint_keys_update_denomkeys ())
- return 1;
- if (NULL != auditor_output_file)
- {
- FCLOSE (auditor_output_file);
- auditor_output_file = NULL;
- }
- return 0;
-}
-
-/* end of taler-mint-keyup.c */
diff --git a/src/mint-tools/taler-mint-reservemod.c b/src/mint-tools/taler-mint-reservemod.c
deleted file mode 100644
index 38d27054a..000000000
--- a/src/mint-tools/taler-mint-reservemod.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-reservemod.c
- * @brief Modify reserves. Allows manipulation of reserve balances.
- * @author Florian Dold
- * @author Benedikt Mueller
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <libpq-fe.h>
-#include <jansson.h>
-#include "taler_mintdb_plugin.h"
-
-/**
- * Director of the mint, containing the keys.
- */
-static char *mint_directory;
-
-/**
- * Handle to the mint's configuration
- */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Our DB plugin.
- */
-static struct TALER_MINTDB_Plugin *plugin;
-
-
-/**
- * The main function of the reservemod tool
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc, char *const *argv)
-{
- char *reserve_pub_str = NULL;
- char *add_str = NULL;
- struct TALER_Amount add_value;
- char *details = NULL;
- json_t *jdetails;
- json_error_t error;
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_MINTDB_Session *session;
- const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'a', "add", "DENOM",
- "value to add", 1,
- &GNUNET_GETOPT_set_string, &add_str},
- {'d', "mint-dir", "DIR",
- "mint directory with keys to update", 1,
- &GNUNET_GETOPT_set_filename, &mint_directory},
- {'D', "details", "JSON",
- "details about the bank transaction which justify why we add this amount", 1,
- &GNUNET_GETOPT_set_string, &details},
- TALER_GETOPT_OPTION_HELP ("Deposit funds into a Taler reserve"),
- {'R', "reserve", "KEY",
- "reserve (public key) to modify", 1,
- &GNUNET_GETOPT_set_string, &reserve_pub_str},
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- int ret;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-reservemod",
- "WARNING",
- NULL));
-
- if (GNUNET_GETOPT_run ("taler-mint-reservemod",
- options,
- argc, argv) < 0)
- return 1;
- if (NULL == mint_directory)
- {
- fprintf (stderr,
- "Mint directory not given\n");
- GNUNET_free_non_null (add_str);
- GNUNET_free_non_null (details);
- GNUNET_free_non_null (reserve_pub_str);
- return 1;
- }
- if ((NULL == reserve_pub_str) ||
- (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (reserve_pub_str,
- strlen (reserve_pub_str),
- &reserve_pub,
- sizeof (struct TALER_ReservePublicKeyP))))
- {
- fprintf (stderr,
- "Parsing reserve key invalid\n");
- GNUNET_free_non_null (add_str);
- GNUNET_free_non_null (details);
- GNUNET_free_non_null (reserve_pub_str);
- return 1;
- }
- if ( (NULL == add_str) ||
- (GNUNET_OK !=
- TALER_string_to_amount (add_str,
- &add_value)) )
- {
- fprintf (stderr,
- "Failed to parse currency amount `%s'\n",
- add_str);
- GNUNET_free_non_null (add_str);
- GNUNET_free_non_null (details);
- GNUNET_free_non_null (reserve_pub_str);
- return 1;
- }
-
- if (NULL == details)
- {
- fprintf (stderr,
- "No wiring details given (justification required)\n");
- GNUNET_free_non_null (add_str);
- GNUNET_free_non_null (reserve_pub_str);
- return 1;
- }
-
- cfg = TALER_config_load (mint_directory);
- if (NULL == cfg)
- {
- fprintf (stderr,
- "Failed to load mint configuration\n");
- GNUNET_free_non_null (add_str);
- GNUNET_free_non_null (details);
- GNUNET_free_non_null (reserve_pub_str);
- return 1;
- }
- ret = 1;
- if (NULL ==
- (plugin = TALER_MINTDB_plugin_load (cfg)))
- {
- fprintf (stderr,
- "Failed to initialize database plugin.\n");
- goto cleanup;
- }
-
- session = plugin->get_session (plugin->cls,
- GNUNET_NO);
- if (NULL == session)
- {
- fprintf (stderr,
- "Failed to initialize DB session\n");
- goto cleanup;
- }
- jdetails = json_loads (details,
- JSON_REJECT_DUPLICATES,
- &error);
- if (NULL == jdetails)
- {
- fprintf (stderr,
- "Failed to parse JSON transaction details `%s': %s (%s)\n",
- details,
- error.text,
- error.source);
- goto cleanup;
- }
- /* FIXME: maybe allow passing timestamp via command-line? */
- ret = plugin->reserves_in_insert (plugin->cls,
- session,
- &reserve_pub,
- &add_value,
- GNUNET_TIME_absolute_get (),
- jdetails);
- json_decref (jdetails);
- if (GNUNET_SYSERR == ret)
- {
- fprintf (stderr,
- "Failed to update reserve.\n");
- goto cleanup;
- }
- if (GNUNET_NO == ret)
- {
- fprintf (stderr,
- "Record exists, reserve not updated.\n");
- }
- ret = 0;
- cleanup:
- if (NULL != plugin)
- TALER_MINTDB_plugin_unload (plugin);
- if (NULL != cfg)
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free_non_null (add_str);
- GNUNET_free_non_null (details);
- GNUNET_free_non_null (reserve_pub_str);
- return ret;
-}
-
-/* end taler-mint-reservemod.c */
diff --git a/src/mint-tools/taler-mint-sepa.c b/src/mint-tools/taler-mint-sepa.c
deleted file mode 100644
index e66db541e..000000000
--- a/src/mint-tools/taler-mint-sepa.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-sepa.c
- * @brief Create signed response for /wire/sepa requests.
- * @author Christian Grothoff
- */
-#include <platform.h>
-#include <jansson.h>
-#include "taler_crypto_lib.h"
-#include "taler_signatures.h"
-
-
-/**
- * Filename of the master private key.
- */
-static char *masterkeyfile;
-
-/**
- * Account holder name.
- */
-static char *sepa_name;
-
-/**
- * IBAN number.
- */
-static char *iban;
-
-/**
- * BIC number.
- */
-static char *bic;
-
-/**
- * Where to write the result.
- */
-static char *output_filename;
-
-
-/**
- * The main function of the taler-mint-sepa tool. This tool is used
- * to sign the SEPA bank account details using the master key.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc,
- char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'b', "bic", "BICCODE",
- "bank BIC code", 1,
- &GNUNET_GETOPT_set_string, &bic},
- {'i', "iban", "IBAN",
- "IBAN number of the account", 1,
- &GNUNET_GETOPT_set_string, &iban},
- {'m', "master-key", "FILE",
- "master key file (private key)", 1,
- &GNUNET_GETOPT_set_filename, &masterkeyfile},
- {'n', "name", "NAME",
- "name of the account holder", 1,
- &GNUNET_GETOPT_set_string, &sepa_name},
- {'o', "output", "FILE",
- "where to write the result", 1,
- &GNUNET_GETOPT_set_filename, &output_filename},
- TALER_GETOPT_OPTION_HELP ("Setup /wire/sepa response"),
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
- struct TALER_MasterWireSepaDetailsPS wsd;
- struct TALER_MasterSignatureP sig;
- struct GNUNET_HashContext *hc;
- json_t *reply;
- char *json_str;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-sepa",
- "WARNING",
- NULL));
-
- if (GNUNET_GETOPT_run ("taler-mint-sepa",
- options,
- argc, argv) < 0)
- return 1;
- if (NULL == masterkeyfile)
- {
- fprintf (stderr,
- "Master key file not given\n");
- return 1;
- }
- eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
- if (NULL == eddsa_priv)
- {
- fprintf (stderr,
- "Failed to initialize master key from file `%s'\n",
- masterkeyfile);
- return 1;
- }
-
- /* Compute message to sign */
- hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc,
- sepa_name,
- strlen (sepa_name) + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- iban,
- strlen (iban) + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- bic,
- strlen (bic) + 1);
- wsd.purpose.size = htonl (sizeof (wsd));
- wsd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
- GNUNET_CRYPTO_hash_context_finish (hc,
- &wsd.h_sepa_details);
- GNUNET_CRYPTO_eddsa_sign (eddsa_priv,
- &wsd.purpose,
- &sig.eddsa_signature);
- GNUNET_free (eddsa_priv);
-
- /* build JSON message */
- reply = json_pack ("{s:s, s:s, s:s, s:o}",
- "receiver_name", sepa_name,
- "iban", iban,
- "bic", bic,
- "sig", TALER_json_from_data (&sig,
- sizeof (sig)));
- GNUNET_assert (NULL != reply);
-
- /* dump result to stdout */
- json_str = json_dumps (reply, JSON_INDENT(2));
- GNUNET_assert (NULL != json_str);
-
- if (NULL != output_filename)
- {
- fclose (stdout);
- stdout = fopen (output_filename,
- "w+");
- }
- fprintf (stdout,
- "%s",
- json_str);
- fflush (stdout);
- free (json_str);
- return 0;
-}
-
-/* end of taler-mint-sepa.c */
diff --git a/src/mint/.gitignore b/src/mint/.gitignore
deleted file mode 100644
index a2e71d5da..000000000
--- a/src/mint/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-taler-mint-dbinit
-taler-mint-keycheck
-taler-mint-keyup
-taler-mint-pursemod
-taler-mint-reservemod
-taler-mint-httpd \ No newline at end of file
diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am
deleted file mode 100644
index 8e2eae77b..000000000
--- a/src/mint/Makefile.am
+++ /dev/null
@@ -1,59 +0,0 @@
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
-if USE_COVERAGE
- AM_CFLAGS = --coverage -O0
- XLIB = -lgcov
-endif
-
-bin_PROGRAMS = \
- taler-mint-aggregator \
- taler-mint-httpd
-
-taler_mint_aggregator_SOURCES = \
- taler-mint-aggregator.c
-taler_mint_aggregator_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/wire/libtalerwire.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -ljansson \
- -lgnunetutil
-
-taler_mint_httpd_SOURCES = \
- taler-mint-httpd.c taler-mint-httpd.h \
- taler-mint-httpd_admin.c taler-mint-httpd_admin.h \
- taler-mint-httpd_db.c taler-mint-httpd_db.h \
- taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \
- taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
- taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
- taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
- taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h \
- taler-mint-httpd_reserve.c taler-mint-httpd_reserve.h \
- taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
- taler-mint-httpd_tracking.c taler-mint-httpd_tracking.h \
- taler-mint-httpd_wire.c taler-mint-httpd_wire.h \
- taler-mint-httpd_validation.c taler-mint-httpd_validation.h
-taler_mint_httpd_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/mintdb/libtalermintdb.la \
- -lmicrohttpd \
- -ljansson \
- -lgnunetutil \
- -lpthread
-
-if HAVE_DEVELOPER
-taler_mint_httpd_SOURCES += \
- taler-mint-httpd_test.c taler-mint-httpd_test.h
-endif
-
-check_SCRIPTS = \
- test_taler_mint_httpd.sh
-
-if HAVE_EXPENSIVE_TESTS
-check_SCRIPTS += \
- test_taler_mint_httpd_afl.sh
-endif
-
-TESTS = $(check_SCRIPTS)
diff --git a/src/mint/taler-mint-aggregator.c b/src/mint/taler-mint-aggregator.c
deleted file mode 100644
index 5e05c8673..000000000
--- a/src/mint/taler-mint-aggregator.c
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-aggregator.c
- * @brief Process that aggregates outgoing transactions and executes them
- * @author Christian Grothoff
- *
- * TODO:
- * - simplify global_ret: make it a global!
- * - handle shutdown more nicely (call 'cancel' method on wire transfers)
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <pthread.h>
-#include "taler_mintdb_lib.h"
-#include "taler_mintdb_plugin.h"
-#include "taler_wire_lib.h"
-
-/**
- * Which currency is used by this mint?
- */
-static char *mint_currency_string;
-
-/**
- * Which wireformat should be supported by this aggregator?
- */
-static char *mint_wireformat;
-
-/**
- * Base directory of the mint (global)
- */
-static char *mint_directory;
-
-/**
- * The mint's configuration (global)
- */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Our DB plugin.
- */
-static struct TALER_MINTDB_Plugin *db_plugin;
-
-/**
- * Our wire plugin.
- */
-static struct TALER_WIRE_Plugin *wire_plugin;
-
-/**
- * Task for the main #run() function.
- */
-static struct GNUNET_SCHEDULER_Task *task;
-
-/**
- * Limit on the number of transactions we aggregate at once. Note
- * that the limit must be big enough to ensure that when transactions
- * of the smallest possible unit are aggregated, they do surpass the
- * "tiny" threshold beyond which we never trigger a wire transaction!
- *
- * TODO: make configurable (via config file or command line option)
- */
-static unsigned int aggregation_limit = 10000;
-
-
-/**
- * Load configuration parameters for the mint
- * server into the corresponding global variables.
- *
- * @param mint_directory the mint's directory
- * @return #GNUNET_OK on success
- */
-static int
-mint_serve_process_config (const char *mint_directory)
-{
- char *type;
-
- cfg = TALER_config_load (mint_directory);
- if (NULL == cfg)
- {
- fprintf (stderr,
- "Failed to load mint configuration\n");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "currency",
- &mint_currency_string))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "currency");
- return GNUNET_SYSERR;
- }
- if (strlen (mint_currency_string) >= TALER_CURRENCY_LEN)
- {
- fprintf (stderr,
- "Currency `%s' longer than the allowed limit of %u characters.",
- mint_currency_string,
- (unsigned int) TALER_CURRENCY_LEN);
- return GNUNET_SYSERR;
- }
- if (NULL != mint_wireformat)
- GNUNET_CONFIGURATION_set_value_string (cfg,
- "mint",
- "wireformat",
- mint_wireformat);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "wireformat",
- &type))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "wireformat");
- return GNUNET_SYSERR;
- }
-
- if (NULL ==
- (db_plugin = TALER_MINTDB_plugin_load (cfg)))
- {
- fprintf (stderr,
- "Failed to initialize DB subsystem\n");
- GNUNET_free (type);
- return GNUNET_SYSERR;
- }
-
- if (NULL ==
- (wire_plugin = TALER_WIRE_plugin_load (cfg,
- type)))
- {
- fprintf (stderr,
- "Failed to load wire plugin for `%s'\n",
- type);
- GNUNET_free (type);
- return GNUNET_SYSERR;
- }
- GNUNET_free (type);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Information about one aggregation process to
- * be executed.
- */
-struct AggregationUnit
-{
- /**
- * Public key of the merchant.
- */
- struct TALER_MerchantPublicKeyP merchant_pub;
-
- /**
- * Total amount to be transferred.
- */
- struct TALER_Amount total_amount;
-
- /**
- * Hash of @e wire.
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * Wire transfer identifier we use.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /**
- * Row ID of the transaction that started it all.
- */
- unsigned long long row_id;
-
- /**
- * The current time.
- */
- struct GNUNET_TIME_Absolute execution_time;
-
- /**
- * Wire details of the merchant.
- */
- json_t *wire;
-
- /**
- * Database session for all of our transactions.
- */
- struct TALER_MINTDB_Session *session;
-
- /**
- * Wire preparation handle.
- */
- struct TALER_WIRE_PrepareHandle *ph;
-
- /**
- * Array of #aggregation_limit row_ids from the
- * aggregation.
- */
- unsigned long long *additional_rows;
-
- /**
- * Pointer to global return value. Closure for #run().
- */
- int *global_ret;
-
- /**
- * Offset specifying how many #additional_rows are in use.
- */
- unsigned int rows_offset;
-
- /**
- * Set to #GNUNET_YES if we have to abort due to failure.
- */
- int failed;
-
-};
-
-
-/**
- * Function called with details about deposits that have been made,
- * with the goal of executing the corresponding wire transaction.
- *
- * @param cls closure with the `struct AggregationUnit`
- * @param row_id identifies database entry
- * @param merchant_pub public key of the merchant
- * @param coin_pub public key of the coin
- * @param amount_with_fee amount that was deposited including fee
- * @param deposit_fee amount the mint gets to keep as transaction fees
- * @param transaction_id unique transaction ID chosen by the merchant
- * @param h_contract hash of the contract between merchant and customer
- * @param wire_deadline by which the merchant adviced that he would like the
- * wire transfer to be executed
- * @param wire wire details for the merchant
- * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
- */
-static int
-deposit_cb (void *cls,
- unsigned long long row_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *amount_with_fee,
- const struct TALER_Amount *deposit_fee,
- uint64_t transaction_id,
- const struct GNUNET_HashCode *h_contract,
- struct GNUNET_TIME_Absolute wire_deadline,
- const json_t *wire)
-{
- struct AggregationUnit *au = cls;
-
- au->merchant_pub = *merchant_pub;
- if (GNUNET_OK !=
- TALER_amount_subtract (&au->total_amount,
- amount_with_fee,
- deposit_fee))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fatally malformed record at %llu\n",
- row_id);
- return GNUNET_SYSERR;
- }
- au->row_id = row_id;
- au->wire = (json_t *) wire;
- au->execution_time = GNUNET_TIME_absolute_get ();
- TALER_hash_json (au->wire,
- &au->h_wire);
- json_incref (au->wire);
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- &au->wtid,
- sizeof (au->wtid));
- if (GNUNET_OK !=
- db_plugin->insert_aggregation_tracking (db_plugin->cls,
- au->session,
- &au->wtid,
- merchant_pub,
- &au->h_wire,
- h_contract,
- transaction_id,
- au->execution_time,
- coin_pub,
- amount_with_fee,
- deposit_fee))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- db_plugin->mark_deposit_done (db_plugin->cls,
- au->session,
- row_id))
- {
- GNUNET_break (0);
- au->failed = GNUNET_YES;
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-
-/**
- * Function called with details about another deposit we
- * can aggregate into an existing aggregation unit.
- *
- * @param cls closure with the `struct AggregationUnit`
- * @param row_id identifies database entry
- * @param merchant_pub public key of the merchant
- * @param coin_pub public key of the coin
- * @param amount_with_fee amount that was deposited including fee
- * @param deposit_fee amount the mint gets to keep as transaction fees
- * @param transaction_id unique transaction ID chosen by the merchant
- * @param h_contract hash of the contract between merchant and customer
- * @param wire_deadline by which the merchant adviced that he would like the
- * wire transfer to be executed
- * @param wire wire details for the merchant
- * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
- */
-static int
-aggregate_cb (void *cls,
- unsigned long long row_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *amount_with_fee,
- const struct TALER_Amount *deposit_fee,
- uint64_t transaction_id,
- const struct GNUNET_HashCode *h_contract,
- struct GNUNET_TIME_Absolute wire_deadline,
- const json_t *wire)
-{
- struct AggregationUnit *au = cls;
- struct TALER_Amount delta;
-
- GNUNET_break (0 ==
- memcmp (&au->merchant_pub,
- merchant_pub,
- sizeof (struct TALER_MerchantPublicKeyP)));
- /* compute contribution of this coin after fees */
- if (GNUNET_OK !=
- TALER_amount_subtract (&delta,
- amount_with_fee,
- deposit_fee))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fatally malformed record at %llu\n",
- row_id);
- return GNUNET_SYSERR;
- }
- /* add to total */
- if (GNUNET_OK !=
- TALER_amount_add (&au->total_amount,
- &au->total_amount,
- &delta))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Overflow or currency incompatibility during aggregation at %llu\n",
- row_id);
- /* Skip this one, but keep going! */
- return GNUNET_OK;
- }
- if (au->rows_offset >= aggregation_limit)
- {
- /* Bug: we asked for at most #aggregation_limit results! */
- GNUNET_break (0);
- /* Skip this one, but keep going. */
- return GNUNET_OK;
- }
- if (NULL == au->additional_rows)
- au->additional_rows = GNUNET_new_array (aggregation_limit,
- unsigned long long);
- /* "append" to our list of rows */
- au->additional_rows[au->rows_offset++] = row_id;
- /* insert into aggregation tracking table */
- if (GNUNET_OK !=
- db_plugin->insert_aggregation_tracking (db_plugin->cls,
- au->session,
- &au->wtid,
- merchant_pub,
- &au->h_wire,
- h_contract,
- transaction_id,
- au->execution_time,
- coin_pub,
- amount_with_fee,
- deposit_fee))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- db_plugin->mark_deposit_done (db_plugin->cls,
- au->session,
- row_id))
- {
- GNUNET_break (0);
- au->failed = GNUNET_YES;
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function to be called with the prepared transfer data.
- *
- * @param cls closure with the `struct AggregationUnit`
- * @param buf transaction data to persist, NULL on error
- * @param buf_size number of bytes in @a buf, 0 on error
- */
-static void
-prepare_cb (void *cls,
- const char *buf,
- size_t buf_size);
-
-
-/**
- * Main work function that queries the DB and aggregates transactions
- * into larger wire transfers.
- *
- * @param cls pointer to an `int` which we will return from main()
- * @param tc scheduler context
- */
-static void
-run_aggregation (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- int *global_ret = cls;
- struct TALER_MINTDB_Session *session;
- struct AggregationUnit *au;
- unsigned int i;
- int ret;
-
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
- if (NULL == (session = db_plugin->get_session (db_plugin->cls,
- GNUNET_NO)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to obtain database session!\n");
- *global_ret = GNUNET_SYSERR;
- return;
- }
- if (GNUNET_OK !=
- db_plugin->start (db_plugin->cls,
- session))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to start database transaction!\n");
- *global_ret = GNUNET_SYSERR;
- return;
- }
- au = GNUNET_new (struct AggregationUnit);
- au->session = session;
- ret = db_plugin->get_ready_deposit (db_plugin->cls,
- session,
- &deposit_cb,
- au);
- if (GNUNET_OK != ret)
- {
- GNUNET_free (au);
- db_plugin->rollback (db_plugin->cls,
- session);
- if (0 != ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to execute deposit iteration!\n");
- *global_ret = GNUNET_SYSERR;
- return;
- }
- /* nothing to do, sleep for a minute and try again */
- task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &run_aggregation,
- global_ret);
- return;
- }
- /* Now try to find other deposits to aggregate */
- ret = db_plugin->iterate_matching_deposits (db_plugin->cls,
- session,
- &au->h_wire,
- &au->merchant_pub,
- &aggregate_cb,
- au,
- aggregation_limit);
- if ( (GNUNET_SYSERR == ret) ||
- (GNUNET_YES == au->failed) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to execute deposit iteration!\n");
- GNUNET_free_non_null (au->additional_rows);
- GNUNET_free (au);
- db_plugin->rollback (db_plugin->cls,
- session);
- *global_ret = GNUNET_SYSERR;
- return;
- }
- /* Round to the unit supported by the wire transfer method */
- GNUNET_assert (GNUNET_SYSERR !=
- wire_plugin->amount_round (wire_plugin->cls,
- &au->total_amount));
- /* Check if after rounding down, we still have an amount to transfer */
- if ( (0 == au->total_amount.value) &&
- (0 == au->total_amount.fraction) )
- {
- /* Rollback ongoing transaction, as we will not use the respective
- WTID and thus need to remove the tracking data */
- db_plugin->rollback (db_plugin->cls,
- session);
- /* Start another transaction to mark all* of the selected deposits
- *as minor! */
- if (GNUNET_OK !=
- db_plugin->start (db_plugin->cls,
- session))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to start database transaction!\n");
- *global_ret = GNUNET_SYSERR;
- GNUNET_free_non_null (au->additional_rows);
- GNUNET_free (au);
- return;
- }
- /* Mark transactions by row_id as minor */
- ret = GNUNET_OK;
- if (GNUNET_OK !=
- db_plugin->mark_deposit_tiny (db_plugin->cls,
- session,
- au->row_id))
- ret = GNUNET_SYSERR;
- else
- for (i=0;i<au->rows_offset;i++)
- if (GNUNET_OK !=
- db_plugin->mark_deposit_tiny (db_plugin->cls,
- session,
- au->additional_rows[i]))
- ret = GNUNET_SYSERR;
- /* commit */
- if (GNUNET_OK !=
- db_plugin->commit (db_plugin->cls,
- session))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to commit database transaction!\n");
- }
- GNUNET_free_non_null (au->additional_rows);
- GNUNET_free (au);
- /* start again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- return;
- }
- au->global_ret = global_ret;
- au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls,
- au->wire,
- &au->total_amount,
- &au->wtid,
- &prepare_cb,
- au);
- /* FIXME: currently we have no clean-up plan on
- shutdown to call prepare_wire_transfer_cancel!
- Maybe make 'au' global? */
- if (NULL == au->ph)
- {
- GNUNET_break (0); /* why? how to best recover? */
- db_plugin->rollback (db_plugin->cls,
- session);
- GNUNET_free_non_null (au->additional_rows);
- GNUNET_free (au);
- /* start again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- return;
- }
- /* otherwise we continue with #prepare_cb(), see below */
-}
-
-
-/**
- * Execute the wire transfers that we have committed to
- * do.
- *
- * @param cls pointer to an `int` which we will return from main()
- * @param tc scheduler context
- */
-static void
-run_transfers (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Function to be called with the prepared transfer data.
- *
- * @param cls closure with the `struct AggregationUnit`
- * @param buf transaction data to persist, NULL on error
- * @param buf_size number of bytes in @a buf, 0 on error
- */
-static void
-prepare_cb (void *cls,
- const char *buf,
- size_t buf_size)
-{
- struct AggregationUnit *au = cls;
- int *global_ret = au->global_ret;
- struct TALER_MINTDB_Session *session = au->session;
-
- GNUNET_free_non_null (au->additional_rows);
- GNUNET_free (au);
- if (NULL == buf)
- {
- GNUNET_break (0); /* why? how to best recover? */
- db_plugin->rollback (db_plugin->cls,
- session);
- /* start again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- return;
- }
-
- /* Commit our intention to execute the wire transfer! */
- if (GNUNET_OK !=
- db_plugin->wire_prepare_data_insert (db_plugin->cls,
- session,
- mint_wireformat,
- buf,
- buf_size))
- {
- GNUNET_break (0); /* why? how to best recover? */
- db_plugin->rollback (db_plugin->cls,
- session);
- /* start again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- return;
- }
-
- /* Now we can finally commit the overall transaction, as we are
- again consistent if all of this passes. */
- if (GNUNET_OK !=
- db_plugin->commit (db_plugin->cls,
- session))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Failed to commit database transaction!\n");
- /* try again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- return;
- }
-
- /* run alternative task: actually do wire transfer! */
- task = GNUNET_SCHEDULER_add_now (&run_transfers,
- &global_ret);
-}
-
-
-/**
- * Data we keep to #run_transfers().
- */
-struct WirePrepareData
-{
-
- /**
- * Database session for all of our transactions.
- */
- struct TALER_MINTDB_Session *session;
-
- /**
- * Wire execution handle.
- */
- struct TALER_WIRE_ExecuteHandle *eh;
-
- /**
- * Pointer to global return value. Closure for #run().
- */
- int *global_ret;
-
-
- /**
- * Row ID of the transfer.
- */
- unsigned long long row_id;
-
-};
-
-
-/**
- * Function called with the result from the execute step.
- *
- * @param cls closure with the `struct WirePrepareData`
- * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
- * @param emsg NULL on success, otherwise an error message
- */
-static void
-wire_confirm_cb (void *cls,
- int success,
- const char *emsg)
-{
- struct WirePrepareData *wpd = cls;
- int *global_ret = wpd->global_ret;
- struct TALER_MINTDB_Session *session = wpd->session;
-
- wpd->eh = NULL;
- if (GNUNET_SYSERR == success)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire transaction failed: %s\n",
- emsg);
- db_plugin->rollback (db_plugin->cls,
- session);
- *global_ret = GNUNET_SYSERR;
- GNUNET_free (wpd);
- return;
- }
- if (GNUNET_OK !=
- db_plugin->wire_prepare_data_mark_finished (db_plugin->cls,
- session,
- wpd->row_id))
- {
- GNUNET_break (0); /* why!? */
- db_plugin->rollback (db_plugin->cls,
- session);
- *global_ret = GNUNET_SYSERR;
- GNUNET_free (wpd);
- return;
- }
- GNUNET_free (wpd);
- if (GNUNET_OK !=
- db_plugin->commit (db_plugin->cls,
- session))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Failed to commit database transaction!\n");
- /* try again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- return;
- }
- /* continue with #run_transfers(), just to guard
- against the unlikely case that there are more. */
- task = GNUNET_SCHEDULER_add_now (&run_transfers,
- &global_ret);
-
-}
-
-
-/**
- * Callback with data about a prepared transaction.
- *
- * @param cls closure with the `struct WirePrepareData`
- * @param rowid row identifier used to mark prepared transaction as done
- * @param buf transaction data that was persisted, NULL on error
- * @param buf_size number of bytes in @a buf, 0 on error
- */
-static void
-wire_prepare_cb (void *cls,
- unsigned long long rowid,
- const char *buf,
- size_t buf_size)
-{
- struct WirePrepareData *wpd = cls;
- int *global_ret = wpd->global_ret;
-
- wpd->row_id = rowid;
- wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls,
- buf,
- buf_size,
- &wire_confirm_cb,
- wpd);
- /* FIXME: currently we have no clean-up plan on
- shutdown to call execute_wire_transfer_cancel!
- Maybe make 'wpd' global? */
- if (NULL == wpd->eh)
- {
- GNUNET_break (0); /* why? how to best recover? */
- db_plugin->rollback (db_plugin->cls,
- wpd->session);
- *global_ret = GNUNET_SYSERR;
- GNUNET_free (wpd);
- return;
- }
-}
-
-
-/**
- * Execute the wire transfers that we have committed to
- * do.
- *
- * @param cls pointer to an `int` which we will return from main()
- * @param tc scheduler context
- */
-static void
-run_transfers (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- int *global_ret = cls;
- int ret;
- struct WirePrepareData *wpd;
- struct TALER_MINTDB_Session *session;
-
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
- if (NULL == (session = db_plugin->get_session (db_plugin->cls,
- GNUNET_NO)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to obtain database session!\n");
- *global_ret = GNUNET_SYSERR;
- return;
- }
- if (GNUNET_OK !=
- db_plugin->start (db_plugin->cls,
- session))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to start database transaction!\n");
- *global_ret = GNUNET_SYSERR;
- return;
- }
- wpd = GNUNET_new (struct WirePrepareData);
- wpd->session = session;
- wpd->global_ret = global_ret;
- ret = db_plugin->wire_prepare_data_get (db_plugin->cls,
- session,
- mint_wireformat,
- &wire_prepare_cb,
- wpd);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_break (0); /* why? how to best recover? */
- db_plugin->rollback (db_plugin->cls,
- session);
- *global_ret = GNUNET_SYSERR;
- GNUNET_free (wpd);
- return;
- }
- if (GNUNET_NO == ret)
- {
- /* no more prepared wire transfers, go back to aggregation! */
- db_plugin->rollback (db_plugin->cls,
- session);
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- global_ret);
- GNUNET_free (wpd);
- return;
- }
- /* otherwise, continues in #wire_prepare_cb() */
-}
-
-
-/**
- * The main function of the taler-mint-httpd server ("the mint").
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc,
- char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'d', "mint-dir", "DIR",
- "mint directory with configuration and keys for operating the mint", 1,
- &GNUNET_GETOPT_set_filename, &mint_directory},
- {'f', "format", "WIREFORMAT",
- "wireformat to use, overrides WIREFORMAT option in [mint] section", 1,
- &GNUNET_GETOPT_set_filename, &mint_wireformat},
- TALER_GETOPT_OPTION_HELP ("background process that aggregates and executes wire transfers to merchants"),
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- int ret = GNUNET_OK;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-aggregator",
- "INFO",
- NULL));
- if (0 >=
- GNUNET_GETOPT_run ("taler-mint-aggregator",
- options,
- argc, argv))
- return 1;
- if (NULL == mint_directory)
- {
- fprintf (stderr,
- "Mint directory not specified\n");
- return 1;
- }
- if (GNUNET_OK !=
- mint_serve_process_config (mint_directory))
- {
- return 1;
- }
-
- GNUNET_SCHEDULER_run (&run_transfers, &ret);
-
- TALER_MINTDB_plugin_unload (db_plugin);
- TALER_WIRE_plugin_unload (wire_plugin);
- return (GNUNET_SYSERR == ret) ? 1 : 0;
-}
-
-/* end of taler-mint-aggregator.c */
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c
deleted file mode 100644
index 5d6aa0589..000000000
--- a/src/mint/taler-mint-httpd.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd.c
- * @brief Serve the HTTP interface of the mint
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include <pthread.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_mhd.h"
-#include "taler-mint-httpd_admin.h"
-#include "taler-mint-httpd_deposit.h"
-#include "taler-mint-httpd_reserve.h"
-#include "taler-mint-httpd_wire.h"
-#include "taler-mint-httpd_refresh.h"
-#include "taler-mint-httpd_tracking.h"
-#include "taler-mint-httpd_keystate.h"
-#if HAVE_DEVELOPER
-#include "taler-mint-httpd_test.h"
-#endif
-#include "taler_mintdb_plugin.h"
-#include "taler-mint-httpd_validation.h"
-
-/**
- * Which currency is used by this mint?
- */
-char *TMH_mint_currency_string;
-
-/**
- * Should we return "Connection: close" in each response?
- */
-int TMH_mint_connection_close;
-
-/**
- * Base directory of the mint (global)
- */
-char *TMH_mint_directory;
-
-/**
- * The mint's configuration (global)
- */
-struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Master public key (according to the
- * configuration in the mint directory).
- */
-struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
-
-/**
- * Our DB plugin.
- */
-struct TALER_MINTDB_Plugin *TMH_plugin;
-
-/**
- * Are we running in test mode?
- */
-int TMH_test_mode;
-
-/**
- * Default timeout in seconds for HTTP requests.
- */
-static unsigned int connection_timeout = 30;
-
-/**
- * The HTTP Daemon.
- */
-static struct MHD_Daemon *mydaemon;
-
-/**
- * Port to run the daemon on.
- */
-static uint16_t serve_port;
-
-
-/**
- * Function called whenever MHD is done with a request. If the
- * request was a POST, we may have stored a `struct Buffer *` in the
- * @a con_cls that might still need to be cleaned up. Call the
- * respective function to free the memory.
- *
- * @param cls client-defined closure
- * @param connection connection handle
- * @param con_cls value as set by the last call to
- * the #MHD_AccessHandlerCallback
- * @param toe reason for request termination
- * @see #MHD_OPTION_NOTIFY_COMPLETED
- * @ingroup request
- */
-static void
-handle_mhd_completion_callback (void *cls,
- struct MHD_Connection *connection,
- void **con_cls,
- enum MHD_RequestTerminationCode toe)
-{
- if (NULL == *con_cls)
- return;
- TMH_PARSE_post_cleanup_callback (*con_cls);
- *con_cls = NULL;
-}
-
-
-/**
- * Handle a request coming from libmicrohttpd.
- *
- * @param cls closure for MHD daemon (unused)
- * @param connection the connection
- * @param url the requested url
- * @param method the method (POST, GET, ...)
- * @param version HTTP version (ignored)
- * @param upload_data request data
- * @param upload_data_size size of @a upload_data in bytes
- * @param con_cls closure for request (a `struct Buffer *`)
- * @return MHD result code
- */
-static int
-handle_mhd_request (void *cls,
- struct MHD_Connection *connection,
- const char *url,
- const char *method,
- const char *version,
- const char *upload_data,
- size_t *upload_data_size,
- void **con_cls)
-{
- static struct TMH_RequestHandler handlers[] =
- {
- /* Landing page, tell humans to go away. */
- { "/", MHD_HTTP_METHOD_GET, "text/plain",
- "Hello, I'm the Taler mint. This HTTP server is not for humans.\n", 0,
- &TMH_MHD_handler_static_response, MHD_HTTP_OK },
- /* /robots.txt: disallow everything */
- { "/robots.txt", MHD_HTTP_METHOD_GET, "text/plain",
- "User-agent: *\nDisallow: /\n", 0,
- &TMH_MHD_handler_static_response, MHD_HTTP_OK },
- /* AGPL licensing page, redirect to source. As per the AGPL-license,
- every deployment is required to offer the user a download of the
- source. We make this easy by including a redirect to the source
- here. */
- { "/agpl", MHD_HTTP_METHOD_GET, "text/plain",
- NULL, 0,
- &TMH_MHD_handler_agpl_redirect, MHD_HTTP_FOUND },
-
- /* Return key material and fundamental properties for this mint */
- { "/keys", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_KS_handler_keys, MHD_HTTP_OK },
- { "/keys", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- /* Requests for wiring information */
- { "/wire", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_WIRE_handler_wire, MHD_HTTP_OK },
- { "/wire", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/wire/test", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_WIRE_handler_wire_test, MHD_HTTP_FOUND },
- { "/wire/test", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/wire/sepa", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_WIRE_handler_wire_sepa, MHD_HTTP_OK },
- { "/wire/sepa", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- /* Withdrawing coins / interaction with reserves */
- { "/reserve/status", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_RESERVE_handler_reserve_status, MHD_HTTP_OK },
- { "/reserve/status", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/reserve/withdraw", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_RESERVE_handler_reserve_withdraw, MHD_HTTP_OK },
- { "/reserve/withdraw", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- /* Depositing coins */
- { "/deposit", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_DEPOSIT_handler_deposit, MHD_HTTP_OK },
- { "/deposit", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- /* Dealing with change */
- { "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_REFRESH_handler_refresh_melt, MHD_HTTP_OK },
- { "/refresh/melt", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK },
- { "/refresh/reveal", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK },
- { "/refresh/reveal", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/refresh/link", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_REFRESH_handler_refresh_link, MHD_HTTP_OK },
- { "/refresh/link", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- /* FIXME: maybe conditionally compile these? */
- { "/admin/add/incoming", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_ADMIN_handler_admin_add_incoming, MHD_HTTP_OK },
- { "/admin/add/incoming", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/wire/deposits", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_TRACKING_handler_wire_deposits, MHD_HTTP_OK },
- { "/wire/deposits", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
- { "/deposit/wtid", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TRACKING_handler_deposit_wtid, MHD_HTTP_OK },
- { "/deposit/wtid", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-#if HAVE_DEVELOPER
- /* Client crypto-interoperability test functions */
- { "/test", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test, MHD_HTTP_OK },
- { "/test", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/base32", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_base32, MHD_HTTP_OK },
- { "/test/base32", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/encrypt", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_encrypt, MHD_HTTP_OK },
- { "/test/encrypt", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/hkdf", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_hkdf, MHD_HTTP_OK },
- { "/test/hkdf", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/ecdhe", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_ecdhe, MHD_HTTP_OK },
- { "/test/ecdhe", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/eddsa", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_eddsa, MHD_HTTP_OK },
- { "/test/eddsa", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/rsa/get", MHD_HTTP_METHOD_GET, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_rsa_get, MHD_HTTP_OK },
- { "/test/rsa/get", NULL, "text/plain",
- "Only GET is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/rsa/sign", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_rsa_sign, MHD_HTTP_OK },
- { "/test/rsa/sign", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
- { "/test/transfer", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &TMH_TEST_handler_test_transfer, MHD_HTTP_OK },
- { "/test/transfer", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-#endif
-
- { NULL, NULL, NULL, NULL, 0, 0 }
- };
- static struct TMH_RequestHandler h404 =
- {
- "", NULL, "text/html",
- "<html><title>404: not found</title></html>", 0,
- &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND
- };
- struct TMH_RequestHandler *rh;
- unsigned int i;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Handling request for URL '%s'\n",
- url);
- for (i=0;NULL != handlers[i].url;i++)
- {
- rh = &handlers[i];
- if ( (0 == strcasecmp (url,
- rh->url)) &&
- ( (NULL == rh->method) ||
- (0 == strcasecmp (method,
- rh->method)) ) )
- return rh->handler (rh,
- connection,
- con_cls,
- upload_data,
- upload_data_size);
- }
- return TMH_MHD_handler_static_response (&h404,
- connection,
- con_cls,
- upload_data,
- upload_data_size);
-}
-
-
-/**
- * Load configuration parameters for the mint
- * server into the corresponding global variables.
- *
- * @param mint_directory the mint's directory
- * @return #GNUNET_OK on success
- */
-static int
-mint_serve_process_config (const char *mint_directory)
-{
- unsigned long long port;
- char *TMH_master_public_key_str;
-
- cfg = TALER_config_load (mint_directory);
- if (NULL == cfg)
- {
- fprintf (stderr,
- "Failed to load mint configuration\n");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "currency",
- &TMH_mint_currency_string))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "currency");
- return GNUNET_SYSERR;
- }
- if (strlen (TMH_mint_currency_string) >= TALER_CURRENCY_LEN)
- {
- fprintf (stderr,
- "Currency `%s' longer than the allowed limit of %u characters.",
- TMH_mint_currency_string,
- (unsigned int) TALER_CURRENCY_LEN);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TMH_VALIDATION_init (cfg))
- return GNUNET_SYSERR;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "master_public_key",
- &TMH_master_public_key_str))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "master_public_key");
- TMH_VALIDATION_done ();
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_public_key_from_string (TMH_master_public_key_str,
- strlen (TMH_master_public_key_str),
- &TMH_master_public_key))
- {
- fprintf (stderr,
- "Invalid master public key given in mint configuration.");
- GNUNET_free (TMH_master_public_key_str);
- TMH_VALIDATION_done ();
- return GNUNET_SYSERR;
- }
- GNUNET_free (TMH_master_public_key_str);
-
- if (NULL ==
- (TMH_plugin = TALER_MINTDB_plugin_load (cfg)))
- {
- fprintf (stderr,
- "Failed to initialize DB subsystem\n");
- TMH_VALIDATION_done ();
- return GNUNET_SYSERR;
- }
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "mint",
- "TESTRUN"))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Running in TEST mode! Database contents will not persist!\n");
- TMH_test_mode = GNUNET_YES;
- TMH_plugin->create_tables (TMH_plugin->cls,
- GNUNET_YES);
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "mint",
- "port",
- &port))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "port",
- "port number required");
- TMH_VALIDATION_done ();
- return GNUNET_SYSERR;
- }
-
- if ( (0 == port) ||
- (port > UINT16_MAX) )
- {
- fprintf (stderr,
- "Invalid configuration (value out of range): %llu is not a valid port\n",
- port);
- TMH_VALIDATION_done ();
- return GNUNET_SYSERR;
- }
- serve_port = (uint16_t) port;
-
- return GNUNET_OK;
-}
-
-
-/* Developer logic for supporting the `-f' option. */
-#if HAVE_DEVELOPER
-
-/**
- * Option `-f' (specifies an input file to give to the HTTP server).
- */
-static char *input_filename;
-
-
-/**
- * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename
- * as the input for the request. If launching the client worked,
- * run the #TMH_KS_loop() event loop as usual.
- *
- * @return #GNUNET_OK
- */
-static int
-run_fake_client ()
-{
- pid_t cld;
- char ports[6];
- int fd;
- int ret;
- int status;
-
- fd = open (input_filename, O_RDONLY);
- if (-1 == fd)
- {
- fprintf (stderr,
- "Failed to open `%s': %s\n",
- input_filename,
- strerror (errno));
- return GNUNET_SYSERR;
- }
- /* Fake HTTP client request with #input_filename as input.
- We do this using the nc tool. */
- GNUNET_snprintf (ports,
- sizeof (ports),
- "%u",
- serve_port);
- if (0 == (cld = fork()))
- {
- GNUNET_break (0 == close (0));
- GNUNET_break (0 == dup2 (fd, 0));
- GNUNET_break (0 == close (fd));
- if ( (0 != execlp ("nc",
- "nc",
- "localhost",
- ports,
- "-w", "30",
- NULL)) &&
- (0 != execlp ("ncat",
- "ncat",
- "localhost",
- ports,
- "-i", "30",
- NULL)) )
- {
- fprintf (stderr,
- "Failed to run both `nc' and `ncat': %s\n",
- strerror (errno));
- }
- _exit (1);
- }
- /* parent process */
- GNUNET_break (0 == close (fd));
- ret = TMH_KS_loop ();
- if (cld != waitpid (cld, &status, 0))
- fprintf (stderr,
- "Waiting for `nc' child failed: %s\n",
- strerror (errno));
- return ret;
-}
-
-
-/**
- * Signature of the callback used by MHD to notify the application
- * about completed connections. If we are running in test-mode with
- * an #input_filename, this function is used to terminate the HTTPD
- * after the first request has been processed.
- *
- * @param cls client-defined closure, NULL
- * @param connection connection handle (ignored)
- * @param socket_context socket-specific pointer (ignored)
- * @param toe reason for connection notification
- */
-static void
-connection_done (void *cls,
- struct MHD_Connection *connection,
- void **socket_context,
- enum MHD_ConnectionNotificationCode toe)
-{
- /* We only act if the connection is closed. */
- if (MHD_CONNECTION_NOTIFY_CLOSED != toe)
- return;
- /* This callback is also present if the option wasn't, so
- make sure the option was actually set. */
- if (NULL == input_filename)
- return;
- /* We signal ourselves to terminate. */
- if (0 != kill (getpid(),
- SIGTERM))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "kill");
-}
-
-/* end of HAVE_DEVELOPER */
-#endif
-
-
-/**
- * Function called for logging by MHD.
- *
- * @param cls closure, NULL
- * @param fm format string (`printf()`-style)
- * @param ap arguments to @a fm
- */
-static void
-handle_mhd_logs (void *cls,
- const char *fm,
- va_list ap)
-{
- char buf[2048];
-
- vsnprintf (buf,
- sizeof (buf),
- fm,
- ap);
- GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
- "libmicrohttpd",
- "%s",
- buf);
-}
-
-
-/**
- * The main function of the taler-mint-httpd server ("the mint").
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc,
- char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'C', "connection-close", NULL,
- "force HTTP connections to be closed after each request", 0,
- &GNUNET_GETOPT_set_one, &TMH_mint_connection_close},
- {'d', "mint-dir", "DIR",
- "mint directory with configuration and keys for operating the mint", 1,
- &GNUNET_GETOPT_set_filename, &TMH_mint_directory},
- {'t', "timeout", "SECONDS",
- "after how long do connections timeout by default (in seconds)", 1,
- &GNUNET_GETOPT_set_uint, &connection_timeout},
-#if HAVE_DEVELOPER
- {'f', "file-input", "FILENAME",
- "run in test-mode using FILENAME as the HTTP request to process", 1,
- &GNUNET_GETOPT_set_filename, &input_filename},
-#endif
- TALER_GETOPT_OPTION_HELP ("HTTP server providing a RESTful API to access a Taler mint"),
- GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- int ret;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("taler-mint-httpd",
- "INFO",
- NULL));
- if (0 >=
- GNUNET_GETOPT_run ("taler-mint-httpd",
- options,
- argc, argv))
- return 1;
- if (NULL == TMH_mint_directory)
- {
- fprintf (stderr,
- "Mint directory not specified\n");
- return 1;
- }
-
- if (GNUNET_OK !=
- mint_serve_process_config (TMH_mint_directory))
- return 1;
-
- mydaemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
- serve_port,
- NULL, NULL,
- &handle_mhd_request, NULL,
- MHD_OPTION_EXTERNAL_LOGGER, &handle_mhd_logs, NULL,
- MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL,
- MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
-#if HAVE_DEVELOPER
- MHD_OPTION_NOTIFY_CONNECTION, &connection_done, NULL,
-#endif
- MHD_OPTION_END);
-
- if (NULL == mydaemon)
- {
- fprintf (stderr,
- "Failed to start HTTP server.\n");
- return 1;
- }
-#if HAVE_DEVELOPER
- if (NULL != input_filename)
- {
- /* run only the testfile input, then terminate */
- ret = run_fake_client ();
- }
- else
- {
- /* normal behavior */
- ret = TMH_KS_loop ();
- }
-#else
- /* normal behavior */
- ret = TMH_KS_loop ();
-#endif
-
- switch (ret)
- {
- case GNUNET_OK:
- case GNUNET_SYSERR:
- MHD_stop_daemon (mydaemon);
- break;
- case GNUNET_NO:
- {
- MHD_socket sock = MHD_quiesce_daemon (mydaemon);
-
- /* FIXME #3474: fork another MHD, passing on the listen socket! */
- while (0 != MHD_get_daemon_info (mydaemon,
- MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections)
- sleep (1);
- MHD_stop_daemon (mydaemon);
-
- close (sock); /* FIXME: done like this because #3474 is open */
- }
- break;
- default:
- GNUNET_break (0);
- MHD_stop_daemon (mydaemon);
- break;
- }
-
- if (GNUNET_YES == TMH_test_mode)
- {
- struct TALER_MINTDB_Session *session;
-
- session = TMH_plugin->get_session (TMH_plugin->cls,
- GNUNET_YES);
- if (NULL == session)
- GNUNET_break (0);
- else
- TMH_plugin->drop_temporary (TMH_plugin->cls,
- session);
- }
- TALER_MINTDB_plugin_unload (TMH_plugin);
- TMH_VALIDATION_done ();
- return (GNUNET_SYSERR == ret) ? 1 : 0;
-}
-
-/* end of taler-mint-httpd.c */
diff --git a/src/mint/taler-mint-httpd.h b/src/mint/taler-mint-httpd.h
deleted file mode 100644
index d45325aa6..000000000
--- a/src/mint/taler-mint-httpd.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd.h
- * @brief Global declarations for the mint
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- *
- * FIXME: Consider which of these need to really be globals...
- */
-#ifndef TALER_MINT_HTTPD_H
-#define TALER_MINT_HTTPD_H
-
-#include <microhttpd.h>
-
-
-/**
- * Which currency is used by this mint?
- */
-extern char *TMH_mint_currency_string;
-
-/**
- * Should we return "Connection: close" in each response?
- */
-extern int TMH_mint_connection_close;
-
-/**
- * The mint's configuration.
- */
-extern struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Are we running in test mode?
- */
-extern int TMH_test_mode;
-
-/**
- * Main directory with mint data.
- */
-extern char *TMH_mint_directory;
-
-/**
- * Master public key (according to the
- * configuration in the mint directory).
- */
-extern struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
-
-/**
- * Private key of the mint we use to sign messages.
- */
-extern struct GNUNET_CRYPTO_EddsaPrivateKey TMH_mint_private_signing_key;
-
-/**
- * Our DB plugin.
- */
-extern struct TALER_MINTDB_Plugin *TMH_plugin;
-
-
-/**
- * @brief Struct describing an URL and the handler for it.
- */
-struct TMH_RequestHandler
-{
-
- /**
- * URL the handler is for.
- */
- const char *url;
-
- /**
- * Method the handler is for, NULL for "all".
- */
- const char *method;
-
- /**
- * Mime type to use in reply (hint, can be NULL).
- */
- const char *mime_type;
-
- /**
- * Raw data for the @e handler
- */
- const void *data;
-
- /**
- * Number of bytes in @e data, 0 for 0-terminated.
- */
- size_t data_size;
-
- /**
- * Function to call to handle the request.
- *
- * @param rh this struct
- * @param mime_type the @e mime_type for the reply (hint, can be NULL)
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
- int (*handler)(struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
- /**
- * Default response code.
- */
- int response_code;
-};
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_admin.c b/src/mint/taler-mint-httpd_admin.c
deleted file mode 100644
index e6f186f0b..000000000
--- a/src/mint/taler-mint-httpd_admin.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_admin.c
- * @brief Handle /admin/ requests
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include "taler-mint-httpd_admin.h"
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_validation.h"
-
-
-/**
- * Check permissions (we only allow access to /admin/ from loopback).
- *
- * @param connection connection to perform access check for
- * @return #GNUNET_OK if permitted,
- * #GNUNET_NO if denied and error was queued,
- * #GNUNET_SYSERR if denied and we failed to report
- */
-static int
-check_permissions (struct MHD_Connection *connection)
-{
- const union MHD_ConnectionInfo *ci;
- const struct sockaddr *addr;
- int res;
-
- ci = MHD_get_connection_info (connection,
- MHD_CONNECTION_INFO_CLIENT_ADDRESS);
- if (NULL == ci)
- {
- GNUNET_break (0);
- res = TMH_RESPONSE_reply_internal_error (connection,
- "Failed to verify client address");
- return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
- }
- addr = ci->client_addr;
- switch (addr->sa_family)
- {
- case AF_INET:
- {
- const struct sockaddr_in *sin = (const struct sockaddr_in *) addr;
-
- if (INADDR_LOOPBACK != ntohl (sin->sin_addr.s_addr))
- {
- res = TMH_RESPONSE_reply_permission_denied (connection,
- "/admin/ only allowed via loopback");
- return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
- }
- break;
- }
- case AF_INET6:
- {
- const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr;
-
- if (! IN6_IS_ADDR_LOOPBACK (&sin6->sin6_addr))
- {
- res = TMH_RESPONSE_reply_permission_denied (connection,
- "/admin/ only allowed via loopback");
- return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
- }
- break;
- }
- default:
- GNUNET_break (0);
- res = TMH_RESPONSE_reply_internal_error (connection,
- "Unsupported AF");
- return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-
-/**
- * Handle a "/admin/add/incoming" request. Parses the
- * given "reserve_pub", "amount", "transaction" and "h_wire"
- * details and adds the respective transaction to the database.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_Amount amount;
- struct GNUNET_TIME_Absolute at;
- json_t *wire;
- json_t *root;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("reserve_pub", &reserve_pub),
- TMH_PARSE_member_amount ("amount", &amount),
- TMH_PARSE_member_time_abs ("execution_date", &at),
- TMH_PARSE_member_object ("wire", &wire),
- TMH_PARSE_MEMBER_END
- };
- int res;
-
- res = check_permissions (connection);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == root) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- root,
- spec);
- json_decref (root);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- json_decref (root);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- if (GNUNET_YES !=
- TMH_json_validate_wireformat (wire))
- {
- GNUNET_break_op (0);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "wire");
- }
- res = TMH_DB_execute_admin_add_incoming (connection,
- &reserve_pub,
- &amount,
- at,
- wire);
- TMH_PARSE_release_data (spec);
- return res;
-}
-
-/* end of taler-mint-httpd_admin.c */
diff --git a/src/mint/taler-mint-httpd_admin.h b/src/mint/taler-mint-httpd_admin.h
deleted file mode 100644
index b8ca3ce59..000000000
--- a/src/mint/taler-mint-httpd_admin.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_admin.h
- * @brief Handle /admin/ requests
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_ADMIN_H
-#define TALER_MINT_HTTPD_ADMIN_H
-
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-/**
- * Handle a "/admin/add/incoming" request. Parses the
- * given "reserve_pub", "amount", "transaction" and "h_wire"
- * details and adds the respective transaction to the database.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-#endif
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
deleted file mode 100644
index 8c22a0a2a..000000000
--- a/src/mint/taler-mint-httpd_db.c
+++ /dev/null
@@ -1,1900 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_db.c
- * @brief High-level (transactional-layer) database operations for the mint.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <pthread.h>
-#include <jansson.h>
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_keystate.h"
-
-/**
- * How often should we retry a transaction before giving up
- * (for transactions resulting in serialization/dead locks only).
- */
-#define MAX_TRANSACTION_COMMIT_RETRIES 3
-
-/**
- * Code to begin a transaction, must be inline as we define a block
- * that ends with #COMMIT_TRANSACTION() within which we perform a number
- * of retries. Note that this code may call "return" internally, so
- * it must be called within a function where any cleanup will be done
- * by the caller. Furthermore, the function's return value must
- * match that of a #TMH_RESPONSE_reply_internal_db_error() status code.
- *
- * @param session session handle
- * @param connection connection handle
- */
-#define START_TRANSACTION(session,connection) \
-{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\
- unsigned int transaction_retries = 0; \
- int transaction_commit_result; \
-transaction_start_label: /* we will use goto for retries */ \
- if (GNUNET_OK != \
- TMH_plugin->start (TMH_plugin->cls, \
- session)) \
- { \
- GNUNET_break (0); \
- return TMH_RESPONSE_reply_internal_db_error (connection); \
- }
-
-/**
- * Code to conclude a transaction, dual to #START_TRANSACTION(). Note
- * that this code may call "return" internally, so it must be called
- * within a function where any cleanup will be done by the caller.
- * Furthermore, the function's return value must match that of a
- * #TMH_RESPONSE_reply_internal_db_error() status code.
- *
- * @param session session handle
- * @param connection connection handle
- */
-#define COMMIT_TRANSACTION(session,connection) \
- transaction_commit_result = \
- TMH_plugin->commit (TMH_plugin->cls, \
- session); \
- if (GNUNET_SYSERR == transaction_commit_result) \
- { \
- TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
- return TMH_RESPONSE_reply_commit_error (connection); \
- } \
- if (GNUNET_NO == transaction_commit_result) \
- { \
- TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
- if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \
- goto transaction_start_label; \
- TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \
- transaction_retries, \
- __FUNCTION__); \
- return TMH_RESPONSE_reply_commit_error (connection); \
- } \
-} /* end of scope opened by BEGIN_TRANSACTION */
-
-
-/**
- * Calculate the total value of all transactions performed.
- * Stores @a off plus the cost of all transactions in @a tl
- * in @a ret.
- *
- * @param tl transaction list to process
- * @param off offset to use as the starting value
- * @param ret where the resulting total is to be stored
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static int
-calculate_transaction_list_totals (struct TALER_MINTDB_TransactionList *tl,
- const struct TALER_Amount *off,
- struct TALER_Amount *ret)
-{
- struct TALER_Amount spent = *off;
- struct TALER_MINTDB_TransactionList *pos;
-
- for (pos = tl; NULL != pos; pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_MINTDB_TT_DEPOSIT:
- if (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &pos->details.deposit->amount_with_fee))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- break;
- case TALER_MINTDB_TT_REFRESH_MELT:
- if (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &pos->details.melt->amount_with_fee))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- break;
- }
- }
- *ret = spent;
- return GNUNET_OK;
-}
-
-
-/**
- * Execute a deposit. The validity of the coin and signature
- * have already been checked. The database must now check that
- * the coin is not (double or over) spent, and execute the
- * transaction (record details, generate success or failure response).
- *
- * @param connection the MHD connection to handle
- * @param deposit information about the deposit
- * @return MHD result code
- */
-int
-TMH_DB_execute_deposit (struct MHD_Connection *connection,
- const struct TALER_MINTDB_Deposit *deposit)
-{
- struct TALER_MINTDB_Session *session;
- struct TALER_MINTDB_TransactionList *tl;
- struct TALER_Amount spent;
- struct TALER_Amount value;
- struct TALER_Amount amount_without_fee;
- struct TMH_KS_StateHandle *mks;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- int ret;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- if (GNUNET_YES ==
- TMH_plugin->have_deposit (TMH_plugin->cls,
- session,
- deposit))
- {
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_subtract (&amount_without_fee,
- &deposit->amount_with_fee,
- &deposit->deposit_fee));
- return TMH_RESPONSE_reply_deposit_success (connection,
- &deposit->coin.coin_pub,
- &deposit->h_wire,
- &deposit->h_contract,
- deposit->transaction_id,
- deposit->timestamp,
- deposit->refund_deadline,
- &deposit->merchant_pub,
- &amount_without_fee);
- }
- mks = TMH_KS_acquire ();
- dki = TMH_KS_denomination_key_lookup (mks,
- &deposit->coin.denom_pub,
- TMH_KS_DKU_DEPOSIT);
- if (NULL == dki)
- {
- TMH_KS_release (mks);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "denom_pub");
- }
- TALER_amount_ntoh (&value,
- &dki->issue.properties.value);
- TMH_KS_release (mks);
-
- START_TRANSACTION (session, connection);
-
- /* fee for THIS transaction */
- spent = deposit->amount_with_fee;
- /* add cost of all previous transactions */
- tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls,
- session,
- &deposit->coin.coin_pub);
- if (GNUNET_OK !=
- calculate_transaction_list_totals (tl,
- &spent,
- &spent))
- {
- TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
- tl);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- /* Check that cost of all transactions is smaller than
- the value of the coin. */
- if (0 < TALER_amount_cmp (&spent,
- &value))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- ret = TMH_RESPONSE_reply_deposit_insufficient_funds (connection,
- tl);
- TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
- tl);
- return ret;
- }
- TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
- tl);
-
- if (GNUNET_OK !=
- TMH_plugin->insert_deposit (TMH_plugin->cls,
- session,
- deposit))
- {
- TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- COMMIT_TRANSACTION(session, connection);
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_subtract (&amount_without_fee,
- &deposit->amount_with_fee,
- &deposit->deposit_fee));
- return TMH_RESPONSE_reply_deposit_success (connection,
- &deposit->coin.coin_pub,
- &deposit->h_wire,
- &deposit->h_contract,
- deposit->transaction_id,
- deposit->timestamp,
- deposit->refund_deadline,
- &deposit->merchant_pub,
- &amount_without_fee);
-}
-
-
-/**
- * Execute a /reserve/status. Given the public key of a reserve,
- * return the associated transaction history.
- *
- * @param connection the MHD connection to handle
- * @param reserve_pub public key of the reserve to check
- * @return MHD result code
- */
-int
-TMH_DB_execute_reserve_status (struct MHD_Connection *connection,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct TALER_MINTDB_Session *session;
- struct TALER_MINTDB_ReserveHistory *rh;
- int res;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- rh = TMH_plugin->get_reserve_history (TMH_plugin->cls,
- session,
- reserve_pub);
- if (NULL == rh)
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s, s:s}",
- "error", "Reserve not found",
- "parameter", "withdraw_pub");
- res = TMH_RESPONSE_reply_reserve_status_success (connection,
- rh);
- TMH_plugin->free_reserve_history (TMH_plugin->cls,
- rh);
- return res;
-}
-
-
-/**
- * Try to execute /reserve/withdraw transaction.
- *
- * @param connection request we are handling
- * @param session database session we are using
- * @param key_state key state to lookup denomination pubs
- * @param reserve reserve to withdraw from
- * @param denomination_pub public key of the denomination requested
- * @param dki denomination to withdraw
- * @param blinded_msg blinded message to be signed
- * @param blinded_msg_len number of bytes in @a blinded_msg
- * @param h_blind hash of @a blinded_msg
- * @param signature signature over the withdraw request, to be stored in DB
- * @param denom_sig[out] where to write the resulting signature
- * (used to release memory in case of transaction failure
- * @return MHD result code
- */
-static int
-execute_reserve_withdraw_transaction (struct MHD_Connection *connection,
- struct TALER_MINTDB_Session *session,
- struct TMH_KS_StateHandle *key_state,
- const struct TALER_ReservePublicKeyP *reserve,
- const struct TALER_DenominationPublicKey *denomination_pub,
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki,
- const char *blinded_msg,
- size_t blinded_msg_len,
- const struct GNUNET_HashCode *h_blind,
- const struct TALER_ReserveSignatureP *signature,
- struct TALER_DenominationSignature *denom_sig)
-{
- struct TALER_MINTDB_ReserveHistory *rh;
- const struct TALER_MINTDB_ReserveHistory *pos;
- struct TALER_MINTDB_DenominationKeyIssueInformation *tdki;
- struct TALER_MINTDB_CollectableBlindcoin collectable;
- struct TALER_Amount amount_required;
- struct TALER_Amount deposit_total;
- struct TALER_Amount withdraw_total;
- struct TALER_Amount balance;
- struct TALER_Amount value;
- struct TALER_Amount fee_withdraw;
- int res;
-
- /* Check if balance is sufficient */
- START_TRANSACTION (session, connection);
- rh = TMH_plugin->get_reserve_history (TMH_plugin->cls,
- session,
- reserve);
- if (NULL == rh)
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "reserve_pub");
- }
-
- /* calculate amount required including fees */
- TALER_amount_ntoh (&value,
- &dki->issue.properties.value);
- TALER_amount_ntoh (&fee_withdraw,
- &dki->issue.properties.fee_withdraw);
-
- if (GNUNET_OK !=
- TALER_amount_add (&amount_required,
- &value,
- &fee_withdraw))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- /* calculate balance of the reserve */
- res = 0;
- for (pos = rh; NULL != pos; pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_MINTDB_RO_BANK_TO_MINT:
- if (0 == (res & 1))
- deposit_total = pos->details.bank->amount;
- else
- if (GNUNET_OK !=
- TALER_amount_add (&deposit_total,
- &deposit_total,
- &pos->details.bank->amount))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- res |= 1;
- break;
- case TALER_MINTDB_RO_WITHDRAW_COIN:
- tdki = TMH_KS_denomination_key_lookup (key_state,
- &pos->details.withdraw->denom_pub,
- TMH_KS_DKU_WITHDRAW);
- if (NULL == tdki)
- {
- GNUNET_break (0);
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- TALER_amount_ntoh (&value,
- &tdki->issue.properties.value);
- if (0 == (res & 2))
- withdraw_total = value;
- else
- if (GNUNET_OK !=
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- res |= 2;
- break;
- }
- }
- if (0 == (res & 1))
- {
- /* did not encounter any deposit operations, how can we have a reserve? */
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- if (0 == (res & 2))
- {
- /* did not encounter any withdraw operations, set to zero */
- TALER_amount_get_zero (deposit_total.currency,
- &withdraw_total);
- }
- /* All reserve balances should be non-negative */
- GNUNET_assert (GNUNET_SYSERR !=
- TALER_amount_subtract (&balance,
- &deposit_total,
- &withdraw_total));
- if (0 < TALER_amount_cmp (&amount_required,
- &balance))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- res = TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (connection,
- rh);
- TMH_plugin->free_reserve_history (TMH_plugin->cls,
- rh);
- return res;
- }
- TMH_plugin->free_reserve_history (TMH_plugin->cls,
- rh);
-
- /* Balance is good, sign the coin! */
- denom_sig->rsa_signature
- = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
- blinded_msg,
- blinded_msg_len);
- if (NULL == denom_sig->rsa_signature)
- {
- GNUNET_break (0);
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Internal error");
- }
- collectable.sig = *denom_sig;
- collectable.denom_pub = *denomination_pub;
- collectable.amount_with_fee = amount_required;
- collectable.withdraw_fee = fee_withdraw;
- collectable.reserve_pub = *reserve;
- collectable.h_coin_envelope = *h_blind;
- collectable.reserve_sig = *signature;
- if (GNUNET_OK !=
- TMH_plugin->insert_withdraw_info (TMH_plugin->cls,
- session,
- &collectable))
- {
- GNUNET_break (0);
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- COMMIT_TRANSACTION (session, connection);
-
- return TMH_RESPONSE_reply_reserve_withdraw_success (connection,
- &collectable);
-}
-
-
-
-/**
- * Execute a "/reserve/withdraw". Given a reserve and a properly signed
- * request to withdraw a coin, check the balance of the reserve and
- * if it is sufficient, store the request and return the signed
- * blinded envelope.
- *
- * @param connection the MHD connection to handle
- * @param reserve public key of the reserve
- * @param denomination_pub public key of the denomination requested
- * @param blinded_msg blinded message to be signed
- * @param blinded_msg_len number of bytes in @a blinded_msg
- * @param signature signature over the withdraw request, to be stored in DB
- * @return MHD result code
- */
-int
-TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
- const struct TALER_ReservePublicKeyP *reserve,
- const struct TALER_DenominationPublicKey *denomination_pub,
- const char *blinded_msg,
- size_t blinded_msg_len,
- const struct TALER_ReserveSignatureP *signature)
-{
- struct TALER_MINTDB_Session *session;
- struct TMH_KS_StateHandle *key_state;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TALER_MINTDB_CollectableBlindcoin collectable;
- struct TALER_DenominationSignature denom_sig;
- struct GNUNET_HashCode h_blind;
- int res;
-
- GNUNET_CRYPTO_hash (blinded_msg,
- blinded_msg_len,
- &h_blind);
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- res = TMH_plugin->get_withdraw_info (TMH_plugin->cls,
- session,
- &h_blind,
- &collectable);
- if (GNUNET_SYSERR == res)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- /* Don't sign again if we have already signed the coin */
- if (GNUNET_YES == res)
- {
- res = TMH_RESPONSE_reply_reserve_withdraw_success (connection,
- &collectable);
- GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key);
- return res;
- }
- GNUNET_assert (GNUNET_NO == res);
-
- key_state = TMH_KS_acquire ();
- dki = TMH_KS_denomination_key_lookup (key_state,
- denomination_pub,
- TMH_KS_DKU_WITHDRAW);
- if (NULL == dki)
- {
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error",
- "Denomination not found");
- }
- denom_sig.rsa_signature = NULL;
- res = execute_reserve_withdraw_transaction (connection,
- session,
- key_state,
- reserve,
- denomination_pub,
- dki,
- blinded_msg,
- blinded_msg_len,
- &h_blind,
- signature,
- &denom_sig);
- if (NULL != denom_sig.rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature);
- TMH_KS_release (key_state);
- return res;
-}
-
-
-/**
- * Parse coin melt requests from a JSON object and write them to
- * the database.
- *
- * @param connection the connection to send errors to
- * @param session the database connection
- * @param key_state the mint's key state
- * @param session_hash hash identifying the refresh session
- * @param coin_details details about the coin being melted
- * @param oldcoin_index what is the number assigned to this coin
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if an error message was generated,
- * #GNUNET_SYSERR on internal errors (no response generated)
- */
-static int
-refresh_accept_melts (struct MHD_Connection *connection,
- struct TALER_MINTDB_Session *session,
- const struct TMH_KS_StateHandle *key_state,
- const struct GNUNET_HashCode *session_hash,
- const struct TMH_DB_MeltDetails *coin_details,
- uint16_t oldcoin_index)
-{
- struct TALER_MINTDB_DenominationKeyIssueInformation *dk;
- struct TALER_MINTDB_DenominationKeyInformationP *dki;
- struct TALER_MINTDB_TransactionList *tl;
- struct TALER_Amount coin_value;
- struct TALER_Amount coin_residual;
- struct TALER_Amount spent;
- struct TALER_MINTDB_RefreshMelt melt;
- int res;
-
- dk = TMH_KS_denomination_key_lookup (key_state,
- &coin_details->coin_info.denom_pub,
- TMH_KS_DKU_DEPOSIT);
- if (NULL == dk)
- return (MHD_YES ==
- TMH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub"))
- ? GNUNET_NO : GNUNET_SYSERR;
- dki = &dk->issue;
- TALER_amount_ntoh (&coin_value,
- &dki->properties.value);
- /* fee for THIS transaction; the melt amount includes the fee! */
- spent = coin_details->melt_amount_with_fee;
- /* add historic transaction costs of this coin */
- tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls,
- session,
- &coin_details->coin_info.coin_pub);
- if (GNUNET_OK !=
- calculate_transaction_list_totals (tl,
- &spent,
- &spent))
- {
- GNUNET_break (0);
- TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
- tl);
- return (MHD_YES ==
- TMH_RESPONSE_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- /* Refuse to refresh when the coin's value is insufficient
- for the cost of all transactions. */
- if (TALER_amount_cmp (&coin_value,
- &spent) < 0)
- {
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_subtract (&coin_residual,
- &spent,
- &coin_details->melt_amount_with_fee));
- res = (MHD_YES ==
- TMH_RESPONSE_reply_refresh_melt_insufficient_funds (connection,
- &coin_details->coin_info.coin_pub,
- coin_value,
- tl,
- coin_details->melt_amount_with_fee,
- coin_residual))
- ? GNUNET_NO : GNUNET_SYSERR;
- TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
- tl);
- return res;
- }
- TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
- tl);
-
- melt.coin = coin_details->coin_info;
- melt.coin_sig = coin_details->melt_sig;
- melt.session_hash = *session_hash;
- melt.amount_with_fee = coin_details->melt_amount_with_fee;
- melt.melt_fee = coin_details->melt_fee;
- if (GNUNET_OK !=
- TMH_plugin->insert_refresh_melt (TMH_plugin->cls,
- session,
- oldcoin_index,
- &melt))
- {
- GNUNET_break (0);
- return (MHD_YES ==
- TMH_RESPONSE_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Execute a "/refresh/melt". We have been given a list of valid
- * coins and a request to melt them into the given
- * @a refresh_session_pub. Check that the coins all have the
- * required value left and if so, store that they have been
- * melted and confirm the melting operation to the client.
- *
- * @param connection the MHD connection to handle
- * @param session_hash hash code of the session the coins are melted into
- * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array
- * @param denom_pubs public keys of the coins we want to withdraw in the end
- * @param coin_count number of entries in @a coin_melt_details, size of y-dimension of @a commit_link array
- * @param coin_melt_details signatures and (residual) value of the respective coin should be melted
- * @param commit_coin 2d array of coin commitments (what the mint is to sign
- * once the "/refres/reveal" of cut and choose is done),
- * x-dimension must be #TALER_CNC_KAPPA
- * @param commit_link 2d array of coin link commitments (what the mint is
- * to return via "/refresh/link" to enable linkage in the
- * future)
- * x-dimension must be #TALER_CNC_KAPPA
- * @return MHD result code
- */
-int
-TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- unsigned int num_new_denoms,
- const struct TALER_DenominationPublicKey *denom_pubs,
- unsigned int coin_count,
- const struct TMH_DB_MeltDetails *coin_melt_details,
- struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin,
- struct TALER_RefreshCommitLinkP *const* commit_link)
-{
- struct TMH_KS_StateHandle *key_state;
- struct TALER_MINTDB_RefreshSession refresh_session;
- struct TALER_MINTDB_Session *session;
- int res;
- unsigned int i;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- START_TRANSACTION (session, connection);
- res = TMH_plugin->get_refresh_session (TMH_plugin->cls,
- session,
- session_hash,
- &refresh_session);
- if (GNUNET_YES == res)
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- res = TMH_RESPONSE_reply_refresh_melt_success (connection,
- session_hash,
- refresh_session.noreveal_index);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- if (GNUNET_SYSERR == res)
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- /* store 'global' session data */
- refresh_session.num_oldcoins = coin_count;
- refresh_session.num_newcoins = num_new_denoms;
- refresh_session.noreveal_index
- = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
- TALER_CNC_KAPPA);
- if (GNUNET_OK !=
- (res = TMH_plugin->create_refresh_session (TMH_plugin->cls,
- session,
- session_hash,
- &refresh_session)))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- /* Melt old coins and check that they had enough residual value */
- key_state = TMH_KS_acquire ();
- for (i=0;i<coin_count;i++)
- {
- if (GNUNET_OK !=
- (res = refresh_accept_melts (connection,
- session,
- key_state,
- session_hash,
- &coin_melt_details[i],
- i)))
- {
- TMH_KS_release (key_state);
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- }
- TMH_KS_release (key_state);
-
- /* store requested new denominations */
- if (GNUNET_OK !=
- TMH_plugin->insert_refresh_order (TMH_plugin->cls,
- session,
- session_hash,
- num_new_denoms,
- denom_pubs))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- for (i = 0; i < TALER_CNC_KAPPA; i++)
- {
- if (GNUNET_OK !=
- TMH_plugin->insert_refresh_commit_coins (TMH_plugin->cls,
- session,
- session_hash,
- i,
- num_new_denoms,
- commit_coin[i]))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- }
- for (i = 0; i < TALER_CNC_KAPPA; i++)
- {
- if (GNUNET_OK !=
- TMH_plugin->insert_refresh_commit_links (TMH_plugin->cls,
- session,
- session_hash,
- i,
- coin_count,
- commit_link[i]))
- {
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- }
-
- COMMIT_TRANSACTION (session, connection);
- return TMH_RESPONSE_reply_refresh_melt_success (connection,
- session_hash,
- refresh_session.noreveal_index);
-}
-
-
-/**
- * Send an error response with the details of the original melt
- * commitment and the location of the mismatch.
- *
- * @param connection the MHD connection to handle
- * @param session database connection to use
- * @param session_hash hash of session to query
- * @param off commitment offset to check
- * @param index index of the mismatch
- * @param object_name name of the object with the problem
- * @return #GNUNET_NO if we generated the error message
- * #GNUNET_SYSERR if we could not even generate an error message
- */
-static int
-send_melt_commitment_error (struct MHD_Connection *connection,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- unsigned int off,
- unsigned int index,
- const char *object_name)
-{
- struct TALER_MINTDB_MeltCommitment *mc;
- int ret;
-
- mc = TMH_plugin->get_melt_commitment (TMH_plugin->cls,
- session,
- session_hash);
- if (NULL == mc)
- {
- GNUNET_break (0);
- return (MHD_YES ==
- TMH_RESPONSE_reply_internal_error (connection,
- "Melt commitment assembly"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_refresh_reveal_missmatch (connection,
- mc,
- off,
- index,
- object_name))
- ? GNUNET_NO : GNUNET_SYSERR;
- TMH_plugin->free_melt_commitment (TMH_plugin->cls,
- mc);
- return ret;
-}
-
-
-/**
- * Check if the given @a transfer_privs correspond to an honest
- * commitment for the given session.
- * Checks that the transfer private keys match their commitments.
- * Then derives the shared secret for each #TALER_CNC_KAPPA, and check that they match.
- *
- * @param connection the MHD connection to handle
- * @param session database connection to use
- * @param session_hash hash of session to query
- * @param off commitment offset to check
- * @param num_oldcoins size of the @a transfer_privs and @a melts arrays
- * @param transfer_privs private transfer keys
- * @param melts array of melted coins
- * @param num_newcoins number of newcoins being generated
- * @param denom_pubs array of @a num_newcoins keys for the new coins
- * @return #GNUNET_OK if the committment was honest,
- * #GNUNET_NO if there was a problem and we generated an error message
- * #GNUNET_SYSERR if we could not even generate an error message
- */
-static int
-check_commitment (struct MHD_Connection *connection,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- unsigned int off,
- unsigned int num_oldcoins,
- const struct TALER_TransferPrivateKeyP *transfer_privs,
- const struct TALER_MINTDB_RefreshMelt *melts,
- unsigned int num_newcoins,
- const struct TALER_DenominationPublicKey *denom_pubs)
-{
- unsigned int j;
- struct TALER_LinkSecretP last_shared_secret;
- int secret_initialized = GNUNET_NO;
- struct TALER_RefreshCommitLinkP *commit_links;
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins;
-
- commit_links = GNUNET_malloc (num_oldcoins *
- sizeof (struct TALER_RefreshCommitLinkP));
- if (GNUNET_OK !=
- TMH_plugin->get_refresh_commit_links (TMH_plugin->cls,
- session,
- session_hash,
- off,
- num_oldcoins,
- commit_links))
- {
- GNUNET_break (0);
- GNUNET_free (commit_links);
- return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
- for (j = 0; j < num_oldcoins; j++)
- {
- struct TALER_LinkSecretP shared_secret;
- struct TALER_TransferPublicKeyP transfer_pub_check;
-
- GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[j].ecdhe_priv,
- &transfer_pub_check.ecdhe_pub);
- if (0 !=
- memcmp (&transfer_pub_check,
- &commit_links[j].transfer_pub,
- sizeof (struct TALER_TransferPublicKeyP)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "transfer keys do not match\n");
- GNUNET_free (commit_links);
- return send_melt_commitment_error (connection,
- session,
- session_hash,
- off,
- j,
- "transfer key");
- }
-
- if (GNUNET_OK !=
- TALER_link_decrypt_secret (&commit_links[j].shared_secret_enc,
- &transfer_privs[j],
- &melts[j].coin.coin_pub,
- &shared_secret))
- {
- GNUNET_free (commit_links);
- return (MHD_YES ==
- TMH_RESPONSE_reply_internal_error (connection,
- "Transfer secret decryption error"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- if (GNUNET_NO == secret_initialized)
- {
- secret_initialized = GNUNET_YES;
- last_shared_secret = shared_secret;
- }
- else if (0 != memcmp (&shared_secret,
- &last_shared_secret,
- sizeof (struct GNUNET_HashCode)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "shared secrets do not match\n");
- GNUNET_free (commit_links);
- return send_melt_commitment_error (connection,
- session,
- session_hash,
- off,
- j,
- "transfer secret");
- }
- }
- GNUNET_break (GNUNET_YES == secret_initialized);
- GNUNET_free (commit_links);
-
- /* Check that the commitments for all new coins were correct */
- commit_coins = GNUNET_malloc (num_newcoins *
- sizeof (struct TALER_MINTDB_RefreshCommitCoin));
-
- if (GNUNET_OK !=
- TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls,
- session,
- session_hash,
- off,
- num_newcoins,
- commit_coins))
- {
- GNUNET_break (0);
- GNUNET_free (commit_coins);
- return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
- for (j = 0; j < num_newcoins; j++)
- {
- struct TALER_RefreshLinkDecrypted *link_data;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_HashCode h_msg;
- char *buf;
- size_t buf_len;
-
- link_data = TALER_refresh_decrypt (commit_coins[j].refresh_link,
- &last_shared_secret);
- if (NULL == link_data)
- {
- GNUNET_break (0);
- GNUNET_free (commit_coins);
- return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection,
- "Decryption error"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
- GNUNET_CRYPTO_eddsa_key_get_public (&link_data->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash (&coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP),
- &h_msg);
- if (0 == (buf_len =
- GNUNET_CRYPTO_rsa_blind (&h_msg,
- link_data->blinding_key.rsa_blinding_key,
- denom_pubs[j].rsa_public_key,
- &buf)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "blind failed\n");
- GNUNET_free (commit_coins);
- return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection,
- "Blinding error"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
- if ( (buf_len != commit_coins[j].coin_ev_size) ||
- (0 != memcmp (buf,
- commit_coins[j].coin_ev,
- buf_len)) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "blind envelope does not match for k=%u, old=%d\n",
- off,
- (int) j);
- GNUNET_free (commit_coins);
- return send_melt_commitment_error (connection,
- session,
- session_hash,
- off,
- j,
- "envelope");
- }
- GNUNET_free (buf);
- }
- GNUNET_free (commit_coins);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Mint a coin as part of a refresh operation. Obtains the
- * envelope from the database and performs the signing operation.
- *
- * @param connection the MHD connection to handle
- * @param session database connection to use
- * @param session_hash hash of session to query
- * @param key_state key state to lookup denomination pubs
- * @param denom_pub denomination key for the coin to create
- * @param commit_coin the coin that was committed
- * @param coin_off number of the coin
- * @return NULL on error, otherwise signature over the coin
- */
-static struct TALER_DenominationSignature
-refresh_mint_coin (struct MHD_Connection *connection,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- struct TMH_KS_StateHandle *key_state,
- const struct TALER_DenominationPublicKey *denom_pub,
- const struct TALER_MINTDB_RefreshCommitCoin *commit_coin,
- unsigned int coin_off)
-{
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TALER_DenominationSignature ev_sig;
-
- dki = TMH_KS_denomination_key_lookup (key_state,
- denom_pub,
- TMH_KS_DKU_WITHDRAW);
- if (NULL == dki)
- {
- GNUNET_break (0);
- ev_sig.rsa_signature = NULL;
- return ev_sig;
- }
- ev_sig.rsa_signature
- = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
- commit_coin->coin_ev,
- commit_coin->coin_ev_size);
- if (NULL == ev_sig.rsa_signature)
- {
- GNUNET_break (0);
- return ev_sig;
- }
- if (GNUNET_OK !=
- TMH_plugin->insert_refresh_out (TMH_plugin->cls,
- session,
- session_hash,
- coin_off,
- &ev_sig))
- {
- GNUNET_break (0);
- GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature);
- ev_sig.rsa_signature = NULL;
- }
- return ev_sig;
-}
-
-
-/**
- * The client request was well-formed, now execute the DB transaction
- * of a "/refresh/reveal" operation. We use the @a ev_sigs and
- * @a commit_coins to clean up resources after this function returns
- * as we might experience retries of the database transaction.
- *
- * @param connection the MHD connection to handle
- * @param session database session
- * @param session_hash hash identifying the refresh session
- * @param refresh_session information about the refresh operation we are doing
- * @param melts array of "num_oldcoins" with information about melted coins
- * @param denom_pubs array of "num_newcoins" denomination keys for the new coins
- * @param[out] ev_sigs where to store generated signatures for the new coins,
- * array of length "num_newcoins", memory released by the
- * caller
- * @param[out] commit_coins array of length "num_newcoins" to be used for
- * information about the new coins from the commitment.
- * @return MHD result code
- */
-static int
-execute_refresh_reveal_transaction (struct MHD_Connection *connection,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- const struct TALER_MINTDB_RefreshSession *refresh_session,
- const struct TALER_MINTDB_RefreshMelt *melts,
- const struct TALER_DenominationPublicKey *denom_pubs,
- struct TALER_DenominationSignature *ev_sigs,
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins)
-{
- unsigned int j;
- struct TMH_KS_StateHandle *key_state;
-
- START_TRANSACTION (session, connection);
- if (GNUNET_OK !=
- TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls,
- session,
- session_hash,
- refresh_session->noreveal_index,
- refresh_session->num_newcoins,
- commit_coins))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- key_state = TMH_KS_acquire ();
- for (j=0;j<refresh_session->num_newcoins;j++)
- {
- if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries */
- ev_sigs[j] = refresh_mint_coin (connection,
- session,
- session_hash,
- key_state,
- &denom_pubs[j],
- &commit_coins[j],
- j);
- if (NULL == ev_sigs[j].rsa_signature)
- {
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- }
- TMH_KS_release (key_state);
- COMMIT_TRANSACTION (session, connection);
- return TMH_RESPONSE_reply_refresh_reveal_success (connection,
- refresh_session->num_newcoins,
- ev_sigs);
-}
-
-
-/**
- * Execute a "/refresh/reveal". The client is revealing to us the
- * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins. Verify that the
- * revealed transfer keys would allow linkage to the blinded coins,
- * and if so, return the signed coins for corresponding to the set of
- * coins that was not chosen.
- *
- * @param connection the MHD connection to handle
- * @param session_hash hash identifying the refresh session
- * @param num_oldcoins size of y-dimension of @a transfer_privs array
- * @param transfer_privs array with the revealed transfer keys,
- * x-dimension must be #TALER_CNC_KAPPA - 1
- * @return MHD result code
- */
-int
-TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- unsigned int num_oldcoins,
- struct TALER_TransferPrivateKeyP **transfer_privs)
-{
- int res;
- struct TALER_MINTDB_Session *session;
- struct TALER_MINTDB_RefreshSession refresh_session;
- struct TALER_MINTDB_RefreshMelt *melts;
- struct TALER_DenominationPublicKey *denom_pubs;
- struct TALER_DenominationSignature *ev_sigs;
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins;
- unsigned int i;
- unsigned int j;
- unsigned int off;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- res = TMH_plugin->get_refresh_session (TMH_plugin->cls,
- session,
- session_hash,
- &refresh_session);
- if (GNUNET_NO == res)
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "session_hash");
- if (GNUNET_SYSERR == res)
- return TMH_RESPONSE_reply_internal_db_error (connection);
- if (0 == refresh_session.num_oldcoins)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
-
- melts = GNUNET_malloc (refresh_session.num_oldcoins *
- sizeof (struct TALER_MINTDB_RefreshMelt));
- for (j=0;j<refresh_session.num_oldcoins;j++)
- {
- if (GNUNET_OK !=
- TMH_plugin->get_refresh_melt (TMH_plugin->cls,
- session,
- session_hash,
- j,
- &melts[j]))
- {
- GNUNET_break (0);
- for (i=0;i<j;i++)
- {
- GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
- }
- GNUNET_free (melts);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- }
- denom_pubs = GNUNET_malloc (refresh_session.num_newcoins *
- sizeof (struct TALER_DenominationPublicKey));
- if (GNUNET_OK !=
- TMH_plugin->get_refresh_order (TMH_plugin->cls,
- session,
- session_hash,
- refresh_session.num_newcoins,
- denom_pubs))
- {
- GNUNET_break (0);
- GNUNET_free (denom_pubs);
- for (i=0;i<refresh_session.num_oldcoins;i++)
- {
- GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
- }
- GNUNET_free (melts);
- return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
-
- off = 0;
- for (i=0;i<TALER_CNC_KAPPA - 1;i++)
- {
- if (i == refresh_session.noreveal_index)
- off = 1;
- if (GNUNET_OK !=
- (res = check_commitment (connection,
- session,
- session_hash,
- i + off,
- refresh_session.num_oldcoins,
- transfer_privs[i],
- melts,
- refresh_session.num_newcoins,
- denom_pubs)))
- {
- for (j=0;j<refresh_session.num_newcoins;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
- GNUNET_free (denom_pubs);
- for (i=0;i<refresh_session.num_oldcoins;i++)
- {
- GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
- }
- GNUNET_free (melts);
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
- }
- for (i=0;i<refresh_session.num_oldcoins;i++)
- {
- GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key);
- }
- GNUNET_free (melts);
-
- /* Client request OK, start transaction */
- commit_coins = GNUNET_malloc (refresh_session.num_newcoins *
- sizeof (struct TALER_MINTDB_RefreshCommitCoin));
- ev_sigs = GNUNET_malloc (refresh_session.num_newcoins *
- sizeof (struct TALER_DenominationSignature));
- res = execute_refresh_reveal_transaction (connection,
- session,
- session_hash,
- &refresh_session,
- melts,
- denom_pubs,
- ev_sigs,
- commit_coins);
- for (i=0;i<refresh_session.num_newcoins;i++)
- if (NULL != ev_sigs[i].rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature);
- for (j=0;j<refresh_session.num_newcoins;j++)
- if (NULL != denom_pubs[j].rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
- GNUNET_free (ev_sigs);
- GNUNET_free (denom_pubs);
- GNUNET_free (commit_coins);
- return res;
-}
-
-
-/**
- * Closure for #handle_transfer_data().
- */
-struct HTD_Context
-{
-
- /**
- * Session link data we collect.
- */
- struct TMH_RESPONSE_LinkSessionInfo *sessions;
-
- /**
- * Database session. Nothing to do with @a sessions.
- */
- struct TALER_MINTDB_Session *session;
-
- /**
- * MHD connection, for queueing replies.
- */
- struct MHD_Connection *connection;
-
- /**
- * Number of sessions the coin was melted into.
- */
- unsigned int num_sessions;
-
- /**
- * How are we expected to proceed. #GNUNET_SYSERR if we
- * failed to return an error (should return #MHD_NO).
- * #GNUNET_NO if we succeeded in queueing an MHD error
- * (should return #MHD_YES from #TMH_execute_refresh_link),
- * #GNUNET_OK if we should call #TMH_RESPONSE_reply_refresh_link_success().
- */
- int status;
-};
-
-
-/**
- * Function called with the session hashes and transfer secret
- * information for a given coin. Gets the linkage data and
- * builds the reply for the client.
- *
- *
- * @param cls closure, a `struct HTD_Context`
- * @param session_hash a session the coin was melted in
- * @param transfer_pub public transfer key for the session
- * @param shared_secret_enc set to shared secret for the session
- */
-static void
-handle_transfer_data (void *cls,
- const struct GNUNET_HashCode *session_hash,
- const struct TALER_TransferPublicKeyP *transfer_pub,
- const struct TALER_EncryptedLinkSecretP *shared_secret_enc)
-{
- struct HTD_Context *ctx = cls;
- struct TALER_MINTDB_LinkDataList *ldl;
- struct TMH_RESPONSE_LinkSessionInfo *lsi;
-
- if (GNUNET_OK != ctx->status)
- return;
- ldl = TMH_plugin->get_link_data_list (TMH_plugin->cls,
- ctx->session,
- session_hash);
- if (NULL == ldl)
- {
- ctx->status = GNUNET_NO;
- if (MHD_NO ==
- TMH_RESPONSE_reply_json_pack (ctx->connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error",
- "link data not found (link)"))
- ctx->status = GNUNET_SYSERR;
- return;
- }
- GNUNET_array_grow (ctx->sessions,
- ctx->num_sessions,
- ctx->num_sessions + 1);
- lsi = &ctx->sessions[ctx->num_sessions - 1];
- lsi->transfer_pub = *transfer_pub;
- lsi->shared_secret_enc = *shared_secret_enc;
- lsi->ldl = ldl;
-}
-
-
-/**
- * Execute a "/refresh/link". Returns the linkage information that
- * will allow the owner of a coin to follow the refresh trail to
- * the refreshed coin.
- *
- * @param connection the MHD connection to handle
- * @param coin_pub public key of the coin to link
- * @return MHD result code
- */
-int
-TMH_DB_execute_refresh_link (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub)
-{
- struct HTD_Context ctx;
- int res;
- unsigned int i;
-
- if (NULL == (ctx.session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- ctx.connection = connection;
- ctx.num_sessions = 0;
- ctx.sessions = NULL;
- ctx.status = GNUNET_OK;
- res = TMH_plugin->get_transfer (TMH_plugin->cls,
- ctx.session,
- coin_pub,
- &handle_transfer_data,
- &ctx);
- if (GNUNET_SYSERR == ctx.status)
- {
- res = MHD_NO;
- goto cleanup;
- }
- if (GNUNET_NO == ctx.status)
- {
- res = MHD_YES;
- goto cleanup;
- }
- GNUNET_assert (GNUNET_OK == ctx.status);
- if (0 == ctx.num_sessions)
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "coin_pub");
- res = TMH_RESPONSE_reply_refresh_link_success (connection,
- ctx.num_sessions,
- ctx.sessions);
- cleanup:
- for (i=0;i<ctx.num_sessions;i++)
- TMH_plugin->free_link_data_list (TMH_plugin->cls,
- ctx.sessions[i].ldl);
- GNUNET_free_non_null (ctx.sessions);
- return res;
-}
-
-
-/**
- * Add an incoming transaction to the database. Checks if the
- * transaction is fresh (not a duplicate) and if so adds it to
- * the database.
- *
- * @param connection the MHD connection to handle
- * @param reserve_pub public key of the reserve
- * @param amount amount to add to the reserve
- * @param execution_time when did we receive the wire transfer
- * @param wire details about the wire transfer
- * @return MHD result code
- */
-int
-TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute execution_time,
- json_t *wire)
-{
- struct TALER_MINTDB_Session *session;
- int ret;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- ret = TMH_plugin->reserves_in_insert (TMH_plugin->cls,
- session,
- reserve_pub,
- amount,
- execution_time,
- wire);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:s}",
- "status",
- (GNUNET_OK == ret)
- ? "NEW"
- : "DUP");
-}
-
-
-/**
- * Closure for #handle_transaction_data.
- */
-struct WtidTransactionContext
-{
-
- /**
- * Total amount of the wire transfer, as calculated by
- * summing up the individual amounts. To be rounded down
- * to calculate the real transfer amount at the end.
- * Only valid if @e is_valid is #GNUNET_YES.
- */
- struct TALER_Amount total;
-
- /**
- * Public key of the merchant, only valid if @e is_valid
- * is #GNUNET_YES.
- */
- struct TALER_MerchantPublicKeyP merchant_pub;
-
- /**
- * Hash of the wire details of the merchant (identical for all
- * deposits), only valid if @e is_valid is #GNUNET_YES.
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * JSON array with details about the individual deposits.
- */
- json_t *deposits;
-
- /**
- * Initially #GNUNET_NO, if we found no deposits so far. Set to
- * #GNUNET_YES if we got transaction data, and the database replies
- * remained consistent with respect to @e merchant_pub and @e h_wire
- * (as they should). Set to #GNUNET_SYSERR if we encountered an
- * internal error.
- */
- int is_valid;
-
-};
-
-
-/**
- * Function called with the results of the lookup of the
- * transaction data for the given wire transfer identifier.
- *
- * @param cls our context for transmission
- * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_contract which contract was this payment about
- * @param transaction_id merchant's transaction ID for the payment
- * @param coin_pub which public key was this payment about
- * @param deposit_value amount contributed by this coin in total
- * @param deposit_fee deposit fee charged by mint for this coin
- */
-static void
-handle_transaction_data (void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *deposit_value,
- const struct TALER_Amount *deposit_fee)
-{
- struct WtidTransactionContext *ctx = cls;
- struct TALER_Amount delta;
-
- if (GNUNET_SYSERR == ctx->is_valid)
- return;
- if (GNUNET_NO == ctx->is_valid)
- {
- ctx->merchant_pub = *merchant_pub;
- ctx->h_wire = *h_wire;
- ctx->is_valid = GNUNET_YES;
- if (GNUNET_OK !=
- TALER_amount_subtract (&ctx->total,
- deposit_value,
- deposit_fee))
- {
- GNUNET_break (0);
- ctx->is_valid = GNUNET_SYSERR;
- return;
- }
- }
- else
- {
- if ( (0 != memcmp (&ctx->merchant_pub,
- merchant_pub,
- sizeof (struct TALER_MerchantPublicKeyP))) ||
- (0 != memcmp (&ctx->h_wire,
- h_wire,
- sizeof (struct GNUNET_HashCode))) )
- {
- GNUNET_break (0);
- ctx->is_valid = GNUNET_SYSERR;
- return;
- }
- if (GNUNET_OK !=
- TALER_amount_subtract (&delta,
- deposit_value,
- deposit_fee))
- {
- GNUNET_break (0);
- ctx->is_valid = GNUNET_SYSERR;
- return;
- }
- if (GNUNET_OK !=
- TALER_amount_add (&ctx->total,
- &ctx->total,
- &delta))
- {
- GNUNET_break (0);
- ctx->is_valid = GNUNET_SYSERR;
- return;
- }
- }
- /* NOTE: We usually keep JSON stuff out of the _DB file, and this
- is also ugly if we ever add signatures over this data. (#4135) */
- json_array_append (ctx->deposits,
- json_pack ("{s:o, s:o, s:o, s:I, s:o}",
- "deposit_value", TALER_json_from_amount (deposit_value),
- "deposit_fee", TALER_json_from_amount (deposit_fee),
- "H_contract", TALER_json_from_data (h_contract,
- sizeof (struct GNUNET_HashCode)),
- "transaction_id", (json_int_t) transaction_id,
- "coin_pub", TALER_json_from_data (coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP))));
-}
-
-
-/**
- * Execute a "/wire/deposits". Returns the transaction information
- * associated with the given wire transfer identifier.
- *
- * @param connection the MHD connection to handle
- * @param wtid wire transfer identifier to resolve
- * @return MHD result code
- */
-int
-TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
- const struct TALER_WireTransferIdentifierRawP *wtid)
-{
- int ret;
- struct WtidTransactionContext ctx;
- struct TALER_MINTDB_Session *session;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- ctx.is_valid = GNUNET_NO;
- ctx.deposits = json_array ();
- ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls,
- session,
- wtid,
- &handle_transaction_data,
- &ctx);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_break (0);
- json_decref (ctx.deposits);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- if (GNUNET_SYSERR == ctx.is_valid)
- {
- GNUNET_break (0);
- json_decref (ctx.deposits);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- if (GNUNET_NO == ctx.is_valid)
- {
- json_decref (ctx.deposits);
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "wtid");
- }
- return TMH_RESPONSE_reply_wire_deposit_details (connection,
- &ctx.total,
- &ctx.merchant_pub,
- &ctx.h_wire,
- ctx.deposits);
-}
-
-
-/**
- * Closure for #handle_wtid_data.
- */
-struct DepositWtidContext
-{
-
- /**
- * Where should we send the reply?
- */
- struct MHD_Connection *connection;
-
- /**
- * Hash of the contract we are looking up.
- */
- struct GNUNET_HashCode h_contract;
-
- /**
- * Hash of the wire transfer details we are looking up.
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * Public key we are looking up.
- */
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- /**
- * Transaction ID we are looking up.
- */
- uint64_t transaction_id;
-
- /**
- * MHD result code to return.
- */
- int res;
-};
-
-
-/**
- * Function called with the results of the lookup of the
- * wire transfer identifier information.
- *
- * @param cls our context for transmission
- * @param wtid raw wire transfer identifier, NULL
- * if the transaction was not yet done
- * @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value including fee)
- * @param coin_fee how much did the mint charge for the deposit fee
- * @param execution_time when was the transaction done, or
- * when we expect it to be done (if @a wtid was NULL);
- * #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
- * to the mint
- */
-static void
-handle_wtid_data (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time)
-{
- struct DepositWtidContext *ctx = cls;
- struct TALER_Amount coin_delta;
-
- if (NULL == wtid)
- {
- ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
- execution_time);
- }
- else
- {
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (&coin_delta,
- coin_contribution,
- coin_fee))
- {
- GNUNET_break (0);
- ctx->res = TMH_RESPONSE_reply_internal_db_error (ctx->connection);
- }
- else
- {
- ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection,
- &ctx->h_contract,
- &ctx->h_wire,
- &ctx->coin_pub,
- &coin_delta,
- ctx->transaction_id,
- wtid,
- execution_time);
- }
- }
-}
-
-
-/**
- * Execute a "/deposit/wtid". Returns the transfer information
- * associated with the given deposit.
- *
- * @param connection the MHD connection to handle
- * @param h_contract hash of the contract
- * @param h_wire hash of the wire details
- * @param coin_pub public key of the coin to link
- * @param merchant_pub public key of the merchant
- * @param transaction_id transaction ID of the merchant
- * @return MHD result code
- */
-int
-TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *h_contract,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- uint64_t transaction_id)
-{
- int ret;
- struct DepositWtidContext ctx;
- struct TALER_MINTDB_Session *session;
-
- if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode)))
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- ctx.connection = connection;
- ctx.h_contract = *h_contract;
- ctx.h_wire = *h_wire;
- ctx.coin_pub = *coin_pub;
- ctx.transaction_id = transaction_id;
- ctx.res = GNUNET_SYSERR;
- ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls,
- session,
- h_contract,
- h_wire,
- coin_pub,
- merchant_pub,
- transaction_id,
- &handle_wtid_data,
- &ctx);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_break (0);
- GNUNET_break (GNUNET_SYSERR == ctx.res);
- return TMH_RESPONSE_reply_internal_db_error (connection);
- }
- if (GNUNET_NO == ret)
- {
- GNUNET_break (GNUNET_SYSERR == ctx.res);
- return TMH_RESPONSE_reply_deposit_unknown (connection);
- }
- if (GNUNET_SYSERR == ctx.res)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_error (connection,
- "bug resolving deposit wtid");
- }
- return ctx.res;
-}
-
-
-/* end of taler-mint-httpd_db.c */
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
deleted file mode 100644
index 0327bef2a..000000000
--- a/src/mint/taler-mint-httpd_db.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint/taler-mint-httpd_db.h
- * @brief High-level (transactional-layer) database operations for the mint
- * @author Chrisitan Grothoff
- */
-#ifndef TALER_MINT_HTTPD_DB_H
-#define TALER_MINT_HTTPD_DB_H
-
-#include <microhttpd.h>
-#include "taler_mintdb_plugin.h"
-
-
-/**
- * Execute a "/deposit". The validity of the coin and signature
- * have already been checked. The database must now check that
- * the coin is not (double or over) spent, and execute the
- * transaction (record details, generate success or failure response).
- *
- * @param connection the MHD connection to handle
- * @param deposit information about the deposit
- * @return MHD result code
- */
-int
-TMH_DB_execute_deposit (struct MHD_Connection *connection,
- const struct TALER_MINTDB_Deposit *deposit);
-
-
-/**
- * Execute a "/reserve/status". Given the public key of a reserve,
- * return the associated transaction history.
- *
- * @param connection the MHD connection to handle
- * @param reserve_pub public key of the reserve to check
- * @return MHD result code
- */
-int
-TMH_DB_execute_reserve_status (struct MHD_Connection *connection,
- const struct TALER_ReservePublicKeyP *reserve_pub);
-
-
-/**
- * Execute a "/reserve/withdraw". Given a reserve and a properly signed
- * request to withdraw a coin, check the balance of the reserve and
- * if it is sufficient, store the request and return the signed
- * blinded envelope.
- *
- * @param connection the MHD connection to handle
- * @param reserve public key of the reserve
- * @param denomination_pub public key of the denomination requested
- * @param blinded_msg blinded message to be signed
- * @param blinded_msg_len number of bytes in @a blinded_msg
- * @param signature signature over the withdraw request, to be stored in DB
- * @return MHD result code
- */
-int
-TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,
- const struct TALER_ReservePublicKeyP *reserve,
- const struct TALER_DenominationPublicKey *denomination_pub,
- const char *blinded_msg,
- size_t blinded_msg_len,
- const struct TALER_ReserveSignatureP *signature);
-
-
-/**
- * @brief Details about a melt operation of an individual coin.
- */
-struct TMH_DB_MeltDetails
-{
-
- /**
- * Information about the coin being melted.
- */
- struct TALER_CoinPublicInfo coin_info;
-
- /**
- * Signature allowing the melt (using
- * a `struct TALER_MINTDB_RefreshMeltConfirmSignRequestBody`) to sign over.
- */
- struct TALER_CoinSpendSignatureP melt_sig;
-
- /**
- * How much of the coin's value did the client allow to be melted?
- * This amount includes the fees, so the final amount contributed
- * to the melt is this value minus the fee for melting the coin.
- */
- struct TALER_Amount melt_amount_with_fee;
-
- /**
- * What fee is earned by the mint? Set delayed during
- * #verify_coin_public_info().
- */
- struct TALER_Amount melt_fee;
-};
-
-
-/**
- * Execute a "/refresh/melt". We have been given a list of valid
- * coins and a request to melt them into the given
- * @a refresh_session_pub. Check that the coins all have the
- * required value left and if so, store that they have been
- * melted and confirm the melting operation to the client.
- *
- * @param connection the MHD connection to handle
- * @param session_hash hash code of the session the coins are melted into
- * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array
- * @param denom_pubs array of public denomination keys for the refresh (?)
- * @param coin_count number of entries in @ a coin_melt_details, size of y-dimension of @a commit_link array
- * @param coin_melt_details signatures and (residual) value of and information about the respective coin to be melted
- * @param commit_coin 2d array of coin commitments (what the mint is to sign
- * once the "/refres/reveal" of cut and choose is done)
- * @param commit_link 2d array of coin link commitments (what the mint is
- * to return via "/refresh/link" to enable linkage in the
- * future)
- * @return MHD result code
- */
-int
-TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- unsigned int num_new_denoms,
- const struct TALER_DenominationPublicKey *denom_pubs,
- unsigned int coin_count,
- const struct TMH_DB_MeltDetails *coin_melt_details,
- struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin,
- struct TALER_RefreshCommitLinkP *const* commit_link);
-
-
-/**
- * Execute a "/refresh/reveal". The client is revealing to us the
- * transfer keys for #TALER_CNC_KAPPA-1 sets of coins. Verify that the
- * revealed transfer keys would allow linkage to the blinded coins,
- * and if so, return the signed coins for corresponding to the set of
- * coins that was not chosen.
- *
- * @param connection the MHD connection to handle
- * @param session_hash hash over the refresh session
- * @param num_oldcoins size of y-dimension of @a transfer_privs array
- * @param transfer_privs array with the revealed transfer keys, #TALER_CNC_KAPPA is 1st-dimension
- * @return MHD result code
- */
-int
-TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- unsigned int num_oldcoins,
- struct TALER_TransferPrivateKeyP **transfer_privs);
-
-
-/**
- * Execute a "/refresh/link". Returns the linkage information that
- * will allow the owner of a coin to follow the refresh trail to the
- * refreshed coin.
- *
- * @param connection the MHD connection to handle
- * @param coin_pub public key of the coin to link
- * @return MHD result code
- */
-int
-TMH_DB_execute_refresh_link (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub);
-
-
-
-/**
- * Add an incoming transaction to the database.
- *
- * @param connection the MHD connection to handle
- * @param reserve_pub public key of the reserve
- * @param amount amount to add to the reserve
- * @param execution_time when did we receive the wire transfer
- * @param wire details about the wire transfer
- * @return MHD result code
- */
-int
-TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute execution_time,
- json_t *wire);
-
-
-/**
- * Execute a "/wire/deposits". Returns the transaction information
- * associated with the given wire transfer identifier.
- *
- * @param connection the MHD connection to handle
- * @param wtid wire transfer identifier to resolve
- * @return MHD result code
- */
-int
-TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
- const struct TALER_WireTransferIdentifierRawP *wtid);
-
-
-/**
- * Execute a "/deposit/wtid". Returns the transfer information
- * associated with the given deposit.
- *
- * @param connection the MHD connection to handle
- * @param h_contract hash of the contract
- * @param h_wire hash of the wire details
- * @param coin_pub public key of the coin to link
- * @param merchant_pub public key of the merchant
- * @param transaction_id transaction ID of the merchant
- * @return MHD result code
- */
-int
-TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *h_contract,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- uint64_t transaction_id);
-
-
-#endif
-/* TALER_MINT_HTTPD_DB_H */
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c
deleted file mode 100644
index 40c5a4db7..000000000
--- a/src/mint/taler-mint-httpd_deposit.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_deposit.c
- * @brief Handle /deposit requests; parses the POST and JSON and
- * verifies the coin signature before handing things off
- * to the database.
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- *
- * TODO:
- * - ugly if-construction for deposit type
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include <pthread.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_deposit.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_keystate.h"
-#include "taler-mint-httpd_validation.h"
-
-
-/**
- * We have parsed the JSON information about the deposit, do some
- * basic sanity checks (especially that the signature on the coin is
- * valid, and that this type of coin exists) and then execute the
- * deposit.
- *
- * @param connection the MHD connection to handle
- * @param deposit information about the deposit
- * @return MHD result code
- */
-static int
-verify_and_execute_deposit (struct MHD_Connection *connection,
- const struct TALER_MINTDB_Deposit *deposit)
-{
- struct TMH_KS_StateHandle *key_state;
- struct TALER_DepositRequestPS dr;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TALER_Amount fee_deposit;
-
- dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
- dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
- dr.h_contract = deposit->h_contract;
- dr.h_wire = deposit->h_wire;
- dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp);
- dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline);
- dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
- TALER_amount_hton (&dr.amount_with_fee,
- &deposit->amount_with_fee);
- TALER_amount_hton (&dr.deposit_fee,
- &deposit->deposit_fee);
- dr.merchant = deposit->merchant_pub;
- dr.coin_pub = deposit->coin.coin_pub;
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
- &dr.purpose,
- &deposit->csig.eddsa_signature,
- &deposit->coin.coin_pub.eddsa_pub))
- {
- TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
- return TMH_RESPONSE_reply_signature_invalid (connection,
- "coin_sig");
- }
- /* check denomination exists and is valid */
- key_state = TMH_KS_acquire ();
- dki = TMH_KS_denomination_key_lookup (key_state,
- &deposit->coin.denom_pub,
- TMH_KS_DKU_DEPOSIT);
- if (NULL == dki)
- {
- TMH_KS_release (key_state);
- TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n");
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub");
- }
- /* check coin signature */
- if (GNUNET_YES !=
- TALER_test_coin_valid (&deposit->coin))
- {
- TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_signature_invalid (connection,
- "ub_sig");
- }
- TALER_amount_ntoh (&fee_deposit,
- &dki->issue.properties.fee_deposit);
- if (0 < TALER_amount_cmp (&fee_deposit,
- &deposit->amount_with_fee))
- {
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_external_error (connection,
- "deposited amount smaller than depositing fee");
- }
- TMH_KS_release (key_state);
-
- return TMH_DB_execute_deposit (connection,
- deposit);
-}
-
-
-/**
- * Handle a "/deposit" request. This function parses the
- * JSON information and then calls #verify_and_execute_deposit()
- * to verify the signatures and execute the deposit.
- *
- * @param connection the MHD connection to handle
- * @param root root of the posted JSON
- * @param amount how much should be deposited
- * @param wire json describing the wire details (?)
- * @return MHD result code
- */
-static int
-parse_and_handle_deposit_request (struct MHD_Connection *connection,
- const json_t *root,
- const struct TALER_Amount *amount,
- json_t *wire)
-{
- int res;
- struct TALER_MINTDB_Deposit deposit;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TMH_KS_StateHandle *ks;
- struct GNUNET_HashCode my_h_wire;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_denomination_public_key ("denom_pub", &deposit.coin.denom_pub),
- TMH_PARSE_member_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
- TMH_PARSE_member_fixed ("coin_pub", &deposit.coin.coin_pub),
- TMH_PARSE_member_fixed ("merchant_pub", &deposit.merchant_pub),
- TMH_PARSE_member_fixed ("H_contract", &deposit.h_contract),
- TMH_PARSE_member_fixed ("H_wire", &deposit.h_wire),
- TMH_PARSE_member_fixed ("coin_sig", &deposit.csig),
- TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id),
- TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp),
- TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline),
- TMH_PARSE_member_time_abs ("edate", &deposit.wire_deadline),
- TMH_PARSE_MEMBER_END
- };
-
- memset (&deposit, 0, sizeof (deposit));
- res = TMH_PARSE_json_data (connection,
- root,
- spec);
- if (GNUNET_SYSERR == res)
- return MHD_NO; /* hard failure */
- if (GNUNET_NO == res)
- return MHD_YES; /* failure */
-
- if (GNUNET_YES !=
- TMH_json_validate_wireformat (wire))
- {
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "wire");
- }
- if (GNUNET_OK !=
- TALER_hash_json (wire,
- &my_h_wire))
- {
- TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "wire");
- }
- if (0 != memcmp (&deposit.h_wire,
- &my_h_wire,
- sizeof (struct GNUNET_HashCode)))
- {
- /* Client hashed contract differently than we did, reject */
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "H_wire");
- }
- ks = TMH_KS_acquire ();
- dki = TMH_KS_denomination_key_lookup (ks,
- &deposit.coin.denom_pub,
- TMH_KS_DKU_DEPOSIT);
- if (NULL == dki)
- {
- TMH_KS_release (ks);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub");
- }
- TALER_amount_ntoh (&deposit.deposit_fee,
- &dki->issue.properties.fee_deposit);
- TMH_KS_release (ks);
- deposit.wire = wire;
- deposit.amount_with_fee = *amount;
- if (-1 == TALER_amount_cmp (&deposit.amount_with_fee,
- &deposit.deposit_fee))
- {
- /* Total amount smaller than fee, invalid */
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "f");
- }
- res = verify_and_execute_deposit (connection,
- &deposit);
- TMH_PARSE_release_data (spec);
- return res;
-}
-
-
-/**
- * Handle a "/deposit" request. Parses the JSON in the post to find
- * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if
- * successful, passes the JSON data to
- * #parse_and_handle_deposit_request() to further check the details
- * of the operation specified in the "wire" field of the JSON data.
- * If everything checks out, this will ultimately lead to the
- * "/deposit" being executed, or rejected.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- json_t *wire;
- int res;
- struct TALER_Amount amount;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_object ("wire", &wire),
- TMH_PARSE_member_amount ("f", &amount),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- if (GNUNET_OK != res)
- {
- json_decref (json);
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
- res = parse_and_handle_deposit_request (connection,
- json,
- &amount,
- wire);
- TMH_PARSE_release_data (spec);
- json_decref (json);
- return res;
-}
-
-
-/* end of taler-mint-httpd_deposit.c */
diff --git a/src/mint/taler-mint-httpd_deposit.h b/src/mint/taler-mint-httpd_deposit.h
deleted file mode 100644
index c2d3fe13c..000000000
--- a/src/mint/taler-mint-httpd_deposit.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_deposit.h
- * @brief Handle /deposit requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_DEPOSIT_H
-#define TALER_MINT_HTTPD_DEPOSIT_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Handle a "/deposit" request. Parses the JSON in the post to find
- * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if
- * successful, passes the JSON data to
- * #parse_and_handle_deposit_request() to further check the details
- * of the operation specified in the "wire" field of the JSON data.
- * If everything checks out, this will ultimately lead to the
- * "/deposit" being executed, or rejected.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-#endif
diff --git a/src/mint/taler-mint-httpd_keystate.c b/src/mint/taler-mint-httpd_keystate.c
deleted file mode 100644
index f1856e673..000000000
--- a/src/mint/taler-mint-httpd_keystate.c
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_keystate.c
- * @brief management of our coin signing keys
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <pthread.h>
-#include "taler-mint-httpd_keystate.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler_mintdb_plugin.h"
-
-
-/**
- * Snapshot of the (coin and signing) keys (including private keys) of
- * the mint. There can be multiple instances of this struct, as it is
- * reference counted and only destroyed once the last user is done
- * with it. The current instance is acquired using
- * #TMH_KS_acquire(). Using this function increases the
- * reference count. The contents of this structure (except for the
- * reference counter) should be considered READ-ONLY until it is
- * ultimately destroyed (as there can be many concurrent users).
- */
-struct TMH_KS_StateHandle
-{
- /**
- * JSON array with denomination keys. (Currently not really used
- * after initialization.)
- */
- json_t *denom_keys_array;
-
- /**
- * JSON array with signing keys. (Currently not really used
- * after initialization.)
- */
- json_t *sign_keys_array;
-
- /**
- * JSON array with auditor information. (Currently not really used
- * after initialization.)
- */
- json_t *auditors_array;
-
- /**
- * Cached JSON text that the mint will send for a "/keys" request.
- * Includes our @e TMH_master_public_key public key, the signing and
- * denomination keys as well as the @e reload_time.
- */
- char *keys_json;
-
- /**
- * Mapping from denomination keys to denomination key issue struct.
- * Used to lookup the key by hash.
- */
- struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
-
- /**
- * Hash context we used to combine the hashes of all denomination
- * keys into one big hash.
- */
- struct GNUNET_HashContext *hash_context;
-
- /**
- * When did we initiate the key reloading?
- */
- struct GNUNET_TIME_Absolute reload_time;
-
- /**
- * When is the next key invalid and we have to reload? (We also
- * reload on SIGUSR1.)
- */
- struct GNUNET_TIME_Absolute next_reload;
-
- /**
- * Mint signing key that should be used currently.
- */
- struct TALER_MINTDB_PrivateSigningKeyInformationP current_sign_key_issue;
-
- /**
- * Reference count. The struct is released when the RC hits zero.
- */
- unsigned int refcnt;
-};
-
-
-/**
- * Mint key state. Never use directly, instead access via
- * #TMH_KS_acquire() and #TMH_KS_release().
- */
-static struct TMH_KS_StateHandle *internal_key_state;
-
-/**
- * Mutex protecting access to #internal_key_state.
- */
-static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-/**
- * Pipe used for signaling reloading of our key state.
- */
-static int reload_pipe[2];
-
-
-/**
- * Convert the public part of a denomination key issue to a JSON
- * object.
- *
- * @param pk public key of the denomination key
- * @param dki the denomination key issue
- * @return a JSON object describing the denomination key isue (public part)
- */
-static json_t *
-denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk,
- const struct TALER_MINTDB_DenominationKeyInformationP *dki)
-{
- struct TALER_Amount value;
- struct TALER_Amount fee_withdraw;
- struct TALER_Amount fee_deposit;
- struct TALER_Amount fee_refresh;
-
- TALER_amount_ntoh (&value,
- &dki->properties.value);
- TALER_amount_ntoh (&fee_withdraw,
- &dki->properties.fee_withdraw);
- TALER_amount_ntoh (&fee_deposit,
- &dki->properties.fee_deposit);
- TALER_amount_ntoh (&fee_refresh,
- &dki->properties.fee_refresh);
- return
- json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
- "master_sig",
- TALER_json_from_data (&dki->signature,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature)),
- "stamp_start",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)),
- "stamp_expire_withdraw",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)),
- "stamp_expire_deposit",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_spend)),
- "stamp_expire_legal",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)),
- "denom_pub",
- TALER_json_from_rsa_public_key (pk->rsa_public_key),
- "value",
- TALER_json_from_amount (&value),
- "fee_withdraw",
- TALER_json_from_amount (&fee_withdraw),
- "fee_deposit",
- TALER_json_from_amount (&fee_deposit),
- "fee_refresh",
- TALER_json_from_amount (&fee_refresh));
-}
-
-
-/**
- * Get the relative time value that describes how
- * far in the future do we want to provide coin keys.
- *
- * @return the provide duration
- */
-static struct GNUNET_TIME_Relative
-TALER_MINT_conf_duration_provide ()
-{
- struct GNUNET_TIME_Relative rel;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (cfg,
- "mint_keys",
- "lookahead_provide",
- &rel))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "mint_keys",
- "lookahead_provide",
- "time value required");
- GNUNET_assert (0);
- }
- return rel;
-}
-
-
-/**
- * Iterator for (re)loading/initializing denomination keys.
- *
- * @param cls closure
- * @param dki the denomination key issue
- * @param alias coin alias
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-reload_keys_denom_iter (void *cls,
- const char *alias,
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- struct TMH_KS_StateHandle *ctx = cls;
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Absolute horizon;
- struct GNUNET_HashCode denom_key_hash;
- struct TALER_MINTDB_DenominationKeyIssueInformation *d2;
- struct TALER_MINTDB_Session *session;
- int res;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Loading denomination key `%s'\n",
- alias);
- horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ());
- if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us >
- horizon.abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping future denomination key `%s'\n",
- alias);
- return GNUNET_OK;
- }
- now = GNUNET_TIME_absolute_get ();
- if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us <
- now.abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping expired denomination key `%s'\n",
- alias);
- return GNUNET_OK;
- }
-
- GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
- &denom_key_hash);
- GNUNET_CRYPTO_hash_context_read (ctx->hash_context,
- &denom_key_hash,
- sizeof (struct GNUNET_HashCode));
- session = TMH_plugin->get_session (TMH_plugin->cls,
- TMH_test_mode);
- if (NULL == session)
- return GNUNET_SYSERR;
- /* Try to insert DKI into DB until we succeed; note that if the DB
- failure is persistent, this code may loop forever (as there is no
- sane alternative, we cannot continue without the DKI being in the
- DB). */
- res = GNUNET_SYSERR;
- while (GNUNET_OK != res)
- {
- res = TMH_plugin->start (TMH_plugin->cls,
- session);
- if (GNUNET_OK != res)
- {
- /* Transaction start failed!? Very bad error, log and retry */
- GNUNET_break (0);
- continue;
- }
- res = TMH_plugin->get_denomination_info (TMH_plugin->cls,
- session,
- &dki->denom_pub,
- NULL);
- if (GNUNET_SYSERR == res)
- {
- /* Fetch failed!? Very bad error, log and retry */
- GNUNET_break (0);
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- continue;
- }
- if (GNUNET_OK == res)
- {
- /* Record exists, we're good, just exit */
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- break;
- }
- res = TMH_plugin->insert_denomination_info (TMH_plugin->cls,
- session,
- &dki->denom_pub,
- &dki->issue);
- if (GNUNET_OK != res)
- {
- /* Insert failed!? Very bad error, log and retry */
- GNUNET_break (0);
- TMH_plugin->rollback (TMH_plugin->cls,
- session);
- continue;
- }
- res = TMH_plugin->commit (TMH_plugin->cls,
- session);
- /* If commit succeeded, we're done, otherwise we retry; this
- time without logging, as theroetically commits can fail
- in a transactional DB due to concurrent activities that
- cannot be reconciled. This should be rare for DKIs, but
- as it is possible we just retry until we succeed. */
- }
-
- d2 = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation);
- d2->issue = dki->issue;
- d2->denom_priv.rsa_private_key
- = GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key);
- d2->denom_pub.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
- res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map,
- &denom_key_hash,
- d2,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- if (GNUNET_OK != res)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Duplicate denomination key `%s'\n",
- alias);
- GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key);
- GNUNET_free (d2);
- return GNUNET_OK;
- }
- json_array_append_new (ctx->denom_keys_array,
- denom_key_issue_to_json (&dki->denom_pub,
- &dki->issue));
- return GNUNET_OK;
-}
-
-
-/**
- * Convert the public part of a sign key issue to a JSON object.
- *
- * @param ski the sign key issue
- * @return a JSON object describing the sign key issue (public part)
- */
-static json_t *
-sign_key_issue_to_json (const struct TALER_MintSigningKeyValidityPS *ski)
-{
- return
- json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}",
- "stamp_start",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)),
- "stamp_expire",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)),
- "stamp_end",
- TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->end)),
- "master_pub",
- TALER_json_from_data (&ski->master_public_key,
- sizeof (struct TALER_MasterPublicKeyP)),
- "master_sig",
- TALER_json_from_data (&ski->signature,
- sizeof (struct TALER_MasterSignatureP)),
- "key",
- TALER_json_from_data (&ski->signkey_pub,
- sizeof (struct TALER_MintPublicKeyP)));
-}
-
-
-/**
- * Iterator for sign keys.
- *
- * @param cls closure with the `struct TMH_KS_StateHandle *`
- * @param filename name of the file the key came from
- * @param ski the sign key issue
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-reload_keys_sign_iter (void *cls,
- const char *filename,
- const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski)
-{
- struct TMH_KS_StateHandle *ctx = cls;
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Absolute horizon;
-
- horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ());
- if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us >
- horizon.abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping future signing key `%s'\n",
- filename);
- return GNUNET_OK;
- }
- now = GNUNET_TIME_absolute_get ();
- if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us <
- now.abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping expired signing key `%s'\n",
- filename);
- return GNUNET_OK;
- }
-
- /* The signkey is valid at this time, check if it's more recent than
- what we have so far! */
- if ( (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us <
- GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) &&
- (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us <
- now.abs_value_us) )
- {
- /* We use the most recent one, if it is valid now (not just in the near future) */
- ctx->current_sign_key_issue = *ski;
- }
- json_array_append_new (ctx->sign_keys_array,
- sign_key_issue_to_json (&ski->issue));
-
- return GNUNET_OK;
-}
-
-
-/**
- * Convert information from an auditor to a JSON object.
- *
- * @param apub the auditor's public key
- * @param dki_len length of @a dki and @a asigs arrays
- * @param asigs the auditor's signatures
- * @param dki array of denomination coin data signed by the auditor
- * @return a JSON object describing the auditor information and signature
- */
-static json_t *
-auditor_to_json (const struct TALER_AuditorPublicKeyP *apub,
- unsigned int dki_len,
- const struct TALER_AuditorSignatureP **asigs,
- const struct TALER_DenominationKeyValidityPS **dki)
-{
- unsigned int i;
- json_t *ja;
-
- ja = json_array ();
- for (i=0;i<dki_len;i++)
- json_array_append_new (ja,
- json_pack ("{s:o, s:o}",
- "denom_pub_h",
- TALER_json_from_data (&dki[i]->denom_hash,
- sizeof (struct GNUNET_HashCode)),
- "auditor_sig",
- TALER_json_from_data (asigs[i],
- sizeof (struct TALER_AuditorSignatureP))));
- return
- json_pack ("{s:o, s:o}",
- "denomination_keys", ja,
- "auditor_pub",
- TALER_json_from_data (apub,
- sizeof (struct TALER_AuditorPublicKeyP)));
-}
-
-
-/**
- * @brief Iterator called with auditor information.
- * Check that the @a mpub actually matches this mint, and then
- * add the auditor information to our /keys response (if it is
- * (still) applicable).
- *
- * @param cls closure with the `struct TMH_KS_StateHandle *`
- * @param apub the auditor's public key
- * @param mpub the mint's public key (as expected by the auditor)
- * @param dki_len length of @a dki and @a asigs
- * @param asigs array with the auditor's signatures, of length @a dki_len
- * @param dki array of denomination coin data signed by the auditor
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-reload_auditor_iter (void *cls,
- const struct TALER_AuditorPublicKeyP *apub,
- const struct TALER_MasterPublicKeyP *mpub,
- unsigned int dki_len,
- const struct TALER_AuditorSignatureP *asigs,
- const struct TALER_DenominationKeyValidityPS *dki)
-{
- struct TMH_KS_StateHandle *ctx = cls;
- unsigned int i;
- unsigned int keep;
- const struct TALER_AuditorSignatureP *kept_asigs[dki_len];
- const struct TALER_DenominationKeyValidityPS *kept_dkis[dki_len];
-
- /* Check if the signature is at least for this mint. */
- if (0 != memcmp (&mpub->eddsa_pub,
- &TMH_master_public_key,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Auditing information provided for a different mint, ignored\n");
- return GNUNET_OK;
- }
- /* Filter the auditor information for those for which the
- keys actually match the denomination keys that are active right now */
- keep = 0;
- for (i=0;i<dki_len;i++)
- {
- if (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (ctx->denomkey_map,
- &dki[i].denom_hash))
- {
- kept_asigs[keep] = &asigs[i];
- kept_dkis[keep] = &dki[i];
- keep++;
- }
- }
- /* add auditor information to our /keys response */
- json_array_append_new (ctx->auditors_array,
- auditor_to_json (apub,
- keep,
- kept_asigs,
- kept_dkis));
- return GNUNET_OK;
-}
-
-
-/**
- * Iterator for freeing denomination keys.
- *
- * @param cls closure with the `struct TMH_KS_StateHandle`
- * @param key key for the denomination key
- * @param value coin details
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-free_denom_key (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki = value;
-
- GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key);
- GNUNET_free (dki);
- return GNUNET_OK;
-}
-
-
-/**
- * Release key state, free if necessary (if reference count gets to zero).
- * Internal method used when the mutex is already held.
- *
- * @param key_state the key state to release
- */
-static void
-ks_release_ (struct TMH_KS_StateHandle *key_state)
-{
- GNUNET_assert (0 < key_state->refcnt);
- key_state->refcnt--;
- if (0 == key_state->refcnt)
- {
- if (NULL != key_state->denom_keys_array)
- {
- json_decref (key_state->denom_keys_array);
- key_state->denom_keys_array = NULL;
- }
- if (NULL != key_state->sign_keys_array)
- {
- json_decref (key_state->sign_keys_array);
- key_state->sign_keys_array = NULL;
- }
- if (NULL != key_state->denomkey_map)
- {
- GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map,
- &free_denom_key,
- key_state);
- GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map);
- key_state->denomkey_map = NULL;
- }
- GNUNET_free_non_null (key_state->keys_json);
- GNUNET_free (key_state);
- }
-}
-
-
-/**
- * Release key state, free if necessary (if reference count gets to zero).
- *
- * @param location name of the function in which the lock is acquired
- * @param key_state the key state to release
- */
-void
-TMH_KS_release_ (const char *location,
- struct TMH_KS_StateHandle *key_state)
-{
- GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
- ks_release_ (key_state);
- GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
-}
-
-
-/**
- * Acquire the key state of the mint. Updates keys if necessary.
- * For every call to #TMH_KS_acquire(), a matching call
- * to #TMH_KS_release() must be made.
- *
- * @param location name of the function in which the lock is acquired
- * @return the key state
- */
-struct TMH_KS_StateHandle *
-TMH_KS_acquire_ (const char *location)
-{
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct TMH_KS_StateHandle *key_state;
- json_t *keys;
- struct TALER_MintKeySetPS ks;
- struct TALER_MintSignatureP sig;
-
- GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
- if ( (NULL != internal_key_state) &&
- (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) )
- {
- ks_release_ (internal_key_state);
- internal_key_state = NULL;
- }
- if (NULL == internal_key_state)
- {
- key_state = GNUNET_new (struct TMH_KS_StateHandle);
- key_state->hash_context = GNUNET_CRYPTO_hash_context_start ();
-
-
- key_state->denom_keys_array = json_array ();
- GNUNET_assert (NULL != key_state->denom_keys_array);
-
- key_state->sign_keys_array = json_array ();
- GNUNET_assert (NULL != key_state->sign_keys_array);
-
- key_state->auditors_array = json_array ();
- GNUNET_assert (NULL != key_state->auditors_array);
-
- key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32,
- GNUNET_NO);
- key_state->reload_time = GNUNET_TIME_absolute_get ();
- TALER_round_abs_time (&key_state->reload_time);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Loading keys from `%s'\n",
- TMH_mint_directory);
- TALER_MINTDB_denomination_keys_iterate (TMH_mint_directory,
- &reload_keys_denom_iter,
- key_state);
- TALER_MINTDB_signing_keys_iterate (TMH_mint_directory,
- &reload_keys_sign_iter,
- key_state);
- TALER_MINTDB_auditor_iterate (TMH_mint_directory,
- &reload_auditor_iter,
- key_state);
- ks.purpose.size = htonl (sizeof (ks));
- ks.purpose.purpose = htonl (TALER_SIGNATURE_MINT_KEY_SET);
- ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time);
- GNUNET_CRYPTO_hash_context_finish (key_state->hash_context,
- &ks.hc);
- key_state->hash_context = NULL;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
- &ks.purpose,
- &sig.eddsa_signature));
- key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire);
- if (0 == key_state->next_reload.abs_value_us)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No valid signing key found!\n");
-
- keys = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
- "master_public_key",
- TALER_json_from_data (&TMH_master_public_key,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)),
- "signkeys", key_state->sign_keys_array,
- "denoms", key_state->denom_keys_array,
- "auditors", key_state->auditors_array,
- "list_issue_date", TALER_json_from_abs (key_state->reload_time),
- "eddsa_pub", TALER_json_from_data (&key_state->current_sign_key_issue.issue.signkey_pub,
- sizeof (struct TALER_MintPublicKeyP)),
- "eddsa_sig", TALER_json_from_data (&sig,
- sizeof (struct TALER_MintSignatureP)));
- key_state->auditors_array = NULL;
- key_state->sign_keys_array = NULL;
- key_state->denom_keys_array = NULL;
- key_state->keys_json = json_dumps (keys,
- JSON_INDENT (2));
- json_decref (keys);
- internal_key_state = key_state;
- }
- key_state = internal_key_state;
- key_state->refcnt++;
- GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
-
- return key_state;
-}
-
-
-/**
- * Look up the issue for a denom public key.
- *
- * @param key_state state to look in
- * @param denom_pub denomination public key
- * @param use purpose for which the key is being located
- * @return the denomination key issue,
- * or NULL if denom_pub could not be found
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation *
-TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state,
- const struct TALER_DenominationPublicKey *denom_pub,
- enum TMH_KS_DenominationKeyUse use)
-{
- struct GNUNET_HashCode hc;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct GNUNET_TIME_Absolute now;
-
- GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
- &hc);
- dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map,
- &hc);
- if (NULL == dki)
- return NULL;
- now = GNUNET_TIME_absolute_get ();
- if (now.abs_value_us <
- GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Not returning DKI for %s, as start time is in the future\n",
- GNUNET_h2s (&hc));
- return NULL;
- }
- now = GNUNET_TIME_absolute_get ();
- switch (use)
- {
- case TMH_KS_DKU_WITHDRAW:
- if (now.abs_value_us >
- GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Not returning DKI for %s, as time to create coins has passed\n",
- GNUNET_h2s (&hc));
- return NULL;
- }
- break;
- case TMH_KS_DKU_DEPOSIT:
- if (now.abs_value_us >
- GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Not returning DKI for %s, as time to spend coin has passed\n",
- GNUNET_h2s (&hc));
- return NULL;
- }
- break;
- }
- return dki;
-}
-
-
-/**
- * Handle a signal, writing relevant signal numbers to the pipe.
- *
- * @param signal_number the signal number
- */
-static void
-handle_signal (int signal_number)
-{
- ssize_t res;
- char c = signal_number;
-
- res = write (reload_pipe[1],
- &c,
- 1);
- if ( (res < 0) &&
- (EINTR != errno) )
- {
- GNUNET_break (0);
- return;
- }
- if (0 == res)
- {
- GNUNET_break (0);
- return;
- }
-}
-
-
-/**
- * Call #handle_signal() to pass the received signal via
- * the control pipe.
- */
-static void
-handle_sigusr1 ()
-{
- handle_signal (SIGUSR1);
-}
-
-
-/**
- * Call #handle_signal() to pass the received signal via
- * the control pipe.
- */
-static void
-handle_sigint ()
-{
- handle_signal (SIGINT);
-}
-
-
-/**
- * Call #handle_signal() to pass the received signal via
- * the control pipe.
- */
-static void
-handle_sigterm ()
-{
- handle_signal (SIGTERM);
-}
-
-
-/**
- * Call #handle_signal() to pass the received signal via
- * the control pipe.
- */
-static void
-handle_sighup ()
-{
- handle_signal (SIGHUP);
-}
-
-
-/**
- * Call #handle_signal() to pass the received signal via
- * the control pipe.
- */
-static void
-handle_sigchld ()
-{
- handle_signal (SIGCHLD);
-}
-
-
-/**
- * Read signals from a pipe in a loop, and reload keys from disk if
- * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and
- * restart if SIGHUP is received.
- *
- * @return #GNUNET_SYSERR on errors,
- * #GNUNET_OK to terminate normally
- * #GNUNET_NO to restart an update version of the binary
- */
-int
-TMH_KS_loop (void)
-{
- struct GNUNET_SIGNAL_Context *sigusr1;
- struct GNUNET_SIGNAL_Context *sigterm;
- struct GNUNET_SIGNAL_Context *sigint;
- struct GNUNET_SIGNAL_Context *sighup;
- struct GNUNET_SIGNAL_Context *sigchld;
- int ret;
-
- if (0 != pipe (reload_pipe))
- {
- fprintf (stderr,
- "Failed to create pipe.\n");
- return GNUNET_SYSERR;
- }
- sigusr1 = GNUNET_SIGNAL_handler_install (SIGUSR1,
- &handle_sigusr1);
- sigterm = GNUNET_SIGNAL_handler_install (SIGTERM,
- &handle_sigterm);
- sigint = GNUNET_SIGNAL_handler_install (SIGINT,
- &handle_sigint);
- sighup = GNUNET_SIGNAL_handler_install (SIGHUP,
- &handle_sighup);
- sigchld = GNUNET_SIGNAL_handler_install (SIGCHLD,
- &handle_sigchld);
-
- ret = 0;
- while (0 == ret)
- {
- char c;
- ssize_t res;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "(re-)loading keys\n");
- if (NULL != internal_key_state)
- {
- TMH_KS_release (internal_key_state);
- internal_key_state = NULL;
- }
- /* This will re-initialize 'internal_key_state' with
- an initial refcnt of 1 */
- (void) TMH_KS_acquire ();
-
-read_again:
- errno = 0;
- res = read (reload_pipe[0],
- &c,
- 1);
- if ((res < 0) && (EINTR != errno))
- {
- GNUNET_break (0);
- ret = GNUNET_SYSERR;
- break;
- }
- if (EINTR == errno)
- goto read_again;
- switch (c)
- {
- case SIGUSR1:
- /* reload internal key state, we do this in the loop */
- break;
- case SIGTERM:
- case SIGINT:
- /* terminate */
- ret = GNUNET_OK;
- break;
- case SIGHUP:
- /* restart updated binary */
- ret = GNUNET_NO;
- break;
-#if HAVE_DEVELOPER
- case SIGCHLD:
- /* running in test-mode, test finished, terminate */
- ret = GNUNET_OK;
- break;
-#endif
- default:
- /* unexpected character */
- GNUNET_break (0);
- break;
- }
- }
- if (NULL != internal_key_state)
- {
- TMH_KS_release (internal_key_state);
- internal_key_state = NULL;
- }
- GNUNET_SIGNAL_handler_uninstall (sigusr1);
- GNUNET_SIGNAL_handler_uninstall (sigterm);
- GNUNET_SIGNAL_handler_uninstall (sigint);
- GNUNET_SIGNAL_handler_uninstall (sighup);
- GNUNET_SIGNAL_handler_uninstall (sigchld);
- return ret;
-}
-
-
-/**
- * Sign the message in @a purpose with the mint's signing key.
- *
- * @param purpose the message to sign
- * @param[out] pub set to the current public signing key of the mint
- * @param[out] sig signature over purpose using current signing key
- */
-void
-TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct TALER_MintPublicKeyP *pub,
- struct TALER_MintSignatureP *sig)
-
-{
- struct TMH_KS_StateHandle *key_state;
-
- key_state = TMH_KS_acquire ();
- *pub = key_state->current_sign_key_issue.issue.signkey_pub;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
- purpose,
- &sig->eddsa_signature));
- TMH_KS_release (key_state);
-}
-
-
-/**
- * Function to call to handle the request by sending
- * back static data from the @a rh.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_KS_handler_keys (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct TMH_KS_StateHandle *key_state;
- struct MHD_Response *response;
- int ret;
-
- key_state = TMH_KS_acquire ();
- response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
- key_state->keys_json,
- MHD_RESPMEM_MUST_COPY);
- TMH_KS_release (key_state);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (response);
- (void) MHD_add_response_header (response,
- "Content-Type",
- rh->mime_type);
- ret = MHD_queue_response (connection,
- rh->response_code,
- response);
- MHD_destroy_response (response);
- return ret;
-}
-
-
-/* end of taler-mint-httpd_keystate.c */
diff --git a/src/mint/taler-mint-httpd_keystate.h b/src/mint/taler-mint-httpd_keystate.h
deleted file mode 100644
index 0e20ef588..000000000
--- a/src/mint/taler-mint-httpd_keystate.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint/taler-mint-httpd_keystate.h
- * @brief management of our private signing keys (denomination keys)
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_KEYSTATE_H
-#define TALER_MINT_HTTPD_KEYSTATE_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-#include "taler_mintdb_lib.h"
-
-
-/**
- * Snapshot of the (coin and signing)
- * keys (including private keys) of the mint.
- */
-struct TMH_KS_StateHandle;
-
-
-/**
- * Acquire the key state of the mint. Updates keys if necessary.
- * For every call to #TMH_KS_acquire(), a matching call
- * to #TMH_KS_release() must be made.
- *
- * @param location name of the function in which the lock is acquired
- * @return the key state
- */
-struct TMH_KS_StateHandle *
-TMH_KS_acquire_ (const char *location);
-
-
-/**
- * Release key state, free if necessary (if reference count gets to zero).
- *
- * @param location name of the function in which the lock is acquired
- * @param key_state the key state to release
- */
-void
-TMH_KS_release_ (const char *location,
- struct TMH_KS_StateHandle *key_state);
-
-
-/**
- * Acquire the key state of the mint. Updates keys if necessary.
- * For every call to #TMH_KS_acquire(), a matching call
- * to #TMH_KS_release() must be made.
- *
- * @return the key state
- */
-#define TMH_KS_acquire(void) TMH_KS_acquire_(__FUNCTION__)
-
-
-/**
- * Release key state, free if necessary (if reference count gets to zero).
- *
- * @param key_state the key state to release
- */
-#define TMH_KS_release(key_state) TMH_KS_release_ (__FUNCTION__, key_state)
-
-
-/**
- * Denomination key lookups can be for signing of fresh coins
- * or to validate signatures on existing coins. As the validity
- * periods for a key differ, the caller must specify which
- * use is relevant for the current operation.
- */
-enum TMH_KS_DenominationKeyUse {
-
- /**
- * The key is to be used for a /reserve/withdraw or /refresh (mint)
- * operation.
- */
- TMH_KS_DKU_WITHDRAW,
-
- /**
- * The key is to be usd for a /deposit or /refresh (melt) operation.
- */
- TMH_KS_DKU_DEPOSIT
-
-};
-
-
-/**
- * Look up the issue for a denom public key. Note that the result
- * is only valid while the @a key_state is not released!
- *
- * @param key_state state to look in
- * @param denom_pub denomination public key
- * @param use purpose for which the key is being located
- * @return the denomination key issue,
- * or NULL if denom_pub could not be found (or is not valid at this time for the given @a use)
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation *
-TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state,
- const struct TALER_DenominationPublicKey *denom_pub,
- enum TMH_KS_DenominationKeyUse use);
-
-
-/**
- * Read signals from a pipe in a loop, and reload keys from disk if
- * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and
- * restart if SIGHUP is received.
- *
- * @return #GNUNET_SYSERR on errors,
- * #GNUNET_OK to terminate normally
- * #GNUNET_NO to restart an update version of the binary
- */
-int
-TMH_KS_loop (void);
-
-
-/**
- * Sign the message in @a purpose with the mint's signing
- * key.
- *
- * @param purpose the message to sign
- * @param[out] pub set to the current public signing key of the mint
- * @param[out] sig signature over purpose using current signing key
- */
-void
-TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct TALER_MintPublicKeyP *pub,
- struct TALER_MintSignatureP *sig);
-
-
-/**
- * Handle a "/keys" request
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_KS_handler_keys (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_mhd.c b/src/mint/taler-mint-httpd_mhd.c
deleted file mode 100644
index 5719d921a..000000000
--- a/src/mint/taler-mint-httpd_mhd.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd_mhd.c
- * @brief helpers for MHD interaction; these are TALER_MINT_handler_ functions
- * that generate simple MHD replies that do not require any real operations
- * to be performed (error handling, static pages, etc.)
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include <pthread.h>
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd.h"
-#include "taler-mint-httpd_mhd.h"
-
-/**
- * Function to call to handle the request by sending
- * back static data from the @a rh.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct MHD_Response *response;
- int ret;
-
- if (0 == rh->data_size)
- rh->data_size = strlen ((const char *) rh->data);
- response = MHD_create_response_from_buffer (rh->data_size,
- (void *) rh->data,
- MHD_RESPMEM_PERSISTENT);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (response);
- if (NULL != rh->mime_type)
- (void) MHD_add_response_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- rh->mime_type);
- ret = MHD_queue_response (connection,
- rh->response_code,
- response);
- MHD_destroy_response (response);
- return ret;
-}
-
-
-/**
- * Function to call to handle the request by sending
- * back a redirect to the AGPL source code.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- const char *agpl =
- "This server is licensed under the Affero GPL. You will now be redirected to the source code.";
- struct MHD_Response *response;
- int ret;
-
- response = MHD_create_response_from_buffer (strlen (agpl),
- (void *) agpl,
- MHD_RESPMEM_PERSISTENT);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (response);
- if (NULL != rh->mime_type)
- (void) MHD_add_response_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- rh->mime_type);
- MHD_add_response_header (response,
- MHD_HTTP_HEADER_LOCATION,
- "http://www.git.taler.net/?p=mint.git");
- ret = MHD_queue_response (connection,
- rh->response_code,
- response);
- MHD_destroy_response (response);
- return ret;
-}
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply with an error message from @a rh.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- rh->response_code,
- "{s:s}",
- "error",
- rh->data);
-}
-
-
-/* end of taler-mint-httpd_mhd.c */
diff --git a/src/mint/taler-mint-httpd_mhd.h b/src/mint/taler-mint-httpd_mhd.h
deleted file mode 100644
index a9f575df0..000000000
--- a/src/mint/taler-mint-httpd_mhd.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd_mhd.h
- * @brief helpers for MHD interaction, used to generate simple responses
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_MHD_H
-#define TALER_MINT_HTTPD_MHD_H
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Function to call to handle the request by sending
- * back static data from the @a rh.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Function to call to handle the request by sending
- * back a redirect to the AGPL source code.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply from varargs.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param response_code HTTP response code to use
- * @param do_cache can the response be cached? (0: no, 1: yes)
- * @param fmt format string for pack
- * @param ... varargs
- * @return MHD result code
- */
-int
-TMH_MHD_helper_send_json_pack (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void *connection_cls,
- int response_code,
- int do_cache,
- const char *fmt,
- ...);
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply with an error message from @a rh.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c
deleted file mode 100644
index 365202905..000000000
--- a/src/mint/taler-mint-httpd_parsing.c
+++ /dev/null
@@ -1,1137 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd_parsing.c
- * @brief functions to parse incoming requests (MHD arguments and JSON snippets)
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-
-
-/**
- * Initial size for POST request buffer.
- */
-#define REQUEST_BUFFER_INITIAL (2*1024)
-
-/**
- * Maximum POST request size.
- */
-#define REQUEST_BUFFER_MAX (1024*1024)
-
-
-/**
- * Buffer for POST requests.
- */
-struct Buffer
-{
- /**
- * Allocated memory
- */
- char *data;
-
- /**
- * Number of valid bytes in buffer.
- */
- size_t fill;
-
- /**
- * Number of allocated bytes in buffer.
- */
- size_t alloc;
-};
-
-
-/**
- * Initialize a buffer.
- *
- * @param buf the buffer to initialize
- * @param data the initial data
- * @param data_size size of the initial data
- * @param alloc_size size of the buffer
- * @param max_size maximum size that the buffer can grow to
- * @return a GNUnet result code
- */
-static int
-buffer_init (struct Buffer *buf,
- const void *data,
- size_t data_size,
- size_t alloc_size,
- size_t max_size)
-{
- if (data_size > max_size || alloc_size > max_size)
- return GNUNET_SYSERR;
- if (data_size > alloc_size)
- alloc_size = data_size;
- buf->data = GNUNET_malloc (alloc_size);
- memcpy (buf->data, data, data_size);
- return GNUNET_OK;
-}
-
-
-/**
- * Free the data in a buffer. Does *not* free
- * the buffer object itself.
- *
- * @param buf buffer to de-initialize
- */
-static void
-buffer_deinit (struct Buffer *buf)
-{
- GNUNET_free (buf->data);
- buf->data = NULL;
-}
-
-
-/**
- * Append data to a buffer, growing the buffer if necessary.
- *
- * @param buf the buffer to append to
- * @param data the data to append
- * @param data_size the size of @a data
- * @param max_size maximum size that the buffer can grow to
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if the buffer can't accomodate for the new data
- */
-static int
-buffer_append (struct Buffer *buf,
- const void *data,
- size_t data_size,
- size_t max_size)
-{
- if (buf->fill + data_size > max_size)
- return GNUNET_NO;
- if (data_size + buf->fill > buf->alloc)
- {
- char *new_buf;
- size_t new_size = buf->alloc;
- while (new_size < buf->fill + data_size)
- new_size += 2;
- if (new_size > max_size)
- return GNUNET_NO;
- new_buf = GNUNET_malloc (new_size);
- memcpy (new_buf, buf->data, buf->fill);
- GNUNET_free (buf->data);
- buf->data = new_buf;
- buf->alloc = new_size;
- }
- memcpy (buf->data + buf->fill, data, data_size);
- buf->fill += data_size;
- return GNUNET_OK;
-}
-
-
-/**
- * Release all memory allocated for the variable-size fields in
- * the parser specification.
- *
- * @param spec specification to free
- * @param spec_len number of items in @a spec to look at
- */
-static void
-release_data (struct TMH_PARSE_FieldSpecification *spec,
- unsigned int spec_len)
-{
- unsigned int i;
-
- for (i=0; i < spec_len; i++)
- {
- switch (spec[i].command)
- {
- case TMH_PARSE_JNC_FIELD:
- GNUNET_break (0);
- return;
- case TMH_PARSE_JNC_INDEX:
- GNUNET_break (0);
- return;
- case TMH_PARSE_JNC_RET_DATA:
- break;
- case TMH_PARSE_JNC_RET_DATA_VAR:
- if (NULL != spec[i].destination)
- {
- GNUNET_free (* (void**) spec[i].destination);
- *(void**) spec[i].destination = NULL;
- *spec[i].destination_size_out = 0;
- }
- break;
- case TMH_PARSE_JNC_RET_TYPED_JSON:
- {
- json_t *json;
-
- json = *(json_t **) spec[i].destination;
- if (NULL != json)
- {
- json_decref (json);
- *(json_t**) spec[i].destination = NULL;
- }
- }
- break;
- case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
- {
- struct TALER_DenominationPublicKey *pk;
-
- pk = spec[i].destination;
- if (NULL != pk->rsa_public_key)
- {
- GNUNET_CRYPTO_rsa_public_key_free (pk->rsa_public_key);
- pk->rsa_public_key = NULL;
- }
- }
- break;
- case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
- {
- struct TALER_DenominationSignature *sig;
-
- sig = spec[i].destination;
- if (NULL != sig->rsa_signature)
- {
- GNUNET_CRYPTO_rsa_signature_free (sig->rsa_signature);
- sig->rsa_signature = NULL;
- }
- }
- break;
- case TMH_PARSE_JNC_RET_AMOUNT:
- memset (spec[i].destination,
- 0,
- sizeof (struct TALER_Amount));
- break;
- case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
- break;
- case TMH_PARSE_JNC_RET_UINT64:
- break;
- }
- }
-}
-
-
-/**
- * Process a POST request containing a JSON object. This function
- * realizes an MHD POST processor that will (incrementally) process
- * JSON data uploaded to the HTTP server. It will store the required
- * state in the @a con_cls, which must be cleaned up using
- * #TMH_PARSE_post_cleanup_callback().
- *
- * @param connection the MHD connection
- * @param con_cls the closure (points to a `struct Buffer *`)
- * @param upload_data the POST data
- * @param upload_data_size number of bytes in @a upload_data
- * @param json the JSON object for a completed request
- * @return
- * #GNUNET_YES if json object was parsed or at least
- * may be parsed in the future (call again);
- * `*json` will be NULL if we need to be called again,
- * and non-NULL if we are done.
- * #GNUNET_NO is request incomplete or invalid
- * (error message was generated)
- * #GNUNET_SYSERR on internal error
- * (we could not even queue an error message,
- * close HTTP session with MHD_NO)
- */
-int
-TMH_PARSE_post_json (struct MHD_Connection *connection,
- void **con_cls,
- const char *upload_data,
- size_t *upload_data_size,
- json_t **json)
-{
- struct Buffer *r = *con_cls;
-
- *json = NULL;
- if (NULL == *con_cls)
- {
- /* We are seeing a fresh POST request. */
- r = GNUNET_new (struct Buffer);
- if (GNUNET_OK !=
- buffer_init (r,
- upload_data,
- *upload_data_size,
- REQUEST_BUFFER_INITIAL,
- REQUEST_BUFFER_MAX))
- {
- *con_cls = NULL;
- buffer_deinit (r);
- GNUNET_free (r);
- return (MHD_NO ==
- TMH_RESPONSE_reply_internal_error (connection,
- "out of memory"))
- ? GNUNET_SYSERR : GNUNET_NO;
- }
- /* everything OK, wait for more POST data */
- *upload_data_size = 0;
- *con_cls = r;
- return GNUNET_YES;
- }
- if (0 != *upload_data_size)
- {
- /* We are seeing an old request with more data available. */
-
- if (GNUNET_OK !=
- buffer_append (r,
- upload_data,
- *upload_data_size,
- REQUEST_BUFFER_MAX))
- {
- /* Request too long */
- *con_cls = NULL;
- buffer_deinit (r);
- GNUNET_free (r);
- return (MHD_NO ==
- TMH_RESPONSE_reply_request_too_large (connection))
- ? GNUNET_SYSERR : GNUNET_NO;
- }
- /* everything OK, wait for more POST data */
- *upload_data_size = 0;
- return GNUNET_YES;
- }
-
- /* We have seen the whole request. */
-
- *json = json_loadb (r->data,
- r->fill,
- 0,
- NULL);
- if (NULL == *json)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to parse JSON request body\n");
- return (MHD_YES ==
- TMH_RESPONSE_reply_invalid_json (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- buffer_deinit (r);
- GNUNET_free (r);
- *con_cls = NULL;
-
- return GNUNET_YES;
-}
-
-
-/**
- * Function called whenever we are done with a request
- * to clean up our state.
- *
- * @param con_cls value as it was left by
- * #TMH_PARSE_post_json(), to be cleaned up
- */
-void
-TMH_PARSE_post_cleanup_callback (void *con_cls)
-{
- struct Buffer *r = con_cls;
-
- if (NULL != r)
- {
- buffer_deinit (r);
- GNUNET_free (r);
- }
-}
-
-
-/**
- * Extract base32crockford encoded data from request.
- *
- * Queues an error response to the connection if the parameter is missing or
- * invalid.
- *
- * @param connection the MHD connection
- * @param param_name the name of the parameter with the key
- * @param[out] out_data pointer to store the result
- * @param out_size expected size of data
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-int
-TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
- const char *param_name,
- void *out_data,
- size_t out_size)
-{
- const char *str;
-
- str = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- param_name);
- if (NULL == str)
- {
- return (MHD_NO ==
- TMH_RESPONSE_reply_arg_missing (connection, param_name))
- ? GNUNET_SYSERR : GNUNET_NO;
- }
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- out_data,
- out_size))
- return (MHD_NO ==
- TMH_RESPONSE_reply_arg_invalid (connection, param_name))
- ? GNUNET_SYSERR : GNUNET_NO;
- return GNUNET_OK;
-}
-
-
-/**
- * Extraxt variable-size base32crockford encoded data from request.
- *
- * Queues an error response to the connection if the parameter is missing
- * or the encoding is invalid.
- *
- * @param connection the MHD connection
- * @param param_name the name of the parameter with the key
- * @param[out] out_data pointer to allocate buffer and store the result
- * @param[out] out_size set to the size of the buffer allocated in @a out_data
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-int
-TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
- const char *param_name,
- void **out_data,
- size_t *out_size)
-{
- const char *str;
- size_t slen;
- size_t olen;
- void *out;
-
- str = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- param_name);
- if (NULL == str)
- {
- return (MHD_NO ==
- TMH_RESPONSE_reply_arg_missing (connection, param_name))
- ? GNUNET_SYSERR : GNUNET_NO;
- }
- slen = strlen (str);
- olen = (slen * 5) / 8;
- out = GNUNET_malloc (olen);
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- out,
- olen))
- {
- GNUNET_free (out);
- *out_size = 0;
- return (MHD_NO ==
- TMH_RESPONSE_reply_arg_invalid (connection, param_name))
- ? GNUNET_SYSERR : GNUNET_NO;
- }
- *out_data = out;
- *out_size = olen;
- return GNUNET_OK;
-}
-
-
-/**
- * Navigate through a JSON tree.
- *
- * Sends an error response if navigation is impossible (i.e.
- * the JSON object is invalid)
- *
- * @param connection the connection to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
- * @return
- * #GNUNET_YES if navigation was successful
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error (no response was generated,
- * connection must be closed)
- */
-int
-TMH_PARSE_navigate_json (struct MHD_Connection *connection,
- const json_t *root,
- ...)
-{
- va_list argp;
- int ret;
- json_t *path; /* what's our current path from 'root'? */
-
- path = json_array ();
- va_start (argp, root);
- ret = 2; /* just not any of the valid return values */
- while (2 == ret)
- {
- enum TMH_PARSE_JsonNavigationCommand command
- = va_arg (argp,
- enum TMH_PARSE_JsonNavigationCommand);
-
- switch (command)
- {
- case TMH_PARSE_JNC_FIELD:
- {
- const char *fname = va_arg(argp, const char *);
-
- json_array_append_new (path,
- json_string (fname));
- root = json_object_get (root,
- fname);
- if (NULL == root)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s, s:O}",
- "error", "missing field in JSON",
- "field", fname,
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- }
- break;
-
- case TMH_PARSE_JNC_INDEX:
- {
- int fnum = va_arg(argp, int);
-
- json_array_append_new (path,
- json_integer (fnum));
- root = json_array_get (root,
- fnum);
- if (NULL == root)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "missing index in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- }
- break;
-
- case TMH_PARSE_JNC_RET_DATA:
- {
- void *where = va_arg (argp, void *);
- size_t len = va_arg (argp, size_t);
- const char *str;
- int res;
-
- str = json_string_value (root);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "string expected",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- res = GNUNET_STRINGS_string_to_data (str, strlen (str),
- where, len);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "malformed binary data in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- ret = GNUNET_OK;
- }
- break;
-
- case TMH_PARSE_JNC_RET_DATA_VAR:
- {
- void **where = va_arg (argp, void **);
- size_t *len = va_arg (argp, size_t *);
- const char *str;
- int res;
-
- str = json_string_value (root);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_internal_error (connection,
- "json_string_value() failed"))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- *len = (strlen (str) * 5) / 8;
- if (NULL != where)
- {
- *where = GNUNET_malloc (*len);
- res = GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- *where,
- *len);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- GNUNET_free (*where);
- *where = NULL;
- *len = 0;
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "malformed binary data in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- }
- ret = GNUNET_OK;
- }
- break;
-
- case TMH_PARSE_JNC_RET_TYPED_JSON:
- {
- int typ = va_arg (argp, int);
- const json_t **r_json = va_arg (argp, const json_t **);
-
- if ( (NULL == root) ||
- ( (-1 != typ) &&
- (json_typeof (root) != typ)) )
- {
- GNUNET_break_op (0);
- *r_json = NULL;
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:i, s:i, s:O}",
- "error", "wrong JSON field type",
- "type_expected", typ,
- "type_actual", json_typeof (root),
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- *r_json = root;
- json_incref ((json_t *) root);
- ret = GNUNET_OK;
- }
- break;
-
- case TMH_PARSE_JNC_RET_UINT64:
- {
- uint64_t *r_u64 = va_arg (argp, uint64_t *);
-
- if (json_typeof (root) != JSON_INTEGER)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s, s:i, s:O}",
- "error", "wrong JSON field type",
- "type_expected", "integer",
- "type_actual", json_typeof (root),
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- *r_u64 = (uint64_t) json_integer_value (root);
- ret = GNUNET_OK;
- }
- break;
-
- case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
- {
- struct TALER_DenominationPublicKey *where;
- size_t len;
- const char *str;
- int res;
- void *buf;
-
- where = va_arg (argp,
- struct TALER_DenominationPublicKey *);
- str = json_string_value (root);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "string expected",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- len = (strlen (str) * 5) / 8;
- buf = GNUNET_malloc (len);
- res = GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- buf,
- len);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- GNUNET_free (buf);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "malformed binary data in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf,
- len);
- GNUNET_free (buf);
- if (NULL == where->rsa_public_key)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "malformed RSA public key in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- ret = GNUNET_OK;
- break;
- }
-
- case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
- {
- struct TALER_DenominationSignature *where;
- size_t len;
- const char *str;
- int res;
- void *buf;
-
- where = va_arg (argp,
- struct TALER_DenominationSignature *);
- str = json_string_value (root);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "string expected",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- len = (strlen (str) * 5) / 8;
- buf = GNUNET_malloc (len);
- res = GNUNET_STRINGS_string_to_data (str,
- strlen (str),
- buf,
- len);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- GNUNET_free (buf);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "malformed binary data in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf,
- len);
- GNUNET_free (buf);
- if (NULL == where->rsa_signature)
- {
- GNUNET_break_op (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "malformed RSA signature in JSON",
- "path", path))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- ret = GNUNET_OK;
- break;
- }
-
- case TMH_PARSE_JNC_RET_AMOUNT:
- {
- struct TALER_Amount *where = va_arg (argp, void *);
-
- if (GNUNET_OK !=
- TALER_json_to_amount ((json_t *) root,
- where))
- {
- GNUNET_break_op (0);
- ret = (MHD_YES !=
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O}",
- "error", "Bad format",
- "path", path))
- ? GNUNET_SYSERR : GNUNET_NO;
- break;
- }
- if (0 != strcmp (where->currency,
- TMH_mint_currency_string))
- {
- GNUNET_break_op (0);
- ret = (MHD_YES !=
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:O, s:s}",
- "error", "Currency not supported",
- "path", path,
- "currency", where->currency))
- ? GNUNET_SYSERR : GNUNET_NO;
- memset (where, 0, sizeof (struct TALER_Amount));
- break;
- }
- ret = GNUNET_OK;
- break;
- }
-
- case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
- {
- struct GNUNET_TIME_Absolute *where = va_arg (argp, void *);
-
- if (GNUNET_OK !=
- TALER_json_to_abs ((json_t *) root,
- where))
- {
- GNUNET_break_op (0);
- ret = (MHD_YES !=
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s, s:O}",
- "error", "Bad format",
- "hint", "expected absolute time",
- "path", path))
- ? GNUNET_SYSERR : GNUNET_NO;
- break;
- }
- ret = GNUNET_OK;
- break;
- }
-
- default:
- GNUNET_break (0);
- ret = (MHD_YES ==
- TMH_RESPONSE_reply_internal_error (connection,
- "unhandled value in switch"))
- ? GNUNET_NO : GNUNET_SYSERR;
- break;
- }
- }
- va_end (argp);
- json_decref (path);
- return ret;
-}
-
-
-/**
- * Parse JSON object into components based on the given field
- * specification.
- *
- * @param connection the connection to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param spec field specification for the parser
- * @return
- * #GNUNET_YES if navigation was successful (caller is responsible
- * for freeing allocated variable-size data using
- * #TMH_PARSE_release_data() when done)
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error
- */
-int
-TMH_PARSE_json_data (struct MHD_Connection *connection,
- const json_t *root,
- struct TMH_PARSE_FieldSpecification *spec)
-{
- unsigned int i;
- int ret;
-
- ret = GNUNET_YES;
- for (i=0; NULL != spec[i].field_name; i++)
- {
- if (GNUNET_YES != ret)
- break;
- switch (spec[i].command)
- {
- case TMH_PARSE_JNC_FIELD:
- GNUNET_break (0);
- return GNUNET_SYSERR;
- case TMH_PARSE_JNC_INDEX:
- GNUNET_break (0);
- return GNUNET_SYSERR;
- case TMH_PARSE_JNC_RET_DATA:
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_DATA,
- spec[i].destination,
- spec[i].destination_size_in);
- break;
- case TMH_PARSE_JNC_RET_DATA_VAR:
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_DATA_VAR,
- (void **) spec[i].destination,
- spec[i].destination_size_out);
- break;
- case TMH_PARSE_JNC_RET_TYPED_JSON:
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_TYPED_JSON,
- spec[i].type,
- spec[i].destination);
- break;
- case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
- spec[i].destination);
- break;
- case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_RSA_SIGNATURE,
- spec[i].destination);
- break;
- case TMH_PARSE_JNC_RET_AMOUNT:
- GNUNET_assert (sizeof (struct TALER_Amount) ==
- spec[i].destination_size_in);
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_AMOUNT,
- spec[i].destination);
- break;
- case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
- GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) ==
- spec[i].destination_size_in);
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
- spec[i].destination);
- break;
- case TMH_PARSE_JNC_RET_UINT64:
- GNUNET_assert (sizeof (uint64_t) ==
- spec[i].destination_size_in);
- ret = TMH_PARSE_navigate_json (connection,
- root,
- TMH_PARSE_JNC_FIELD,
- spec[i].field_name,
- TMH_PARSE_JNC_RET_UINT64,
- spec[i].destination);
- break;
- }
- }
- if (GNUNET_YES != ret)
- release_data (spec,
- i - 1);
- return ret;
-}
-
-
-/**
- * Release all memory allocated for the variable-size fields in
- * the parser specification.
- *
- * @param spec specification to free
- */
-void
-TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec)
-{
- unsigned int i;
-
- for (i=0; NULL != spec[i].field_name; i++) ;
- release_data (spec, i);
-}
-
-
-/**
- * Generate line in parser specification for 64-bit integer
- * given as an integer in JSON.
- *
- * @param field name of the field
- * @param[out] u64 integer to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_uint64 (const char *field,
- uint64_t *u64)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, (void *) u64, sizeof (uint64_t), NULL, TMH_PARSE_JNC_RET_UINT64, 0 };
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for JSON object value.
- *
- * @param field name of the field
- * @param[out] jsonp address of pointer to JSON to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_object (const char *field,
- json_t **jsonp)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT };
- *jsonp = NULL;
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for JSON array value.
- *
- * @param field name of the field
- * @param[out] jsonp address of JSON pointer to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_array (const char *field,
- json_t **jsonp)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY };
- *jsonp = NULL;
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for an absolute time.
- *
- * @param field name of the field
- * @param[out] atime time to initialize
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_time_abs (const char *field,
- struct GNUNET_TIME_Absolute *atime)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, atime, sizeof(struct GNUNET_TIME_Absolute), NULL, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, 0 };
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for RSA public key.
- *
- * @param field name of the field
- * @param[out] pk key to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_denomination_public_key (const char *field,
- struct TALER_DenominationPublicKey *pk)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 };
- pk->rsa_public_key = NULL;
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for RSA public key.
- *
- * @param field name of the field
- * @param sig the signature to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_denomination_signature (const char *field,
- struct TALER_DenominationSignature *sig)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 };
- sig->rsa_signature = NULL;
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for an amount.
- *
- * @param field name of the field
- * @param amount a `struct TALER_Amount *` to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_amount (const char *field,
- struct TALER_Amount *amount)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 };
- memset (amount, 0, sizeof (struct TALER_Amount));
- return ret;
-}
-
-
-/**
- * Generate line in parser specification for variable-size value.
- *
- * @param field name of the field
- * @param[out] ptr pointer to initialize
- * @param[out] ptr_size size to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_variable (const char *field,
- void **ptr,
- size_t *ptr_size)
-{
- struct TMH_PARSE_FieldSpecification ret =
- { field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 };
- *ptr = NULL;
- return ret;
-}
-
-/* end of taler-mint-httpd_parsing.c */
diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h
deleted file mode 100644
index a2cf4c469..000000000
--- a/src/mint/taler-mint-httpd_parsing.h
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_parsing.h
- * @brief functions to parse incoming requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_PARSING_H
-#define TALER_MINT_HTTPD_PARSING_H
-
-#include <microhttpd.h>
-#include <jansson.h>
-#include "taler_util.h"
-
-
-/**
- * Process a POST request containing a JSON object. This
- * function realizes an MHD POST processor that will
- * (incrementally) process JSON data uploaded to the HTTP
- * server. It will store the required state in the
- * "connection_cls", which must be cleaned up using
- * #TMH_PARSE_post_cleanup_callback().
- *
- * @param connection the MHD connection
- * @param con_cls the closure (points to a `struct Buffer *`)
- * @param upload_data the POST data
- * @param upload_data_size number of bytes in @a upload_data
- * @param json the JSON object for a completed request
- * @return
- * #GNUNET_YES if json object was parsed or at least
- * may be parsed in the future (call again);
- * `*json` will be NULL if we need to be called again,
- * and non-NULL if we are done.
- * #GNUNET_NO is request incomplete or invalid
- * (error message was generated)
- * #GNUNET_SYSERR on internal error
- * (we could not even queue an error message,
- * close HTTP session with MHD_NO)
- */
-int
-TMH_PARSE_post_json (struct MHD_Connection *connection,
- void **con_cls,
- const char *upload_data,
- size_t *upload_data_size,
- json_t **json);
-
-
-/**
- * Function called whenever we are done with a request
- * to clean up our state.
- *
- * @param con_cls value as it was left by
- * #TMH_PARSE_post_json(), to be cleaned up
- */
-void
-TMH_PARSE_post_cleanup_callback (void *con_cls);
-
-
-/**
- * Constants for JSON navigation description.
- */
-enum TMH_PARSE_JsonNavigationCommand
-{
- /**
- * Access a field.
- * Param: const char *
- */
- TMH_PARSE_JNC_FIELD,
-
- /**
- * Access an array index.
- * Param: int
- */
- TMH_PARSE_JNC_INDEX,
-
- /**
- * Return base32crockford encoded data of
- * constant size.
- * Params: (void *, size_t)
- */
- TMH_PARSE_JNC_RET_DATA,
-
- /**
- * Return base32crockford encoded data of
- * variable size.
- * Params: (void **, size_t *)
- */
- TMH_PARSE_JNC_RET_DATA_VAR,
-
- /**
- * Return a json object, which must be
- * of the given type (JSON_* type constants,
- * or -1 for any type).
- * Params: (int, json_t **)
- */
- TMH_PARSE_JNC_RET_TYPED_JSON,
-
- /**
- * Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was
- * encoded as variable-size base32crockford encoded data.
- */
- TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
-
- /**
- * Return a `struct GNUNET_CRYPTO_rsa_Signature` which was
- * encoded as variable-size base32crockford encoded data.
- */
- TMH_PARSE_JNC_RET_RSA_SIGNATURE,
-
- /**
- * Return a `struct TALER_Amount` which was
- * encoded within its own json object.
- */
- TMH_PARSE_JNC_RET_AMOUNT,
-
- /**
- * Return a `struct GNUNET_TIME_Absolute` which was
- * encoded within its own json object.
- * Param: struct GNUNET_TIME_Absolute *
- */
- TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
-
- /**
- * Return a `uint64_t` which was
- * encoded as a JSON integer.
- * Param: uint64_t *
- */
- TMH_PARSE_JNC_RET_UINT64
-
-};
-
-
-/**
- * Navigate through a JSON tree.
- *
- * Sends an error response if navigation is impossible (i.e.
- * the JSON object is invalid)
- *
- * @param connection the connection to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
- * @return
- * #GNUNET_YES if navigation was successful
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error
- */
-int
-TMH_PARSE_navigate_json (struct MHD_Connection *connection,
- const json_t *root,
- ...);
-
-
-/**
- * @brief Specification for how to parse a JSON field.
- */
-struct TMH_PARSE_FieldSpecification
-{
- /**
- * Name of the field. NULL only to terminate array.
- */
- const char *field_name;
-
- /**
- * Where to store the result. Must have exactly
- * @e destination_size bytes, except if @e destination_size is zero.
- * NULL to skip assignment (but check presence of the value).
- */
- void *destination;
-
- /**
- * How big should the result be, 0 for variable size. In
- * this case, @e destination must be a "void **", pointing
- * to a location that is currently NULL and is to be allocated.
- */
- size_t destination_size_in;
-
- /**
- * @e destination_size_out will then be set to the size of the
- * value that was stored in @e destination (useful for
- * variable-size allocations).
- */
- size_t *destination_size_out;
-
- /**
- * Navigation command to use to extract the value. Note that
- * #TMH_PARSE_JNC_RET_DATA or #TMH_PARSE_JNC_RET_DATA_VAR must be used for @e
- * destination_size_in and @e destination_size_out to have a
- * meaning. #TMH_PARSE_JNC_FIELD and #TMH_PARSE_JNC_INDEX must not be used here!
- */
- enum TMH_PARSE_JsonNavigationCommand command;
-
- /**
- * JSON type to use, only meaningful in connection with a @e command
- * value of #TMH_PARSE_JNC_RET_TYPED_JSON. Typical values are
- * #JSON_ARRAY and #JSON_OBJECT.
- */
- int type;
-
-};
-
-
-/**
- * Parse JSON object into components based on the given field
- * specification.
- *
- * @param connection the connection to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param spec field specification for the parser
- * @return
- * #GNUNET_YES if navigation was successful (caller is responsible
- * for freeing allocated variable-size data using
- * #TMH_PARSE_release_data() when done)
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error
- */
-int
-TMH_PARSE_json_data (struct MHD_Connection *connection,
- const json_t *root,
- struct TMH_PARSE_FieldSpecification *spec);
-
-
-/**
- * Release all memory allocated for the variable-size fields in
- * the parser specification.
- *
- * @param spec specification to free
- */
-void
-TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec);
-
-
-/**
- * Generate line in parser specification for fixed-size value.
- *
- * @param field name of the field
- * @param value where to store the value
- */
-#define TMH_PARSE_member_fixed(field,value) { field, value, sizeof (*value), NULL, TMH_PARSE_JNC_RET_DATA, 0 }
-
-
-/**
- * Generate line in parser specification for variable-size value.
- *
- * @param field name of the field
- * @param[out] ptr pointer to initialize
- * @param[out] ptr_size size to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_variable (const char *field,
- void **ptr,
- size_t *ptr_size);
-
-
-/**
- * Generate line in parser specification for 64-bit integer
- * given as an integer in JSON.
- *
- * @param field name of the field
- * @param[out] u64 integer to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_uint64 (const char *field,
- uint64_t *u64);
-
-
-/**
- * Generate line in parser specification for JSON array value.
- *
- * @param field name of the field
- * @param[out] jsonp address of JSON pointer to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_array (const char *field,
- json_t **jsonp);
-
-
-/**
- * Generate line in parser specification for JSON object value.
- *
- * @param field name of the field
- * @param[out] jsonp address of pointer to JSON to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_object (const char *field,
- json_t **jsonp);
-
-
-/**
- * Generate line in parser specification for RSA public key.
- *
- * @param field name of the field
- * @param[out] pk key to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_denomination_public_key (const char *field,
- struct TALER_DenominationPublicKey *pk);
-
-
-/**
- * Generate line in parser specification for RSA public key.
- *
- * @param field name of the field
- * @param sig the signature to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_denomination_signature (const char *field,
- struct TALER_DenominationSignature *sig);
-
-
-/**
- * Generate line in parser specification for an amount.
- *
- * @param field name of the field
- * @param[out] amount a `struct TALER_Amount *` to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_amount (const char *field,
- struct TALER_Amount *amount);
-
-
-/**
- * Generate line in parser specification for an absolute time.
- *
- * @param field name of the field
- * @param[out] atime time to initialize
- * @return corresponding field spec
- */
-struct TMH_PARSE_FieldSpecification
-TMH_PARSE_member_time_abs (const char *field,
- struct GNUNET_TIME_Absolute *atime);
-
-
-
-/**
- * Generate line in parser specification indicating the end of the spec.
- */
-#define TMH_PARSE_MEMBER_END { NULL, NULL, 0, NULL, TMH_PARSE_JNC_FIELD, 0 }
-
-
-/**
- * Extraxt fixed-size base32crockford encoded data from request.
- *
- * Queues an error response to the connection if the parameter is missing or
- * invalid.
- *
- * @param connection the MHD connection
- * @param param_name the name of the parameter with the key
- * @param[out] out_data pointer to store the result
- * @param out_size expected size of @a out_data
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-int
-TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
- const char *param_name,
- void *out_data,
- size_t out_size);
-
-
-/**
- * Extraxt variable-size base32crockford encoded data from request.
- *
- * Queues an error response to the connection if the parameter is missing
- * or the encoding is invalid.
- *
- * @param connection the MHD connection
- * @param param_name the name of the parameter with the key
- * @param[out] out_data pointer to allocate buffer and store the result
- * @param[out] out_size set to the size of the buffer allocated in @a out_data
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-int
-TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
- const char *param_name,
- void **out_data,
- size_t *out_size);
-
-
-
-
-#endif /* TALER_MINT_HTTPD_PARSING_H */
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
deleted file mode 100644
index 4d89fe892..000000000
--- a/src/mint/taler-mint-httpd_refresh.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_refresh.c
- * @brief Handle /refresh/ requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_mhd.h"
-#include "taler-mint-httpd_refresh.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_keystate.h"
-
-
-/**
- * Handle a "/refresh/melt" request after the main JSON parsing has happened.
- * We now need to validate the coins being melted and the session signature
- * and then hand things of to execute the melt operation.
- *
- * @param connection the MHD connection to handle
- * @param num_new_denoms number of coins to be created, size of y-dimension of @a commit_link array
- * @param denom_pubs array of @a num_new_denoms keys
- * @param coin_count number of coins to be melted, size of y-dimension of @a commit_coin array
- * @param coin_melt_details array with @a coin_count entries with melting details
- * @param session_hash hash over the data that the client commits to
- * @param commit_coin 2d array of coin commitments (what the mint is to sign
- * once the "/refres/reveal" of cut and choose is done)
- * @param commit_link 2d array of coin link commitments (what the mint is
- * to return via "/refresh/link" to enable linkage in the
- * future)
- * @return MHD result code
- */
-static int
-handle_refresh_melt_binary (struct MHD_Connection *connection,
- unsigned int num_new_denoms,
- const struct TALER_DenominationPublicKey *denom_pubs,
- unsigned int coin_count,
- const struct TMH_DB_MeltDetails *coin_melt_details,
- const struct GNUNET_HashCode *session_hash,
- struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin,
- struct TALER_RefreshCommitLinkP *const* commit_link)
-{
- unsigned int i;
- struct TMH_KS_StateHandle *key_state;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dk;
- struct TALER_MINTDB_DenominationKeyInformationP *dki;
- struct TALER_Amount cost;
- struct TALER_Amount total_cost;
- struct TALER_Amount melt;
- struct TALER_Amount value;
- struct TALER_Amount fee_withdraw;
- struct TALER_Amount fee_melt;
- struct TALER_Amount total_melt;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero (TMH_mint_currency_string,
- &total_cost));
- key_state = TMH_KS_acquire ();
- for (i=0;i<num_new_denoms;i++)
- {
- dk = TMH_KS_denomination_key_lookup (key_state,
- &denom_pubs[i],
- TMH_KS_DKU_WITHDRAW);
- if (NULL == dk)
- {
- GNUNET_break_op (0);
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "new_denoms");
- }
- dki = &dk->issue;
- TALER_amount_ntoh (&value,
- &dki->properties.value);
- TALER_amount_ntoh (&fee_withdraw,
- &dki->properties.fee_withdraw);
- if ( (GNUNET_OK !=
- TALER_amount_add (&cost,
- &value,
- &fee_withdraw)) ||
- (GNUNET_OK !=
- TALER_amount_add (&total_cost,
- &cost,
- &total_cost)) )
- {
- GNUNET_break_op (0);
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_internal_error (connection,
- "cost calculation failure");
- }
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero (TMH_mint_currency_string,
- &total_melt));
- for (i=0;i<coin_count;i++)
- {
- /* calculate contribution of the i-th melt by subtracting
- the fee; add the rest to the total_melt value */
- dk = TMH_KS_denomination_key_lookup (key_state,
- &coin_melt_details[i].coin_info.denom_pub,
- TMH_KS_DKU_DEPOSIT);
- if (NULL == dk)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "denom_pub");
- }
- dki = &dk->issue;
- TALER_amount_ntoh (&fee_melt,
- &dki->properties.fee_refresh);
- if (GNUNET_OK !=
- TALER_amount_subtract (&melt,
- &coin_melt_details->melt_amount_with_fee,
- &fee_melt))
- {
- GNUNET_break_op (0);
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_external_error (connection,
- "Melt contribution below melting fee");
- }
- if (GNUNET_OK !=
- TALER_amount_add (&total_melt,
- &melt,
- &total_melt))
- {
- GNUNET_break_op (0);
- TMH_KS_release (key_state);
- return TMH_RESPONSE_reply_internal_error (connection,
- "balance calculation failure");
- }
- }
- TMH_KS_release (key_state);
- if (0 !=
- TALER_amount_cmp (&total_cost,
- &total_melt))
- {
- GNUNET_break_op (0);
- /* We require total value of coins being melted and
- total value of coins being generated to match! */
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error", "value mismatch");
- }
- return TMH_DB_execute_refresh_melt (connection,
- session_hash,
- num_new_denoms,
- denom_pubs,
- coin_count,
- coin_melt_details,
- commit_coin,
- commit_link);
-}
-
-
-/**
- * Extract public coin information from a JSON object.
- *
- * @param connection the connection to send error responses to
- * @param coin_info the JSON object to extract the coin info from
- * @param[out] r_melt_detail set to details about the coin's melting permission (if valid)
- * @return #GNUNET_YES if coin public info in JSON was valid
- * #GNUNET_NO JSON was invalid, response was generated
- * #GNUNET_SYSERR on internal error
- */
-static int
-get_coin_public_info (struct MHD_Connection *connection,
- json_t *coin_info,
- struct TMH_DB_MeltDetails *r_melt_detail)
-{
- int ret;
- struct TALER_CoinSpendSignatureP melt_sig;
- struct TALER_DenominationSignature sig;
- struct TALER_DenominationPublicKey pk;
- struct TALER_Amount amount;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("coin_pub", &r_melt_detail->coin_info.coin_pub),
- TMH_PARSE_member_denomination_signature ("denom_sig", &sig),
- TMH_PARSE_member_denomination_public_key ("denom_pub", &pk),
- TMH_PARSE_member_fixed ("confirm_sig", &melt_sig),
- TMH_PARSE_member_amount ("value_with_fee", &amount),
- TMH_PARSE_MEMBER_END
- };
-
- ret = TMH_PARSE_json_data (connection,
- coin_info,
- spec);
- if (GNUNET_OK != ret)
- {
- GNUNET_break_op (0);
- return ret;
- }
- /* check mint signature on the coin */
- r_melt_detail->coin_info.denom_sig = sig;
- r_melt_detail->coin_info.denom_pub = pk;
- if (GNUNET_OK !=
- TALER_test_coin_valid (&r_melt_detail->coin_info))
- {
- GNUNET_break_op (0);
- TMH_PARSE_release_data (spec);
- r_melt_detail->coin_info.denom_sig.rsa_signature = NULL;
- r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
- return (MHD_YES ==
- TMH_RESPONSE_reply_signature_invalid (connection,
- "denom_sig"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- r_melt_detail->melt_sig = melt_sig;
- r_melt_detail->melt_amount_with_fee = amount;
- return GNUNET_OK;
-}
-
-
-/**
- * Verify that the signature shows that this coin is to be melted into
- * the given @a session_hash melting session, and that this is a valid
- * coin (we know the denomination key and the signature on it is
- * valid). Essentially, this does all of the per-coin checks that can
- * be done before the transaction starts.
- *
- * @param connection the connection to send error responses to
- * @param session_hash hash over refresh session the coin is melted into
- * @param[in,out] melt_detail details about the coin's melting permission,
- * the `melt_fee` is updated
- * @return #GNUNET_YES if coin public info in JSON was valid
- * #GNUNET_NO JSON was invalid, response was generated
- * #GNUNET_SYSERR on internal error
- */
-static int
-verify_coin_public_info (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- struct TMH_DB_MeltDetails *melt_detail)
-{
- struct TALER_RefreshMeltCoinAffirmationPS body;
- struct TMH_KS_StateHandle *key_state;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TALER_Amount fee_refresh;
-
- key_state = TMH_KS_acquire ();
- dki = TMH_KS_denomination_key_lookup (key_state,
- &melt_detail->coin_info.denom_pub,
- TMH_KS_DKU_DEPOSIT);
- if (NULL == dki)
- {
- TMH_KS_release (key_state);
- TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub");
- }
- TALER_amount_ntoh (&fee_refresh,
- &dki->issue.properties.fee_refresh);
- melt_detail->melt_fee = fee_refresh;
- body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
- body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
- body.session_hash = *session_hash;
- TALER_amount_hton (&body.amount_with_fee,
- &melt_detail->melt_amount_with_fee);
- TALER_amount_hton (&body.melt_fee,
- &fee_refresh);
- body.coin_pub = melt_detail->coin_info.coin_pub;
- if (TALER_amount_cmp (&fee_refresh,
- &melt_detail->melt_amount_with_fee) > 0)
- {
- GNUNET_break_op (0);
- TMH_KS_release (key_state);
- return (MHD_YES ==
- TMH_RESPONSE_reply_external_error (connection,
- "melt amount smaller than melting fee"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
- TMH_KS_release (key_state);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
- &body.purpose,
- &melt_detail->melt_sig.eddsa_signature,
- &melt_detail->coin_info.coin_pub.eddsa_pub))
- {
- GNUNET_break_op (0);
- if (MHD_YES !=
- TMH_RESPONSE_reply_signature_invalid (connection,
- "confirm_sig"))
- return GNUNET_SYSERR;
- return GNUNET_NO;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Release memory from the @a commit_coin array.
- *
- * @param commit_coin array to release
- * @param kappa size of 1st dimension
- * @param num_new_coins size of 2nd dimension
- */
-static void
-free_commit_coins (struct TALER_MINTDB_RefreshCommitCoin **commit_coin,
- unsigned int kappa,
- unsigned int num_new_coins)
-{
- unsigned int i;
- unsigned int j;
-
- for (i=0;i<kappa;i++)
- {
- if (NULL == commit_coin[i])
- break;
- for (j=0;j<num_new_coins;j++)
- {
- GNUNET_free_non_null (commit_coin[i][j].coin_ev);
- GNUNET_free_non_null (commit_coin[i][j].refresh_link);
- }
- GNUNET_free (commit_coin[i]);
- }
-}
-
-
-/**
- * Release memory from the @a commit_link array.
- *
- * @param commit_link array to release
- * @param kappa size of 1st dimension
- * @param num_old_coins size of 2nd dimension
- */
-static void
-free_commit_links (struct TALER_RefreshCommitLinkP **commit_link,
- unsigned int kappa,
- unsigned int num_old_coins)
-{
- unsigned int i;
-
- for (i=0;i<kappa;i++)
- {
- if (NULL == commit_link[i])
- break;
- GNUNET_free (commit_link[i]);
- }
-}
-
-
-/**
- * Handle a "/refresh/melt" request after the first parsing has happened.
- * We now need to validate the coins being melted and the session signature
- * and then hand things of to execute the melt operation. This function
- * parses the JSON arrays and then passes processing on to
- * #handle_refresh_melt_binary().
- *
- * @param connection the MHD connection to handle
- * @param new_denoms array of denomination keys
- * @param melt_coins array of coins to melt
- * @param num_oldcoins number of coins that are being melted
- * @param transfer_pubs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins transfer keys
- * @param secret_encs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins secrets
- * @param num_newcoins number of coins that the refresh will generate
- * @param coin_evs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins envelopes to sign
- * @param link_encs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins encrypted links
- * @return MHD result code
- */
-static int
-handle_refresh_melt_json (struct MHD_Connection *connection,
- const json_t *new_denoms,
- const json_t *melt_coins,
- unsigned int num_oldcoins,
- const json_t *transfer_pubs,
- const json_t *secret_encs,
- unsigned int num_newcoins,
- const json_t *coin_evs,
- const json_t *link_encs)
-{
- int res;
- unsigned int i;
- unsigned int j;
- struct TALER_DenominationPublicKey *denom_pubs;
- unsigned int num_new_denoms;
- struct TMH_DB_MeltDetails *coin_melt_details;
- unsigned int coin_count;
- struct GNUNET_HashCode session_hash;
- struct GNUNET_HashContext *hash_context;
- struct TALER_MINTDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA];
- struct TALER_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA];
-
- /* For the signature check, we hash most of the inputs together
- (except for the signatures on the coins). */
- hash_context = GNUNET_CRYPTO_hash_context_start ();
- num_new_denoms = json_array_size (new_denoms);
- denom_pubs = GNUNET_malloc (num_new_denoms *
- sizeof (struct TALER_DenominationPublicKey));
- for (i=0;i<num_new_denoms;i++)
- {
- char *buf;
- size_t buf_size;
-
- res = TMH_PARSE_navigate_json (connection,
- new_denoms,
- TMH_PARSE_JNC_INDEX, (int) i,
- TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
- &denom_pubs[i].rsa_public_key);
- if (GNUNET_OK != res)
- {
- res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- goto cleanup_denoms;
- }
- buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key,
- &buf);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- buf,
- buf_size);
- GNUNET_free (buf);
- }
-
- coin_count = json_array_size (melt_coins);
- coin_melt_details = GNUNET_new_array (coin_count,
- struct TMH_DB_MeltDetails);
- for (i=0;i<coin_count;i++)
- {
- /* decode JSON data on coin to melt */
- struct TALER_AmountNBO melt_amount;
-
- res = get_coin_public_info (connection,
- json_array_get (melt_coins, i),
- &coin_melt_details[i]);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- goto cleanup_melt_details;
- }
- /* Check that the client does not try to melt the same coin twice
- into the same session! */
- for (j=0;j<i;j++)
- {
- if (0 == memcmp (&coin_melt_details[i].coin_info.coin_pub,
- &coin_melt_details[j].coin_info.coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP)))
- {
- GNUNET_break_op (0);
- res = TMH_RESPONSE_reply_external_error (connection,
- "melting same coin twice in same session is not allowed");
- goto cleanup_melt_details;
- }
- }
- TALER_amount_hton (&melt_amount,
- &coin_melt_details[i].melt_amount_with_fee);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &coin_melt_details[i].coin_info.coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP));
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &melt_amount,
- sizeof (struct TALER_AmountNBO));
- }
-
- /* parse JSON arrays into 2d binary arrays and hash everything
- together for the signature check */
- memset (commit_coin, 0, sizeof (commit_coin));
- memset (commit_link, 0, sizeof (commit_link));
- for (i = 0; i < TALER_CNC_KAPPA; i++)
- {
- commit_coin[i] = GNUNET_malloc (num_newcoins *
- sizeof (struct TALER_MINTDB_RefreshCommitCoin));
- for (j = 0; j < num_newcoins; j++)
- {
- char *link_enc;
- size_t link_enc_size;
- struct TALER_MINTDB_RefreshCommitCoin *rcc = &commit_coin[i][j];
-
- res = TMH_PARSE_navigate_json (connection,
- coin_evs,
- TMH_PARSE_JNC_INDEX, (int) i,
- TMH_PARSE_JNC_INDEX, (int) j,
- TMH_PARSE_JNC_RET_DATA_VAR,
- &rcc->coin_ev,
- &rcc->coin_ev_size);
-
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- goto cleanup;
- }
-
- GNUNET_CRYPTO_hash_context_read (hash_context,
- rcc->coin_ev,
- rcc->coin_ev_size);
- res = TMH_PARSE_navigate_json (connection,
- link_encs,
- TMH_PARSE_JNC_INDEX, (int) i,
- TMH_PARSE_JNC_INDEX, (int) j,
- TMH_PARSE_JNC_RET_DATA_VAR,
- &link_enc,
- &link_enc_size);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- goto cleanup;
- }
- rcc->refresh_link
- = TALER_refresh_link_encrypted_decode (link_enc,
- link_enc_size);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- link_enc,
- link_enc_size);
- GNUNET_free (link_enc);
- }
- }
-
- for (i = 0; i < TALER_CNC_KAPPA; i++)
- {
- commit_link[i] = GNUNET_malloc (num_oldcoins *
- sizeof (struct TALER_RefreshCommitLinkP));
- for (j = 0; j < num_oldcoins; j++)
- {
- struct TALER_RefreshCommitLinkP *rcl = &commit_link[i][j];
-
- res = TMH_PARSE_navigate_json (connection,
- transfer_pubs,
- TMH_PARSE_JNC_INDEX, (int) i,
- TMH_PARSE_JNC_INDEX, (int) j,
- TMH_PARSE_JNC_RET_DATA,
- &rcl->transfer_pub,
- sizeof (struct TALER_TransferPublicKeyP));
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- goto cleanup;
- }
- res = TMH_PARSE_navigate_json (connection,
- secret_encs,
- TMH_PARSE_JNC_INDEX, (int) i,
- TMH_PARSE_JNC_INDEX, (int) j,
- TMH_PARSE_JNC_RET_DATA,
- &rcl->shared_secret_enc,
- sizeof (struct TALER_EncryptedLinkSecretP));
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- goto cleanup;
- }
- GNUNET_CRYPTO_hash_context_read (hash_context,
- rcl,
- sizeof (struct TALER_RefreshCommitLinkP));
- }
- }
- GNUNET_CRYPTO_hash_context_finish (hash_context,
- &session_hash);
- hash_context = NULL;
- for (i=0;i<coin_count;i++)
- {
- /* verify signatures on coins to melt */
- res = verify_coin_public_info (connection,
- &session_hash,
- &coin_melt_details[i]);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- goto cleanup;
- }
- }
-
- /* execute commit */
- res = handle_refresh_melt_binary (connection,
- num_new_denoms,
- denom_pubs,
- coin_count,
- coin_melt_details,
- &session_hash,
- commit_coin,
- commit_link);
- cleanup:
- free_commit_coins (commit_coin,
- TALER_CNC_KAPPA,
- num_newcoins);
- free_commit_links (commit_link,
- TALER_CNC_KAPPA,
- num_oldcoins);
- cleanup_melt_details:
- for (j=0;j<coin_count;j++)
- {
- if (NULL != coin_melt_details[j].coin_info.denom_pub.rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key);
- if (NULL != coin_melt_details[j].coin_info.denom_sig.rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature);
- }
- GNUNET_free (coin_melt_details);
- cleanup_denoms:
- for (j=0;j<num_new_denoms;j++)
- if (NULL != denom_pubs[j].rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
- GNUNET_free (denom_pubs);
- if (NULL != hash_context)
- GNUNET_CRYPTO_hash_context_abort (hash_context);
- return res;
-}
-
-
-/**
- * Handle a "/refresh/melt" request. Parses the request into the JSON
- * components and then hands things of to #handle_refresh_melt_json()
- * to validate the melted coins, the signature and execute the melt
- * using TMH_DB_execute_refresh_melt().
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *root;
- json_t *new_denoms;
- json_t *melt_coins;
- json_t *coin_evs;
- json_t *link_encs;
- json_t *transfer_pubs;
- json_t *secret_encs;
- unsigned int num_oldcoins;
- unsigned int num_newcoins;
- json_t *coin_detail;
- int res;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_array ("new_denoms", &new_denoms),
- TMH_PARSE_member_array ("melt_coins", &melt_coins),
- TMH_PARSE_member_array ("coin_evs", &coin_evs),
- TMH_PARSE_member_array ("link_encs", &link_encs),
- TMH_PARSE_member_array ("transfer_pubs", &transfer_pubs),
- TMH_PARSE_member_array ("secret_encs", &secret_encs),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == root) )
- return MHD_YES;
-
- res = TMH_PARSE_json_data (connection,
- root,
- spec);
- json_decref (root);
- if (GNUNET_OK != res)
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
-
- /* Determine dimensionality of the request (kappa, #old and #new coins) */
- if (TALER_CNC_KAPPA != json_array_size (coin_evs))
- {
- GNUNET_break_op (0);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "coin_evs");
- }
- if (TALER_CNC_KAPPA != json_array_size (transfer_pubs))
- {
- GNUNET_break_op (0);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "transfer_pubs");
- }
- res = TMH_PARSE_navigate_json (connection,
- coin_evs,
- TMH_PARSE_JNC_INDEX, (int) 0,
- TMH_PARSE_JNC_RET_TYPED_JSON,
- JSON_ARRAY, &coin_detail);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- TMH_PARSE_release_data (spec);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- num_newcoins = json_array_size (coin_detail);
- json_decref (coin_detail);
- res = TMH_PARSE_navigate_json (connection,
- transfer_pubs,
- TMH_PARSE_JNC_INDEX, (int) 0,
- TMH_PARSE_JNC_RET_TYPED_JSON,
- JSON_ARRAY, &coin_detail);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- TMH_PARSE_release_data (spec);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- num_oldcoins = json_array_size (coin_detail);
- json_decref (coin_detail);
- res = handle_refresh_melt_json (connection,
- new_denoms,
- melt_coins,
- num_oldcoins,
- transfer_pubs,
- secret_encs,
- num_newcoins,
- coin_evs,
- link_encs);
- TMH_PARSE_release_data (spec);
- return res;
-}
-
-
-/**
- * Handle a "/refresh/reveal" request. Parses the given JSON
- * transfer private keys and if successful, passes everything to
- * #TMH_DB_execute_refresh_reveal() which will verify that the
- * revealed information is valid then returns the signed refreshed
- * coins.
- *
- * @param connection the MHD connection to handle
- * @param session_hash hash identifying the melting session
- * @param num_oldcoins length of the 2nd dimension of @a transfer_privs array
- * @param tp_json private transfer keys in JSON format
- * @return MHD result code
- */
-static int
-handle_refresh_reveal_json (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- unsigned int num_oldcoins,
- const json_t *tp_json)
-{
- struct TALER_TransferPrivateKeyP *transfer_privs[TALER_CNC_KAPPA - 1];
- unsigned int i;
- unsigned int j;
- int res;
-
- for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
- transfer_privs[i] = GNUNET_malloc (num_oldcoins *
- sizeof (struct TALER_TransferPrivateKeyP));
- res = GNUNET_OK;
- for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
- {
- if (GNUNET_OK != res)
- break;
- for (j = 0; j < num_oldcoins; j++)
- {
- if (GNUNET_OK != res)
- break;
- res = TMH_PARSE_navigate_json (connection,
- tp_json,
- TMH_PARSE_JNC_INDEX, (int) i,
- TMH_PARSE_JNC_INDEX, (int) j,
- TMH_PARSE_JNC_RET_DATA,
- &transfer_privs[i][j],
- sizeof (struct TALER_TransferPrivateKeyP));
- GNUNET_break_op (GNUNET_OK == res);
- }
- }
- if (GNUNET_OK != res)
- res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- else
- res = TMH_DB_execute_refresh_reveal (connection,
- session_hash,
- num_oldcoins,
- transfer_privs);
- for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
- GNUNET_free (transfer_privs[i]);
- return res;
-}
-
-
-/**
- * Handle a "/refresh/reveal" request. This time, the client reveals
- * the private transfer keys except for the cut-and-choose value
- * returned from "/refresh/melt". This function parses the revealed
- * keys and secrets and ultimately passes everything to
- * #TMH_DB_execute_refresh_reveal() which will verify that the
- * revealed information is valid then returns the signed refreshed
- * coins.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct GNUNET_HashCode session_hash;
- int res;
- unsigned int num_oldcoins;
- json_t *reveal_detail;
- json_t *root;
- json_t *transfer_privs;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("session_hash", &session_hash),
- TMH_PARSE_member_array ("transfer_privs", &transfer_privs),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == root) )
- return MHD_YES;
-
- res = TMH_PARSE_json_data (connection,
- root,
- spec);
- json_decref (root);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- /* Determine dimensionality of the request (kappa and #old coins) */
- /* Note we do +1 as 1 row (cut-and-choose!) is missing! */
- if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1)
- {
- TMH_PARSE_release_data (spec);
- GNUNET_break_op (0);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "transfer_privs");
- }
- res = TMH_PARSE_navigate_json (connection,
- transfer_privs,
- TMH_PARSE_JNC_INDEX, 0,
- TMH_PARSE_JNC_RET_TYPED_JSON,
- JSON_ARRAY,
- &reveal_detail);
- if (GNUNET_OK != res)
- {
- TMH_PARSE_release_data (spec);
- GNUNET_break_op (0);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- }
- num_oldcoins = json_array_size (reveal_detail);
- json_decref (reveal_detail);
- res = handle_refresh_reveal_json (connection,
- &session_hash,
- num_oldcoins,
- transfer_privs);
- TMH_PARSE_release_data (spec);
- return res;
-}
-
-
-/**
- * Handle a "/refresh/link" request. Note that for "/refresh/link"
- * we do use a simple HTTP GET, and a HTTP POST!
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct TALER_CoinSpendPublicKeyP coin_pub;
- int res;
-
- res = TMH_PARSE_mhd_request_arg_data (connection,
- "coin_pub",
- &coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP));
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if (GNUNET_OK != res)
- return MHD_YES;
- return TMH_DB_execute_refresh_link (connection,
- &coin_pub);
-}
-
-
-/* end of taler-mint-httpd_refresh.c */
diff --git a/src/mint/taler-mint-httpd_refresh.h b/src/mint/taler-mint-httpd_refresh.h
deleted file mode 100644
index 8fe12a272..000000000
--- a/src/mint/taler-mint-httpd_refresh.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_refresh.h
- * @brief Handle /refresh/ requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_REFRESH_H
-#define TALER_MINT_HTTPD_REFRESH_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Handle a "/refresh/melt" request. Parses the request into the JSON
- * components and then hands things of to #handle_refresh_melt_json()
- * to validate the melted coins, the signature and execute the melt
- * using TMH_DB_execute_refresh_melt().
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/refresh/reveal" request. This time, the client reveals
- * the private transfer keys except for the cut-and-choose value
- * returned from "/refresh/commit". This function parses the revealed
- * keys and secrets and ultimately passes everything to
- * #TMH_DB_execute_refresh_reveal() which will verify that the
- * revealed information is valid then returns the signed refreshed
- * coins.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/refresh/link" request
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_reserve.c b/src/mint/taler-mint-httpd_reserve.c
deleted file mode 100644
index c887ee750..000000000
--- a/src/mint/taler-mint-httpd_reserve.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014,2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_reserve.c
- * @brief Handle /reserve/ requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include "taler-mint-httpd_reserve.h"
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_keystate.h"
-
-
-/**
- * Handle a "/reserve/status" request. Parses the
- * given "reserve_pub" argument (which should contain the
- * EdDSA public key of a reserve) and then respond with the
- * status of the reserve.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct TALER_ReservePublicKeyP reserve_pub;
- int res;
-
- res = TMH_PARSE_mhd_request_arg_data (connection,
- "reserve_pub",
- &reserve_pub,
- sizeof (struct TALER_ReservePublicKeyP));
- if (GNUNET_SYSERR == res)
- return MHD_NO; /* internal error */
- if (GNUNET_NO == res)
- return MHD_YES; /* parse error */
- return TMH_DB_execute_reserve_status (connection,
- &reserve_pub);
-}
-
-
-/**
- * Handle a "/reserve/withdraw" request. Parses the "reserve_pub"
- * EdDSA key of the reserve and the requested "denom_pub" which
- * specifies the key/value of the coin to be withdrawn, and checks
- * that the signature "reserve_sig" makes this a valid withdrawl
- * request from the specified reserve. If so, the envelope
- * with the blinded coin "coin_ev" is passed down to execute the
- * withdrawl operation.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *root;
- struct TALER_WithdrawRequestPS wsrd;
- int res;
- struct TALER_DenominationPublicKey denomination_pub;
- char *blinded_msg;
- size_t blinded_msg_len;
- struct TALER_Amount amount;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount fee_withdraw;
- struct TALER_ReserveSignatureP signature;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TMH_KS_StateHandle *ks;
-
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_variable ("coin_ev",
- (void **) &blinded_msg,
- &blinded_msg_len),
- TMH_PARSE_member_fixed ("reserve_pub",
- &wsrd.reserve_pub),
- TMH_PARSE_member_fixed ("reserve_sig",
- &signature),
- TMH_PARSE_member_denomination_public_key ("denom_pub",
- &denomination_pub),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == root) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- root,
- spec);
- json_decref (root);
- if (GNUNET_OK != res)
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
- ks = TMH_KS_acquire ();
- dki = TMH_KS_denomination_key_lookup (ks,
- &denomination_pub,
- TMH_KS_DKU_WITHDRAW);
- if (NULL == dki)
- {
- TMH_PARSE_release_data (spec);
- TMH_KS_release (ks);
- return TMH_RESPONSE_reply_arg_unknown (connection,
- "denom_pub");
- }
- TALER_amount_ntoh (&amount,
- &dki->issue.properties.value);
- TALER_amount_ntoh (&fee_withdraw,
- &dki->issue.properties.fee_withdraw);
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_add (&amount_with_fee,
- &amount,
- &fee_withdraw));
- TALER_amount_hton (&wsrd.amount_with_fee,
- &amount_with_fee);
- TALER_amount_hton (&wsrd.withdraw_fee,
- &fee_withdraw);
- TMH_KS_release (ks);
- /* verify signature! */
- wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
- wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
-
- GNUNET_CRYPTO_rsa_public_key_hash (denomination_pub.rsa_public_key,
- &wsrd.h_denomination_pub);
- GNUNET_CRYPTO_hash (blinded_msg,
- blinded_msg_len,
- &wsrd.h_coin_envelope);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
- &wsrd.purpose,
- &signature.eddsa_signature,
- &wsrd.reserve_pub.eddsa_pub))
- {
- TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n");
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_signature_invalid (connection,
- "reserve_sig");
- }
- res = TMH_DB_execute_reserve_withdraw (connection,
- &wsrd.reserve_pub,
- &denomination_pub,
- blinded_msg,
- blinded_msg_len,
- &signature);
- TMH_PARSE_release_data (spec);
- return res;
-}
-
-/* end of taler-mint-httpd_reserve.c */
diff --git a/src/mint/taler-mint-httpd_reserve.h b/src/mint/taler-mint-httpd_reserve.h
deleted file mode 100644
index 71a779fe3..000000000
--- a/src/mint/taler-mint-httpd_reserve.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_reserve.h
- * @brief Handle /reserve/ requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_RESERVE_H
-#define TALER_MINT_HTTPD_RESERVE_H
-
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-/**
- * Handle a "/reserve/status" request. Parses the
- * given "reserve_pub" argument (which should contain the
- * EdDSA public key of a reserve) and then respond with the
- * status of the reserve.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/reserve/withdraw" request. Parses the "reserve_pub"
- * EdDSA key of the reserve and the requested "denom_pub" which
- * specifies the key/value of the coin to be withdrawn, and checks
- * that the signature "reserve_sig" makes this a valid withdrawl
- * request from the specified reserve. If so, the envelope
- * with the blinded coin "coin_ev" is passed down to execute the
- * withdrawl operation.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-#endif
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
deleted file mode 100644
index 2ebd0d331..000000000
--- a/src/mint/taler-mint-httpd_responses.c
+++ /dev/null
@@ -1,1177 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_responses.c
- * @brief API for generating the various replies of the mint; these
- * functions are called TMH_RESPONSE_reply_ and they generate
- * and queue MHD response objects for a given connection.
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler_util.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler-mint-httpd_keystate.h"
-
-
-/**
- * Add headers we want to return in every response.
- * Useful for testing, like if we want to always close
- * connections.
- *
- * @param response response to modify
- */
-void
-TMH_RESPONSE_add_global_headers (struct MHD_Response *response)
-{
- if (TMH_mint_connection_close)
- (void) MHD_add_response_header (response,
- MHD_HTTP_HEADER_CONNECTION,
- "close");
-}
-
-
-/**
- * Send JSON object as response.
- *
- * @param connection the MHD connection
- * @param json the json object
- * @param response_code the http response code
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
- const json_t *json,
- unsigned int response_code)
-{
- struct MHD_Response *resp;
- char *json_str;
- int ret;
-
- json_str = json_dumps (json, JSON_INDENT(2));
- GNUNET_assert (NULL != json_str);
- resp = MHD_create_response_from_buffer (strlen (json_str), json_str,
- MHD_RESPMEM_MUST_FREE);
- if (NULL == resp)
- {
- free (json_str);
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (resp);
- (void) MHD_add_response_header (resp,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "application/json");
- ret = MHD_queue_response (connection,
- response_code,
- resp);
- MHD_destroy_response (resp);
- return ret;
-}
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply from a format string and varargs.
- *
- * @param connection the MHD connection to handle
- * @param response_code HTTP response code to use
- * @param fmt format string for pack
- * @param ... varargs
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
- unsigned int response_code,
- const char *fmt,
- ...)
-{
- json_t *json;
- va_list argp;
- int ret;
- json_error_t jerror;
-
- va_start (argp, fmt);
- json = json_vpack_ex (&jerror, 0, fmt, argp);
- va_end (argp);
- if (NULL == json)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to pack JSON with format `%s': %s\n",
- fmt,
- jerror.text);
- GNUNET_break (0);
- return MHD_NO;
- }
- ret = TMH_RESPONSE_reply_json (connection,
- json,
- response_code);
- json_decref (json);
- return ret;
-}
-
-
-/**
- * Send a response indicating an invalid argument.
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is invalid
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
- const char *param_name)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s}",
- "error", "invalid parameter",
- "parameter", param_name);
-}
-
-
-/**
- * Send a response indicating an argument refering to a
- * resource unknown to the mint (i.e. unknown reserve or
- * denomination key).
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is invalid
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
- const char *param_name)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s, s:s}",
- "error", "unknown entity referenced",
- "parameter", param_name);
-}
-
-
-/**
- * Send a response indicating an invalid signature.
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is invalid
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
- const char *param_name)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_UNAUTHORIZED,
- "{s:s, s:s}",
- "error", "invalid signature",
- "parameter", param_name);
-}
-
-
-/**
- * Send a response indicating a missing argument.
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is missing
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
- const char *param_name)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{ s:s, s:s}",
- "error", "missing parameter",
- "parameter", param_name);
-}
-
-
-/**
- * Send a response indicating permission denied.
- *
- * @param connection the MHD connection to use
- * @param hint hint about why access was denied
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
- const char *hint)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_FORBIDDEN,
- "{s:s, s:s}",
- "error", "permission denied",
- "hint", hint);
-}
-
-
-/**
- * Send a response indicating an internal error.
- *
- * @param connection the MHD connection to use
- * @param hint hint about the internal error's nature
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
- const char *hint)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- "{s:s, s:s}",
- "error", "internal error",
- "hint", hint);
-}
-
-
-/**
- * Send a response indicating an external error.
- *
- * @param connection the MHD connection to use
- * @param hint hint about the error's nature
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
- const char *hint)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:s}",
- "error", "client error",
- "hint", hint);
-}
-
-
-/**
- * Send a response indicating an error committing a
- * transaction (concurrent interference).
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error", "commit failure");
-}
-
-
-/**
- * Send a response indicating a failure to talk to the Mint's
- * database.
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection)
-{
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to connect to database");
-}
-
-
-/**
- * Send a response indicating that the request was too big.
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection)
-{
- struct MHD_Response *resp;
- int ret;
-
- resp = MHD_create_response_from_buffer (0,
- NULL,
- MHD_RESPMEM_PERSISTENT);
- if (NULL == resp)
- return MHD_NO;
- TMH_RESPONSE_add_global_headers (resp);
- ret = MHD_queue_response (connection,
- MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
- resp);
- MHD_destroy_response (resp);
- return ret;
-}
-
-
-/**
- * Send a response indicating that the JSON was malformed.
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error",
- "invalid json");
-}
-
-
-/**
- * Send confirmation of deposit success to client. This function
- * will create a signed message affirming the given information
- * and return it to the client. By this, the mint affirms that
- * the coin had sufficient (residual) value for the specified
- * transaction and that it will execute the requested deposit
- * operation with the given wiring details.
- *
- * @param connection connection to the client
- * @param coin_pub public key of the coin
- * @param h_wire hash of wire details
- * @param h_contract hash of contract details
- * @param transaction_id transaction ID
- * @param timestamp client's timestamp
- * @param refund_deadline until when this deposit be refunded
- * @param merchant merchant public key
- * @param amount_without_fee fraction of coin value to deposit, without the fee
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- struct GNUNET_TIME_Absolute timestamp,
- struct GNUNET_TIME_Absolute refund_deadline,
- const struct TALER_MerchantPublicKeyP *merchant,
- const struct TALER_Amount *amount_without_fee)
-{
- struct TALER_DepositConfirmationPS dc;
- struct TALER_MintPublicKeyP pub;
- struct TALER_MintSignatureP sig;
-
- dc.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT);
- dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
- dc.h_contract = *h_contract;
- dc.h_wire = *h_wire;
- dc.transaction_id = GNUNET_htonll (transaction_id);
- dc.timestamp = GNUNET_TIME_absolute_hton (timestamp);
- dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
- TALER_amount_hton (&dc.amount_without_fee,
- amount_without_fee);
- dc.coin_pub = *coin_pub;
- dc.merchant = *merchant;
- TMH_KS_sign (&dc.purpose,
- &pub,
- &sig);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:s, s:o, s:o}",
- "status", "DEPOSIT_OK",
- "sig", TALER_json_from_data (&sig,
- sizeof (sig)),
- "pub", TALER_json_from_data (&pub,
- sizeof (pub)));
-}
-
-
-/**
- * Compile the transaction history of a coin into a JSON object.
- *
- * @param tl transaction history to JSON-ify
- * @return json representation of the @a rh
- */
-static json_t *
-compile_transaction_history (const struct TALER_MINTDB_TransactionList *tl)
-{
- json_t *details;
- const char *type;
- struct TALER_Amount value;
- json_t *history;
- const struct TALER_CoinSpendSignatureP *sig;
- const struct TALER_MINTDB_TransactionList *pos;
-
- history = json_array ();
- for (pos = tl; NULL != pos; pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_MINTDB_TT_DEPOSIT:
- {
- struct TALER_DepositRequestPS dr;
- const struct TALER_MINTDB_Deposit *deposit = pos->details.deposit;
-
- type = "DEPOSIT";
- value = deposit->amount_with_fee;
- dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
- dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
- dr.h_contract = deposit->h_contract;
- dr.h_wire = deposit->h_wire;
- dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp);
- dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline);
- dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
- TALER_amount_hton (&dr.amount_with_fee,
- &deposit->amount_with_fee);
- TALER_amount_hton (&dr.deposit_fee,
- &deposit->deposit_fee);
- dr.merchant = deposit->merchant_pub;
- dr.coin_pub = deposit->coin.coin_pub;
- sig = &deposit->csig;
- /* internal sanity check before we hand out a bogus sig... */
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
- &dr.purpose,
- &sig->eddsa_signature,
- &deposit->coin.coin_pub.eddsa_pub))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
-
- details = TALER_json_from_data (&dr.purpose,
- sizeof (struct TALER_DepositRequestPS));
- break;
- }
- case TALER_MINTDB_TT_REFRESH_MELT:
- {
- struct TALER_RefreshMeltCoinAffirmationPS ms;
- const struct TALER_MINTDB_RefreshMelt *melt = pos->details.melt;
-
- type = "MELT";
- value = melt->amount_with_fee;
- ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
- ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
- ms.session_hash = melt->session_hash;
- TALER_amount_hton (&ms.amount_with_fee,
- &melt->amount_with_fee);
- TALER_amount_hton (&ms.melt_fee,
- &melt->melt_fee);
- ms.coin_pub = melt->coin.coin_pub;
- sig = &melt->coin_sig;
- /* internal sanity check before we hand out a bogus sig... */
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
- &ms.purpose,
- &sig->eddsa_signature,
- &melt->coin.coin_pub.eddsa_pub))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
-
- details = TALER_json_from_data (&ms.purpose,
- sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
- }
- break;
- default:
- GNUNET_assert (0);
- }
- json_array_append_new (history,
- json_pack ("{s:s, s:o, s:o, s:o}",
- "type", type,
- "amount", TALER_json_from_amount (&value),
- "signature", TALER_json_from_data (sig,
- sizeof (struct TALER_CoinSpendSignatureP)),
- "details", details));
- }
- return history;
-}
-
-
-/**
- * Send proof that a /deposit request is invalid to client. This
- * function will create a message with all of the operations affecting
- * the coin that demonstrate that the coin has insufficient value.
- *
- * @param connection connection to the client
- * @param tl transaction list to use to build reply
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_MINTDB_TransactionList *tl)
-{
- json_t *history;
-
- history = compile_transaction_history (tl);
- if (NULL == history)
- return TMH_RESPONSE_reply_internal_db_error (connection);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_FORBIDDEN,
- "{s:s, s:o}",
- "error", "insufficient funds",
- "history", history);
-}
-
-
-/**
- * Compile the history of a reserve into a JSON object
- * and calculate the total balance.
- *
- * @param rh reserve history to JSON-ify
- * @param[out] balance set to current reserve balance
- * @return json representation of the @a rh, NULL on error
- */
-static json_t *
-compile_reserve_history (const struct TALER_MINTDB_ReserveHistory *rh,
- struct TALER_Amount *balance)
-{
- struct TALER_Amount deposit_total;
- struct TALER_Amount withdraw_total;
- struct TALER_Amount value;
- json_t *json_history;
- int ret;
- const struct TALER_MINTDB_ReserveHistory *pos;
- struct TALER_WithdrawRequestPS wr;
-
- json_history = json_array ();
- ret = 0;
- for (pos = rh; NULL != pos; pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_MINTDB_RO_BANK_TO_MINT:
- if (0 == ret)
- deposit_total = pos->details.bank->amount;
- else
- if (GNUNET_OK !=
- TALER_amount_add (&deposit_total,
- &deposit_total,
- &pos->details.bank->amount))
- {
- json_decref (json_history);
- return NULL;
- }
- ret = 1;
- json_array_append_new (json_history,
- json_pack ("{s:s, s:O, s:o}",
- "type", "DEPOSIT",
- "wire", pos->details.bank->wire,
- "amount", TALER_json_from_amount (&pos->details.bank->amount)));
- break;
- case TALER_MINTDB_RO_WITHDRAW_COIN:
- break;
- }
- }
-
- ret = 0;
- for (pos = rh; NULL != pos; pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_MINTDB_RO_BANK_TO_MINT:
- break;
- case TALER_MINTDB_RO_WITHDRAW_COIN:
- value = pos->details.withdraw->amount_with_fee;
- if (0 == ret)
- {
- withdraw_total = value;
- }
- else
- {
- if (GNUNET_OK !=
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- json_decref (json_history);
- return NULL;
- }
- }
- ret = 1;
- wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
- wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
- wr.reserve_pub = pos->details.withdraw->reserve_pub;
- TALER_amount_hton (&wr.amount_with_fee,
- &value);
- TALER_amount_hton (&wr.withdraw_fee,
- &pos->details.withdraw->withdraw_fee);
- GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key,
- &wr.h_denomination_pub);
- wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope;
- json_array_append_new (json_history,
- json_pack ("{s:s, s:o, s:o, s:o}",
- "type", "WITHDRAW",
- "signature", TALER_json_from_data (&pos->details.withdraw->reserve_sig,
- sizeof (struct TALER_ReserveSignatureP)),
- "details", TALER_json_from_data (&wr,
- sizeof (wr)),
- "amount", TALER_json_from_amount (&value)));
- break;
- }
- }
- if (0 == ret)
- {
- /* did not encounter any withdraw operations, set to zero */
- TALER_amount_get_zero (deposit_total.currency,
- &withdraw_total);
- }
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (balance,
- &deposit_total,
- &withdraw_total))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
-
- return json_history;
-}
-
-
-/**
- * Send reserve status information to client.
- *
- * @param connection connection to the client
- * @param rh reserve history to return
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection,
- const struct TALER_MINTDB_ReserveHistory *rh)
-{
- json_t *json_balance;
- json_t *json_history;
- struct TALER_Amount balance;
-
- json_history = compile_reserve_history (rh,
- &balance);
- if (NULL == json_history)
- return TMH_RESPONSE_reply_internal_error (connection,
- "balance calculation failure");
- json_balance = TALER_json_from_amount (&balance);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o, s:o}",
- "balance", json_balance,
- "history", json_history);
-}
-
-
-/**
- * Send reserve status information to client with the
- * message that we have insufficient funds for the
- * requested /reserve/withdraw operation.
- *
- * @param connection connection to the client
- * @param rh reserve history to return
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_MINTDB_ReserveHistory *rh)
-{
- json_t *json_balance;
- json_t *json_history;
- struct TALER_Amount balance;
-
- json_history = compile_reserve_history (rh,
- &balance);
- if (NULL == json_history)
- return TMH_RESPONSE_reply_internal_error (connection,
- "balance calculation failure");
- json_balance = TALER_json_from_amount (&balance);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_PAYMENT_REQUIRED,
- "{s:s, s:o, s:o}",
- "error", "Insufficient funds",
- "balance", json_balance,
- "history", json_history);
-}
-
-
-/**
- * Send blinded coin information to client.
- *
- * @param connection connection to the client
- * @param collectable blinded coin to return
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection,
- const struct TALER_MINTDB_CollectableBlindcoin *collectable)
-{
- json_t *sig_json;
-
- sig_json = TALER_json_from_rsa_signature (collectable->sig.rsa_signature);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "ev_sig", sig_json);
-}
-
-
-/**
- * Send a response for a failed "/refresh/melt" request. The
- * transaction history of the given coin demonstrates that the
- * @a residual value of the coin is below the @a requested
- * contribution of the coin for the melt. Thus, the mint
- * refuses the melt operation.
- *
- * @param connection the connection to send the response to
- * @param coin_pub public key of the coin
- * @param coin_value original value of the coin
- * @param tl transaction history for the coin
- * @param requested how much this coin was supposed to contribute, including fee
- * @param residual remaining value of the coin (after subtracting @a tl)
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- struct TALER_Amount coin_value,
- struct TALER_MINTDB_TransactionList *tl,
- struct TALER_Amount requested,
- struct TALER_Amount residual)
-{
- json_t *history;
-
- history = compile_transaction_history (tl);
- if (NULL == history)
- return TMH_RESPONSE_reply_internal_db_error (connection);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_FORBIDDEN,
- "{s:s, s:o, s:o, s:o, s:o, s:o}",
- "error",
- "insufficient funds",
- "coin_pub",
- TALER_json_from_data (coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP)),
- "original_value",
- TALER_json_from_amount (&coin_value),
- "residual_value",
- TALER_json_from_amount (&residual),
- "requested_value",
- TALER_json_from_amount (&requested),
- "history",
- history);
-}
-
-
-/**
- * Send a response to a "/refresh/melt" request.
- *
- * @param connection the connection to send the response to
- * @param session_hash hash of the refresh session
- * @param noreveal_index which index will the client not have to reveal
- * @return a MHD status code
- */
-int
-TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- uint16_t noreveal_index)
-{
- struct TALER_RefreshMeltConfirmationPS body;
- struct TALER_MintPublicKeyP pub;
- struct TALER_MintSignatureP sig;
- json_t *sig_json;
-
- body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
- body.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_MELT);
- body.session_hash = *session_hash;
- body.noreveal_index = htons (noreveal_index);
- body.reserved = htons (0);
- TMH_KS_sign (&body.purpose,
- &pub,
- &sig);
- sig_json = TALER_json_from_data (&sig,
- sizeof (sig));
- GNUNET_assert (NULL != sig_json);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:i, s:o, s:o}",
- "noreveal_index", (int) noreveal_index,
- "mint_sig", sig_json,
- "mint_pub", TALER_json_from_data (&pub,
- sizeof (pub)));
-}
-
-
-/**
- * Send a response for "/refresh/reveal".
- *
- * @param connection the connection to send the response to
- * @param num_newcoins number of new coins for which we reveal data
- * @param sigs array of @a num_newcoins signatures revealed
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection,
- unsigned int num_newcoins,
- const struct TALER_DenominationSignature *sigs)
-{
- int newcoin_index;
- json_t *root;
- json_t *obj;
- json_t *list;
- int ret;
-
- list = json_array ();
- for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++)
- {
- obj = json_object ();
- json_object_set_new (obj,
- "ev_sig",
- TALER_json_from_rsa_signature (sigs[newcoin_index].rsa_signature));
- json_array_append_new (list,
- obj);
- }
- root = json_object ();
- json_object_set_new (root,
- "ev_sigs",
- list);
- ret = TMH_RESPONSE_reply_json (connection,
- root,
- MHD_HTTP_OK);
- json_decref (root);
- return ret;
-}
-
-
-/**
- * Send a response for a failed "/refresh/reveal", where the
- * revealed value(s) do not match the original commitment.
- *
- * @param connection the connection to send the response to
- * @param mc all information about the original commitment
- * @param off offset in the array of kappa-commitments where
- * the missmatch was detected
- * @param j index of the coin for which the missmatch was
- * detected
- * @param missmatch_object name of the object that was
- * bogus (i.e. "transfer key").
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
- const struct TALER_MINTDB_MeltCommitment *mc,
- unsigned int off,
- unsigned int j,
- const char *missmatch_object)
-{
- json_t *info_old;
- json_t *info_new;
- json_t *info_commit;
- json_t *info_links;
- unsigned int i;
- unsigned int k;
-
- info_old = json_array ();
- for (i=0;i<mc->num_oldcoins;i++)
- {
- const struct TALER_MINTDB_RefreshMelt *rm;
- json_t *rm_json;
-
- rm = &mc->melts[i];
- rm_json = json_object ();
- json_object_set_new (rm_json,
- "coin_sig",
- TALER_json_from_data (&rm->coin_sig,
- sizeof (struct TALER_CoinSpendSignatureP)));
- json_object_set_new (rm_json,
- "coin_pub",
- TALER_json_from_data (&rm->coin.coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP)));
- json_object_set_new (rm_json,
- "melt_amount_with_fee",
- TALER_json_from_amount (&rm->amount_with_fee));
- json_object_set_new (rm_json,
- "melt_fee",
- TALER_json_from_amount (&rm->melt_fee));
- json_array_append_new (info_old,
- rm_json);
- }
- info_new = json_array ();
- for (i=0;i<mc->num_newcoins;i++)
- {
- const struct TALER_DenominationPublicKey *pk;
-
- pk = &mc->denom_pubs[i];
- json_array_append_new (info_new,
- TALER_json_from_rsa_public_key (pk->rsa_public_key));
-
- }
- info_commit = json_array ();
- info_links = json_array ();
- for (k=0;k<TALER_CNC_KAPPA;k++)
- {
- json_t *info_commit_k;
- json_t *info_link_k;
-
- info_commit_k = json_array ();
- for (i=0;i<mc->num_newcoins;i++)
- {
- const struct TALER_MINTDB_RefreshCommitCoin *cc;
- json_t *cc_json;
-
- cc = &mc->commit_coins[k][i];
- cc_json = json_object ();
- json_object_set_new (cc_json,
- "coin_ev",
- TALER_json_from_data (cc->coin_ev,
- cc->coin_ev_size));
- json_object_set_new (cc_json,
- "coin_priv_enc",
- TALER_json_from_data (cc->refresh_link->coin_priv_enc,
- sizeof (struct TALER_CoinSpendPrivateKeyP)));
- json_object_set_new (cc_json,
- "blinding_key_enc",
- TALER_json_from_data (cc->refresh_link->blinding_key_enc,
- cc->refresh_link->blinding_key_enc_size));
-
- json_array_append_new (info_commit_k,
- cc_json);
- }
- json_array_append_new (info_commit,
- info_commit_k);
- info_link_k = json_array ();
- for (i=0;i<mc->num_oldcoins;i++)
- {
- const struct TALER_RefreshCommitLinkP *cl;
- json_t *cl_json;
-
- cl = &mc->commit_links[k][i];
- cl_json = json_object ();
- json_object_set_new (cl_json,
- "transfer_pub",
- TALER_json_from_data (&cl->transfer_pub,
- sizeof (struct TALER_TransferPublicKeyP)));
- json_object_set_new (cl_json,
- "shared_secret_enc",
- TALER_json_from_data (&cl->shared_secret_enc,
- sizeof (struct TALER_EncryptedLinkSecretP)));
- json_array_append_new (info_link_k,
- cl_json);
- }
- json_array_append_new (info_links,
- info_link_k);
- }
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_CONFLICT,
- "{s:s, s:i, s:i, s:o, s:o, s:o, s:o, s:s}",
- "error", "commitment violation",
- "offset", (int) off,
- "index", (int) j,
- "oldcoin_infos", info_old,
- "newcoin_infos", info_new,
- "commit_infos", info_commit,
- "link_infos", info_links,
- "object", missmatch_object);
-}
-
-
-/**
- * Send a response for "/refresh/link".
- *
- * @param connection the connection to send the response to
- * @param num_sessions number of sessions the coin was used in
- * @param sessions array of @a num_session entries with
- * information for each session
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
- unsigned int num_sessions,
- const struct TMH_RESPONSE_LinkSessionInfo *sessions)
-{
- json_t *root;
- json_t *mlist;
- int res;
- unsigned int i;
-
- mlist = json_array ();
- for (i=0;i<num_sessions;i++)
- {
- const struct TALER_MINTDB_LinkDataList *pos;
- json_t *list = json_array ();
-
- for (pos = sessions[i].ldl; NULL != pos; pos = pos->next)
- {
- json_t *obj;
-
- obj = json_object ();
- json_object_set_new (obj,
- "link_enc",
- TALER_json_from_data (pos->link_data_enc->coin_priv_enc,
- sizeof (struct TALER_CoinSpendPrivateKeyP) +
- pos->link_data_enc->blinding_key_enc_size));
- json_object_set_new (obj,
- "denom_pub",
- TALER_json_from_rsa_public_key (pos->denom_pub.rsa_public_key));
- json_object_set_new (obj,
- "ev_sig",
- TALER_json_from_rsa_signature (pos->ev_sig.rsa_signature));
- json_array_append_new (list,
- obj);
- }
- root = json_object ();
- json_object_set_new (root,
- "new_coins",
- list);
- json_object_set_new (root,
- "transfer_pub",
- TALER_json_from_data (&sessions[i].transfer_pub,
- sizeof (struct TALER_TransferPublicKeyP)));
- json_object_set_new (root,
- "secret_enc",
- TALER_json_from_data (&sessions[i].shared_secret_enc,
- sizeof (struct TALER_EncryptedLinkSecretP)));
- json_array_append_new (mlist,
- root);
- }
- res = TMH_RESPONSE_reply_json (connection,
- mlist,
- MHD_HTTP_OK);
- json_decref (mlist);
- return res;
-}
-
-
-/**
- * A merchant asked for details about a deposit, but
- * we do not know anything about the deposit. Generate the
- * 404 reply.
- *
- * @param connection connection to the client
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error", "Deposit unknown");
-}
-
-
-/**
- * A merchant asked for details about a deposit, but
- * we did not execute the deposit yet. Generate a 202 reply.
- *
- * @param connection connection to the client
- * @param planned_exec_time planned execution time
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
- struct GNUNET_TIME_Absolute planned_exec_time)
-{
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_ACCEPTED,
- "{s:o}",
- "execution_time", TALER_json_from_abs (planned_exec_time));
-}
-
-
-/**
- * A merchant asked for details about a deposit. Provide
- * them. Generates the 200 reply.
- *
- * @param connection connection to the client
- * @param h_contract hash of the contract
- * @param h_wire hash of wire account details
- * @param coin_pub public key of the coin
- * @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value minus fee)
- * @param transaction_id merchant transaction identifier
- * @param wtid raw wire transfer identifier
- * @param exec_time execution time of the wire transfer
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *h_contract,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_contribution,
- uint64_t transaction_id,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct GNUNET_TIME_Absolute exec_time)
-{
- struct TALER_ConfirmWirePS cw;
- struct TALER_MintPublicKeyP pub;
- struct TALER_MintSignatureP sig;
-
- cw.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
- cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
- cw.h_wire = *h_wire;
- cw.h_contract = *h_contract;
- cw.wtid = *wtid;
- cw.coin_pub = *coin_pub;
- cw.transaction_id = GNUNET_htonll (transaction_id);
- cw.execution_time = GNUNET_TIME_absolute_hton (exec_time);
- TALER_amount_hton (&cw.coin_contribution,
- coin_contribution);
- TMH_KS_sign (&cw.purpose,
- &pub,
- &sig);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o, s:o, s:o, s:o, s:o, s:o}",
- "wtid", TALER_json_from_data (wtid,
- sizeof (*wtid)),
- "execution_time", TALER_json_from_abs (exec_time),
- "coin_contribution", TALER_json_from_amount (coin_contribution),
- "mint_sig", TALER_json_from_data (&sig,
- sizeof (sig)),
- "mint_pub", TALER_json_from_data (&pub,
- sizeof (pub)));
-}
-
-
-/**
- * A merchant asked for transaction details about a wire transfer.
- * Provide them. Generates the 200 reply.
- *
- * @param connection connection to the client
- * @param total total amount that was transferred
- * @param merchant_pub public key of the merchant
- * @param h_wire destination account
- * @param deposits details about the combined deposits
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
- const struct TALER_Amount *total,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- json_t *deposits)
-{
- /* FIXME: #4135: signing not implemented here */
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o, s:o, s:o, s:o}",
- "total", TALER_json_from_amount (total),
- "merchant_pub", TALER_json_from_data (merchant_pub,
- sizeof (struct TALER_MerchantPublicKeyP)),
- "h_wire", TALER_json_from_data (h_wire,
- sizeof (struct GNUNET_HashCode)),
- "deposits", deposits);
-}
-
-
-/* end of taler-mint-httpd_responses.c */
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
deleted file mode 100644
index a0396c8a1..000000000
--- a/src/mint/taler-mint-httpd_responses.h
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd_responses.h
- * @brief API for generating the various replies of the mint; these
- * functions are called TMH_RESPONSE_reply_ and they generate
- * and queue MHD response objects for a given connection.
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_RESPONSES_H
-#define TALER_MINT_HTTPD_RESPONSES_H
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include <pthread.h>
-#include "taler-mint-httpd.h"
-#include "taler-mint-httpd_db.h"
-
-/**
- * Add headers we want to return in every response.
- * Useful for testing, like if we want to always close
- * connections.
- *
- * @param response response to modify
- */
-void
-TMH_RESPONSE_add_global_headers (struct MHD_Response *response);
-
-
-/**
- * Send JSON object as response.
- *
- * @param connection the MHD connection
- * @param json the json object
- * @param response_code the http response code
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
- const json_t *json,
- unsigned int response_code);
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply from a format string and varargs.
- *
- * @param connection the MHD connection to handle
- * @param response_code HTTP response code to use
- * @param fmt format string for pack
- * @param ... varargs
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
- unsigned int response_code,
- const char *fmt,
- ...);
-
-
-/**
- * Send a response indicating an invalid signature.
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is invalid
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection,
- const char *param_name);
-
-
-/**
- * Send a response indicating an invalid argument.
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is invalid
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
- const char *param_name);
-
-
-/**
- * Send a response indicating an argument refering to a
- * resource unknown to the mint (i.e. unknown reserve or
- * denomination key).
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is invalid
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection,
- const char *param_name);
-
-
-/**
- * Send a response indicating a missing argument.
- *
- * @param connection the MHD connection to use
- * @param param_name the parameter that is missing
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
- const char *param_name);
-
-
-/**
- * Send a response indicating permission denied.
- *
- * @param connection the MHD connection to use
- * @param hint hint about why access was denied
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection,
- const char *hint);
-
-
-/**
- * Send a response indicating an internal error.
- *
- * @param connection the MHD connection to use
- * @param hint hint about the internal error's nature
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
- const char *hint);
-
-
-/**
- * Send a response indicating an external error.
- *
- * @param connection the MHD connection to use
- * @param hint hint about the error's nature
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
- const char *hint);
-
-
-/**
- * Send a response indicating an error committing a
- * transaction (concurrent interference).
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection);
-
-
-/**
- * Send a response indicating a failure to talk to the Mint's
- * database.
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection);
-
-
-/**
- * Send a response indicating that the request was too big.
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection);
-
-
-/**
- * Send a response indicating that the JSON was malformed.
- *
- * @param connection the MHD connection to use
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection);
-
-
-/**
- * Send confirmation of deposit success to client. This function
- * will create a signed message affirming the given information
- * and return it to the client. By this, the mint affirms that
- * the coin had sufficient (residual) value for the specified
- * transaction and that it will execute the requested deposit
- * operation with the given wiring details.
- *
- * @param connection connection to the client
- * @param coin_pub public key of the coin
- * @param h_wire hash of wire details
- * @param h_contract hash of contract details
- * @param transaction_id transaction ID
- * @param timestamp client's timestamp
- * @param refund_deadline until when this deposit be refunded
- * @param merchant merchant public key
- * @param amount_without_fee fraction of coin value to deposit (without fee)
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- struct GNUNET_TIME_Absolute timestamp,
- struct GNUNET_TIME_Absolute refund_deadline,
- const struct TALER_MerchantPublicKeyP *merchant,
- const struct TALER_Amount *amount_without_fee);
-
-
-/**
- * Send proof that a /deposit request is invalid to client. This
- * function will create a message with all of the operations affecting
- * the coin that demonstrate that the coin has insufficient value.
- *
- * @param connection connection to the client
- * @param tl transaction list to use to build reply
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_MINTDB_TransactionList *tl);
-
-
-/**
- * A merchant asked for details about a deposit, but
- * we do not know anything about the deposit. Generate the
- * 404 reply.
- *
- * @param connection connection to the client
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection);
-
-
-/**
- * A merchant asked for details about a deposit, but
- * we did not execute the deposit yet. Generate a 202 reply.
- *
- * @param connection connection to the client
- * @param planned_exec_time planned execution time
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
- struct GNUNET_TIME_Absolute planned_exec_time);
-
-
-/**
- * A merchant asked for details about a deposit. Provide
- * them. Generates the 200 reply.
- *
- * @param connection connection to the client
- * @param h_contract hash of the contract
- * @param h_wire hash of wire account details
- * @param coin_pub public key of the coin
- * @param coin_contribution contribution of this coin to the total amount transferred
- * @param transaction_id merchant transaction identifier
- * @param wtid raw wire transfer identifier
- * @param exec_time execution time of the wire transfer
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *h_contract,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_contribution,
- uint64_t transaction_id,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct GNUNET_TIME_Absolute exec_time);
-
-
-/**
- * A merchant asked for transaction details about a wire transfer.
- * Provide them. Generates the 200 reply.
- *
- * @param connection connection to the client
- * @param total total amount that was transferred
- * @param merchant_pub public key of the merchant
- * @param h_wire destination account
- * @param deposits details about the combined deposits
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
- const struct TALER_Amount *total,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- json_t *deposits);
-
-
-/**
- * Send reserve status information to client.
- *
- * @param connection connection to the client
- * @param rh reserve history to return
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection,
- const struct TALER_MINTDB_ReserveHistory *rh);
-
-
-/**
- * Send reserve status information to client with the
- * message that we have insufficient funds for the
- * requested /reserve/withdraw operation.
- *
- * @param connection connection to the client
- * @param rh reserve history to return
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_MINTDB_ReserveHistory *rh);
-
-
-/**
- * Send blinded coin information to client.
- *
- * @param connection connection to the client
- * @param collectable blinded coin to return
- * @return MHD result code
- */
-int
-TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection,
- const struct TALER_MINTDB_CollectableBlindcoin *collectable);
-
-
-/**
- * Send a confirmation response to a "/refresh/melt" request.
- *
- * @param connection the connection to send the response to
- * @param session_hash hash of the refresh session
- * @param noreveal_index which index will the client not have to reveal
- * @return a MHD status code
- */
-int
-TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *session_hash,
- uint16_t noreveal_index);
-
-
-/**
- * Send a response for a failed "/refresh/melt" request. The
- * transaction history of the given coin demonstrates that the
- * @a residual value of the coin is below the @a requested
- * contribution of the coin for the melt. Thus, the mint
- * refuses the melt operation.
- *
- * @param connection the connection to send the response to
- * @param coin_pub public key of the coin
- * @param coin_value original value of the coin
- * @param tl transaction history for the coin
- * @param requested how much this coin was supposed to contribute
- * @param residual remaining value of the coin (after subtracting @a tl)
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- struct TALER_Amount coin_value,
- struct TALER_MINTDB_TransactionList *tl,
- struct TALER_Amount requested,
- struct TALER_Amount residual);
-
-
-/**
- * Send a response for "/refresh/reveal".
- *
- * @param connection the connection to send the response to
- * @param num_newcoins number of new coins for which we reveal data
- * @param sigs array of @a num_newcoins signatures revealed
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection,
- unsigned int num_newcoins,
- const struct TALER_DenominationSignature *sigs);
-
-
-/**
- * Send a response for a failed "/refresh/reveal", where the
- * revealed value(s) do not match the original commitment.
- *
- * @param connection the connection to send the response to
- * @param mc all information about the original commitment
- * @param off offset in the array of kappa-commitments where
- * the missmatch was detected
- * @param j index of the coin for which the missmatch was
- * detected
- * @param missmatch_object name of the object that was
- * bogus (i.e. "transfer key").
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
- const struct TALER_MINTDB_MeltCommitment *mc,
- unsigned int off,
- unsigned int j,
- const char *missmatch_object);
-
-
-/**
- * @brief Information for each session a coin was melted into.
- */
-struct TMH_RESPONSE_LinkSessionInfo
-{
- /**
- * Transfer public key of the coin.
- */
- struct TALER_TransferPublicKeyP transfer_pub;
-
- /**
- * Encrypted shared secret for decrypting the transfer secrets.
- */
- struct TALER_EncryptedLinkSecretP shared_secret_enc;
-
- /**
- * Linked data of coins being created in the session.
- */
- struct TALER_MINTDB_LinkDataList *ldl;
-
-};
-
-
-/**
- * Send a response for "/refresh/link".
- *
- * @param connection the connection to send the response to
- * @param num_sessions number of sessions the coin was used in
- * @param sessions array of @a num_session entries with
- * information for each session
- * @return a MHD result code
- */
-int
-TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
- unsigned int num_sessions,
- const struct TMH_RESPONSE_LinkSessionInfo *sessions);
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_test.c b/src/mint/taler-mint-httpd_test.c
deleted file mode 100644
index b894854f3..000000000
--- a/src/mint/taler-mint-httpd_test.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_test.c
- * @brief Handle /test requests; parses the POST and JSON and
- * checks that the client is binary-compatible
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include "taler_signatures.h"
-#include "taler-mint-httpd_test.h"
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-
-
-/**
- * Private key the test module uses for signing.
- */
-static struct GNUNET_CRYPTO_rsa_PrivateKey *rsa_pk;
-
-
-/**
- * Handle a "/test/base32" request. Parses the JSON in the post, runs
- * the Crockford Base32 decoder on the "input" field in the JSON,
- * hashes the result and sends the hashed value back as a JSON
- * string with in Base32 Crockford encoding. Thus, this API
- * allows testing the hashing and Crockford encoding/decoding
- * functions.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- void *in_ptr;
- size_t in_ptr_size;
- struct GNUNET_HashCode hc;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- GNUNET_CRYPTO_hash (in_ptr,
- in_ptr_size,
- &hc);
- TMH_PARSE_release_data (spec);
- json_decref (json);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "output",
- TALER_json_from_data (&hc, sizeof (struct GNUNET_HashCode)));
-}
-
-
-/**
- * Handle a "/test/encrypt" request. Parses the JSON in the post,
- * runs the Crockford Base32 decoder on the "input" field in the JSON,
- * and encrypts the result with a shared secret derived using the HKDF
- * function with salt "skey" and IV derived with salt "iv" of the
- * Crockford Base32-encoded "key_hash" field in the JSON. The
- * symmetric encryption is the AES/Twofish double-encryption used in
- * Taler/GNUnet. The resulting ciphertext is returned as a Crockford
- * Base32 encoded JSON string.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- struct GNUNET_HashCode key;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct GNUNET_CRYPTO_SymmetricSessionKey skey;
- void *in_ptr;
- size_t in_ptr_size;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
- TMH_PARSE_member_fixed ("key_hash", &key),
- TMH_PARSE_MEMBER_END
- };
- char *out;
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- json_decref (json);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CRYPTO_kdf (&skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
- "skey", strlen ("skey"),
- &key, sizeof (key),
- NULL, 0));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CRYPTO_kdf (&iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
- "iv", strlen ("iv"),
- &key, sizeof (key),
- NULL, 0));
- out = GNUNET_malloc (in_ptr_size);
- GNUNET_break (in_ptr_size ==
- GNUNET_CRYPTO_symmetric_encrypt (in_ptr,
- in_ptr_size,
- &skey,
- &iv,
- out));
- json = TALER_json_from_data (out,
- in_ptr_size);
- GNUNET_free (out);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "output",
- json);
-}
-
-
-/**
- * Handle a "/test/hkdf" request. Parses the JSON in the post, runs
- * the Crockford Base32 decoder on the "input" field in the JSON,
- * computes `HKDF(input, "salty")` and sends the result back as a JSON
- * string with in Base32 Crockford encoding. Thus, this API allows
- * testing the use of the (H)KDF. Note that the test fixes the
- * input and output sizes and the salt (and the hash functions used
- * by the HKDF), so this is only useful to test the HKDF in the
- * same way it will be used within Taler/GNUnet.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- struct GNUNET_HashCode hc;
- void *in_ptr;
- size_t in_ptr_size;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- json_decref (json);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
- "salty", strlen ("salty"),
- in_ptr,
- in_ptr_size,
- NULL, 0);
- TMH_PARSE_release_data (spec);
- json = TALER_json_from_data (&hc,
- sizeof (struct GNUNET_HashCode));
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "output",
- json);
-}
-
-
-/**
- * Handle a "/test/ecdhe" request. Parses the JSON in the post, which
- * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv"
- * with a private key. The reply is the resulting JSON is an object
- * with the field "ecdh_hash" containing a Crockford Base32-encoded
- * string representing the hash derived via ECDH of the two keys.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- struct GNUNET_CRYPTO_EcdhePublicKey pub;
- struct GNUNET_CRYPTO_EcdhePrivateKey priv;
- struct GNUNET_HashCode hc;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("ecdhe_pub", &pub),
- TMH_PARSE_member_fixed ("ecdhe_priv", &priv),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- json_decref (json);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecc_ecdh (&priv,
- &pub,
- &hc))
- {
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to perform ECDH");
- }
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "ecdh_hash",
- TALER_json_from_data (&hc,
- sizeof (hc)));
-}
-
-
-/**
- * Handle a "/test/eddsa" request. Parses the JSON in the post,
- * which must contain a "eddsa_pub" with a public key and an
- *"eddsa_sig" with the corresponding signature for a purpose
- * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is
- * valid, a reply with a #TALER_SIGNATURE_MINT_TEST_EDDSA is
- * returned using the same JSON format.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- struct GNUNET_CRYPTO_EddsaPublicKey pub;
- struct GNUNET_CRYPTO_EddsaSignature sig;
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("eddsa_pub", &pub),
- TMH_PARSE_member_fixed ("eddsa_sig", &sig),
- TMH_PARSE_MEMBER_END
- };
- struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- json_decref (json);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
- purpose.purpose = htonl (TALER_SIGNATURE_CLIENT_TEST_EDDSA);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_CLIENT_TEST_EDDSA,
- &purpose,
- &sig,
- &pub))
- {
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_signature_invalid (connection,
- "eddsa_sig");
- }
- TMH_PARSE_release_data (spec);
- pk = GNUNET_CRYPTO_eddsa_key_create ();
- purpose.purpose = htonl (TALER_SIGNATURE_MINT_TEST_EDDSA);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_sign (pk,
- &purpose,
- &sig))
- {
- GNUNET_free (pk);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to EdDSA-sign");
- }
- GNUNET_CRYPTO_eddsa_key_get_public (pk,
- &pub);
- GNUNET_free (pk);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o, s:o}",
- "eddsa_pub",
- TALER_json_from_data (&pub,
- sizeof (pub)),
- "eddsa_sig",
- TALER_json_from_data (&sig,
- sizeof (sig)));
-}
-
-
-/**
- * Handle a "/test/rsa/get" request. Returns the RSA public key
- * ("rsa_pub") which is used for signing in "/test/rsa/sign".
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- int res;
- struct GNUNET_CRYPTO_rsa_PublicKey *pub;
-
- if (NULL == rsa_pk)
- rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024);
- if (NULL == rsa_pk)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to create RSA key");
- }
- pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk);
- if (NULL == pub)
- {
- GNUNET_break (0);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to get public RSA key");
- }
- res = TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "rsa_pub",
- TALER_json_from_rsa_public_key (pub));
- GNUNET_CRYPTO_rsa_public_key_free (pub);
- return res;
-}
-
-
-/**
- * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which
- * must contain an "blind_ev" blinded value. A a blinded signature
- * ("rsa_blind_sig") is returned.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
- void *in_ptr;
- size_t in_ptr_size;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_variable ("blind_ev", &in_ptr, &in_ptr_size),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- json_decref (json);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- if (NULL == rsa_pk)
- rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024);
- if (NULL == rsa_pk)
- {
- GNUNET_break (0);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to create RSA key");
- }
- sig = GNUNET_CRYPTO_rsa_sign (rsa_pk,
- in_ptr,
- in_ptr_size);
- if (NULL == sig)
- {
- GNUNET_break (0);
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to RSA-sign");
- }
- TMH_PARSE_release_data (spec);
- res = TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "rsa_blind_sig",
- TALER_json_from_rsa_signature (sig));
- GNUNET_CRYPTO_rsa_signature_free (sig);
- return res;
-}
-
-
-/**
- * Handle a "/test/transfer" request. Parses the JSON in the post,
- * which must contain a "secret_enc" with the encrypted link secret,
- * a "trans_priv" with the transfer private key, a "coin_pub" with
- * a coin public key. A reply with the decrypted "secret" is
- * returned.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
- struct TALER_EncryptedLinkSecretP secret_enc;
- struct TALER_TransferPrivateKeyP trans_priv;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("secret_enc", &secret_enc),
- TMH_PARSE_member_fixed ("trans_priv", &trans_priv),
- TMH_PARSE_member_fixed ("coin_pub", &coin_pub),
- TMH_PARSE_MEMBER_END
- };
- struct TALER_LinkSecretP secret;
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- json_decref (json);
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- if (GNUNET_OK !=
- TALER_link_decrypt_secret (&secret_enc,
- &trans_priv,
- &coin_pub,
- &secret))
- {
- TMH_PARSE_release_data (spec);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to decrypt secret");
- }
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "secret",
- TALER_json_from_data (&secret,
- sizeof (secret)));
-}
-
-
-/**
- * Handle a "/test" request. Parses the JSON in the post.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *json;
- int res;
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
-
- json_decref (json);
- return MHD_NO;
-}
-
-
-/* end of taler-mint-httpd_test.c */
diff --git a/src/mint/taler-mint-httpd_test.h b/src/mint/taler-mint-httpd_test.h
deleted file mode 100644
index 33844aab1..000000000
--- a/src/mint/taler-mint-httpd_test.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_test.h
- * @brief Handle /test requests
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_TEST_H
-#define TALER_MINT_HTTPD_TEST_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Handle a "/test/base32" request. Parses the JSON in the post, runs
- * the Crockford Base32 decoder on the "input" field in the JSON,
- * hashes the result and sends the hashed value back as a JSON
- * string with in Base32 Crockford encoding. Thus, this API
- * allows testing the hashing and Crockford encoding/decoding
- * functions.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/encrypt" request. Parses the JSON in the post,
- * runs the Crockford Base32 decoder on the "input" field in the JSON,
- * and encrypts the result with a shared secret derived using the HKDF
- * function with salt "skey" and IV derived with salt "iv" of the
- * Crockford Base32-encoded "key_hash" field in the JSON. The
- * symmetric encryption is the AES/Twofish double-encryption used in
- * Taler/GNUnet. The resulting ciphertext is returned as a Crockford
- * Base32 encoded JSON string.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/hkdf" request. Parses the JSON in the post, runs
- * the Crockford Base32 decoder on the "input" field in the JSON,
- * computes `HKDF(input, "salty")` and sends the result back as a JSON
- * string with in Base32 Crockford encoding. Thus, this API allows
- * testing the use of the (H)KDF. Note that the test fixes the
- * input and output sizes and the salt (and the hash functions used
- * by the HKDF), so this is only useful to test the HKDF in the
- * same way it will be used within Taler/GNUnet.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/ecdhe" request. Parses the JSON in the post, which
- * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv"
- * with a private key. The reply is the resulting JSON is an object
- * with the field "ecdh_hash" containing a Crockford Base32-encoded
- * string representing the hash derived via ECDH of the two keys.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/eddsa" request. Parses the JSON in the post,
- * which must contain a "eddsa_pub" with a public key and an
- *"ecdsa_sig" with the corresponding signature for a purpose
- * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is
- * valid, a reply with a #TALER_SIGNATURE_MINT_TEST_EDDSA is
- * returned using the same JSON format.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/rsa/get" request. Returns the RSA public key
- * ("rsa_pub") which is used for signing in "/test/rsa/sign".
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which
- * must contain an "blind_ev" blinded value. A a blinded signature
- * ("rsa_blind_sig") is returned.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test/transfer" request. Parses the JSON in the post,
- * which must contain a "secret_enc" with the encrypted link secret,
- * a "trans_priv" with the transfer private key, a "coin_pub" with
- * a coin public key. A reply with the decrypted "secret" is
- * returned.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/test" request. Parses the JSON in the post.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TEST_handler_test (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-#endif
diff --git a/src/mint/taler-mint-httpd_tracking.c b/src/mint/taler-mint-httpd_tracking.c
deleted file mode 100644
index a6b41cf86..000000000
--- a/src/mint/taler-mint-httpd_tracking.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_tracking.c
- * @brief Handle wire transfer tracking-related requests
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include <pthread.h>
-#include "taler_signatures.h"
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_tracking.h"
-#include "taler-mint-httpd_responses.h"
-
-
-/**
- * Handle a "/wire/deposits" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct TALER_WireTransferIdentifierRawP wtid;
- int res;
-
- res = TMH_PARSE_mhd_request_arg_data (connection,
- "wtid",
- &wtid,
- sizeof (struct TALER_WireTransferIdentifierRawP));
- if (GNUNET_SYSERR == res)
- return MHD_NO; /* internal error */
- if (GNUNET_NO == res)
- return MHD_YES; /* parse error */
- return TMH_DB_execute_wire_deposits (connection,
- &wtid);
-}
-
-
-/**
- * Check the merchant signature, and if it is valid,
- * return the wire transfer identifier.
- *
- * @param connection the MHD connection to handle
- * @param tps signed request to execute
- * @param merchant_pub public key from the merchant
- * @param merchant_sig signature from the merchant (to be checked)
- * @param transaction_id transaction ID (in host byte order)
- * @return MHD result code
- */
-static int
-check_and_handle_deposit_wtid_request (struct MHD_Connection *connection,
- const struct TALER_DepositTrackPS *tps,
- struct TALER_MerchantPublicKeyP *merchant_pub,
- struct TALER_MerchantSignatureP *merchant_sig,
- uint64_t transaction_id)
-{
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID,
- &tps->purpose,
- &merchant_sig->eddsa_sig,
- &merchant_pub->eddsa_pub))
- {
- GNUNET_break_op (0);
- return TMH_RESPONSE_reply_signature_invalid (connection,
- "merchant_sig");
- }
- return TMH_DB_execute_deposit_wtid (connection,
- &tps->h_contract,
- &tps->h_wire,
- &tps->coin_pub,
- merchant_pub,
- transaction_id);
-}
-
-
-/**
- * Handle a "/deposit/wtid" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- int res;
- json_t *json;
- struct TALER_DepositTrackPS tps;
- uint64_t transaction_id;
- struct TALER_MerchantSignatureP merchant_sig;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_fixed ("H_wire", &tps.h_wire),
- TMH_PARSE_member_fixed ("H_contract", &tps.h_contract),
- TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub),
- TMH_PARSE_member_uint64 ("transaction_id", &transaction_id),
- TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant),
- TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &json);
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
- return MHD_YES;
- res = TMH_PARSE_json_data (connection,
- json,
- spec);
- if (GNUNET_OK != res)
- {
- json_decref (json);
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
- tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS));
- tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID);
- tps.transaction_id = GNUNET_htonll (transaction_id);
- res = check_and_handle_deposit_wtid_request (connection,
- &tps,
- &tps.merchant,
- &merchant_sig,
- transaction_id);
- TMH_PARSE_release_data (spec);
- json_decref (json);
- return res;
-}
-
-
-/* end of taler-mint-httpd_tracking.c */
diff --git a/src/mint/taler-mint-httpd_tracking.h b/src/mint/taler-mint-httpd_tracking.h
deleted file mode 100644
index 9ec4c6827..000000000
--- a/src/mint/taler-mint-httpd_tracking.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_tracking.h
- * @brief Handle wire transfer tracking-related requests
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_TRACKING_H
-#define TALER_MINT_HTTPD_TRACKING_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Handle a "/wire/deposits" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/deposit/wtid" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_validation.c b/src/mint/taler-mint-httpd_validation.c
deleted file mode 100644
index 8f8ab415e..000000000
--- a/src/mint/taler-mint-httpd_validation.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd_validation.c
- * @brief helpers for calling the wire plugins to validate addresses
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler-mint-httpd_validation.h"
-#include "taler_wire_plugin.h"
-
-
-/**
- * Information we keep for each plugin.
- */
-struct Plugin
-{
-
- /**
- * We keep plugins in a DLL.
- */
- struct Plugin *next;
-
- /**
- * We keep plugins in a DLL.
- */
- struct Plugin *prev;
-
- /**
- * Type of the wireformat.
- */
- char *type;
-
- /**
- * Pointer to the plugin.
- */
- struct TALER_WIRE_Plugin *plugin;
-
-};
-
-/**
- * Head of DLL of wire plugins.
- */
-static struct Plugin *wire_head;
-
-/**
- * Tail of DLL of wire plugins.
- */
-static struct Plugin *wire_tail;
-
-
-/**
- * Initialize validation subsystem.
- *
- * @param cfg configuration to use
- * @return #GNUNET_OK on success
- */
-int
-TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct Plugin *p;
- char *wireformats;
- char *lib_name;
- const char *token;
-
- /* Find out list of supported wire formats */
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "wireformat",
- &wireformats))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "wireformat");
- return GNUNET_SYSERR;
- }
- for (token = strtok (wireformats,
- " ");
- NULL != token;
- token = strtok (NULL,
- " "))
- {
- (void) GNUNET_asprintf (&lib_name,
- "libtaler_plugin_wire_%s",
- token);
- p = GNUNET_new (struct Plugin);
- p->type = GNUNET_strdup (token);
- p->plugin = GNUNET_PLUGIN_load (lib_name,
- (void *) cfg);
- if (NULL == p->plugin)
- {
- GNUNET_free (p);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to load plugin %s\n",
- lib_name);
- GNUNET_free (lib_name);
- TMH_VALIDATION_done ();
- return GNUNET_SYSERR;
- }
- p->plugin->library_name = lib_name;
- GNUNET_CONTAINER_DLL_insert (wire_head,
- wire_tail,
- p);
- }
- GNUNET_free (wireformats);
- return GNUNET_OK;
-}
-
-
-/**
- * Shutdown validation subsystem.
- */
-void
-TMH_VALIDATION_done ()
-{
- struct Plugin *p;
- char *lib_name;
-
- while (NULL != (p = wire_head))
- {
- GNUNET_CONTAINER_DLL_remove (wire_head,
- wire_tail,
- p);
- lib_name = p->plugin->library_name;
- GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
- p->plugin));
- GNUNET_free (lib_name);
- GNUNET_free (p->type);
- GNUNET_free (p);
- }
-}
-
-
-/**
- * Check if the given wire format JSON object is correctly formatted as
- * a wire address.
- *
- * @param wire the JSON wire format object
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-int
-TMH_json_validate_wireformat (const json_t *wire)
-{
- const char *stype;
- json_error_t error;
- struct Plugin *p;
-
- if (0 != json_unpack_ex ((json_t *) wire,
- &error, 0,
- "{s:s}",
- "type", &stype))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- for (p=wire_head; NULL != p; p = p->next)
- if (0 == strcasecmp (p->type,
- stype))
- return p->plugin->wire_validate (wire);
- return GNUNET_NO;
-}
-
-
-/**
- * Check if we support the given wire method.
- *
- * @param type type of wire method to check
- * @return #GNUNET_YES if the method is supported
- */
-int
-TMH_VALIDATION_test_method (const char *type)
-{
- struct Plugin *p;
-
- for (p=wire_head;NULL != p;p = p->next)
- if (0 == strcasecmp (type,
- p->type))
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-/**
- * Obtain supported validation methods as a JSON array,
- * and as a hash.
- *
- * @param[out] h set to the hash of the JSON methods
- * @return JSON array with the supported validation methods
- */
-json_t *
-TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h)
-{
- json_t *methods;
- struct GNUNET_HashContext *hc;
- const char *wf;
- struct Plugin *p;
-
- methods = json_array ();
- hc = GNUNET_CRYPTO_hash_context_start ();
- for (p=wire_head;NULL != p;p = p->next)
- {
- wf = p->type;
- json_array_append_new (methods,
- json_string (wf));
- GNUNET_CRYPTO_hash_context_read (hc,
- wf,
- strlen (wf) + 1);
- }
- GNUNET_CRYPTO_hash_context_finish (hc,
- h);
- return methods;
-}
-
-
-/* end of taler-mint-httpd_validation.c */
diff --git a/src/mint/taler-mint-httpd_validation.h b/src/mint/taler-mint-httpd_validation.h
deleted file mode 100644
index f5fb19003..000000000
--- a/src/mint/taler-mint-httpd_validation.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file taler-mint-httpd_validation.h
- * @brief helpers for calling the wire plugins to validate addresses
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_VALIDATION_H
-#define TALER_MINT_HTTPD_VALIDATION_H
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-
-
-/**
- * Initialize validation subsystem.
- *
- * @param cfg configuration to use
- * @return #GNUNET_OK on success
- */
-int
-TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-
-/**
- * Shutdown validation subsystem.
- */
-void
-TMH_VALIDATION_done (void);
-
-
-/**
- * Check if the given wire format JSON object is correctly formatted as
- * a wire address.
- *
- * @param wire the JSON wire format object
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-int
-TMH_json_validate_wireformat (const json_t *wire);
-
-/**
- * Check if we support the given wire method.
- *
- * @param type type of wire method to check
- * @return #GNUNET_YES if the method is supported
- */
-int
-TMH_VALIDATION_test_method (const char *type);
-
-
-/**
- * Obtain supported validation methods as a JSON array,
- * and as a hash.
- *
- * @param[out] h set to the hash of the JSON methods
- * @return JSON array with the supported validation methods
- */
-json_t *
-TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h);
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_wire.c b/src/mint/taler-mint-httpd_wire.c
deleted file mode 100644
index 020a7e108..000000000
--- a/src/mint/taler-mint-httpd_wire.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_wire.c
- * @brief Handle /wire requests
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler-mint-httpd_keystate.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_validation.h"
-#include "taler-mint-httpd_wire.h"
-#include <jansson.h>
-
-/**
- * Handle a "/wire" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct TALER_MintWireSupportMethodsPS wsm;
- struct TALER_MintPublicKeyP pub;
- struct TALER_MintSignatureP sig;
- json_t *methods;
-
- wsm.purpose.size = htonl (sizeof (wsm));
- wsm.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES);
- methods = TMH_VALIDATION_get_methods (&wsm.h_wire_types);
- TMH_KS_sign (&wsm.purpose,
- &pub,
- &sig);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o, s:o, s:o}",
- "methods", methods,
- "sig", TALER_json_from_data (&sig,
- sizeof (sig)),
- "pub", TALER_json_from_data (&pub,
- sizeof (pub)));
-}
-
-
-/**
- * Handle a "/wire/test" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct MHD_Response *response;
- int ret;
- char *wire_test_redirect;
-
- response = MHD_create_response_from_buffer (0, NULL,
- MHD_RESPMEM_PERSISTENT);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (response);
- if (GNUNET_NO == TMH_VALIDATION_test_method ("test"))
- {
- /* Return 501: not implemented */
- ret = MHD_queue_response (connection,
- MHD_HTTP_NOT_IMPLEMENTED,
- response);
- MHD_destroy_response (response);
- return ret;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint-wire-test",
- "REDIRECT_URL",
- &wire_test_redirect))
- {
- /* oopsie, configuration error */
- MHD_destroy_response (response);
- return TMH_RESPONSE_reply_internal_error (connection,
- "REDIRECT_URL not configured");
- }
- MHD_add_response_header (response,
- MHD_HTTP_HEADER_LOCATION,
- wire_test_redirect);
- GNUNET_free (wire_test_redirect);
- ret = MHD_queue_response (connection,
- rh->response_code,
- response);
- MHD_destroy_response (response);
- return ret;
-}
-
-
-/**
- * Handle a "/wire/sepa" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct MHD_Response *response;
- int ret;
- char *sepa_wire_file;
- int fd;
- struct stat sbuf;
-
- if (GNUNET_NO == TMH_VALIDATION_test_method ("sepa"))
- {
- /* Return 501: not implemented */
- response = MHD_create_response_from_buffer (0, NULL,
- MHD_RESPMEM_PERSISTENT);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (response);
- ret = MHD_queue_response (connection,
- MHD_HTTP_NOT_IMPLEMENTED,
- response);
- MHD_destroy_response (response);
- return ret;
- }
- /* Fetch reply */
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "mint-wire-sepa",
- "SEPA_RESPONSE_FILE",
- &sepa_wire_file))
- {
- return TMH_RESPONSE_reply_internal_error (connection,
- "SEPA_RESPONSE_FILE not configured");
- }
- fd = open (sepa_wire_file,
- O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- sepa_wire_file);
- GNUNET_free (sepa_wire_file);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to open SEPA_RESPONSE_FILE");
- }
- if (0 != fstat (fd, &sbuf))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "fstat",
- sepa_wire_file);
- (void) close (fd);
- GNUNET_free (sepa_wire_file);
- return TMH_RESPONSE_reply_internal_error (connection,
- "Failed to open SEPA_RESPONSE_FILE");
- }
- response = MHD_create_response_from_fd ((size_t) sbuf.st_size,
- fd);
- GNUNET_free (sepa_wire_file);
- if (NULL == response)
- {
- (void) close (fd);
- GNUNET_break (0);
- return MHD_NO;
- }
- TMH_RESPONSE_add_global_headers (response);
- if (NULL != rh->mime_type)
- (void) MHD_add_response_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- rh->mime_type);
- ret = MHD_queue_response (connection,
- rh->response_code,
- response);
- MHD_destroy_response (response);
- return ret;
-}
-
-/* end of taler-mint-httpd_wire.c */
diff --git a/src/mint/taler-mint-httpd_wire.h b/src/mint/taler-mint-httpd_wire.h
deleted file mode 100644
index e77daf019..000000000
--- a/src/mint/taler-mint-httpd_wire.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_wire.h
- * @brief Handle /wire requests
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_WIRE_H
-#define TALER_MINT_HTTPD_WIRE_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Handle a "/wire" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/wire/test" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-/**
- * Handle a "/wire/sepa" request.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-#endif
diff --git a/src/mint/test_taler_mint_httpd.data b/src/mint/test_taler_mint_httpd.data
deleted file mode 100644
index 2d6020355..000000000
--- a/src/mint/test_taler_mint_httpd.data
+++ /dev/null
@@ -1,48 +0,0 @@
-# This file is part of TALER
-# Copyright (C) 2015 GNUnet e.V.
-#
-# TALER is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Affero General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License along with
-# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-#
-#
-# This is a resource file for test_taler_mint_httpd.sh.
-# Lines starting with '#' (must be first character in line) are comments.
-#
-# Each non-comment line must contain two strings, the first being the
-# URL on the HTTP serve which a HTTP POST request should be made out
-# two, followed by the JSON data to POST to the server.
-#
-# Note that neither element may contain any spaces!
-#
-#
-# Bad amount:
-/admin/add/incoming {"reserve_pub":"7RZBZ86677QMASD2KAYGEPD246C7B7RC6P101FNTG6ZK8X61A620","amount":"1","execution_date":"\/Date(1435934428788)\/","wire":{"empty":"empty"}}
-#
-# Bad wire format:
-/admin/add/incoming {"reserve_pub":"6VRFYZRVHJ434BV3J018MS6H7Q1V5Q6YECNMEF9G4WKB8QJQCAX0","amount":{"currency":"EUR","value":10,"fraction":3},"execution_date":"\/Date(1436258333286)\/","wire":{"empty":"empty"}}
-#
-# Malformed JSON (ill-balanced quotes around 'amount')
-/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0",amount":{"currency":"EUR","value":5,"fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}}
-#
-# Bad amount (value not a string)
-/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":{"currency":"EUR","value":"5","fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}}
-#
-# Bad amount (overall amount is a string)
-/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":"{\"currency\":\"EUR\",\"value\":5,\"fraction\":3}","execution_date":"\/Date(1436271156447)\/","wire":{"type":"test"}}
-#
-# Bogus denomination key
-/deposit {"f":{"currency":"EUR","value":5,"fraction":0},"H_contract":"NRT9E07FYT147V4VCDG0102P0YX0FZ11ZRG90F4X1HDV95M0J64ZVE4XQGNN9MJ3B5K3JX6TJ181KNGRYSZSTYZ5PQHBM1F9QKQ5B50","wire":{"bank":"dest bank","type":"TEST","account":42},"timestamp":"/Date(1436823947)/","coin_pub":"2KCPBGZ77VGJT4DG99EZAY0GQ5TJ89DF53FWYR5RFRTK0CCXRMFG","denom_pub":"51B7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_sig":"W1TDFCSW5XQX9ZF4QPVP3JAJFYA7G4X6SY2B49KRNTDMA685M9YNFETV4610RFKZMSQ3RBRCYBJQH1ZQSMTDMW9W8X6C9SGPCA5ST0R","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26DSQ8913AC1S7513EC9G6914AE228H236HHR68VKCCSK650MAGSM6GV3GCHP6D330H1R8GVKJD9P68W46H9Q8GVK8HA6752M2CSN8N248DHJ8H346E9J8RS4CDA28D33ECJ38S33JC9R6MRM8D9G74WM8HA668T44H1N6RT44GHS8CSK8H1G6D346C9J6CS3EC1N8H2M4HA38CSK2D246CW4CD1P70VMAD1Q891K8H1M64TK6C258MRM6G9R88RM6E2488WK2CSQ6GW3GH9N64RKGH2375136GA66533GCSJ65344CHH84W38HHP75330DA58RSKJCJ364SK0C1R8GVK6DSP61134HA48GT4CE1J6MW36C9G891K2GT68GTMCCSQ890M8E1P88R44DA174VK4E135452081918G2J2G0","transaction_id":1,"merchant_pub":"4032W2ZXFW000KRJQDH3CZR00000000004000030P6YG1NR50000","refund_deadline":"/Date(0)/"}
-#
-# missing coin_ev argument
-/withdraw/sign {"denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","#oin_ev":"7DPN42W14BWWD2NWNDYP086276CFV0H8VEV43NFWQGZ3Y8WVR5R5HCN8THX43Z61TFN3CH9N6X5Q0P0T9NF2G8ZWBH8KXEQFQ973CMDDHF1FSE2G9289AB9ERHM8X222VB2WS733X36P8EMG4D3T1N2JHFP530C9RPEAPHDQXZABB6CJ63YD0581JVRY365HHF20RW3BNVKXP","reserve_sig":"VPKYWKGE6FB172XX222N1J0TAEXQE6VERN5X4ANJ0D9K1E7JAX01CPR1PT51SKK5JD72H1GRJ0S2ZQSKN22ZBEGKS77GMT6BF6DD030","reserve_pub":"FN7ARB2MJH2EDMMVT2985Y141YTCE503FS27BTNQ6JSCG3GMBJDG"}
-#
-# malformed coin_ev argument
-/withdraw/sign {"denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_ev":"'DPN42W14BWWD2NWNDYP086276CFV0H8VEV43NFWQGZ3Y8WVR5R5HCN8THX43Z61TFN3CH9N6X5Q0P0T9NF2G8ZWBH8KXEQFQ973CMDDHF1FSE2G9289AB9ERHM8X222VB2WS733X36P8EMG4D3T1N2JHFP530C9RPEAPHDQXZABB6CJ63YD0581JVRY365HHF20RW3BNVKXP","reserve_sig":"VPKYWKGE6FB172XX222N1J0TAEXQE6VERN5X4ANJ0D9K1E7JAX01CPR1PT51SKK5JD72H1GRJ0S2ZQSKN22ZBEGKS77GMT6BF6DD030","reserve_pub":"FN7ARB2MJH2EDMMVT2985Y141YTCE503FS27BTNQ6JSCG3GMBJDG"}
diff --git a/src/mint/test_taler_mint_httpd.sh b/src/mint/test_taler_mint_httpd.sh
deleted file mode 100755
index 05d26620b..000000000
--- a/src/mint/test_taler_mint_httpd.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-#
-# This file is part of TALER
-# Copyright (C) 2015 GNUnet e.V.
-#
-# TALER is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Affero General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License along with
-# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-#
-#
-# This script uses 'curl' to POST various ill-formed requests to the
-# taler-mint-httpd. Basically, the goal is to make sure that the
-# HTTP server survives (and produces the 'correct' error code).
-#
-# We read the JSON snippets to POST from test_taler_mint_httpd.data
-#
-# Setup keys.
-taler-mint-keyup -d test-mint-home -m test-mint-home/master.priv
-# Run Mint HTTPD (in background)
-taler-mint-httpd -d test-mint-home &
-# Give HTTP time to start
-sleep 2
-# Run test...
-cat test_taler_mint_httpd.data | grep -v ^\# | awk '{ print "curl -d '\''" $2 "'\'' http://localhost:8081"$1 }' | bash
-# Stop HTTP server
-kill -TERM %%
-# FIXME: not sure this is the 'correct' return code...
-exit $?
diff --git a/src/mint/test_taler_mint_httpd_afl.sh b/src/mint/test_taler_mint_httpd_afl.sh
deleted file mode 100755
index d2c40c216..000000000
--- a/src/mint/test_taler_mint_httpd_afl.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-#
-# This file is part of TALER
-# Copyright (C) 2015 GNUnet e.V.
-#
-# TALER is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Affero General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License along with
-# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-#
-#
-# This script uses 'curl' to POST various ill-formed requests to the
-# taler-mint-httpd. Basically, the goal is to make sure that the
-# HTTP server survives (and produces the 'correct' error code).
-#
-# We read the JSON snippets from afl-tests/
-#
-PREFIX=
-# Uncomment this line to run with valgrind...
-PREFIX="valgrind --leak-check=yes --log-file=valgrind.%p"
-# Setup keys.
-taler-mint-keyup -d test-mint-home -m test-mint-home/master.priv
-# Setup database (just to be sure)
-taler-mint-dbinit -d test-mint-home &> /dev/null || true
-# Only log hard errors, we expect lots of warnings...
-export GNUNET_FORCE_LOG="taler-mint-httpd;;;;ERROR/libmicrohttpd;;;;ERROR/util;;;;ERROR/"
-# Run test...
-for n in afl-tests/*
-do
- echo -n "Test $n "
- $PREFIX taler-mint-httpd -d test-mint-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; }
-# $PREFIX taler-mint-httpd -d test-mint-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; exit 1; }
- echo "OK"
-done
-exit 0
diff --git a/src/mintdb/Makefile.am b/src/mintdb/Makefile.am
deleted file mode 100644
index e3d37b2e5..000000000
--- a/src/mintdb/Makefile.am
+++ /dev/null
@@ -1,110 +0,0 @@
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/pq/ $(POSTGRESQL_CPPFLAGS)
-
-if USE_COVERAGE
- AM_CFLAGS = --coverage -O0
- XLIB = -lgcov
-endif
-
-plugindir = $(libdir)/taler
-
-if HAVE_POSTGRESQL
-plugin_LTLIBRARIES = \
- libtaler_plugin_mintdb_postgres.la
-endif
-
-EXTRA_DIST = \
- plugin_mintdb_common.c \
- test-mint-db-postgres.conf
-
-libtaler_plugin_mintdb_postgres_la_SOURCES = \
- plugin_mintdb_postgres.c
-libtaler_plugin_mintdb_postgres_la_LIBADD = \
- $(LTLIBINTL)
-libtaler_plugin_mintdb_postgres_la_LDFLAGS = \
- $(TALER_PLUGIN_LDFLAGS) \
- $(top_builddir)/src/pq/libtalerpq.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lpq \
- -lgnunetpq \
- -lgnunetutil $(XLIB)
-
-lib_LTLIBRARIES = \
- libtalermintdb.la
-
-libtalermintdb_la_SOURCES = \
- mintdb_keyio.c \
- mintdb_plugin.c
-
-libtalermintdb_la_LIBADD = \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetutil $(XLIB)
-
-libtalermintdb_la_LDFLAGS = \
- $(POSTGRESQL_LDFLAGS) \
- -version-info 0:0:0 \
- -no-undefined
-
-
-check_PROGRAMS = \
- test-mintdb-deposits \
- test-mintdb-keyio \
- test-mintdb-postgres \
- test-perf-taler-mintdb \
- perf-mintdb
-
-TESTS = \
- test-mintdb-postgres \
- test-perf-taler-mintdb
-
-test_mintdb_deposits_SOURCES = \
- test_mintdb_deposits.c
-test_mintdb_deposits_LDADD = \
- libtalermintdb.la \
- $(top_srcdir)/src/util/libtalerutil.la \
- $(top_srcdir)/src/pq/libtalerpq.la \
- -lgnunetutil \
- -ljansson \
- -lpq
-
-test_mintdb_keyio_SOURCES = \
- test_mintdb_keyio.c
-test_mintdb_keyio_LDADD = \
- libtalermintdb.la \
- $(top_srcdir)/src/util/libtalerutil.la \
- $(top_srcdir)/src/pq/libtalerpq.la \
- -lgnunetutil
-
-test_mintdb_postgres_SOURCES = \
- test_mintdb.c
-test_mintdb_postgres_LDADD = \
- libtalermintdb.la \
- $(top_srcdir)/src/util/libtalerutil.la \
- $(top_srcdir)/src/pq/libtalerpq.la \
- -lgnunetutil -ljansson
-
-test_perf_taler_mintdb_SOURCES = \
- test_perf_taler_mintdb.c \
- perf_taler_mintdb_init.c \
- perf_taler_mintdb_interpreter.c
-test_perf_taler_mintdb_LDADD = \
- libtalermintdb.la \
- $(top_srcdir)/src/util/libtalerutil.la \
- $(top_srcdir)/src/pq/libtalerpq.la \
- -ljansson \
- -lgnunetutil
-
-perf_mintdb_SOURCES = \
- perf_taler_mintdb.c \
- perf_taler_mintdb_init.c \
- perf_taler_mintdb_interpreter.c
-perf_mintdb_LDADD = \
- libtalermintdb.la \
- $(top_srcdir)/src/util/libtalerutil.la \
- $(top_srcdir)/src/pq/libtalerpq.la \
- -ljansson \
- -lgnunetutil
-
-
-EXTRA_test_mintdb_postgres_DEPENDENCIES = \
- libtaler_plugin_mintdb_postgres.la
diff --git a/src/mintdb/mintdb_keyio.c b/src/mintdb/mintdb_keyio.c
deleted file mode 100644
index 89ac9055a..000000000
--- a/src/mintdb/mintdb_keyio.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mintdb/mintdb_keyio.c
- * @brief I/O operations for the Mint's private keys
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Sree Harsha Totakura
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_mintdb_lib.h"
-
-
-/**
- * Closure for the #signkeys_iterate_dir_iter().
- */
-struct SignkeysIterateContext
-{
-
- /**
- * Function to call on each signing key.
- */
- TALER_MINTDB_SigningKeyIterator it;
-
- /**
- * Closure for @e it.
- */
- void *it_cls;
-};
-
-
-/**
- * Function called on each file in the directory with our signing
- * keys. Parses the file and calls the iterator from @a cls.
- *
- * @param cls the `struct SignkeysIterateContext *`
- * @param filename name of the file to parse
- * @return #GNUNET_OK to continue,
- * #GNUNET_NO to stop iteration without error,
- * #GNUNET_SYSERR to stop iteration with error
- */
-static int
-signkeys_iterate_dir_iter (void *cls,
- const char *filename)
-{
- struct SignkeysIterateContext *skc = cls;
- ssize_t nread;
- struct TALER_MINTDB_PrivateSigningKeyInformationP issue;
-
- nread = GNUNET_DISK_fn_read (filename,
- &issue,
- sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP));
- if (nread != sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Invalid signkey file `%s': wrong size (%d, expected %u)\n",
- filename,
- (int) nread,
- sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP));
- return GNUNET_OK;
- }
- return skc->it (skc->it_cls,
- filename,
- &issue);
-}
-
-
-/**
- * Call @a it for each signing key found in the @a mint_base_dir.
- *
- * @param mint_base_dir base directory for the mint,
- * the signing keys must be in the #TALER_MINTDB_DIR_SIGNING_KEYS
- * subdirectory
- * @param it function to call on each signing key
- * @param it_cls closure for @a it
- * @return number of files found (may not match
- * number of keys given to @a it as malformed
- * files are simply skipped), -1 on error
- */
-int
-TALER_MINTDB_signing_keys_iterate (const char *mint_base_dir,
- TALER_MINTDB_SigningKeyIterator it,
- void *it_cls)
-{
- char *signkey_dir;
- struct SignkeysIterateContext skc;
- int ret;
-
- GNUNET_asprintf (&signkey_dir,
- "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_SIGNING_KEYS,
- mint_base_dir);
- skc.it = it;
- skc.it_cls = it_cls;
- ret = GNUNET_DISK_directory_scan (signkey_dir,
- &signkeys_iterate_dir_iter,
- &skc);
- GNUNET_free (signkey_dir);
- return ret;
-}
-
-
-/**
- * Import a denomination key from the given file.
- *
- * @param filename the file to import the key from
- * @param[out] dki set to the imported denomination key
- * @return #GNUNET_OK upon success;
- * #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINTDB_denomination_key_read (const char *filename,
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- uint64_t size;
- size_t offset;
- void *data;
- struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
-
- if (GNUNET_OK != GNUNET_DISK_file_size (filename,
- &size,
- GNUNET_YES,
- GNUNET_YES))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping inaccessable denomination key file `%s'\n",
- filename);
- return GNUNET_SYSERR;
- }
- offset = sizeof (struct TALER_MINTDB_DenominationKeyInformationP);
- if (size <= offset)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- data = GNUNET_malloc (size);
- if (size !=
- GNUNET_DISK_fn_read (filename,
- data,
- size))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "read",
- filename);
- GNUNET_free (data);
- return GNUNET_SYSERR;
- }
- if (NULL ==
- (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset,
- size - offset)))
- {
- GNUNET_free (data);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (NULL == dki->denom_priv.rsa_private_key);
- dki->denom_priv.rsa_private_key = priv;
- dki->denom_pub.rsa_public_key
- = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
- memcpy (&dki->issue,
- data,
- offset);
- GNUNET_free (data);
- return GNUNET_OK;
-}
-
-
-/**
- * Exports a denomination key to the given file.
- *
- * @param filename the file where to write the denomination key
- * @param dki the denomination key
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
- */
-int
-TALER_MINTDB_denomination_key_write (const char *filename,
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- char *priv_enc;
- size_t priv_enc_size;
- struct GNUNET_DISK_FileHandle *fh;
- ssize_t wrote;
- size_t wsize;
- int ret;
-
- fh = NULL;
- priv_enc_size
- = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key,
- &priv_enc);
- ret = GNUNET_SYSERR;
- if (NULL == (fh = GNUNET_DISK_file_open
- (filename,
- GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
- GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
- goto cleanup;
- wsize = sizeof (struct TALER_MINTDB_DenominationKeyInformationP);
- if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
- &dki->issue,
- wsize)))
- goto cleanup;
- if (wrote != wsize)
- goto cleanup;
- if (GNUNET_SYSERR ==
- (wrote = GNUNET_DISK_file_write (fh,
- priv_enc,
- priv_enc_size)))
- goto cleanup;
- if (wrote != priv_enc_size)
- goto cleanup;
- ret = GNUNET_OK;
- cleanup:
- GNUNET_free_non_null (priv_enc);
- if (NULL != fh)
- (void) GNUNET_DISK_file_close (fh);
- return ret;
-}
-
-
-/**
- * Closure for #denomkeys_iterate_keydir_iter() and
- * #denomkeys_iterate_topdir_iter().
- */
-struct DenomkeysIterateContext
-{
-
- /**
- * Set to the name of the directory below the top-level directory
- * during the call to #denomkeys_iterate_keydir_iter().
- */
- const char *alias;
-
- /**
- * Function to call on each denomination key.
- */
- TALER_MINTDB_DenominationKeyIterator it;
-
- /**
- * Closure for @e it.
- */
- void *it_cls;
-};
-
-
-/**
- * Decode the denomination key in the given file @a filename and call
- * the callback in @a cls with the information.
- *
- * @param cls the `struct DenomkeysIterateContext *`
- * @param filename name of a file that should contain
- * a denomination key
- * @return #GNUNET_OK to continue to iterate
- * #GNUNET_NO to abort iteration with success
- * #GNUNET_SYSERR to abort iteration with failure
- */
-static int
-denomkeys_iterate_keydir_iter (void *cls,
- const char *filename)
-{
- struct DenomkeysIterateContext *dic = cls;
- struct TALER_MINTDB_DenominationKeyIssueInformation issue;
- int ret;
-
- memset (&issue, 0, sizeof (issue));
- if (GNUNET_OK !=
- TALER_MINTDB_denomination_key_read (filename,
- &issue))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Invalid denomkey file: '%s'\n",
- filename);
- return GNUNET_OK;
- }
- ret = dic->it (dic->it_cls,
- dic->alias,
- &issue);
- GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key);
- return ret;
-}
-
-
-/**
- * Function called on each subdirectory in the #TALER_MINTDB_DIR_DENOMINATION_KEYS. Will
- * call the #denomkeys_iterate_keydir_iter() on each file in the
- * subdirectory.
- *
- * @param cls the `struct DenomkeysIterateContext *`
- * @param filename name of the subdirectory to scan
- * @return #GNUNET_OK on success,
- * #GNUNET_SYSERR if we need to abort
- */
-static int
-denomkeys_iterate_topdir_iter (void *cls,
- const char *filename)
-{
- struct DenomkeysIterateContext *dic = cls;
-
- dic->alias = GNUNET_STRINGS_get_short_name (filename);
- if (0 > GNUNET_DISK_directory_scan (filename,
- &denomkeys_iterate_keydir_iter,
- dic))
- return GNUNET_SYSERR;
- return GNUNET_OK;
-}
-
-
-/**
- * Call @a it for each denomination key found in the @a mint_base_dir.
- *
- * @param mint_base_dir base directory for the mint,
- * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS
- * subdirectory
- * @param it function to call on each denomination key found
- * @param it_cls closure for @a it
- * @return -1 on error, 0 if no files were found, otherwise
- * a positive number (however, even with a positive
- * number it is possible that @a it was never called
- * as maybe none of the files were well-formed)
- */
-int
-TALER_MINTDB_denomination_keys_iterate (const char *mint_base_dir,
- TALER_MINTDB_DenominationKeyIterator it,
- void *it_cls)
-{
- char *dir;
- struct DenomkeysIterateContext dic;
- int ret;
-
- GNUNET_asprintf (&dir,
- "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_DENOMINATION_KEYS,
- mint_base_dir);
- dic.it = it;
- dic.it_cls = it_cls;
- ret = GNUNET_DISK_directory_scan (dir,
- &denomkeys_iterate_topdir_iter,
- &dic);
- GNUNET_free (dir);
- return ret;
-}
-
-
-/**
- * Closure for #auditor_iter() and
- */
-struct AuditorIterateContext
-{
-
- /**
- * Function to call with the information for each auditor.
- */
- TALER_MINTDB_AuditorIterator it;
-
- /**
- * Closure for @e it.
- */
- void *it_cls;
-};
-
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * Header of a file with auditing information.
- */
-struct AuditorFileHeaderP
-{
-
- /**
- * Public key of the auditor.
- */
- struct TALER_AuditorPublicKeyP apub;
-
- /**
- * Master public key of the mint the auditor is signing
- * information for.
- */
- struct TALER_MasterPublicKeyP mpub;
-
-};
-GNUNET_NETWORK_STRUCT_END
-
-
-/**
- * Load the auditor signature and the information signed by the
- * auditor and call the callback in @a cls with the information.
- *
- * @param cls the `struct AuditorIterateContext *`
- * @param filename name of a file that should contain
- * a denomination key
- * @return #GNUNET_OK to continue to iterate
- * #GNUNET_NO to abort iteration with success
- * #GNUNET_SYSERR to abort iteration with failure
- */
-static int
-auditor_iter (void *cls,
- const char *filename)
-{
- struct AuditorIterateContext *aic = cls;
- uint64_t size;
- struct AuditorFileHeaderP *af;
- const struct TALER_AuditorSignatureP *sigs;
- const struct TALER_DenominationKeyValidityPS *dki;
- unsigned int len;
- int ret;
-
- if (GNUNET_OK != GNUNET_DISK_file_size (filename,
- &size,
- GNUNET_YES,
- GNUNET_YES))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping inaccessable auditor information file `%s'\n",
- filename);
- return GNUNET_SYSERR;
- }
- if ( (size < sizeof (struct AuditorFileHeaderP)) ||
- (0 != (len = ((size - sizeof (struct AuditorFileHeaderP)) %
- (sizeof (struct TALER_DenominationKeyValidityPS) +
- sizeof (struct TALER_AuditorSignatureP))))) )
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- af = GNUNET_malloc (size);
- if (size !=
- GNUNET_DISK_fn_read (filename,
- af,
- size))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "read",
- filename);
- GNUNET_free (af);
- return GNUNET_SYSERR;
- }
- sigs = (const struct TALER_AuditorSignatureP *) &af[1];
- dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[len];
- ret = aic->it (aic->it_cls,
- &af->apub,
- &af->mpub,
- len,
- sigs,
- dki);
- GNUNET_free (af);
- return ret;
-}
-
-
-/**
- * Call @a it with information for each auditor found in the @a mint_base_dir.
- *
- * @param mint_base_dir base directory for the mint,
- * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS
- * subdirectory
- * @param it function to call with auditor information
- * @param it_cls closure for @a it
- * @return -1 on error, 0 if no files were found, otherwise
- * a positive number (however, even with a positive
- * number it is possible that @a it was never called
- * as maybe none of the files were well-formed)
- */
-int
-TALER_MINTDB_auditor_iterate (const char *mint_base_dir,
- TALER_MINTDB_AuditorIterator it,
- void *it_cls)
-{
- char *dir;
- struct AuditorIterateContext aic;
- int ret;
-
- GNUNET_asprintf (&dir,
- "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_AUDITORS,
- mint_base_dir);
- aic.it = it;
- aic.it_cls = it_cls;
- ret = GNUNET_DISK_directory_scan (dir,
- &auditor_iter,
- &aic);
- GNUNET_free (dir);
- return ret;
-}
-
-
-/**
- * Write auditor information to the given file.
- *
- * @param filename the file where to write the auditor information to
- * @param apub the auditor's public key
- * @param asigs the auditor's signatures, array of length @a dki_len
- * @param mpub the mint's public key (as expected by the auditor)
- * @param dki_len length of @a dki
- * @param dki array of denomination coin data signed by the auditor
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
- */
-int
-TALER_MINTDB_auditor_write (const char *filename,
- const struct TALER_AuditorPublicKeyP *apub,
- const struct TALER_AuditorSignatureP *asigs,
- const struct TALER_MasterPublicKeyP *mpub,
- unsigned int dki_len,
- const struct TALER_DenominationKeyValidityPS *dki)
-{
- struct AuditorFileHeaderP af;
- struct GNUNET_DISK_FileHandle *fh;
- ssize_t wrote;
- size_t wsize;
- int ret;
- int eno;
-
- af.apub = *apub;
- af.mpub = *mpub;
- ret = GNUNET_SYSERR;
- if (NULL == (fh = GNUNET_DISK_file_open
- (filename,
- GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
- GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
- goto cleanup;
- wsize = sizeof (struct AuditorFileHeaderP);
- if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
- &af,
- wsize)))
- goto cleanup;
- if (wrote != wsize)
- goto cleanup;
- wsize = dki_len * sizeof (struct TALER_AuditorSignatureP);
- if (wsize ==
- GNUNET_DISK_file_write (fh,
- asigs,
- wsize))
- ret = GNUNET_OK;
- wsize = dki_len * sizeof (struct TALER_DenominationKeyValidityPS);
- if (wsize ==
- GNUNET_DISK_file_write (fh,
- dki,
- wsize))
- ret = GNUNET_OK;
- cleanup:
- eno = errno;
- if (NULL != fh)
- (void) GNUNET_DISK_file_close (fh);
- errno = eno;
- return ret;
-}
-
-
-/* end of mintdb_keyio.c */
diff --git a/src/mintdb/mintdb_plugin.c b/src/mintdb/mintdb_plugin.c
deleted file mode 100644
index 4a0f1dc04..000000000
--- a/src/mintdb/mintdb_plugin.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mintdb/mintdb_plugin.c
- * @brief Logic to load database plugin
- * @author Christian Grothoff
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include "taler_mintdb_plugin.h"
-#include <ltdl.h>
-
-
-/**
- * Initialize the plugin.
- *
- * @param cfg configuration to use
- * @return #GNUNET_OK on success
- */
-struct TALER_MINTDB_Plugin *
-TALER_MINTDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- char *plugin_name;
- char *lib_name;
- struct GNUNET_CONFIGURATION_Handle *cfg_dup;
- struct TALER_MINTDB_Plugin *plugin;
-
- if (GNUNET_SYSERR ==
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "db",
- &plugin_name))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "db");
- return NULL;
- }
- (void) GNUNET_asprintf (&lib_name,
- "libtaler_plugin_mintdb_%s",
- plugin_name);
- GNUNET_free (plugin_name);
- cfg_dup = GNUNET_CONFIGURATION_dup (cfg);
- plugin = GNUNET_PLUGIN_load (lib_name, cfg_dup);
- if (NULL != plugin)
- plugin->library_name = lib_name;
- else
- GNUNET_free (lib_name);
- GNUNET_CONFIGURATION_destroy (cfg_dup);
- return plugin;
-}
-
-
-/**
- * Shutdown the plugin.
- *
- * @param plugin the plugin to unload
- */
-void
-TALER_MINTDB_plugin_unload (struct TALER_MINTDB_Plugin *plugin)
-{
- char *lib_name;
-
- if (NULL == plugin)
- return;
- lib_name = plugin->library_name;
- GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
- plugin));
- GNUNET_free (lib_name);
-}
-
-
-
-/* end of mintdb_plugin.c */
diff --git a/src/mintdb/perf_taler_mintdb.c b/src/mintdb/perf_taler_mintdb.c
deleted file mode 100644
index fbaa2ce34..000000000
--- a/src/mintdb/perf_taler_mintdb.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file mintdb/perf_taler_mintdb.c
- * @brief Mint database performance analysis
- * @author Nicolas Fournier
- */
-#include "platform.h"
-#include "perf_taler_mintdb_interpreter.h"
-
-
-#define NB_DENOMINATION_INIT 15
-#define NB_DENOMINATION_SAVE 15
-
-#define SMALL 1000
-#define BIG 10000
-#define BIGGER 100000
-
-#define NB_RESERVE_INIT BIGGER
-#define NB_RESERVE_SAVE BIG
-
-#define NB_DEPOSIT_INIT BIGGER
-#define NB_DEPOSIT_SAVE BIG
-
-#define NB_WITHDRAW_INIT BIGGER
-#define NB_WITHDRAW_SAVE BIG
-
-#define NB_REFRESH_INIT BIGGER
-#define NB_REFRESH_SAVE BIG
-
-#define NB_MELT_INIT BIG
-#define NB_MELT_SAVE SMALL
-
-/**
- * Runs the performances tests for the mint database
- * and logs the results using Gauger
- */
-int
-main (int argc, char ** argv)
-{
- int ret;
- struct PERF_TALER_MINTDB_Cmd benchmark[] =
- {
- /* Denomination used to create coins */
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("Initializing database"),
-
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("01 - denomination loop",
- NB_DENOMINATION_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert",
- "01 - denomination"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination",
- "01 - denomination loop",
- "01 - denomination",
- NB_DENOMINATION_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("01 - end",
- "01 - denomination loop"),
- /* End of initialization */
- /* Reserve initialization */
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("02 - init reserve loop",
- NB_RESERVE_INIT),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("02 - insert",
- "02 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve",
- "02 - init reserve loop",
- "02 - reserve",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("02 - end",
- "02 - init reserve loop"),
- /* End reserve init */
- /* Withdrawal initialization */
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("03 - init withdraw loop",
- NB_WITHDRAW_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load",
- "03 - init withdraw loop",
- "01 - save denomination"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load",
- "03 - init withdraw loop",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw",
- "03 - denomination load",
- "03 - reserve load"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert",
- "03 - withdraw"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("03 - save coin",
- "03 - init withdraw loop",
- "03 - withdraw",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("03 - end",
- "03 - init withdraw loop"),
- /*End of withdrawal initialization */
- /*Deposit initialization */
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("04 - deposit init loop",
- NB_DEPOSIT_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("04 - coin load",
- "04 - deposit init loop",
- "03 - save coin"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit",
- "04 - coin load"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert",
- "04 - deposit"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array",
- "04 - deposit init loop",
- "04 - deposit",
- NB_DEPOSIT_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "04 - deposit init loop"),
- /* End of deposit initialization */
- /* Session initialization */
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("05 - refresh session init loop",
- NB_REFRESH_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_REFRESH_SESSION ("05 - refresh session"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("05 - session array",
- "05 - refresh session init loop",
- "05 - refresh session",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("05 - end",
- "05 - refresh session init loop"),
- /* End of refresh session initialization */
- /* Refresh melt initialization */
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("06 - refresh melt init loop",
- NB_MELT_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- /* TODO: initialize using coins & sessions created localy
- * in order to make sure the same coin are not melted twice*/
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("06 - session hash",
- "06 - refresh melt init loop",
- "05 - session array"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("06 - coin",
- "06 - refresh melt init loop",
- "03 - save coin"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_REFRESH_MELT ("06 - refresh melt",
- "06 - session hash",
- "06 - coin"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("06 - end",
- "06 - refresh melt init loop"),
- /* End of refresh melt initialization */
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of initialization"),
-
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("Start of performances measuring"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("21 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("21 - reserve insert measure",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("21 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("21 - insert",
- "21 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "21 - reserve insert measure"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("21 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("21 - gauger",
- "21 - start",
- "21 - stop",
- "POSTGRES",
- "Number of reserve inserted per second",
- "item/sec",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of reserve insertion"),
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("22 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("22 - reserve load measure",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("22 - reserve",
- "22 - reserve load measure",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE ("22 - get",
- "22 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "22 - reserve load measure"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("22 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "22 - start",
- "22 - stop",
- "POSTGRES",
- "Number of reserve loaded per second",
- "item/sec",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of reserve retreival"),
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("23 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("23 - reserve history measure",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("23 - reserve",
- "23 - reserve history measure",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE_HISTORY ("",
- "23 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "23 - reserve history measure"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("23 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "23 - start",
- "23 - stop",
- "POSTGRES",
- "Number of reserve history loaded per second",
- "item/sec",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of reserve history access"),
-
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("24 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("24 - withdraw insert measure",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("24 - reserve",
- "24 - withdraw insert measure",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("24 - denomination",
- "24 - withdraw insert measure",
- "01 - save denomination"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("24 - withdraw",
- "24 - denomination",
- "24 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("24 - insert",
- "24 - withdraw"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "24 - withdraw insert measure"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("24 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "24 - start",
- "24 - stop",
- "POSTGRES",
- "Number of withdraw insert per second",
- "item/sec",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of withdraw insertion"),
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("25 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("25 - withdraw insert measure",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("25 - coin",
- "25 - withdraw insert measure",
- "03 - save coin"),
- PERF_TALER_MINTDB_INIT_CMD_GET_WITHDRAW ("",
- "25 - coin"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "25 - withdraw insert measure"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("25 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "25 - start",
- "25 - stop",
- "POSTGRES",
- "Number of withdraw loaded per second",
- "item/sec",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of withdraw loading"),
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("26 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("26 - get coin transaction",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("26 - coin",
- "26 - get coin transaction",
- "03 - save coin"),
- PERF_TALER_MINTDB_INIT_CMD_GET_COIN_TRANSACTION("",
- "26 - coin"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "26 - get coin transaction"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("26 - end"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "26 - start",
- "26 - end",
- "POSTGRES",
- "Number of coin transaction history loaded per second",
- "item/sec",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of transaction loading"),
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("27 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("27 - /reserve/withdraw",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("27 - reserve",
- "27 - /reserve/withdraw",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("27 - dki",
- "27 - /reserve/withdraw",
- "01 - save denomination"),
- PERF_TALER_MINTDB_INIT_CMD_WITHDRAW_SIGN ("",
- "27 - dki",
- "27 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "27 - /reserve/withdraw"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("27 - end"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "27 - start",
- "27 - end",
- "POSTGRES",
- "Number of /reserve/withdraw per second",
- "item/sec",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of /reserve/withdraw"),
-
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("28 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("28 - /deposit",
- NB_DEPOSIT_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("28 - coin",
- "28 - /deposit",
- "03 - save coin"),
- PERF_TALER_MINTDB_INIT_CMD_DEPOSIT ("28 - deposit",
- "28 - coin"),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "28 - /deposit"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("28 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "28 - start",
- "28 - stop",
- "POSTGRES",
- "Number of /deposit per second",
- "item/sec",
- NB_DEPOSIT_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("29 - start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("29 - insert refresh session",
- NB_REFRESH_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_REFRESH_SESSION (""),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "29 - insert refresh session"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("29 - stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("",
- "29 - start",
- "29 - stop",
- "POSTGRES",
- "Number of refresh session inserted per second",
- "item/sec",
- NB_REFRESH_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END (""),
- };
-
- ret = PERF_TALER_MINTDB_run_benchmark (
- "perf-taler-mintdb",
- "./test-mint-db-postgres.conf",
- (struct PERF_TALER_MINTDB_Cmd []) {PERF_TALER_MINTDB_INIT_CMD_END("")},
- benchmark);
- if (GNUNET_SYSERR == ret)
- return 1;
- return 0;
-}
diff --git a/src/mintdb/perf_taler_mintdb_init.c b/src/mintdb/perf_taler_mintdb_init.c
deleted file mode 100644
index ccfc6a05a..000000000
--- a/src/mintdb/perf_taler_mintdb_init.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file mintdb/perf_taler_mintdb_init.c
- * @brief Interpreter library for mint database performance analysis
- * @author Nicolas Fournier
- */
-#include "platform.h"
-#include "perf_taler_mintdb_init.h"
-#include <gnunet/gnunet_signatures.h>
-#include "taler_signatures.h"
-#include "taler_amount_lib.h"
-
-
-#define CURRENCY "EUR"
-#define PERF_TALER_MINTDB_RSA_SIZE 512
-
-
-/**
- * Generate a dummy DenominationKeyInformation for testing purposes
- * @return a dummy denomination key
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation *
-PERF_TALER_MINTDB_denomination_init ()
-{
- struct GNUNET_CRYPTO_EddsaPrivateKey *master_prvt;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- struct TALER_DenominationPrivateKey denom_priv;
- struct TALER_DenominationPublicKey denom_pub;
- struct TALER_MINTDB_DenominationKeyInformationP issue;
-
- master_prvt = GNUNET_CRYPTO_eddsa_key_create();
-
- dki = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation);
- GNUNET_assert (NULL != dki);
- denom_priv.rsa_private_key
- = GNUNET_CRYPTO_rsa_private_key_create (PERF_TALER_MINTDB_RSA_SIZE);
- GNUNET_assert (NULL != denom_priv.rsa_private_key);
- denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv.rsa_private_key);
- GNUNET_assert (NULL != denom_pub.rsa_public_key);
- {/* issue */
- struct TALER_MasterSignatureP signature;
- struct TALER_DenominationKeyValidityPS properties;
-
- {/* properties */
- struct TALER_Amount amount;
-
- properties.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
- properties.purpose.size = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
- GNUNET_CRYPTO_eddsa_key_get_public (master_prvt,
- &properties.master.eddsa_pub);
- properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get());
- properties.expire_withdraw = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
- properties.expire_spend = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
- properties.expire_legal = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.1", &amount));
- TALER_amount_hton (&properties.value, &amount);
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.1", &amount));
- TALER_amount_hton (&properties.fee_withdraw, &amount);
- TALER_amount_hton (&properties.fee_deposit, &amount);
- TALER_amount_hton (&properties.fee_refresh, &amount);
- GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
- &properties.denom_hash);
- issue.properties = properties;
- }
- {/* signature */
- GNUNET_CRYPTO_eddsa_sign (master_prvt,
- &properties.purpose,
- &signature.eddsa_signature);
- issue.signature = signature;
- }
- }
- dki->denom_priv = denom_priv;
- dki->denom_pub = denom_pub;
- dki->issue = issue;
- GNUNET_free (master_prvt);
- return dki;
-}
-
-
-/**
- * Copies the given denomination
- * @param reserve the deposit copy
- * @return a copy of @a deposit; NULL if error
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation *
-PERF_TALER_MINTDB_denomination_copy (const struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- struct TALER_MINTDB_DenominationKeyIssueInformation *copy;
-
- GNUNET_assert (NULL !=
- (copy = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation)));
- {/* denom_priv */
- copy->denom_priv.rsa_private_key =
- GNUNET_CRYPTO_rsa_private_key_dup ( dki->denom_priv.rsa_private_key);
- }
- {/* denom_pub */
- copy->denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
- }
- {/* issue */
- copy->issue.properties = dki->issue.properties;
- copy->issue.signature = dki->issue.signature;
- }
- return copy;
-}
-
-
-/**
- * Free memory of a DenominationKeyIssueInformation
- * @param dki pointer to the struct to free
- */
-int
-PERF_TALER_MINTDB_denomination_free (struct TALER_MINTDB_DenominationKeyIssueInformation *dki)
-{
- if (NULL == dki)
- return GNUNET_OK;
- GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key);
-
- GNUNET_free (dki);
- return GNUNET_OK;
-}
-
-
-/**
- * Generate a dummy reserve for testing
- * @return a reserve with 1000 EUR in it
- */
-struct PERF_TALER_MINTDB_Reserve *
-PERF_TALER_MINTDB_reserve_init ()
-{
- struct PERF_TALER_MINTDB_Reserve *reserve;
-
- GNUNET_assert (NULL !=
- (reserve = GNUNET_new (struct PERF_TALER_MINTDB_Reserve)));
- {/* private */
- struct GNUNET_CRYPTO_EddsaPrivateKey *private;
- private = GNUNET_CRYPTO_eddsa_key_create ();
- GNUNET_assert (NULL != private);
- reserve->private = *private;
- GNUNET_free (private);
- }
-
- GNUNET_CRYPTO_eddsa_key_get_public (&reserve->private,
- &reserve->reserve.pub.eddsa_pub);
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1000", &reserve->reserve.balance));
- reserve->reserve.expiry = GNUNET_TIME_absolute_get_forever_ ();
- return reserve;
-}
-
-
-/**
- * Copies the given reserve
- * @param reserve the reserve to copy
- * @return a copy of @a reserve; NULL if error
- */
-struct PERF_TALER_MINTDB_Reserve *
-PERF_TALER_MINTDB_reserve_copy (const struct PERF_TALER_MINTDB_Reserve *reserve)
-{
- struct PERF_TALER_MINTDB_Reserve *copy;
- GNUNET_assert (NULL !=
- (copy = GNUNET_new (struct PERF_TALER_MINTDB_Reserve)));
- *copy = *reserve;
- return copy;
-}
-
-
-/**
- * Free memory of a reserve
- * @param reserve pointer to the structure to be freed
- */
-int
-PERF_TALER_MINTDB_reserve_free (struct PERF_TALER_MINTDB_Reserve *reserve)
-{
- if (NULL == reserve)
- return GNUNET_OK;
- GNUNET_free (reserve);
- return GNUNET_OK;
-}
-
-
-/**
- * Generate a dummy deposit for testing purposes
- * @param dki the denomination key used to sign the key
- */
-struct TALER_MINTDB_Deposit *
-PERF_TALER_MINTDB_deposit_init (const struct PERF_TALER_MINTDB_Coin *coin)
-{
- struct TALER_MINTDB_Deposit *deposit;
- struct TALER_CoinSpendSignatureP csig;
- struct TALER_MerchantPublicKeyP merchant_pub;
- struct GNUNET_HashCode h_contract;
- struct GNUNET_HashCode h_wire;
- const char wire[] = "{"
- "\"type\":\"SEPA\","
- "\"IBAN\":\"DE67830654080004822650\","
- "\"NAME\":\"GNUNET E.\","
- "\"BIC\":\"GENODEF1SRL\""
- "}";
- static uint64_t transaction_id = 0;
- struct GNUNET_TIME_Absolute timestamp;
- struct GNUNET_TIME_Absolute refund_deadline;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
-
- GNUNET_assert (NULL !=
- (deposit = GNUNET_malloc (sizeof (struct TALER_MINTDB_Deposit) + sizeof (wire))));
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &h_contract);
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &h_wire);
- { //csig
- struct u32_presign
- {
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_contract;
- } unsigned_data;
-
- unsigned_data.h_contract = h_contract;
- unsigned_data.h_wire = h_wire;
- unsigned_data.purpose.size = htonl (sizeof (struct u32_presign));
- unsigned_data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&coin->priv,
- &unsigned_data.purpose,
- &csig.eddsa_signature));
- }
- { //merchant_pub
- struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_prv;
-
- eddsa_prv = GNUNET_CRYPTO_eddsa_key_create ();
- GNUNET_assert(NULL != eddsa_prv);
- GNUNET_CRYPTO_eddsa_key_get_public (
- eddsa_prv,
- &merchant_pub.eddsa_pub);
- GNUNET_free (eddsa_prv);
- }
- timestamp = GNUNET_TIME_absolute_get ();
- refund_deadline = GNUNET_TIME_absolute_get ();
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.1",
- &amount_with_fee));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.1",
- &deposit_fee));
- {
- deposit->coin.coin_pub = coin->public_info.coin_pub;
- deposit->coin.denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (
- coin->public_info.denom_pub.rsa_public_key);
- GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key);
- deposit->coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (
- coin->public_info.denom_sig.rsa_signature);
- GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature);
- }
- deposit->csig = csig;
- deposit->h_contract = h_contract;
- deposit->h_wire = h_wire;
- deposit->wire = json_loads (wire, 0, NULL);
- deposit->transaction_id = transaction_id++;
- deposit->timestamp = timestamp;
- deposit->refund_deadline = refund_deadline;
- deposit->amount_with_fee = amount_with_fee;
- deposit->deposit_fee = deposit_fee;
- return deposit;
-}
-
-
-/**
- * Copies the given deposit
- * @param reserve the deposit copy
- * @return a copy of @a deposit; NULL if error
- */
-struct TALER_MINTDB_Deposit *
-PERF_TALER_MINTDB_deposit_copy (const struct TALER_MINTDB_Deposit *deposit)
-{
- struct TALER_MINTDB_Deposit *copy;
-
- copy = GNUNET_new (struct TALER_MINTDB_Deposit);
- *copy = *deposit;
- json_incref (copy->wire);
- copy->coin.denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (deposit->coin.denom_pub.rsa_public_key);
- copy->coin.denom_sig.rsa_signature =
- GNUNET_CRYPTO_rsa_signature_dup (deposit->coin.denom_sig.rsa_signature);
- return copy;
-}
-
-
-/**
- * Free memory of a deposit
- * @param deposit pointer to the structure to free
- */
-int
-PERF_TALER_MINTDB_deposit_free (struct TALER_MINTDB_Deposit *deposit)
-{
- if (NULL == deposit)
- return GNUNET_OK;
- GNUNET_CRYPTO_rsa_public_key_free (deposit->coin.denom_pub.rsa_public_key);
- GNUNET_CRYPTO_rsa_signature_free (deposit->coin.denom_sig.rsa_signature);
- json_decref (deposit->wire);
- GNUNET_free (deposit);
- return GNUNET_OK;
-}
-
-
-/**
- * Generate a CollectableBlindcoin for testing purpuses
- * @param dki denomination key used to sign the coin
- * @param reserve reserve providing the money for the coin
- * @return a randomly generated CollectableBlindcoin
- */
-struct PERF_TALER_MINTDB_Coin *
-PERF_TALER_MINTDB_coin_init (
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki,
- const struct PERF_TALER_MINTDB_Reserve *reserve)
-{
- struct PERF_TALER_MINTDB_Coin *coin;
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
- coin = GNUNET_new (struct PERF_TALER_MINTDB_Coin);
- GNUNET_assert (NULL != coin);
- /* priv */
-
- priv = GNUNET_CRYPTO_eddsa_key_create();
- GNUNET_assert (NULL != priv);
- coin->priv = *priv;
- GNUNET_free (priv);
-
- /* public_info */
- GNUNET_CRYPTO_eddsa_key_get_public (&coin->priv,
- &coin->public_info.coin_pub.eddsa_pub);
- coin->public_info.denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
- coin->public_info.denom_sig.rsa_signature =
- GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
- &coin->public_info.coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP));
- GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key);
- GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature);
-
- /* blind */
- coin->blind.sig.rsa_signature =
- GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
- coin->blind.denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
- GNUNET_assert (NULL != coin->blind.sig.rsa_signature);
- GNUNET_assert (NULL != coin->blind.denom_pub.rsa_public_key);
- TALER_amount_ntoh (&coin->blind.amount_with_fee,
- &dki->issue.properties.value);
- TALER_amount_ntoh (&coin->blind.withdraw_fee,
- &dki->issue.properties.fee_withdraw);
- coin->blind.reserve_pub = reserve->reserve.pub;
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &coin->blind.h_coin_envelope);
-
- return coin;
-}
-
-
-/**
- * Copies the given coin
- *
- * @param coin the coin to copy
- * @return a copy of coin; NULL if error
- */
-struct PERF_TALER_MINTDB_Coin *
-PERF_TALER_MINTDB_coin_copy (const struct PERF_TALER_MINTDB_Coin *coin)
-{
- struct PERF_TALER_MINTDB_Coin *copy;
-
- copy = GNUNET_new (struct PERF_TALER_MINTDB_Coin);
- /* priv */
- copy->priv = coin->priv;
- /* public_info */
- copy->public_info.coin_pub = coin->public_info.coin_pub;
- copy->public_info.denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key);
- copy->public_info.denom_sig.rsa_signature =
- GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
-
- /* blind */
- copy->blind.sig.rsa_signature =
- GNUNET_CRYPTO_rsa_signature_dup (coin->blind.sig.rsa_signature);
- copy->blind.denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (coin->blind.denom_pub.rsa_public_key);
- copy->blind.amount_with_fee = coin->blind.amount_with_fee;
- copy->blind.withdraw_fee = coin->blind.withdraw_fee;
- copy->blind.reserve_pub = coin->blind.reserve_pub;
- copy->blind.h_coin_envelope = coin->blind.h_coin_envelope;
- copy->blind.reserve_sig = coin->blind.reserve_sig;
-
- return copy;
-}
-
-
-/**
- * Free memory of @a coin
- *
- * @param coin pointer to the structure to free
- */
-int
-PERF_TALER_MINTDB_coin_free (struct PERF_TALER_MINTDB_Coin *coin)
-{
- if (NULL == coin)
- return GNUNET_OK;
- GNUNET_CRYPTO_rsa_public_key_free (coin->public_info.denom_pub.rsa_public_key);
- GNUNET_CRYPTO_rsa_signature_free (coin->public_info.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_signature_free (coin->blind.sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (coin->blind.denom_pub.rsa_public_key);
- GNUNET_free (coin);
- return GNUNET_OK;
-}
-
-
-/**
- * @return a randomly generated refresh session
- */
-struct TALER_MINTDB_RefreshSession *
-PERF_TALER_MINTDB_refresh_session_init ()
-{
- struct TALER_MINTDB_RefreshSession *refresh_session;
-
- GNUNET_assert (NULL !=
- (refresh_session = GNUNET_new (struct TALER_MINTDB_RefreshSession)));
- refresh_session->noreveal_index = 1;
- refresh_session->num_oldcoins = 1;
- refresh_session->num_newcoins = 1;
-
- return refresh_session;
-}
-
-
-/**
- * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't
- */
-int
-PERF_TALER_MINTDB_refresh_session_copy (struct TALER_MINTDB_RefreshSession *session,
- struct TALER_MINTDB_RefreshSession *copy)
-{
- *copy = *session;
- return GNUNET_OK;
-}
-
-
-/**
- * Free a refresh session
- */
-int
-PERF_TALER_MINTDB_refresh_session_free (struct TALER_MINTDB_RefreshSession *refresh_session)
-{
- if (NULL == refresh_session)
- return GNUNET_OK;
- GNUNET_free (refresh_session);
- return GNUNET_OK;
-}
-
-
-/**
- * Create a melt operation
- *
- * @param session the refresh session
- * @param dki the denomination the melted coin uses
- * @return a pointer to a #TALER_MINTDB_RefreshMelt
- */
-struct TALER_MINTDB_RefreshMelt *
-PERF_TALER_MINTDB_refresh_melt_init (struct GNUNET_HashCode *session,
- struct PERF_TALER_MINTDB_Coin *coin)
-{
- struct TALER_MINTDB_RefreshMelt *melt;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct TALER_Amount amount;
- struct TALER_Amount amount_with_fee;
-
- {
- struct
- {
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode session;
- } to_sign;
-
- to_sign.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_TEST;
- to_sign.purpose.size = htonl (sizeof (to_sign));
- to_sign.session = *session;
- GNUNET_CRYPTO_eddsa_sign (&coin->priv,
- &to_sign.purpose,
- &coin_sig.eddsa_signature);
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.1",
- &amount));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.1",
- &amount_with_fee));
- melt = GNUNET_new (struct TALER_MINTDB_RefreshMelt);
- melt->coin.coin_pub = coin->public_info.coin_pub;
- melt->coin.denom_sig.rsa_signature =
- GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature);
- melt->coin.denom_pub.rsa_public_key =
- GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key);
- GNUNET_assert (NULL != melt->coin.denom_pub.rsa_public_key);
- GNUNET_assert (NULL != melt->coin.denom_sig.rsa_signature);
- melt->coin_sig = coin_sig;
- melt->session_hash = *session;
- melt->amount_with_fee = amount;
- melt->melt_fee = amount_with_fee;
- return melt;
-}
-
-
-/**
- * Copies the internals of a #TALER_MINTDB_RefreshMelt
- *
- * @param melt the refresh melt to copy
- * @return an copy of @ melt
- */
-struct TALER_MINTDB_RefreshMelt *
-PERF_TALER_MINTDB_refresh_melt_copy (const struct TALER_MINTDB_RefreshMelt *melt)
-{
- struct TALER_MINTDB_RefreshMelt *copy;
-
- copy = GNUNET_new (struct TALER_MINTDB_RefreshMelt);
- *copy = *melt;
- copy->coin.denom_sig.rsa_signature =
- GNUNET_CRYPTO_rsa_signature_dup (melt->coin.denom_sig.rsa_signature);
- GNUNET_assert (NULL != copy->coin.denom_sig.rsa_signature);
-
- return copy;
-}
-
-
-/**
- * Free the internal memory of a #TALER_MINTDB_RefreshMelt
- *
- * @param melt the #TALER_MINTDB_RefreshMelt to free
- * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR
- */
-int
-PERF_TALER_MINTDB_refresh_melt_free (struct TALER_MINTDB_RefreshMelt *melt)
-{
- GNUNET_CRYPTO_rsa_signature_free (melt->coin.denom_sig.rsa_signature);
- GNUNET_free (melt);
- return GNUNET_OK;
-}
-
-
-/**
- * Create a #TALER_MINTDB_RefreshCommitCoin
- */
-struct TALER_MINTDB_RefreshCommitCoin *
-PERF_TALER_MINTDB_refresh_commit_coin_init ()
-{
- struct TALER_MINTDB_RefreshCommitCoin *commit_coin;
- struct TALER_RefreshLinkEncrypted refresh_link;
-
- commit_coin = GNUNET_new (struct TALER_MINTDB_RefreshCommitCoin);
- GNUNET_assert (NULL != commit_coin);
- {/* refresh_link */
- refresh_link = (struct TALER_RefreshLinkEncrypted)
- {
- .blinding_key_enc = "blinding_key",
- .blinding_key_enc_size = 13
- };
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- &refresh_link.coin_priv_enc,
- sizeof(struct TALER_CoinSpendPrivateKeyP));
- }
- commit_coin->coin_ev = "coin_ev";
- commit_coin->coin_ev_size = 8;
- commit_coin->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted);
- *commit_coin->refresh_link = refresh_link;
- return commit_coin;
-}
-
-
-/**
- * Copies a #TALER_MINTDB_RefreshCommitCoin
- *
- * @param commit_coin the commit to copy
- * @return a copy of @a commit_coin
- */
-struct TALER_MINTDB_RefreshCommitCoin *
-PERF_TALER_MINTDB_refresh_commit_coin_copy (struct TALER_MINTDB_RefreshCommitCoin *commit_coin)
-{
- struct TALER_MINTDB_RefreshCommitCoin *copy;
-
- copy = GNUNET_new (struct TALER_MINTDB_RefreshCommitCoin);
- copy->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted);
- *copy->refresh_link = *commit_coin->refresh_link;
- return copy;
-}
-
-
-/**
- * Free a #TALER_MINTDB_RefreshCommitCoin
- *
- * @param commit_coin the coin to free
- */
-void
-PERF_TALER_MINTDB_refresh_commit_coin_free (struct TALER_MINTDB_RefreshCommitCoin *commit_coin)
-{
- GNUNET_free (commit_coin->refresh_link);
- GNUNET_free (commit_coin);
-}
diff --git a/src/mintdb/perf_taler_mintdb_init.h b/src/mintdb/perf_taler_mintdb_init.h
deleted file mode 100644
index f94beef10..000000000
--- a/src/mintdb/perf_taler_mintdb_init.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file mintdb/perf_taler_mintdb_init.h
- * @brief Heler function for creating dummy inputs for the mint database
- * @author Nicolas Fournier
- */
-#ifndef __PERF_TALER_MINTDB_INIT_H___
-#define __PERF_TALER_MINTDB_INIT_H___
-
-#include "taler_mintdb_plugin.h"
-
-
-#define CURRENCY "EUR"
-
-/**
- * All information about a reserve
- */
-struct PERF_TALER_MINTDB_Reserve
-{
- /**
- * Information about a rserve available to the Mint
- */
- struct TALER_MINTDB_Reserve reserve;
-
- /**
- * Private key of a reserve
- */
- struct GNUNET_CRYPTO_EddsaPrivateKey private;
-};
-
-
-/**
- * All informations about a coin
- */
-struct PERF_TALER_MINTDB_Coin
-{
- /**
- * Blinded coin, known by the mint
- */
- struct TALER_MINTDB_CollectableBlindcoin blind;
-
- /**
- * Public key of the coin and othes informations
- */
- struct TALER_CoinPublicInfo public_info;
-
- /**
- * Private key of the coin
- */
- struct GNUNET_CRYPTO_EddsaPrivateKey priv;
-};
-
-
-/**
- * Generate a dummy DenominationKeyInformation for testing purposes
- * @return a dummy denomination key
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation *
-PERF_TALER_MINTDB_denomination_init (void);
-
-
-/**
- * Copies the given denomination
- * @param reserve the deposit copy
- * @return a copy of @a deposit; NULL if error
- */
-struct TALER_MINTDB_DenominationKeyIssueInformation *
-PERF_TALER_MINTDB_denomination_copy (
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
-
-
-/**
- * Free memory of a DenominationKeyIssueInformation
- * @param dki pointer to the struct to free
- */
-int
-PERF_TALER_MINTDB_denomination_free (
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
-
-
-/**
- * Generate a dummy reserve for testing
- * @return a reserve with 1000 EUR in it
- */
-struct PERF_TALER_MINTDB_Reserve *
-PERF_TALER_MINTDB_reserve_init (void);
-
-
-/**
- * Copies the given reserve
- * @param reserve the reserve to copy
- * @return a copy of @a reserve; NULL if error
- */
-struct PERF_TALER_MINTDB_Reserve *
-PERF_TALER_MINTDB_reserve_copy (const struct PERF_TALER_MINTDB_Reserve *reserve);
-
-
-/**
- * Free memory of a reserve
- * @param reserve pointer to the structure to be freed
- */
-int
-PERF_TALER_MINTDB_reserve_free (struct PERF_TALER_MINTDB_Reserve *reserve);
-
-
-/**
- * Generate a dummy deposit for testing purposes
- * @param dki the denomination key used to sign the key
- */
-struct TALER_MINTDB_Deposit *
-PERF_TALER_MINTDB_deposit_init (
- const struct PERF_TALER_MINTDB_Coin *coin);
-
-
-/**
- * Copies the given deposit
- * @param reserve the deposit copy
- * @return a copy of @a deposit; NULL if error
- */
-struct TALER_MINTDB_Deposit *
-PERF_TALER_MINTDB_deposit_copy (const struct TALER_MINTDB_Deposit *deposit);
-
-
-/**
- * Free memory of a deposit
- * @param deposit pointer to the structure to free
- */
-int
-PERF_TALER_MINTDB_deposit_free (struct TALER_MINTDB_Deposit *deposit);
-
-
-/**
- * Generate a coin for testing purpuses
- * @param dki denomination key used to sign the coin
- * @param reserve reserve providing the money for the coin
- * @return a randomly generated CollectableBlindcoin
- */
-struct PERF_TALER_MINTDB_Coin *
-PERF_TALER_MINTDB_coin_init (
- const struct TALER_MINTDB_DenominationKeyIssueInformation *dki,
- const struct PERF_TALER_MINTDB_Reserve *reserve);
-
-
-/**
- * Copies the given coin
- * @param coin the coin to copy
- * @return a copy of coin; NULL if error
- */
-struct PERF_TALER_MINTDB_Coin *
-PERF_TALER_MINTDB_coin_copy (
- const struct PERF_TALER_MINTDB_Coin *coin);
-
-
-/**
- * Liberate memory of @a coin
- * @param coin pointer to the structure to free
- */
-int
-PERF_TALER_MINTDB_coin_free (
- struct PERF_TALER_MINTDB_Coin *coin);
-
-
-/**
- * @return a randomly generated refresh session
- */
-struct TALER_MINTDB_RefreshSession *
-PERF_TALER_MINTDB_refresh_session_init (void);
-
-
-/**
- * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't
- */
-int
-PERF_TALER_MINTDB_refresh_session_copy (struct TALER_MINTDB_RefreshSession *session,
- struct TALER_MINTDB_RefreshSession *copy);
-
-
-/**
- * Frees memory of a refresh_session
- */
-int
-PERF_TALER_MINTDB_refresh_session_free (
- struct TALER_MINTDB_RefreshSession *refresh_session);
-
-
-/**
- * Create a melt operation
- *
- * @param session the refresh session
- * @param dki the denomination the melted coin uses
- * @return a pointer to a #TALER_MINTDB_RefreshMelt
- */
-struct TALER_MINTDB_RefreshMelt *
-PERF_TALER_MINTDB_refresh_melt_init (struct GNUNET_HashCode *session,
- struct PERF_TALER_MINTDB_Coin *coin);
-
-
-/**
- * Copies the internals of a #TALER_MINTDB_RefreshMelt
- *
- * @param melt the refresh melt to copy
- * @return an copy of @ melt
- */
-struct TALER_MINTDB_RefreshMelt *
-PERF_TALER_MINTDB_refresh_melt_copy (const struct TALER_MINTDB_RefreshMelt *melt);
-
-
-/**
- * Free the internal memory of a #TALER_MINTDB_RefreshMelt
- *
- * @param melt the #TALER_MINTDB_RefreshMelt to free
- * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR
- */
-int
-PERF_TALER_MINTDB_refresh_melt_free (struct TALER_MINTDB_RefreshMelt *melt);
-
-
-/**
- * Create a #TALER_MINTDB_RefreshCommitCoin
- */
-struct TALER_MINTDB_RefreshCommitCoin *
-PERF_TALER_MINTDB_refresh_commit_coin_init (void);
-
-
-/**
- * Copies a #TALER_MINTDB_RefreshCommitCoin
- *
- * @param commit_coin the commit to copy
- * @return a copy of @a commit_coin
- */
-struct TALER_MINTDB_RefreshCommitCoin *
-PERF_TALER_MINTDB_refresh_commit_coin_copy (struct TALER_MINTDB_RefreshCommitCoin *commit_coin);
-
-
-/**
- * Free a #TALER_MINTDB_RefreshCommitCoin
- *
- * @param commit_coin the coin to free
- */
-void
-PERF_TALER_MINTDB_refresh_commit_coin_free (struct TALER_MINTDB_RefreshCommitCoin *commit_coin);
-
-#endif
diff --git a/src/mintdb/perf_taler_mintdb_interpreter.c b/src/mintdb/perf_taler_mintdb_interpreter.c
deleted file mode 100644
index 293d5f35f..000000000
--- a/src/mintdb/perf_taler_mintdb_interpreter.c
+++ /dev/null
@@ -1,1998 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file mintdb/perf_taler_mintdb_interpreter.c
- * @brief Interpreter library for mint database performance analysis
- * @author Nicolas Fournier
- */
-#include "platform.h"
-#include "perf_taler_mintdb_interpreter.h"
-#include "perf_taler_mintdb_init.h"
-#include "gauger.h"
-
-
-/**
- * Represents the state of the interpreter
- */
-struct PERF_TALER_MINTDB_interpreter_state
-{
- /**
- * State of the commands
- */
- struct PERF_TALER_MINTDB_Cmd *cmd;
-
- /**
- * Database plugin
- */
- struct TALER_MINTDB_Plugin *plugin;
-
- /**
- * Current database session
- */
- struct TALER_MINTDB_Session *session;
-
- /**
- * The current index of the interpreter
- */
- unsigned int i;
-};
-
-
-/**
- * Free the memory of @a data
- */
-static void
-data_free (struct PERF_TALER_MINTDB_Data *data)
-{
- switch (data->type)
- {
- case PERF_TALER_MINTDB_TIME:
- if (NULL == data->data.time)
- break;
- GNUNET_free (data->data.time);
- data->data.time = NULL;
- break;
-
- case PERF_TALER_MINTDB_DEPOSIT:
- if (NULL == data->data.deposit)
- break;
- PERF_TALER_MINTDB_deposit_free (data->data.deposit);
- data->data.deposit = NULL;
- break;
-
- case PERF_TALER_MINTDB_COIN:
- if (NULL == data->data.coin)
- break;
- PERF_TALER_MINTDB_coin_free (data->data.coin);
- data->data.coin = NULL;
- break;
-
- case PERF_TALER_MINTDB_RESERVE:
- if (NULL == data->data.reserve)
- break;
- PERF_TALER_MINTDB_reserve_free (data->data.reserve);
- data->data.reserve = NULL;
- break;
-
- case PERF_TALER_MINTDB_DENOMINATION_INFO:
- if (NULL == data->data.dki)
- break;
- PERF_TALER_MINTDB_denomination_free (data->data.dki);
- data->data.dki = NULL;
- break;
-
- case PERF_TALER_MINTDB_REFRESH_HASH:
- if (NULL == data->data.session_hash)
- break;
- GNUNET_free (data->data.session_hash);
- data->data.session_hash = NULL;
- break;
-
- case PERF_TALER_MINTDB_REFRESH_MELT:
- if (NULL == data->data.refresh_melt)
- break;
- PERF_TALER_MINTDB_refresh_melt_free (data->data.refresh_melt);
- data->data.refresh_melt = NULL;
- break;
-
- case PERF_TALER_MINTDB_NONE:
- break;
- }
-}
-
-
-/**
- * Copies @a data into @a copy
- *
- * @param data the data to be copied
- * @param[out] copy the copy made
- */
-static void
-data_copy (const struct PERF_TALER_MINTDB_Data *data,
- struct PERF_TALER_MINTDB_Data *copy)
-{
- copy->type = data->type;
- switch (data->type)
- {
- case PERF_TALER_MINTDB_TIME:
- copy->data.time = GNUNET_new (struct GNUNET_TIME_Absolute);
- *copy->data.time = *data->data.time;
- return;
-
- case PERF_TALER_MINTDB_DEPOSIT:
- copy->data.deposit
- = PERF_TALER_MINTDB_deposit_copy (data->data.deposit);
- return;
-
- case PERF_TALER_MINTDB_COIN:
- copy->data.coin
- = PERF_TALER_MINTDB_coin_copy (data->data.coin);
- return;
-
- case PERF_TALER_MINTDB_RESERVE:
- copy->data.reserve
- = PERF_TALER_MINTDB_reserve_copy (data->data.reserve);
- return;
-
- case PERF_TALER_MINTDB_DENOMINATION_INFO:
- copy->data.dki
- = PERF_TALER_MINTDB_denomination_copy (data->data.dki);
- return;
-
- case PERF_TALER_MINTDB_REFRESH_HASH:
- copy-> data.session_hash = GNUNET_new (struct GNUNET_HashCode);
- *copy->data.session_hash
- = *data->data.session_hash;
- break;
-
- case PERF_TALER_MINTDB_REFRESH_MELT:
- copy->data.refresh_melt
- = PERF_TALER_MINTDB_refresh_melt_copy (data->data.refresh_melt);
- break;
-
- case PERF_TALER_MINTDB_NONE:
- break;
- }
-}
-
-
-/**
- * Finds the first command in cmd with the name search
- *
- * @return the index of the first command with name search
- * #GNUNET_SYSERR if none found
- */
-static int
-cmd_find (const struct PERF_TALER_MINTDB_Cmd *cmd,
- const char *search)
-{
- unsigned int i;
-
- for (i=0; PERF_TALER_MINTDB_CMD_END != cmd[i].command; i++)
- if (0 == strcmp (cmd[i].label, search))
- return i;
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Initialization of a command array
- * and check for the type of the label
- *
- * @param cmd the comand array initialized
- * @return #GNUNET_OK if the initialization was sucessful
- * #GNUNET_SYSERR if there was a probleb. See the log for details
- */
-static int
-cmd_init (struct PERF_TALER_MINTDB_Cmd cmd[])
-{
- unsigned int i;
-
- for (i=0; PERF_TALER_MINTDB_CMD_END != cmd[i].command; i++)
- {
- switch (cmd[i].command)
- {
- case PERF_TALER_MINTDB_CMD_END_LOOP:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.end_loop.label_loop);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.end_loop.label_loop);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_CMD_LOOP != cmd[ret].command)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.end_loop.label_loop);
- return GNUNET_SYSERR;
- }
- cmd[i].details.end_loop.index_loop = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_SAVE_ARRAY:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.save_array.label_save);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.save_array.label_save);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_NONE == cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.save_array.label_save);
- return GNUNET_SYSERR;
- }
- cmd[i].details.save_array.index_save = ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.save_array.label_loop);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.save_array.label_loop);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_CMD_LOOP != cmd[ret].command)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.save_array.label_loop);
- return GNUNET_SYSERR;
- }
- cmd[i].details.save_array.index_loop = ret;
-
- GNUNET_assert (NULL == cmd[i].details.save_array.data_saved);
- cmd[i].details.save_array.data_saved =
- GNUNET_new_array (cmd[i].details.save_array.nb_saved,
- struct PERF_TALER_MINTDB_Data);
- cmd[i].details.save_array.type_saved =
- cmd[cmd[i].details.save_array.index_save].exposed.type;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_LOAD_ARRAY:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.load_array.label_save);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.load_array.label_save);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_CMD_SAVE_ARRAY != cmd[ret].command)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.load_array.label_save);
- return GNUNET_SYSERR;
- }
- cmd[i].details.load_array.index_save = ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.load_array.label_loop);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.load_array.label_loop);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_CMD_LOOP != cmd[ret].command)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.load_array.label_loop);
- return GNUNET_SYSERR;
- }
- cmd[i].details.load_array.index_loop = ret;
-
- cmd[i].details.load_array.permutation =
- GNUNET_CRYPTO_random_permute (
- GNUNET_CRYPTO_QUALITY_WEAK,
- cmd[cmd[i].details.load_array.index_save].details.save_array.nb_saved);
- GNUNET_assert (NULL != cmd[i].details.load_array.permutation);
-
- cmd[i].exposed.type = cmd[cmd[i].details.load_array.index_save].details.save_array.type_saved;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_LOAD_RANDOM:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.load_random.label_save);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.load_random.label_save);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_CMD_SAVE_ARRAY != cmd[ret].command)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.load_random.label_save);
- return GNUNET_SYSERR;
- }
- cmd[i].details.load_random.index_save = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GAUGER:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.gauger.label_start);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.gauger.label_start);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_TIME != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.gauger.label_start);
- return GNUNET_SYSERR;
- }
- cmd[i].details.gauger.index_start = ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.gauger.label_stop);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.gauger.label_stop);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_TIME != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.gauger.label_stop);
- return GNUNET_SYSERR;
- }
- cmd[i].details.gauger.index_stop = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.insert_denomination.label_denom);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_denomination.label_denom);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_denomination.label_denom);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_denomination.index_denom = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_DENOMINATION:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.get_denomination.label_denom);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_denomination.label_denom);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_denomination.label_denom);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_denomination.index_denom = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_RESERVE:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.insert_reserve.label_reserve);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_reserve.label_reserve);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_reserve.label_reserve);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_reserve.index_reserve = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_RESERVE:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.get_reserve.label_reserve);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_reserve.label_reserve);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_reserve.label_reserve);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_reserve.index_reserve = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.get_reserve_history.label_reserve);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_reserve_history.label_reserve);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_reserve_history.label_reserve);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_reserve_history.index_reserve = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.create_withdraw.label_dki);
- {
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.create_withdraw.label_dki);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.create_withdraw.label_dki);
- return GNUNET_SYSERR;
- }
- }
- cmd[i].details.create_withdraw.index_dki = ret;
- ret = cmd_find (cmd,
- cmd[i].details.create_withdraw.label_reserve);
- {
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.create_withdraw.label_reserve);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.create_withdraw.label_reserve);
- return GNUNET_SYSERR;
- }
- }
- cmd[i].details.create_withdraw.index_reserve = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.insert_withdraw.label_coin);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_withdraw.label_coin);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_withdraw.label_coin);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_withdraw.index_coin = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_WITHDRAW:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.get_withdraw.label_coin);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_withdraw.label_coin);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_withdraw.label_coin);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_withdraw.index_coin = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_coin_transaction.label_coin);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_coin_transaction.label_coin);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_coin_transaction.label_coin);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_coin_transaction.index_coin = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.create_deposit.label_coin);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.create_deposit.label_coin);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.create_deposit.label_coin);
- return GNUNET_SYSERR;
- }
- cmd[i].details.create_deposit.index_coin = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT:
- {
- int ret;
-
- ret = cmd_find( cmd,
- cmd[i].details.insert_deposit.label_deposit);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_deposit.label_deposit);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_DEPOSIT != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_deposit.label_deposit);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_deposit.index_deposit = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_DEPOSIT:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.get_deposit.label_deposit);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_deposit.label_deposit);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_DEPOSIT != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_deposit.label_deposit);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_deposit.index_deposit = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.get_refresh_session.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_refresh_session.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_refresh_session.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_refresh_session.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT:
- {
- int ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_melt.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_melt.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_melt.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_melt.index_hash = ret;
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_melt.label_coin);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_melt.label_coin);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_melt.label_coin);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_melt.index_coin = ret; }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_refresh_melt.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_refresh_melt.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_refresh_melt.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_refresh_melt.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_order.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_order.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_order.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_order.index_hash = ret;
-
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_order.label_denom);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_order.label_denom);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_order.label_denom);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_order.index_denom = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_refresh_order.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_refresh_order.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_refresh_order.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_refresh_order.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_commit_coin.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_commit_coin.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_commit_coin.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_commit_coin.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_refresh_commit_coin.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_refresh_commit_coin.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_refresh_commit_coin.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_refresh_commit_coin.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_commit_link.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_commit_link.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_commit_link.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_commit_link.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_refresh_commit_link.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_refresh_commit_link.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_refresh_commit_link.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_refresh_commit_link.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_melt_commitment.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_melt_commitment.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_melt_commitment.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_melt_commitment.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.insert_refresh_out.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.insert_refresh_out.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.insert_refresh_out.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.insert_refresh_out.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_link_data_list.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_link_data_list.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_link_data_list.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_link_data_list.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_TRANSFER:
- {
- int ret;
- ret = cmd_find (cmd,
- cmd[i].details.get_transfer.label_hash);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Undefined reference to %s\n",
- i,
- cmd[i].details.get_transfer.label_hash);
- return GNUNET_SYSERR;
- }
- if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%d:Wrong type reference to %s\n",
- i,
- cmd[i].details.get_transfer.label_hash);
- return GNUNET_SYSERR;
- }
- cmd[i].details.get_transfer.index_hash = ret;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_END:
- case PERF_TALER_MINTDB_CMD_DEBUG:
- case PERF_TALER_MINTDB_CMD_LOOP:
- case PERF_TALER_MINTDB_CMD_NEW_SESSION:
- case PERF_TALER_MINTDB_CMD_START_TRANSACTION:
- case PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION:
- case PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION:
- case PERF_TALER_MINTDB_CMD_GET_TIME:
- case PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION:
- case PERF_TALER_MINTDB_CMD_CREATE_RESERVE:
- case PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION:
- break;
- }
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Free the memory of the command chain
- */
-static int
-cmd_clean (struct PERF_TALER_MINTDB_Cmd cmd[])
-{
- unsigned int i;
-
- for (i=0; PERF_TALER_MINTDB_CMD_END != cmd[i].command; i++)
- {
- switch (cmd[i].command)
- {
- case PERF_TALER_MINTDB_CMD_SAVE_ARRAY:
- {
- unsigned int j;
-
- for (j = 0; j < cmd[i].details.save_array.nb_saved; j++)
- {
- data_free (&cmd[i].details.save_array.data_saved[j]);
- }
- GNUNET_free (cmd[i].details.save_array.data_saved);
- cmd[i].details.save_array.data_saved = NULL;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_LOAD_ARRAY:
- GNUNET_free (cmd[i].details.load_array.permutation);
- cmd[i].details.load_array.permutation = NULL;
- break;
-
- default:
- break;
- }
- data_free (&cmd[i].exposed);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Handles the command #PERF_TALER_MINTDB_CMD_END_LOOP for the interpreter
- * Cleans the memory at the end of the loop
- */
-static void
-interpret_end_loop (struct PERF_TALER_MINTDB_interpreter_state *state)
-{
- unsigned int i;
- int jump;
-
- jump = state->cmd[state->i].details.end_loop.index_loop;
- // Cleaning up the memory in the loop
- for (i = jump; i < state->i; i++)
- data_free (&state->cmd[i].exposed);
-
- state->cmd[jump].details.loop.curr_iteration++;
- /* If the loop is not finished */
- if (state->cmd[jump].details.loop.max_iterations >
- state->cmd[jump].details.loop.curr_iteration)
- {
- /* jump back to the start */
- state->i = jump;
- }
- else
- {
- /* Reset the loop counter and continue running */
- state->cmd[jump].details.loop.curr_iteration = 0;
- }
-}
-
-
-/**
- * Part of the interpreter specific to
- * #PERF_TALER_MINTDB_CMD_SAVE_ARRAY
- * Saves the data exposed by another command into
- * an array in the command specific struct.
- */
-static void
-interpret_save_array (struct PERF_TALER_MINTDB_interpreter_state *state)
-{
- struct PERF_TALER_MINTDB_Cmd *cmd = &state->cmd[state->i];
- struct PERF_TALER_MINTDB_Cmd *save_ref;
- struct PERF_TALER_MINTDB_Cmd *loop_ref;
- int loop_index;
- int save_index;
- unsigned int selection_chance;
-
- loop_index = cmd->details.save_array.index_loop;
- save_index = cmd->details.save_array.index_save;
- loop_ref = &state->cmd[loop_index];
- save_ref = &state->cmd[save_index];
- /* Array initialization on first loop iteration
- Alows for nested loops */
- if (0 == cmd->details.loop.curr_iteration)
- {
- cmd->details.save_array.index = 0;
- }
- /* The probability distribution of the saved items will be a little biased
- against the few last items but it should not be a big problem. */
- selection_chance = loop_ref->details.loop.max_iterations /
- cmd->details.save_array.nb_saved;
- /*
- * If the remaining space is equal to the remaining number of
- * iterations, the item is automaticly saved.
- *
- * Else it is saved only if the random numbre generated is 0
- */
- if ( (0 < (cmd->details.save_array.nb_saved -
- cmd->details.save_array.index) ) &&
- ( ((loop_ref->details.loop.max_iterations -
- loop_ref->details.loop.curr_iteration) ==
- (cmd->details.save_array.nb_saved -
- cmd->details.save_array.index)) ||
- (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- selection_chance)) ) )
- {
- struct PERF_TALER_MINTDB_Data *save_location;
- struct PERF_TALER_MINTDB_Data *item_saved;
-
- save_location = &cmd->details.save_array.data_saved[cmd->details.save_array.index];
- item_saved = &save_ref->exposed;
- data_copy (item_saved, save_location);
- cmd->details.save_array.index++;
- }
-}
-
-
-/**
- * Part of the interpreter specific to
- * #PERF_TALER_MINTDB_CMD_LOAD_ARRAY
- * Gets data from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY and exposes a copy
- */
-static void
-interpret_load_array (struct PERF_TALER_MINTDB_interpreter_state *state)
-{
- struct PERF_TALER_MINTDB_Cmd *cmd = &state->cmd[state->i];
- unsigned int loop_iter;
- int loop_index;
- int save_index;
- struct PERF_TALER_MINTDB_Data *loaded_data;
-
- loop_index = cmd->details.load_array.index_loop;
- save_index = cmd->details.load_array.index_save;
- loop_iter = state->cmd[loop_index].details.loop.curr_iteration;
- {
- unsigned int i;
- unsigned int quotient;
-
- /* In case the iteration number is higher than the amount saved,
- * the number is run several times in the permutation array */
- quotient = loop_iter / state->cmd[save_index].details.save_array.nb_saved;
- loop_iter = loop_iter % state->cmd[save_index].details.save_array.nb_saved;
- for (i=0; i<=quotient; i++)
- loop_iter = cmd->details.load_array.permutation[loop_iter];
- }
- /* Extracting the data from the loop_indexth indice in save_index
- * array.
- */
- loaded_data = &state->cmd[save_index].details.save_array.data_saved[loop_iter];
- data_copy (loaded_data,
- &cmd->exposed);
-}
-
-
-/**
- * Part of the interpreter specific to
- * #PERF_TALER_MINTDB_CMD_LOAD_RANDOM
- * Get a random element from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY and exposes it
- */
-static void
-interprete_load_random (struct PERF_TALER_MINTDB_interpreter_state *state)
-{
- struct PERF_TALER_MINTDB_Cmd *cmd = &state->cmd[state->i];
- unsigned int index;
- int save_index;
-
- save_index = cmd->details.load_random.index_save;
- index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- state->cmd[save_index].details.save_array.nb_saved);
- data_copy (&state->cmd[save_index].details.save_array.data_saved[index],
- &cmd->exposed);
-}
-
-
-/**
- * Iterate over the commands, acting accordingly at each step
- *
- * @param state the current state of the interpreter
- */
-static int
-interpret (struct PERF_TALER_MINTDB_interpreter_state *state)
-{
- for (state->i=0; PERF_TALER_MINTDB_CMD_END != state->cmd[state->i].command; state->i++)
- {
- switch (state->cmd[state->i].command)
- {
- case PERF_TALER_MINTDB_CMD_END:
- return GNUNET_YES;
-
- case PERF_TALER_MINTDB_CMD_DEBUG:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "%s\n",
- state->cmd[state->i].label);
- break;
-
- case PERF_TALER_MINTDB_CMD_LOOP:
- break;
-
- case PERF_TALER_MINTDB_CMD_END_LOOP:
- interpret_end_loop (state);
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_TIME:
- state->cmd[state->i].exposed.data.time =
- GNUNET_new (struct GNUNET_TIME_Absolute);
- *state->cmd[state->i].exposed.data.time =
- GNUNET_TIME_absolute_get ();
- break;
-
- case PERF_TALER_MINTDB_CMD_GAUGER:
- {
- unsigned int start_index;
- unsigned int stop_index;
- float ips;
- struct GNUNET_TIME_Absolute start;
- struct GNUNET_TIME_Absolute stop;
- struct GNUNET_TIME_Relative elapsed;
-
- start_index = state->cmd[state->i].details.gauger.index_start;
- stop_index = state->cmd[state->i].details.gauger.index_stop;
- start = *state->cmd[start_index].exposed.data.time;
- stop = *state->cmd[stop_index].exposed.data.time;
- elapsed = GNUNET_TIME_absolute_get_difference (start,
- stop);
- ips = (1.0 * state->cmd[state->i].details.gauger.divide) / (elapsed.rel_value_us/1000000.0);
- GAUGER (state->cmd[state->i].details.gauger.category,
- state->cmd[state->i].details.gauger.description,
- ips,
- state->cmd[state->i].details.gauger.unit);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_NEW_SESSION:
- state->session = state->plugin->get_session (state->plugin->cls, GNUNET_YES);
- break;
-
- case PERF_TALER_MINTDB_CMD_START_TRANSACTION:
- state->plugin->start (state->plugin->cls, state->session);
- break;
-
- case PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION:
- state->plugin->commit (state->plugin->cls, state->session);
- break;
-
- case PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION:
- state->plugin->rollback (state->plugin->cls,
- state->session);
- break;
-
- case PERF_TALER_MINTDB_CMD_SAVE_ARRAY:
- interpret_save_array (state);
- break;
-
- case PERF_TALER_MINTDB_CMD_LOAD_ARRAY:
- interpret_load_array (state);
- break;
-
- case PERF_TALER_MINTDB_CMD_LOAD_RANDOM:
- interprete_load_random (state);
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT:
- {
- int coin_index;
- struct TALER_MINTDB_Deposit *deposit;
-
- coin_index = state->cmd[state->i].details.create_deposit.index_coin;
- deposit = PERF_TALER_MINTDB_deposit_init (state->cmd[coin_index].exposed.data.coin);
- GNUNET_assert (NULL != deposit);
- state->cmd[state->i].exposed.data.deposit = deposit;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT:
- {
- int deposit_index;
- int ret;
- struct TALER_MINTDB_Deposit *deposit;
-
- deposit_index = state->cmd[state->i].details.insert_deposit.index_deposit;
- deposit = state->cmd[deposit_index].exposed.data.deposit;
- ret = state->plugin->insert_deposit (state->plugin->cls,
- state->session,
- deposit);
- GNUNET_assert (GNUNET_SYSERR != ret);
- state->cmd[state->i].exposed.data.deposit = deposit;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_DEPOSIT:
- {
- unsigned int source_index;
- int ret;
- struct PERF_TALER_MINTDB_Data *data;
-
- source_index = state->cmd[state->i].details.get_deposit.index_deposit;
- data = &state->cmd[source_index].exposed;
- ret = state->plugin->have_deposit (state->plugin->cls,
- state->session,
- data->data.deposit);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_RESERVE:
- {
- struct PERF_TALER_MINTDB_Reserve *reserve;
-
- reserve = PERF_TALER_MINTDB_reserve_init ();
- state->cmd[state->i].exposed.data.reserve = reserve;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_RESERVE:
- {
- unsigned int reserve_index;
- int ret;
- struct PERF_TALER_MINTDB_Reserve *reserve;
- json_t *details = NULL;
-
- reserve_index = state->cmd[state->i].details.insert_reserve.index_reserve;
- reserve = state->cmd[reserve_index].exposed.data.reserve;
- details = json_pack ("{s:i}","justification",
- GNUNET_CRYPTO_random_u32 (
- GNUNET_CRYPTO_QUALITY_WEAK,
- UINT32_MAX));
- GNUNET_assert (NULL != details);
- ret = state->plugin->reserves_in_insert (state->plugin->cls,
- state->session,
- &reserve->reserve.pub,
- &reserve->reserve.balance,
- GNUNET_TIME_absolute_get (),
- details);
- GNUNET_assert (GNUNET_SYSERR != ret);
- json_decref (details);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_RESERVE:
- {
- unsigned int reserve_index;
- int ret;
- struct PERF_TALER_MINTDB_Data *data;
-
-
- reserve_index = state->cmd[state->i].details.get_reserve.index_reserve;
- data = &state->cmd[reserve_index].exposed;
- ret = state->plugin->reserve_get (state->plugin->cls,
- state->session,
- &data->data.reserve->reserve);
- GNUNET_assert (GNUNET_OK == ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY:
- {
- unsigned int reserve_index;
- struct TALER_MINTDB_ReserveHistory *history;
- struct PERF_TALER_MINTDB_Data *data;
-
- reserve_index = state->cmd[state->i].details.get_reserve_history.index_reserve;
- data = &state->cmd[reserve_index].exposed;
- history = state->plugin->get_reserve_history (state->plugin->cls,
- state->session,
- &data->data.reserve->reserve.pub);
- GNUNET_assert (NULL != history);
- state->plugin->free_reserve_history (state->plugin->cls,
- history);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION:
- {
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki =
- PERF_TALER_MINTDB_denomination_init ();
- GNUNET_assert (NULL != dki);
- state->cmd[state->i].exposed.data.dki = dki;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION:
- {
- unsigned int denom_index;
- int ret;
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki ;
-
- denom_index = state->cmd[state->i].details.insert_denomination.index_denom;
- dki = state->cmd[denom_index].exposed.data.dki;
- ret = state->plugin->insert_denomination_info (state->plugin->cls,
- state->session,
- &dki->denom_pub,
- &dki->issue);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_DENOMINATION:
- {
- unsigned int denom_index;
- int ret;
- struct PERF_TALER_MINTDB_Data *data;
-
- denom_index = state->cmd[state->i].details.get_denomination.index_denom;
- data = &state->cmd[denom_index].exposed;
- ret = state->plugin->get_denomination_info (state->plugin->cls,
- state->session,
- &data->data.dki->denom_pub,
- &data->data.dki->issue);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW:
- {
- unsigned int dki_index;
- unsigned int reserve_index;
- struct PERF_TALER_MINTDB_Coin *coin ;
-
- dki_index = state->cmd[state->i].details.create_withdraw.index_dki;
- reserve_index = state->cmd[state->i].details.create_withdraw.index_reserve;
- coin = PERF_TALER_MINTDB_coin_init (state->cmd[dki_index].exposed.data.dki,
- state->cmd[reserve_index].exposed.data.reserve);
- GNUNET_assert (NULL != coin);
- state->cmd[state->i].exposed.data.coin = coin;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW:
- {
- unsigned int coin_index;
- int ret;
- struct PERF_TALER_MINTDB_Coin *coin ;
-
- coin_index = state->cmd[state->i].details.insert_withdraw.index_coin;
- coin = state->cmd[coin_index].exposed.data.coin;
- ret = state->plugin->insert_withdraw_info (state->plugin->cls,
- state->session,
- &coin->blind);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_WITHDRAW:
- {
- unsigned int source_index;
- int ret;
- struct PERF_TALER_MINTDB_Data *data;
-
- source_index = state->cmd[state->i].details.get_denomination.index_denom;
- data = &state->cmd[source_index].exposed;
- ret = state->plugin->get_withdraw_info (state->plugin->cls,
- state->session,
- &data->data.coin->blind.h_coin_envelope,
- &data->data.coin->blind);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION:
- {
- unsigned int coin_index;
- struct PERF_TALER_MINTDB_Coin *coin;
- struct TALER_MINTDB_TransactionList *transactions;
-
- coin_index = state->cmd[state->i].details.get_coin_transaction.index_coin;
- coin = state->cmd[coin_index].exposed.data.coin;
- transactions = state->plugin->get_coin_transactions (state->plugin->cls,
- state->session,
- &coin->public_info.coin_pub);
- GNUNET_assert (transactions != NULL);
- state->plugin->free_coin_transaction_list (state->plugin->cls,
- transactions);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION:
- {
- struct GNUNET_HashCode *hash;
- struct TALER_MINTDB_RefreshSession *refresh_session;
-
- hash = GNUNET_new (struct GNUNET_HashCode);
- refresh_session = PERF_TALER_MINTDB_refresh_session_init ();
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- hash);
- state->plugin->create_refresh_session (state->session,
- state->session,
- hash,
- refresh_session);
- state->cmd[state->i].exposed.data.session_hash = hash;
- PERF_TALER_MINTDB_refresh_session_free (refresh_session);
- GNUNET_free (refresh_session);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION:
- {
- unsigned int hash_index;
- struct GNUNET_HashCode *hash;
- struct TALER_MINTDB_RefreshSession refresh;
-
- hash_index = state->cmd[state->i].details.get_refresh_session.index_hash;
- hash = state->cmd[hash_index].exposed.data.session_hash;
- state->plugin->get_refresh_session (state->session,
- state->session,
- hash,
- &refresh);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT:
- {
- unsigned int hash_index;
- unsigned int coin_index;
- struct GNUNET_HashCode *hash;
- struct TALER_MINTDB_RefreshMelt *melt;
- struct PERF_TALER_MINTDB_Coin *coin;
-
- hash_index = state->cmd[state->i].details.insert_refresh_melt.index_hash;
- coin_index = state->cmd[state->i].details.insert_refresh_melt.index_coin;
- hash = state->cmd[hash_index].exposed.data.session_hash;
- coin = state->cmd[coin_index].exposed.data.coin;
- melt = PERF_TALER_MINTDB_refresh_melt_init (hash,
- coin);
- state->plugin->insert_refresh_melt (state->plugin->cls,
- state->session,
- 1,
- melt);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT:
- {
- int ret;
- unsigned int hash_index;
- struct GNUNET_HashCode *hash;
- struct TALER_MINTDB_RefreshMelt melt;
-
- hash_index = cmd_find (state->cmd,
- state->cmd[state->i].details.get_refresh_melt.label_hash);
- hash = state->cmd[hash_index].exposed.data.session_hash;
- ret = state->plugin->get_refresh_melt (state->plugin->cls,
- state->session,
- hash,
- 1,
- &melt);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER:
- {
- unsigned int hash_index;
- unsigned int denom_index;
- struct GNUNET_HashCode *session_hash;
- struct TALER_MINTDB_DenominationKeyIssueInformation *denom;
-
- hash_index = state->cmd[state->i].details.insert_refresh_order.index_hash;
- denom_index = state->cmd[state->i].details.insert_refresh_order.index_denom;
- session_hash = state->cmd[hash_index].exposed.data.session_hash;
- denom = state->cmd[denom_index].exposed.data.dki;
- state->plugin->insert_refresh_order (state->plugin->cls,
- state->session,
- session_hash,
- 1,
- &denom->denom_pub);
-
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER:
- {
- int hash_index;
- struct GNUNET_HashCode *hash;
- struct TALER_DenominationPublicKey denom_pub;
-
- hash_index = state->cmd[state->i].details.get_refresh_order.index_hash;
- hash = state->cmd[hash_index].exposed.data.session_hash;
- state->plugin->get_refresh_order (state->plugin->cls,
- state->session,
- hash,
- 1,
- &denom_pub);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN:
- {
- int ret;
- unsigned int hash_index;
- struct TALER_MINTDB_RefreshCommitCoin *refresh_commit;
-
- hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash;
- refresh_commit = PERF_TALER_MINTDB_refresh_commit_coin_init ();
- ret = state->plugin->insert_refresh_commit_coins (state->plugin->cls,
- state->session,
- state->cmd[hash_index].exposed.data.session_hash,
- 1,
- 1,
- refresh_commit);
- GNUNET_assert (GNUNET_OK == ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN:
- {
- unsigned int hash_index;
- struct TALER_MINTDB_RefreshCommitCoin refresh_commit;
-
- hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash;
- state->plugin->get_refresh_commit_coins (state->plugin->cls,
- state->session,
- state->cmd[hash_index].exposed.data.session_hash,
- 1,
- 1,
- &refresh_commit);
-
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK:
- {
-// unsigned int hash_index;
-//
-// hash_index = state->cmd[state->i].details.insert_refresh_commit_link.index_hash;
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK:
- {
- int ret;
- unsigned int hash_index;
- struct TALER_MINTDB_RefreshCommitCoin commit_coin;
-
- hash_index = state->cmd[state->i].details.get_refresh_commit_link.index_hash;
- ret = state->plugin->get_refresh_commit_coins(state->plugin->cls,
- state->session,
- state->cmd[hash_index].exposed.data.session_hash,
- 1,
- 1,
- &commit_coin);
- GNUNET_assert (GNUNET_SYSERR != ret);
- }
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT:
- break;
-
- case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT:
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST:
- break;
-
- case PERF_TALER_MINTDB_CMD_GET_TRANSFER:
- break;
-
- }
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Runs the commands given in @a cmd, working with
- * the database referenced by @a db_plugin
- *
- * @param db_plugin the connection to the database
- * @param cmd the commands to run
- */
-int
-PERF_TALER_MINTDB_interpret (struct TALER_MINTDB_Plugin *db_plugin,
- struct PERF_TALER_MINTDB_Cmd cmd[])
-{
- int ret;
- struct PERF_TALER_MINTDB_interpreter_state state =
- {.i = 0, .cmd = cmd, .plugin = db_plugin};
-
- ret = cmd_init (cmd);
- if (GNUNET_SYSERR == ret)
- return ret;
- state.session = db_plugin->get_session (db_plugin->cls,
- GNUNET_YES);
- GNUNET_assert (NULL != state.session);
- ret = interpret (&state);
- cmd_clean (cmd);
- return ret;
-}
-
-
-/**
- * Initialize the database and run the benchmark
- *
- * @param benchmark_name the name of the benchmark, displayed in the logs
- * @param configuration_file path to the taler configuration file to use
- * @param init the commands to use for the database initialisation,
- * if #NULL the standard initialization is used
- * @param benchmark the commands for the benchmark
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-PERF_TALER_MINTDB_run_benchmark (const char *benchmark_name,
- const char *configuration_file,
- struct PERF_TALER_MINTDB_Cmd *init,
- struct PERF_TALER_MINTDB_Cmd *benchmark)
-{
- struct TALER_MINTDB_Plugin *plugin;
- struct GNUNET_CONFIGURATION_Handle *config;
- int ret = 0;
- struct PERF_TALER_MINTDB_Cmd init_def[] =
- {
- // Denomination used to create coins
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("00 - Start of interpreter"),
-
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("01 - denomination loop",
- PERF_TALER_MINTDB_NB_DENOMINATION_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert",
- "01 - denomination"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination",
- "01 - denomination loop",
- "01 - denomination",
- PERF_TALER_MINTDB_NB_DENOMINATION_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "01 - denomination loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("01 - init denomination complete"),
- // End of initialization
- // Reserve initialization
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("02 - init reserve loop",
- PERF_TALER_MINTDB_NB_RESERVE_INIT),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("02 - insert",
- "02 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve",
- "02 - init reserve loop",
- "02 - reserve",
- PERF_TALER_MINTDB_NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "02 - init reserve loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("02 - reserve init complete"),
- // End reserve init
- // Withdrawal initialization
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("03 - init withdraw loop",
- PERF_TALER_MINTDB_NB_WITHDRAW_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load",
- "03 - init withdraw loop",
- "01 - save denomination"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load",
- "03 - init withdraw loop",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw",
- "03 - denomination load",
- "03 - reserve load"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert",
- "03 - withdraw"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("03 - save coin",
- "03 - init withdraw loop",
- "03 - withdraw",
- PERF_TALER_MINTDB_NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("",
- "03 - init withdraw loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("03 - withdraw init complete"),
- //End of withdrawal initialization
- //Deposit initialization
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("04 - deposit init loop",
- PERF_TALER_MINTDB_NB_DEPOSIT_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("04 - denomination load",
- "04 - deposit init loop",
- "03 - save coin"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT ("04 - deposit",
- "04 - denomination load"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array",
- "04 - deposit init loop",
- "04 - deposit",
- PERF_TALER_MINTDB_NB_DEPOSIT_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("04 - deposit init loop end",
- "04 - deposit init loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("04 - deposit init complete"),
- // End of deposit initialization
- PERF_TALER_MINTDB_INIT_CMD_END ("end")
- };
-
- GNUNET_log_setup (benchmark_name,
- "INFO",
- NULL);
- config = GNUNET_CONFIGURATION_create ();
-
- ret = GNUNET_CONFIGURATION_load (config,
- configuration_file);
- if (GNUNET_OK != ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error parsing configuration file\n");
- return GNUNET_SYSERR;
- }
- plugin = TALER_MINTDB_plugin_load (config);
- if (NULL == plugin)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error connectiong to the database\n");
- return ret;
- }
- ret = plugin->create_tables (plugin->cls,
- GNUNET_YES);
- if (GNUNET_OK != ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error while creating the database architecture\n");
- return ret;
- }
- /*
- * Running the initialization
- */
- if (NULL == init)
- {
- init = init_def;
- }
- ret = PERF_TALER_MINTDB_interpret (plugin,
- init);
- if (GNUNET_OK != ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error during database initialization\n");
- return ret;
- }
- /*
- * Running the benchmark
- */
- ret = PERF_TALER_MINTDB_interpret (plugin,
- benchmark);
- if (GNUNET_OK != ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error while runing the benchmark\n");
- return ret;
- }
- /* Drop tables */
- {
- struct TALER_MINTDB_Session *session;
-
- session = plugin->get_session (plugin->cls,
- GNUNET_YES);
- ret = plugin->drop_temporary (plugin->cls,
- session);
- if (GNUNET_OK != ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error cleaning the database\n");
- return ret;
- }
- }
- TALER_MINTDB_plugin_unload (plugin);
- GNUNET_CONFIGURATION_destroy (config);
- return ret;
-}
diff --git a/src/mintdb/perf_taler_mintdb_interpreter.h b/src/mintdb/perf_taler_mintdb_interpreter.h
deleted file mode 100644
index 3510e3dd4..000000000
--- a/src/mintdb/perf_taler_mintdb_interpreter.h
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mintdb/perf_taler_mintdb_interpreter.h
- * @brief Library for performance analysis of the Taler database
- * @author Nicolas Fournier
- *
- * This library contains functions and macro alowing Taler performance analysis
- * to be written with ease.
- * To do so, create a #PERF_TALER_MINTDB_Cmd array and fill it with the commands
- * to execute in chronological order. Some command have an exposed variable wich
- * can be reused in other commands.
- * Macros are available to make the use much easier so feel free to use them
- * to initialize your own command array.
- */
-
-#ifndef __PERF_TALER_MINTDB_INTERPRETER_H__
-#define __PERF_TALER_MINTDB_INTERPRETER_H__
-
-#include <sys/time.h>
-#include "taler_mintdb_plugin.h"
-
-
-#define PERF_TALER_MINTDB_NB_DENOMINATION_INIT 10
-#define PERF_TALER_MINTDB_NB_DENOMINATION_SAVE 10
-
-#define PERF_TALER_MINTDB_NB_RESERVE_INIT 100
-#define PERF_TALER_MINTDB_NB_RESERVE_SAVE 10
-
-#define PERF_TALER_MINTDB_NB_DEPOSIT_INIT 100
-#define PERF_TALER_MINTDB_NB_DEPOSIT_SAVE 10
-
-#define PERF_TALER_MINTDB_NB_WITHDRAW_INIT 100
-#define PERF_TALER_MINTDB_NB_WITHDRAW_SAVE 10
-
-
-/**
- * Marks the end of the command chain
- *
- * @param _label The label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_END(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_END, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE \
-}
-
-
-/**
- * Prints @ _label to stdout
- *
- * @param _label The label of the command,
- * will be logged each time the command runs
- */
-#define PERF_TALER_MINTDB_INIT_CMD_DEBUG(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_DEBUG, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE \
-}
-
-/**
- * The begining of a loop
- *
- * @param _label the label of the loop
- * @param _iter the number of iterations of the loop
- */
-#define PERF_TALER_MINTDB_INIT_CMD_LOOP(_label, _iter) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_LOOP , \
- .label = _label , \
- .exposed.type = PERF_TALER_MINTDB_NONE , \
- .details.loop = { \
- .max_iterations = _iter , \
- .curr_iteration = 0 } \
-}
-
-/**
- * Marks the end of the loop @_label_loop
- *
- * @param _label the label of the command
- * @param _label_loop the label of the loop closed by this command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_END_LOOP(_label, _label_loop) \
-{\
- .command = PERF_TALER_MINTDB_CMD_END_LOOP , \
- .label = _label , \
- .exposed.type = PERF_TALER_MINTDB_NONE , \
- .details.end_loop.label_loop = _label_loop \
-}
-
-/**
- * Saves the time of execution to use for logging with Gauger
- *
- * @param _label the label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_TIME(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_TIME, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_TIME \
-}
-
-/**
- * Commits the duration between @a _label_start and @a _label_stop
- * to Gauger with @a _description explaining what was measured.
- *
- * @param _label the label of this command
- * @param _label_start label of the start of the measurment
- * @param _label_stop label of the end of the measurment
- * @param _description description of the measure displayed in Gauger
- * @param _unit the unit of the data measured, typicly something/sec
- * @param _divide number of measurments in the interval
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GAUGER(_label, _label_start, _label_stop, _category, _description, _unit, _divide) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GAUGER, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.gauger = { \
- .label_start = _label_start, \
- .label_stop = _label_stop, \
- .category = _category, \
- .description = _description, \
- .unit = _unit, \
- .divide = _divide, \
- } \
-}
-
-/**
- * Initiate a database transaction
- *
- * @param _label the label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_START_TRANSACTION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
-}
-
-/**
- * Commits a database transaction
- *
- * @param _label the label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
-}
-
-/**
- * Abort the current transaction
- *
- * @param _label the label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_ABORT_TRANSACTION(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION, \
- .label = _label,
-
-/**
- * Saves randomly selected items from @a _label_save
- * Saved items can latter be access using #PERF_TALER_MINTDB_CMD_LOAD_ARRAY
- *
- * @param _label the label of the command, used by other commands to reference it
- * @param _label_loop the label of the loop the array iterates over
- * @param _label_save the label of the command which outout is saved by this command
- * @param _nb_saved the total number of items to be saved
- */
-#define PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY(_label, _label_loop, _label_save, _nb_saved) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_SAVE_ARRAY, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.save_array = { \
- .label_loop = _label_loop, \
- .label_save = _label_save, \
- .nb_saved = _nb_saved, \
- } \
-}
-
-/**
- * Loads data from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY to allow other
- * commands to access it
- *
- * @param _label the label of this command, referenced by commands to access it's outpout
- * @param _label_loop the label of the loop to iterate over
- * @param _label_save the label of the #PERF_TALER_MINTDB_CMD_SAVE_ARRAY providing data
- */
-#define PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY(_label, _label_loop, _label_save) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_LOAD_ARRAY, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.load_array = { \
- .label_loop = _label_loop, \
- .label_save = _label_save \
- } \
-}
-
-/**
- * Create a denomination key to use
- * Exposes a #PERF_TALER_MINTDB_DENOMINATION_INFO to be used by other commands
- * @exposed #PERF_TALER_MINTDB_DENOMINATION_INFO
- *
- * @param _label the label of this command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_DENOMINATION_INFO, \
-}
-
-/**
- * Inserts informations about a denomination key in the database
- *
- * @param _label the label of this command
- * @param _label_denom the label of the denomination to insert
- */
-#define PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION(_label, _label_denom) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.insert_denomination.label_denom = _label_denom, \
-}
-
-/**
- * Polls the database about informations regarding a specific denomination key
- *
- * @param _label the label of this command
- * @param _label_denom the label of the command providing information about the denomination key
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_DENOMINATION(_label, _label_denom) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_DENOMINATION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.get_denomination.label_denom = _label_denom \
-}
-
-/**
- * Create a reserve to be used later
- * Exposes a #PERF_TALER_MINTDB_RESERVE
- *
- * @param _label the label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_CREATE_RESERVE, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_RESERVE \
-}
-
-/**
- * Insert a new reserve in the database containing 1000 Euros
- *
- * @param _label the name of this command
- * @param _label_reserve the label of the reserve to insert
- */
-#define PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE(_label, _label_reserve) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_INSERT_RESERVE, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.insert_reserve.label_reserve = _label_reserve \
-}
-
-/**
- * Polls the database for a secific reserve's details
- *
- * @param _label the label of this command
- * @param _label_reserve the reserve to poll
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE(_label, _label_reserve) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_RESERVE, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.get_reserve.label_reserve = _label_reserve \
-}
-
-/**
- * Polls the database for the history of a reserve
- *
- * @param _label the label of the command
- * @param _label_reserve the reserve to examine
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE_HISTORY(_label, _label_reserve) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.get_reserve_history.label_reserve = _label_reserve \
-}
-
-/**
- * Creates a coin to be used later
- *
- * @param _label the label of this command
- * @param _label_dki denomination key used to sign the coin
- * @param _label_reserve reserve used to emmit the coin
- */
-#define PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW(_label, _label_dki, _label_reserve) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_COIN, \
- .details.create_withdraw = {\
- .label_dki = _label_dki, \
- .label_reserve = _label_reserve, \
- } \
-}
-
-/**
- * Inserts informations about a withdrawal in the database
- *
- * @exposes #PERF_TALER_MINTDB_COIN
- *
- * @param _label the label of this command
- * @param _label_coin the coin to insert
- */
-#define PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW(_label, _label_coin) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.insert_withdraw.label_coin = _label_coin\
-}
-
-
-/**
- * Polls the database about informations regarding a specific withdrawal
- *
- * @param _label the label of this command
- * @param _label_coin the coin to check
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_WITHDRAW(_label, _label_coin) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_WITHDRAW, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.get_withdraw.label_coin = _label_coin, \
-}
-
-
-/**
- * The /reserve/withdraw api call
- *
- * Exposes #PERF_TALER_MINTDB_COIN
- *
- * @param _label the label of this command
- * @param _label_dki the denomination of the created coin
- * @param _label_reserve the reserve used to provide currency
- */
-#define PERF_TALER_MINTDB_INIT_CMD_WITHDRAW_SIGN(_label, _label_dki, _label_reserve) \
- PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW (_label "withdraw", \
- _label_dki, \
- _label_reserve), \
- PERF_TALER_MINTDB_INIT_CMD_GET_DENOMINATION(_label "withdraw info", \
- _label_dki), \
- PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE_HISTORY(_label "reserve_history", \
- _label_reserve), \
- PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW(_label "insert withdraw", \
- _label "withdraw")
-
-/**
- * Create a deposit for use later
- * @exposes #PERF_TALER_MINTDB_DEPOSIT
- *
- * @param _label the label of this command
- * @param _label_coin the coin used to pay
- */
-#define PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT(_label, _label_coin) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_DEPOSIT, \
- .details.create_deposit.label_coin = _label_coin, \
-}
-
-/**
- * Insert a deposit into the database
- *
- * @param _label the label of this command
- * @param _label_deposit the deposit inseerted
- */
-#define PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT(_label, _label_deposit) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT,\
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.insert_deposit.label_deposit = _label_deposit, \
-}
-
-/**
- * Check if a deposit is in the database
- *
- * @param _label the label of this command
- * @param _label_deposit the deposit to use
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_DEPOSIT(_label, _label_deposit) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_DEPOSIT, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.get_deposit.label_deposit = _label_deposit \
-}
-
-/**
- * Access the transaction history of a coin
- *
- * @param _label the label of the command
- * @param _label_coin the coin which history is checked
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_COIN_TRANSACTION(_label, _label_coin) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE, \
- .details.get_coin_transaction.label_coin = _label_coin \
-}
-
-/**
- * The /deposit api call
- *
- * @param _label the label of the command
- * @param _label_coin the coin used for the deposit
- */
-#define PERF_TALER_MINTDB_INIT_CMD_DEPOSIT(_label, _label_coin) \
- PERF_TALER_MINTDB_INIT_CMD_GET_COIN_TRANSACTION (_label "coin history", \
- _label_coin), \
- PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT (_label "deposit", \
- _label_coin), \
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT (_label "insert", \
- _label "deposit")
-/**
- * Insert informations about a refresh session
- * melts one coin into another
- *
- * @param _label the label of the command
- */
-#define PERF_TALER_MINTDB_INIT_CMD_CREATE_REFRESH_SESSION(_label) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_REFRESH_HASH \
-}
-
-/**
- * Get informations about a refresh session
- *
- * @param _label the label of the command
- * @param _label_hash the label of the hash to search
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_REFRESH_SESSION(_label, \
- _label_hash) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION, \
- .label = _label, \
- .exposed.type = PERF_TALER_MINTDB_NONE \
-}
-
-/**
- * Insert a melt operation in the database
- *
- * @param _label the label of the command
- * @param _label_hash the label of the hash of the session
- * @param _label_coin the label of the coin to melt
- */
-#define PERF_TALER_MINTDB_INIT_CMD_INSERT_REFRESH_MELT(_label, \
- _label_hash, \
- _label_coin) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT, \
- .label = _label, \
- .details.insert_refresh_melt.label_hash = _label_hash, \
- .details.insert_refresh_melt.label_coin = _label_coin, \
- .exposed.type = PERF_TALER_MINTDB_NONE \
-}
-
-/**
- * Get informations about a melt operation
- *
- * @param _label the label of the command
- * @param _label_hash the label of the hash of the refresh session
- */
-#define PERF_TALER_MINTDB_INIT_CMD_GET_REFRESH_MELT(_label, \
- _label_hash) \
-{ \
- .command = PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT, \
- .label = _label, \
- .detail.get_refresh_melt.label_hash = _label_hash, \
- .exposed.type = PERF_TALER_MINTDB_NONE \
-}
-
-/**
- * The type of data stored in #PERF_TALER_MINTDB_Memory
- */
-enum PERF_TALER_MINTDB_Type
-{
- PERF_TALER_MINTDB_NONE,
- PERF_TALER_MINTDB_TIME,
- PERF_TALER_MINTDB_DENOMINATION_INFO,
- PERF_TALER_MINTDB_RESERVE,
- PERF_TALER_MINTDB_COIN,
- PERF_TALER_MINTDB_DEPOSIT,
- PERF_TALER_MINTDB_REFRESH_HASH,
- PERF_TALER_MINTDB_REFRESH_MELT
-};
-
-
-/**
- * Structure used to handle several data type
- */
-struct PERF_TALER_MINTDB_Data
-{
- enum PERF_TALER_MINTDB_Type type;
-
- /**
- * Storage for a variety of data type
- * The data saved should match #type
- */
- union PERF_TALER_MINTDB_Memory
- {
- /** #PERF_TALER_MINTDB_TIME */
- struct GNUNET_TIME_Absolute *time;
- /** #PERF_TALER_MINTDB_DEPOSIT */
- struct TALER_MINTDB_Deposit *deposit;
- /** #PERF_TALER_MINTDB_COIN */
- struct PERF_TALER_MINTDB_Coin *coin;
- /** #PERF_TALER_MINTDB_RESERVE */
- struct PERF_TALER_MINTDB_Reserve *reserve;
- /** #PERF_TALER_MINTDB_DENOMINATION_INFO */
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki;
- /** #PERF_TALER_MINTDB_REFRESH_HASH */
- struct GNUNET_HashCode *session_hash;
- /** #PERF_TALER_MINTDB_REFRESH_MELT */
- struct TALER_MINTDB_RefreshMelt *refresh_melt;
- } data;
-};
-
-
-/**
- * Name of the command
- */
-enum PERF_TALER_MINTDB_CMD_Name
-{
- /**
- * All comand chain must hace this as their last command
- */
- PERF_TALER_MINTDB_CMD_END,
-
- /**
- * Prints it's label
- */
- PERF_TALER_MINTDB_CMD_DEBUG,
-
- /**
- * Define the start of al command chain loop
- */
- PERF_TALER_MINTDB_CMD_LOOP,
-
- /**
- * Define the end of a command chain loop
- */
- PERF_TALER_MINTDB_CMD_END_LOOP,
-
- /**
- * Save the time at which the command was executed
- */
- PERF_TALER_MINTDB_CMD_GET_TIME,
-
- /**
- * Upload performance to Gauger
- */
- PERF_TALER_MINTDB_CMD_GAUGER,
-
- /**
- * Start a new session
- */
- PERF_TALER_MINTDB_CMD_NEW_SESSION,
-
- /**
- * Start a database transaction
- */
- PERF_TALER_MINTDB_CMD_START_TRANSACTION,
-
- /**
- * End a database transaction
- */
- PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION,
-
- /**
- * Abort a transaction started with #PERF_TALER_MINTDB_CMD_START_TRANSACTION
- */
- PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION,
-
- /**
- * Saves random deposits from a loop
- */
- PERF_TALER_MINTDB_CMD_SAVE_ARRAY,
-
- /**
- * Load items saved earlier in a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY
- * The items are loaded in a random order, but all of them will be loaded
- */
- PERF_TALER_MINTDB_CMD_LOAD_ARRAY,
-
- /**
- * Loads a random item from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY
- * A random item is loaded each time the command is run
- */
- PERF_TALER_MINTDB_CMD_LOAD_RANDOM,
-
- /**
- * Create a denomination to be used later
- */
- PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION,
-
- /**
- * Insert informations about a denomination key in the database
- */
- PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION,
-
- /**
- * Polls the database for informations about a specific denomination key
- */
- PERF_TALER_MINTDB_CMD_GET_DENOMINATION,
-
- /**
- * Create a reserve to be used later
- */
- PERF_TALER_MINTDB_CMD_CREATE_RESERVE,
-
- /**
- * Insert currency in a reserve / Create a reserve
- */
- PERF_TALER_MINTDB_CMD_INSERT_RESERVE,
-
- /**
- * Get Informations about a reserve
- */
- PERF_TALER_MINTDB_CMD_GET_RESERVE,
-
- /**
- * Get the history of a reserve
- */
- PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY,
-
- /**
- * Create a withdrawal to be used later
- */
- PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW,
-
- /**
- * Insert informations about a withdrawal in the database
- */
- PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW,
-
- /**
- * Pulls informations about a withdrawal from the database
- */
- PERF_TALER_MINTDB_CMD_GET_WITHDRAW,
-
- /**
- * Get the list of all transactions the coin has been in
- */
- PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION,
-
- /**
- * Create a deposit to be used later
- */
- PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT,
-
- /**
- * Insert a deposit into the database
- */
- PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT,
-
- /**
- * Check if a deposit is in the database
- */
- PERF_TALER_MINTDB_CMD_GET_DEPOSIT,
-
- /**
- * Create a refresh session
- * The number of melted coins is 1,
- * The number of minted coins is 1
- */
- PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION,
-
- /**
- * Get a refresh session informations
- */
- PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION,
-
- /**
- * Insert a refresh melt
- */
- PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT,
-
- /**
- * Get informations about a refresh melt operation
- */
- PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT,
-
- /**
- * Insert a melt refresh order
- */
- PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER,
-
- /**
- * Get informations about a refresh order
- */
- PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER,
-
- /**
- * Insert refresh commit coin
- */
- PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN,
-
- /**
- * Get refresh commit coin
- */
- PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN,
-
- /**
- * Insert refresh commit link
- */
- PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK,
-
- /**
- * Get refresh commit link
- */
- PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK,
-
- /**
- * Get information avout the melt commit
- */
- PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT,
-
- /**
- * Insert a new coin into the database after a melt operation
- */
- PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT,
-
- /**
- * Get the link data list of a coin
- */
- PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST,
-
- /**
- * Get the shared secret and the transfere public key
- */
- PERF_TALER_MINTDB_CMD_GET_TRANSFER
-
-};
-
-
-/**
- * Contains extra data required for any command
- */
-union PERF_TALER_MINTDB_CMD_Details
-{
- /**
- * Extra data requiered for the #PERF_TALER_MINTDB_CMD_LOOP command
- */
- struct PERF_TALER_MINTDB_CMD_loopDetails
- {
- /**
- * Maximum number of iteration in the loop
- */
- const unsigned int max_iterations;
-
- /**
- * The current iteration of the loop
- */
- unsigned int curr_iteration;
- } loop;
-
- /**
- * Extra data requiered by the #PERF_TALER_MINTDB_CMD_END_LOOP command
- */
- struct PERF_TALER_MINTDB_CMD_endLoopDetails
- {
- /**
- * Label of the loop closed by the command
- */
- const char *label_loop;
- unsigned int index_loop;
- } end_loop;
-
- /**
- * Details about the #PERF_TALER_MINTDB_CMD_GAUGER command
- */
- struct PERF_TALER_MINTDB_CMD_gaugerDetails
- {
- /**
- * Label of the starting timestamp
- */
- const char *label_start;
- unsigned int index_start;
-
- /**
- * Label of the ending timestamp
- */
- const char *label_stop;
- unsigned int index_stop;
-
- /**
- * The category of the measurment
- */
- const char *category;
-
- /**
- * Description of the metric, used in Gauger
- */
- const char *description;
-
- /**
- * The name of the metric beeing used
- */
- const char *unit;
-
- /**
- * Constant the result needs to be divided by
- * to get the result per unit
- */
- float divide;
- } gauger;
-
- /**
- * Contains extra data requiered by the #PERF_TALER_MINTDB_CMD_SAVE_ARRAY command
- */
- struct PERF_TALER_MINTDB_CMD_saveArrayDetails
- {
- /**
- * Number of items to save
- */
- unsigned int nb_saved;
-
- /**
- * Number of items already saved
- */
- unsigned int index;
-
- /**
- * Label of the loop it is attached to
- */
- const char *label_loop;
- unsigned int index_loop;
-
- /**
- * Label of the command exposing the item
- */
- const char *label_save;
- unsigned int index_save;
-
- /**
- * Array of data saved
- */
- struct PERF_TALER_MINTDB_Data *data_saved;
-
- /**
- * Type of the data that will be stored in @a data_saved, for
- * 'static' type checking.
- */
- enum PERF_TALER_MINTDB_Type type_saved;
-
- } save_array;
-
- /**
- * Extra data required for the #PERF_TALER_MINTDB_CMD_LOAD_ARRAY command
- */
- struct PERF_TALER_MINTDB_CMD_loadArrayDetails
- {
- /**
- * The loop in which the command is located
- */
- const char *label_loop;
- unsigned int index_loop;
-
- /**
- * Label of the command where the items were saved
- */
- const char *label_save;
- unsigned int index_save;
-
- /**
- * A permutation array used to randomize the order the items are loaded in
- */
- unsigned int *permutation;
- } load_array;
-
- /**
- * Contains data for the #PERF_TALER_MINTDB_CMD_LOAD_RANDOM command
- */
- struct PERF_TALER_MINTDB_CMD_loadRandomDetails
- {
- /**
- * The label of the #PERF_TALER_MINTDB_CMD_SAVE_ARRAY the items will be extracted from
- */
- const char *label_save;
- unsigned int index_save;
- } load_random;
-
- /**
- * Extra data requiered by the #PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION command
- */
- struct PERF_TALER_MINTDB_CMD_insertDenominationDetails
- {
- /**
- * The label of the source of the denomination to insert
- */
- const char *label_denom;
- unsigned int index_denom;
- } insert_denomination;
-
- /**
- * Extra data requiered by the #PERF_TALER_MINTDB_CMD_GET_DENOMINATION command
- */
- struct PERF_TALER_MINTDB_CMD_getDenominationDetails
- {
- /**
- * The label of the source of the denomination to check
- */
- const char *label_denom;
- unsigned int index_denom;
- } get_denomination;
-
- /**
- * Extra data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_RESERVE command
- */
- struct PERF_TALER_MINTDB_CMD_insertReserveDetails
- {
- /**
- * The label of the source of the reserve to insert
- */
- const char *label_reserve;
- unsigned int index_reserve;
- } insert_reserve;
-
- /**
- * Extra data requiered for the #PERF_TALER_MINTDB_CMD_GET_RESERVE command
- */
- struct PERF_TALER_MINTDB_CMD_getReserveDetails
- {
- /**
- * The label of the source of the reserve to check
- */
- const char *label_reserve;
- unsigned int index_reserve;
- } get_reserve;
-
- /**
- * Extra data requiered for the #PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY command
- */
- struct PERF_TALER_MINTDB_CMD_getReserveHistoryDetails
- {
- /**
- * The label of the source of the reserve to check
- */
- const char *label_reserve;
- unsigned int index_reserve;
- } get_reserve_history;
-
- /**
- * Extra data related to the #PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW command
- */
- struct PERF_TALER_MINTDB_CMD_createWithdrawDetails
- {
- /**
- * label of the denomination key used to sign the coin
- */
- const char *label_dki;
- unsigned int index_dki;
-
- /**
- * label of the reserve the money to mint the coin comes from
- */
- const char *label_reserve;
- unsigned int index_reserve;
- } create_withdraw;
-
- /**
- * data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW
- */
- struct PERF_TALER_MINTDB_CMD_insertWithdrawDetails
- {
- /**
- * label of the source for the coin information
- */
- const char *label_coin;
- unsigned int index_coin;
- } insert_withdraw;
-
- /**
- * data requiered for the #PERF_TALER_MINTDB_CMD_GET_WITHDRAW
- */
- struct PERF_TALER_MINTDB_CMD_getWithdraw
- {
- /**
- * label of the source for the coin information
- */
- const char *label_coin;
- unsigned int index_coin;
- } get_withdraw;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION command
- */
- struct PERF_TALER_MINTDB_CMD_getCoinTransactionDetails
- {
- /**
- * The coin which history is checked
- */
- const char *label_coin;
- unsigned int index_coin;
- } get_coin_transaction;
-
- /**
- * Data used by the #PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT command
- */
- struct PERF_TALER_MINTDB_CMD_createDepositDetails
- {
- /**
- * Label of the source where the reserve used to create the coin is
- */
- const char *label_coin;
- unsigned int index_coin;
- } create_deposit;
-
- /**
- * Extra data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT command
- */
- struct PERF_TALER_MINTDB_CMD_insertDepositDetails
- {
- /**
- * The label of the source of the deposit to check
- */
- const char *label_deposit;
- unsigned int index_deposit;
- } insert_deposit;
-
- /**
- * Extra data requiered for the #PERF_TALER_MINTDB_CMD_GET_DEPOSIT command
- */
- struct PERF_TALER_MINTDB_CMD_getDepositDetails
- {
- /**
- * The label of the source of the deposit to check
- */
- const char *label_deposit;
- unsigned int index_deposit;
- } get_deposit;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION command
- */
- struct PERF_TALER_MINTDB_CMD_getRefreshSessionDetails
- {
- /**
- * label of the source of the hash of the session
- */
- const char *label_hash;
- unsigned int index_hash;
- } get_refresh_session;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT command
- */
- struct PERF_TALER_MINTDB_CMD_insertRefreshMeltDetails
- {
- /**
- * The label of the hash of the refresh session
- */
- const char *label_hash;
- unsigned int index_hash;
-
- /**
- * The label of the coin to melt
- */
- const char *label_coin;
- unsigned int index_coin;
- } insert_refresh_melt;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT command
- */
- struct PERF_TALER_MINTDB_CMD_getRefreshMeltDetails
- {
- /**
- * The label of the hash of the session
- */
- const char *label_hash;
- unsigned int index_hash;
- } get_refresh_melt;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER command
- */
- struct PERF_TALER_MINTDB_CMD_insertRefreshOrderDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
-
- /**
- * The new coin denomination
- */
- const char *label_denom;
- unsigned int index_denom;
- } insert_refresh_order;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER command
- */
- struct PERF_TALER_MINTDB_CMD_getRefreshOrderDetails
- {
- /**
- * The session hash
- */
- const char *label_hash;
- unsigned int index_hash;
-
- } get_refresh_order;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN command
- */
- struct PERF_TALER_MINTDB_CMD_insertRefreshCommitCoinDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
-
- } insert_refresh_commit_coin;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN command
- */
- struct PERF_TALER_MINTDB_CMD_getRefreshCommitCoinDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
-
- } get_refresh_commit_coin;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK command
- */
- struct PERF_TALER_MINTDB_CMD_insertRefreshCommitLinkDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
-
- } insert_refresh_commit_link;
-
- /**
- * Data requiered by the #PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK command
- */
- struct PERF_TALER_MINTDB_CMD_getRefreshCommitLinkDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
- } get_refresh_commit_link;
-
- /**
- * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT command
- */
- struct PERF_TALER_MINTDB_CMD_getMeltCommitmentDaetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
- } get_melt_commitment;
-
- /**
- * Data requiered by the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT command
- */
- struct PERF_TALER_MINTDB_CMD_insertRefreshOutDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
- } insert_refresh_out;
-
- /**
- * Data requiered by the #PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST command
- */
- struct PERF_TALER_MINTDB_CMD_getLinkDataListDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
- } get_link_data_list;
-
- /**
- * Data requiered by the #PERF_TALER_MINTDB_CMD_GET_TRANSFER command
- */
- struct PERF_TALER_MINTDB_CMD_getTransferDetails
- {
- /**
- * The refresh session hash
- */
- const char *label_hash;
- unsigned int index_hash;
- } get_transfer;
-
-};
-
-
-/**
- * Command to be interpreted.
- */
-struct PERF_TALER_MINTDB_Cmd
-{
- /**
- * Type of the command
- */
- enum PERF_TALER_MINTDB_CMD_Name command;
-
- /**
- * Label to refer to the command
- */
- const char *label;
-
- /**
- * Command specific data
- */
- union PERF_TALER_MINTDB_CMD_Details details;
-
- /**
- * Data easily accessible
- */
- struct PERF_TALER_MINTDB_Data exposed;
-};
-
-
-/**
- * Run a benchmark
- *
- * @param benchmark_name the name of the benchmark, displayed in the logs
- * @param configuration_file path to the taler configuration file to use
- * @param init the commands to use for the database initialisation,
- * if #NULL the standard initialization is used
- * @param benchmark the commands for the benchmark
- * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
- */
-int
-PERF_TALER_MINTDB_run_benchmark (const char *benchmark_name,
- const char *configuration_file,
- struct PERF_TALER_MINTDB_Cmd *init,
- struct PERF_TALER_MINTDB_Cmd *benchmark);
-
-
-/**
- * Runs the command array @a cmd
- * using @a db_plugin to connect to the database
- *
- * @param db_plugin the connection to the database
- * @param cmd the commands to run
- */
-int
-PERF_TALER_MINTDB_interpret(
- struct TALER_MINTDB_Plugin *db_plugin,
- struct PERF_TALER_MINTDB_Cmd cmd[]);
-
-
-/**
- * Check if the given command array is syntaxicly correct
- * This will check if the label are corrects but will not check if
- * they are pointing to an apropriate command.
- *
- * @param cmd the command array to check
- * @return #GNUNET_OK is @a cmd is correct; #GNUNET_SYSERR if it is'nt
- */
-int
-PERF_TALER_MINTDB_check (const struct PERF_TALER_MINTDB_Cmd *cmd);
-
-#endif
diff --git a/src/mintdb/perf_taler_mintdb_values.h b/src/mintdb/perf_taler_mintdb_values.h
deleted file mode 100644
index 35f87f5b0..000000000
--- a/src/mintdb/perf_taler_mintdb_values.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file mintdb/perf_taler_mintdb_values.h
- * @brief Values for tweaking the performance analysis
- * @author Nicolas Fournier
- */
-#ifndef __PERF_TALER_MINTDB__VALUES_H__
-#define __PERF_TALER_MINTDB__VALUES_H__
-
-
-#endif
diff --git a/src/mintdb/plugin_mintdb_common.c b/src/mintdb/plugin_mintdb_common.c
deleted file mode 100644
index 1f2fdc58b..000000000
--- a/src/mintdb/plugin_mintdb_common.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mintdb/plugin_mintdb_common.c
- * @brief Functions shared across plugins, this file is meant to be
- * included in each plugin.
- * @author Christian Grothoff
- */
-
-/**
- * Free memory associated with the given reserve history.
- *
- * @param cls the @e cls of this struct with the plugin-specific state (unused)
- * @param rh history to free.
- */
-static void
-common_free_reserve_history (void *cls,
- struct TALER_MINTDB_ReserveHistory *rh)
-{
- struct TALER_MINTDB_BankTransfer *bt;
- struct TALER_MINTDB_CollectableBlindcoin *cbc;
- struct TALER_MINTDB_ReserveHistory *backref;
-
- while (NULL != rh)
- {
- switch(rh->type)
- {
- case TALER_MINTDB_RO_BANK_TO_MINT:
- bt = rh->details.bank;
- if (NULL != bt->wire)
- json_decref (bt->wire);
- GNUNET_free (bt);
- break;
- case TALER_MINTDB_RO_WITHDRAW_COIN:
- cbc = rh->details.withdraw;
- GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key);
- GNUNET_free (cbc);
- break;
- }
- backref = rh;
- rh = rh->next;
- GNUNET_free (backref);
- }
-}
-
-
-/**
- * Free memory of the link data list.
- *
- * @param cls the @e cls of this struct with the plugin-specific state (unused)
- * @param ldl link data list to release
- */
-static void
-common_free_link_data_list (void *cls,
- struct TALER_MINTDB_LinkDataList *ldl)
-{
- struct TALER_MINTDB_LinkDataList *next;
-
- while (NULL != ldl)
- {
- next = ldl->next;
- GNUNET_free (ldl->link_data_enc);
- GNUNET_free (ldl);
- ldl = next;
- }
-}
-
-
-/**
- * Free linked list of transactions.
- *
- * @param cls the @e cls of this struct with the plugin-specific state (unused)
- * @param list list to free
- */
-static void
-common_free_coin_transaction_list (void *cls,
- struct TALER_MINTDB_TransactionList *list)
-{
- struct TALER_MINTDB_TransactionList *next;
-
- while (NULL != list)
- {
- next = list->next;
-
- switch (list->type)
- {
- case TALER_MINTDB_TT_DEPOSIT:
- json_decref (list->details.deposit->wire);
- GNUNET_CRYPTO_rsa_public_key_free (list->details.deposit->coin.denom_pub.rsa_public_key);
- GNUNET_CRYPTO_rsa_signature_free (list->details.deposit->coin.denom_sig.rsa_signature);
- GNUNET_free (list->details.deposit);
- break;
- case TALER_MINTDB_TT_REFRESH_MELT:
- GNUNET_free (list->details.melt);
- break;
- }
- GNUNET_free (list);
- list = next;
- }
-}
-
-
-/**
- * Free melt commitment data.
- *
- * @param cls the @e cls of this struct with the plugin-specific state (unused)
- * @param mc data structure to free
- */
-static void
-common_free_melt_commitment (void *cls,
- struct TALER_MINTDB_MeltCommitment *mc)
-{
- unsigned int i;
- unsigned int k;
-
- if (NULL != mc->melts)
- {
- for (i=0;i<mc->num_oldcoins;i++)
- {
- GNUNET_CRYPTO_rsa_signature_free (mc->melts[i].coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (mc->melts[i].coin.denom_pub.rsa_public_key);
- }
- GNUNET_free (mc->melts);
- }
- if (NULL != mc->denom_pubs)
- {
- for (i=0;i<mc->num_newcoins;i++)
- if (NULL != mc->denom_pubs[i].rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (mc->denom_pubs[i].rsa_public_key);
- GNUNET_free (mc->denom_pubs);
- }
- for (k=0;k<TALER_CNC_KAPPA;k++)
- {
- if (NULL != mc->commit_coins[k])
- {
- for (i=0;i<mc->num_newcoins;i++)
- {
- GNUNET_free (mc->commit_coins[k][i].refresh_link);
- GNUNET_free (mc->commit_coins[k][i].coin_ev);
- }
- GNUNET_free (mc->commit_coins[k]);
- }
- GNUNET_free_non_null (mc->commit_links[k]);
- }
- GNUNET_free (mc);
-}
-
-/* end of plugin_mintdb_common.c */
diff --git a/src/mintdb/plugin_mintdb_postgres.c b/src/mintdb/plugin_mintdb_postgres.c
deleted file mode 100644
index 772b86e83..000000000
--- a/src/mintdb/plugin_mintdb_postgres.c
+++ /dev/null
@@ -1,4295 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file plugin_mintdb_postgres.c
- * @brief Low-level (statement-level) Postgres database access for the mint
- * @author Florian Dold
- * @author Christian Grothoff
- * @author Sree Harsha Totakura
- */
-#include "platform.h"
-#include "taler_pq_lib.h"
-#include "taler_mintdb_plugin.h"
-#include <pthread.h>
-#include <libpq-fe.h>
-
-#include "plugin_mintdb_common.c"
-
-/**
- * For testing / experiments, we set the Postgres schema to
- * #TALER_TEMP_SCHEMA_NAME so we can easily purge everything
- * associated with a test. We *also* should use the database
- * "talercheck" instead of "taler" for testing, but we're doing
- * both: better safe than sorry.
- */
-#define TALER_TEMP_SCHEMA_NAME "taler_temporary"
-
-/**
- * Log a query error.
- *
- * @param result PQ result object of the query that failed
- */
-#define QUERY_ERR(result) \
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result))
-
-
-/**
- * Log a really unexpected PQ error.
- *
- * @param result PQ result object of the PQ operation that failed
- */
-#define BREAK_DB_ERR(result) do { \
- GNUNET_break (0); \
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
- } while (0)
-
-
-/**
- * Shorthand for exit jumps. Logs the current line number
- * and jumps to the "EXITIF_exit" label.
- *
- * @param cond condition that must be TRUE to exit with an error
- */
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-
-/**
- * Execute an SQL statement and log errors on failure. Must be
- * run in a function that has an "SQLEXEC_fail" label to jump
- * to in case the SQL statement failed.
- *
- * @param conn database connection
- * @param sql SQL statement to run
- */
-#define SQLEXEC_(conn, sql) \
- do { \
- PGresult *result = PQexec (conn, sql); \
- if (PGRES_COMMAND_OK != PQresultStatus (result)) \
- { \
- BREAK_DB_ERR (result); \
- PQclear (result); \
- goto SQLEXEC_fail; \
- } \
- PQclear (result); \
- } while (0)
-
-
-/**
- * Run an SQL statement, ignoring errors and clearing the result.
- *
- * @param conn database connection
- * @param sql SQL statement to run
- */
-#define SQLEXEC_IGNORE_ERROR_(conn, sql) \
- do { \
- PGresult *result = PQexec (conn, sql); \
- PQclear (result); \
- } while (0)
-
-
-/**
- * Handle for a database session (per-thread, for transactions).
- */
-struct TALER_MINTDB_Session
-{
- /**
- * Postgres connection handle.
- */
- PGconn *conn;
-};
-
-
-/**
- * Type of the "cls" argument given to each of the functions in
- * our API.
- */
-struct PostgresClosure
-{
-
- /**
- * Thread-local database connection.
- * Contains a pointer to `PGconn` or NULL.
- */
- pthread_key_t db_conn_threadlocal;
-
- /**
- * Database connection string, as read from
- * the configuration.
- */
- char *connection_cfg_str;
-};
-
-
-
-/**
- * Set the given connection to use a temporary schema
- *
- * @param db the database connection
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error
- */
-static int
-set_temporary_schema (PGconn *db)
-{
- SQLEXEC_(db,
- "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";"
- "SET search_path to " TALER_TEMP_SCHEMA_NAME ";");
- return GNUNET_OK;
- SQLEXEC_fail:
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Drop the temporary taler schema. This is only useful for testcases
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database session to use
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-static int
-postgres_drop_temporary (void *cls,
- struct TALER_MINTDB_Session *session)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Dropping temporary tables\n");
- SQLEXEC_ (session->conn,
- "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;");
- return GNUNET_OK;
- SQLEXEC_fail:
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Function called by libpq whenever it wants to log something.
- * We already log whenever we care, so this function does nothing
- * and merely exists to silence the libpq logging.
- *
- * @param arg NULL
- * @param res information about some libpq event
- */
-static void
-pq_notice_receiver_cb (void *arg,
- const PGresult *res)
-{
- /* do nothing, intentionally */
-}
-
-
-/**
- * Function called by libpq whenever it wants to log something.
- * We log those using the Taler logger.
- *
- * @param arg NULL
- * @param message information about some libpq event
- */
-static void
-pq_notice_processor_cb (void *arg,
- const char *message)
-{
- GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
- "pq",
- "%s",
- message);
-}
-
-
-/**
- * Create the necessary tables if they are not present
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param temporary should we use a temporary schema
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-static int
-postgres_create_tables (void *cls,
- int temporary)
-{
- struct PostgresClosure *pc = cls;
- PGconn *conn;
-
- conn = PQconnectdb (pc->connection_cfg_str);
- if (CONNECTION_OK != PQstatus (conn))
- {
- TALER_LOG_ERROR ("Database connection failed: %s\n",
- PQerrorMessage (conn));
- PQfinish (conn);
- return GNUNET_SYSERR;
- }
- PQsetNoticeReceiver (conn,
- &pq_notice_receiver_cb,
- NULL);
- PQsetNoticeProcessor (conn,
- &pq_notice_processor_cb,
- NULL);
- if ( (GNUNET_YES == temporary) &&
- (GNUNET_SYSERR == set_temporary_schema (conn)))
- {
- PQfinish (conn);
- return GNUNET_SYSERR;
- }
-#define SQLEXEC(sql) SQLEXEC_(conn, sql);
-#define SQLEXEC_INDEX(sql) SQLEXEC_IGNORE_ERROR_(conn, sql);
- /* Denomination table for holding the publicly available information of
- denominations keys. The denominations are to be referred to by using
- foreign keys. The denominations are deleted by a housekeeping tool;
- hence, do not use `ON DELETE CASCADE' on these rows in the tables
- referencing these rows */
- SQLEXEC ("CREATE TABLE IF NOT EXISTS denominations"
- "(pub BYTEA PRIMARY KEY"
- ",master_pub BYTEA NOT NULL CHECK (LENGTH(master_pub)=32)"
- ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)"
- ",valid_from INT8 NOT NULL"
- ",expire_withdraw INT8 NOT NULL"
- ",expire_spend INT8 NOT NULL"
- ",expire_legal INT8 NOT NULL"
- ",coin_val INT8 NOT NULL" /* value of this denom */
- ",coin_frac INT4 NOT NULL" /* fractional value of this denom */
- ",coin_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" /* assuming same currency for fees */
- ",fee_withdraw_val INT8 NOT NULL"
- ",fee_withdraw_frac INT4 NOT NULL"
- ",fee_withdraw_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",fee_deposit_val INT8 NOT NULL"
- ",fee_deposit_frac INT4 NOT NULL"
- ",fee_deposit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",fee_refresh_val INT8 NOT NULL"
- ",fee_refresh_frac INT4 NOT NULL"
- ",fee_refresh_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ")");
- /* reserves table is for summarization of a reserve. It is updated when new
- funds are added and existing funds are withdrawn. The 'expiration_date'
- can be used to eventually get rid of reserves that have not been used
- for a very long time (either by refunding the owner or by greedily
- grabbing the money, depending on the Mint's terms of service) */
- SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves"
- "(reserve_pub BYTEA PRIMARY KEY"
- ",current_balance_val INT8 NOT NULL"
- ",current_balance_frac INT4 NOT NULL"
- ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",expiration_date INT8 NOT NULL"
- ")");
- /* index on reserves table */
- SQLEXEC_INDEX ("CREATE INDEX reserves_reserve_pub_index ON "
- "reserves (reserve_pub)");
- /* reserves_in table collects the transactions which transfer funds
- into the reserve. The rows of this table correspond to each
- incoming transaction. */
- SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in"
- "(reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
- ",balance_val INT8 NOT NULL"
- ",balance_frac INT4 NOT NULL"
- ",balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",details TEXT NOT NULL "
- ",execution_date INT8 NOT NULL"
- ",PRIMARY KEY (reserve_pub,details)"
- ");");
- /* Create indices on reserves_in */
- SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_index"
- " ON reserves_in (reserve_pub);");
- SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_details_index"
- " ON reserves_in (reserve_pub,details);");
- SQLEXEC_INDEX ("CREATE INDEX execution_index"
- " ON reserves_in (execution_date);");
- /* Table with the withdraw operations that have been performed on a reserve.
- The 'h_blind_ev' is the hash of the blinded coin. It serves as a primary
- key, as (broken) clients that use a non-random coin and blinding factor
- should fail to even withdraw, as otherwise the coins will fail to deposit
- (as they really must be unique). */
- SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out"
- "(h_blind_ev BYTEA PRIMARY KEY"
- ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
- ",denom_sig BYTEA NOT NULL"
- ",reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32) REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
- ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)"
- ",execution_date INT8 NOT NULL"
- ",amount_with_fee_val INT8 NOT NULL"
- ",amount_with_fee_frac INT4 NOT NULL"
- ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",withdraw_fee_val INT8 NOT NULL"
- ",withdraw_fee_frac INT4 NOT NULL"
- ",withdraw_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ");");
- /* Index blindcoins(reserve_pub) for get_reserves_out statement */
- SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON"
- " reserves_out (reserve_pub)");
- SQLEXEC_INDEX ("CREATE INDEX reserves_out_h_blind_ev_index ON "
- "reserves_out (h_blind_ev)");
- /* Table with coins that have been (partially) spent, used to track
- coin information only once. */
- SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins "
- "(coin_pub BYTEA NOT NULL PRIMARY KEY"
- ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
- ",denom_sig BYTEA NOT NULL"
- ")");
- /**
- * The DB will show negative values for some values of the following fields as
- * we use them as 16 bit unsigned integers
- * @a num_oldcoins
- * @a num_newcoins
- * Do not do arithmetic in SQL on these fields.
- * NOTE: maybe we should instead forbid values >= 2^15 categorically?
- */
- SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions "
- "(session_hash BYTEA PRIMARY KEY CHECK (LENGTH(session_hash)=64)"
- ",num_oldcoins INT2 NOT NULL"
- ",num_newcoins INT2 NOT NULL"
- ",noreveal_index INT2 NOT NULL"
- ")");
- /* Table with coins that have been melted. Gives the coin's public
- key (coin_pub), the melting session, the index of this coin in that
- session, the signature affirming the melting and the amount that
- this coin contributed to the melting session.
- */
- SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melts "
- "(coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)"
- ",session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)"
- ",oldcoin_index INT2 NOT NULL"
- ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)"
- ",amount_with_fee_val INT8 NOT NULL"
- ",amount_with_fee_frac INT4 NOT NULL"
- ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",melt_fee_val INT8 NOT NULL"
- ",melt_fee_frac INT4 NOT NULL"
- ",melt_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",PRIMARY KEY (session_hash, oldcoin_index)" /* a coin can be used only
- once in a refresh session */
- ") ");
- /* Table with information about the desired denominations to be created
- during a refresh operation; contains the denomination key for each
- of the coins (for a given refresh session) */
- SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order "
- "(session_hash BYTEA NOT NULL CHECK (LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash)"
- ",newcoin_index INT2 NOT NULL "
- ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
- ",PRIMARY KEY (session_hash, newcoin_index)"
- ")");
-
- /* Table with the commitments for a refresh operation; includes
- the session_hash for which this is the link information, the
- oldcoin index and the cut-and-choose index (from 0 to #TALER_CNC_KAPPA-1),
- as well as the actual link data (the transfer public key and the encrypted
- link secret).
- NOTE: We might want to simplify this and not have the oldcoin_index
- and instead store all link secrets, one after the other, in one big BYTEA.
- (#3814) */
- SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link "
- "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)"
- ",transfer_pub BYTEA NOT NULL CHECK(LENGTH(transfer_pub)=32)"
- ",link_secret_enc BYTEA NOT NULL"
- ",oldcoin_index INT2 NOT NULL"
- ",cnc_index INT2 NOT NULL"
- ")");
- /* Table with the commitments for the new coins that are to be created
- during a melting session. Includes the session, the cut-and-choose
- index and the index of the new coin, and the envelope of the new
- coin to be signed, as well as the encrypted information about the
- private key and the blinding factor for the coin (for verification
- in case this cnc_index is chosen to be revealed)
-
- NOTE: We might want to simplify this and not have the
- newcoin_index and instead store all coin_evs and
- link_vector_encs, one after the other, in two big BYTEAs.
- (#3815) */
- SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin "
- "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) "
- ",cnc_index INT2 NOT NULL"
- ",newcoin_index INT2 NOT NULL"
- ",link_vector_enc BYTEA NOT NULL"
- ",coin_ev BYTEA NOT NULL"
- ")");
- /* Table with the signatures over coins generated during a refresh
- operation. Needed to answer /refresh/link queries later. Stores
- the coin signatures under the respective session hash and index. */
- SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_out "
- "(session_hash BYTEA NOT NULL CHECK(LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash) "
- ",newcoin_index INT2 NOT NULL"
- ",ev_sig BYTEA NOT NULL"
- ")");
- /* This table contains the wire transfers the mint is supposed to
- execute to transmit funds to the merchants (and manage refunds). */
- SQLEXEC("CREATE TABLE IF NOT EXISTS deposits "
- "(serial_id BIGSERIAL PRIMARY KEY"
- ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
- ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
- ",denom_sig BYTEA NOT NULL"
- ",transaction_id INT8 NOT NULL"
- ",amount_with_fee_val INT8 NOT NULL"
- ",amount_with_fee_frac INT4 NOT NULL"
- ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",deposit_fee_val INT8 NOT NULL"
- ",deposit_fee_frac INT4 NOT NULL"
- ",deposit_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",timestamp INT8 NOT NULL"
- ",refund_deadline INT8 NOT NULL"
- ",wire_deadline INT8 NOT NULL"
- ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
- ",h_contract BYTEA NOT NULL CHECK (LENGTH(h_contract)=64)"
- ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)"
- ",coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)"
- ",wire TEXT NOT NULL"
- ",tiny BOOLEAN NOT NULL DEFAULT false"
- ",done BOOLEAN NOT NULL DEFAULT false"
- ")");
- /* Index for get_deposit statement on coin_pub, transaction_id and merchant_pub */
- SQLEXEC_INDEX("CREATE INDEX deposits_coin_pub_index "
- "ON deposits(coin_pub, transaction_id, merchant_pub)");
- /* Table for the tracking API, mapping from wire transfer identifiers
- to transactions and back */
- SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking "
- "(h_contract BYTEA CHECK (LENGTH(h_contract)=64)"
- ",h_wire BYTEA CHECK (LENGTH(h_wire)=64)"
- ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
- ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
- ",transaction_id INT8 NOT NULL"
- ",wtid_raw BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=" TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR ")"
- ",execution_time INT8 NOT NULL"
- ",coin_amount_val INT8 NOT NULL"
- ",coin_amount_frac INT4 NOT NULL"
- ",coin_amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",coin_fee_val INT8 NOT NULL"
- ",coin_fee_frac INT4 NOT NULL"
- ",coin_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ")");
- /* Index for lookup_transactions statement on wtid */
- SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
- "ON aggregation_tracking(wtid_raw)");
- /* Index for lookup_deposit_wtid statement */
- SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_deposit_index "
- "ON aggregation_tracking(coin_pub,h_contract,h_wire,transaction_id,merchant_pub)");
-
- /* This table contains the pre-commit data for
- wire transfers the mint is about to execute. */
- SQLEXEC("CREATE TABLE IF NOT EXISTS prewire "
- "(serial_id BIGSERIAL PRIMARY KEY"
- ",type TEXT NOT NULL"
- ",finished BOOLEAN NOT NULL DEFAULT false"
- ",buf BYTEA NOT NULL"
- ")");
- /* Index for prepare_data_iterate statement */
- SQLEXEC_INDEX("CREATE INDEX prepare_iteration_index "
- "ON prewire(type,finished)");
-
-
-#undef SQLEXEC
-#undef SQLEXEC_INDEX
-
- PQfinish (conn);
- return GNUNET_OK;
-
- SQLEXEC_fail:
- PQfinish (conn);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Setup prepared statements.
- *
- * @param db_conn connection handle to initialize
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
- */
-static int
-postgres_prepare (PGconn *db_conn)
-{
- PGresult *result;
-
-#define PREPARE(name, sql, ...) \
- do { \
- result = PQprepare (db_conn, name, sql, __VA_ARGS__); \
- if (PGRES_COMMAND_OK != PQresultStatus (result)) \
- { \
- BREAK_DB_ERR (result); \
- PQclear (result); result = NULL; \
- return GNUNET_SYSERR; \
- } \
- PQclear (result); result = NULL; \
- } while (0);
-
- /* Used in #postgres_insert_denomination_info() */
- PREPARE ("denomination_insert",
- "INSERT INTO denominations "
- "(pub"
- ",master_pub"
- ",master_sig"
- ",valid_from"
- ",expire_withdraw"
- ",expire_spend"
- ",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",coin_curr" /* assuming same currency for fees */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_withdraw_curr" /* must match coin_curr */
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_deposit_curr" /* must match coin_curr */
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refresh_curr" /* must match coin_curr */
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
- " $11, $12, $13, $14, $15, $16, $17, $18, $19);",
- 19, NULL);
-
- /* Used in #postgres_get_denomination_info() */
- PREPARE ("denomination_get",
- "SELECT"
- " master_pub"
- ",master_sig"
- ",valid_from"
- ",expire_withdraw"
- ",expire_spend"
- ",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",coin_curr" /* assuming same currency for fees */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_withdraw_curr" /* must match coin_curr */
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_deposit_curr" /* must match coin_curr */
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refresh_curr" /* must match coin_curr */
- " FROM denominations"
- " WHERE pub=$1;",
- 1, NULL);
-
- /* Used in #postgres_reserve_get() */
- PREPARE ("reserve_get",
- "SELECT"
- " current_balance_val"
- ",current_balance_frac"
- ",current_balance_curr"
- ",expiration_date"
- " FROM reserves"
- " WHERE reserve_pub=$1"
- " LIMIT 1;",
- 1, NULL);
-
- /* Used in #postgres_reserves_in_insert() when the reserve is new */
- PREPARE ("reserve_create",
- "INSERT INTO reserves "
- "(reserve_pub"
- ",current_balance_val"
- ",current_balance_frac"
- ",current_balance_curr"
- ",expiration_date"
- ") VALUES "
- "($1, $2, $3, $4, $5);",
- 5, NULL);
-
- /* Used in #postgres_reserves_update() when the reserve is updated */
- PREPARE ("reserve_update",
- "UPDATE reserves"
- " SET"
- " expiration_date=$1 "
- ",current_balance_val=$2 "
- ",current_balance_frac=$3 "
- "WHERE current_balance_curr=$4 AND reserve_pub=$5",
- 5, NULL);
-
- /* Used in #postgres_reserves_in_insert() to store transaction details */
- PREPARE ("reserves_in_add_transaction",
- "INSERT INTO reserves_in "
- "(reserve_pub"
- ",balance_val"
- ",balance_frac"
- ",balance_curr"
- ",details"
- ",execution_date"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6);",
- 6, NULL);
-
- /* Used in #postgres_get_reserve_history() to obtain inbound transactions
- for a reserve */
- PREPARE ("reserves_in_get_transactions",
- "SELECT"
- " balance_val"
- ",balance_frac"
- ",balance_curr"
- ",execution_date"
- ",details"
- " FROM reserves_in"
- " WHERE reserve_pub=$1",
- 1, NULL);
-
- /* Used in #postgres_insert_withdraw_info() to store
- the signature of a blinded coin with the blinded coin's
- details before returning it during /reserve/withdraw. We store
- the coin's denomination information (public key, signature)
- and the blinded message as well as the reserve that the coin
- is being withdrawn from and the signature of the message
- authorizing the withdrawal. */
- PREPARE ("insert_withdraw_info",
- "INSERT INTO reserves_out "
- "(h_blind_ev"
- ",denom_pub"
- ",denom_sig"
- ",reserve_pub"
- ",reserve_sig"
- ",execution_date"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",withdraw_fee_val"
- ",withdraw_fee_frac"
- ",withdraw_fee_curr"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);",
- 12, NULL);
-
- /* Used in #postgres_get_withdraw_info() to
- locate the response for a /reserve/withdraw request
- using the hash of the blinded message. Used to
- make sure /reserve/withdraw requests are idempotent. */
- PREPARE ("get_withdraw_info",
- "SELECT"
- " denom_pub"
- ",denom_sig"
- ",reserve_sig"
- ",reserve_pub"
- ",execution_date"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",withdraw_fee_val"
- ",withdraw_fee_frac"
- ",withdraw_fee_curr"
- " FROM reserves_out"
- " WHERE h_blind_ev=$1",
- 1, NULL);
-
- /* Used during #postgres_get_reserve_history() to
- obtain all of the /reserve/withdraw operations that
- have been performed on a given reserve. (i.e. to
- demonstrate double-spending) */
- PREPARE ("get_reserves_out",
- "SELECT"
- " h_blind_ev"
- ",denom_pub"
- ",denom_sig"
- ",reserve_sig"
- ",execution_date"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",withdraw_fee_val"
- ",withdraw_fee_frac"
- ",withdraw_fee_curr"
- " FROM reserves_out"
- " WHERE reserve_pub=$1;",
- 1, NULL);
-
- /* Used in #postgres_get_refresh_session() to fetch
- high-level information about a refresh session */
- PREPARE ("get_refresh_session",
- "SELECT"
- " num_oldcoins"
- ",num_newcoins"
- ",noreveal_index"
- " FROM refresh_sessions "
- " WHERE session_hash=$1 ",
- 1, NULL);
-
- /* Used in #postgres_create_refresh_session() to store
- high-level information about a refresh session */
- PREPARE ("insert_refresh_session",
- "INSERT INTO refresh_sessions "
- "(session_hash "
- ",num_oldcoins "
- ",num_newcoins "
- ",noreveal_index "
- ") VALUES "
- "($1, $2, $3, $4);",
- 4, NULL);
-
- /* Used in #postgres_get_known_coin() to fetch
- the denomination public key and signature for
- a coin known to the mint. */
- PREPARE ("get_known_coin",
- "SELECT"
- " denom_pub"
- ",denom_sig"
- " FROM known_coins"
- " WHERE coin_pub=$1",
- 1, NULL);
-
- /* Used in #postgres_insert_known_coin() to store
- the denomination public key and signature for
- a coin known to the mint. */
- PREPARE ("insert_known_coin",
- "INSERT INTO known_coins "
- "(coin_pub"
- ",denom_pub"
- ",denom_sig"
- ") VALUES "
- "($1,$2,$3);",
- 3, NULL);
-
- /* Store information about the desired denominations for a
- refresh operation, used in #postgres_insert_refresh_order() */
- PREPARE ("insert_refresh_order",
- "INSERT INTO refresh_order "
- "(newcoin_index "
- ",session_hash "
- ",denom_pub "
- ") VALUES "
- "($1, $2, $3);",
- 3, NULL);
-
- /* Obtain information about the desired denominations for a
- refresh operation, used in #postgres_get_refresh_order() */
- PREPARE ("get_refresh_order",
- "SELECT denom_pub"
- " FROM refresh_order"
- " WHERE session_hash=$1 AND newcoin_index=$2",
- 2, NULL);
-
- /* Used in #postgres_insert_refresh_melt to store information
- about melted coins */
- PREPARE ("insert_refresh_melt",
- "INSERT INTO refresh_melts "
- "(coin_pub "
- ",session_hash"
- ",oldcoin_index "
- ",coin_sig "
- ",amount_with_fee_val "
- ",amount_with_fee_frac "
- ",amount_with_fee_curr "
- ",melt_fee_val "
- ",melt_fee_frac "
- ",melt_fee_curr "
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);",
- 10, NULL);
-
- /* Used in #postgres_get_refresh_melt to obtain information
- about melted coins */
- PREPARE ("get_refresh_melt",
- "SELECT"
- " coin_pub"
- ",coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",melt_fee_val "
- ",melt_fee_frac "
- ",melt_fee_curr "
- " FROM refresh_melts"
- " WHERE session_hash=$1 AND oldcoin_index=$2",
- 2, NULL);
-
- /* Query the 'refresh_melts' by coin public key */
- PREPARE ("get_refresh_melt_by_coin",
- "SELECT"
- " session_hash"
- /* ",oldcoin_index" // not needed */
- ",coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",melt_fee_val "
- ",melt_fee_frac "
- ",melt_fee_curr "
- " FROM refresh_melts"
- " WHERE coin_pub=$1",
- 1, NULL);
-
- /* Used in #postgres_insert_refresh_commit_links() to
- store commitments */
- PREPARE ("insert_refresh_commit_link",
- "INSERT INTO refresh_commit_link "
- "(session_hash"
- ",transfer_pub"
- ",cnc_index"
- ",oldcoin_index"
- ",link_secret_enc"
- ") VALUES "
- "($1, $2, $3, $4, $5);",
- 5, NULL);
-
- /* Used in #postgres_get_refresh_commit_links() to
- retrieve original commitments during /refresh/reveal */
- PREPARE ("get_refresh_commit_link",
- "SELECT"
- " transfer_pub"
- ",link_secret_enc"
- " FROM refresh_commit_link"
- " WHERE session_hash=$1 AND cnc_index=$2 AND oldcoin_index=$3",
- 3, NULL);
-
- /* Used in #postgres_insert_refresh_commit_coins() to
- store coin commitments. */
- PREPARE ("insert_refresh_commit_coin",
- "INSERT INTO refresh_commit_coin "
- "(session_hash"
- ",cnc_index"
- ",newcoin_index"
- ",link_vector_enc"
- ",coin_ev"
- ") VALUES "
- "($1, $2, $3, $4, $5);",
- 5, NULL);
-
- /* Used in #postgres_get_refresh_commit_coins() to
- retrieve the original coin envelopes, to either be
- verified or signed. */
- PREPARE ("get_refresh_commit_coin",
- "SELECT"
- " link_vector_enc"
- ",coin_ev"
- " FROM refresh_commit_coin"
- " WHERE session_hash=$1 AND cnc_index=$2 AND newcoin_index=$3",
- 3, NULL);
-
- /* Store information about a /deposit the mint is to execute.
- Used in #postgres_insert_deposit(). */
- PREPARE ("insert_deposit",
- "INSERT INTO deposits "
- "(coin_pub"
- ",denom_pub"
- ",denom_sig"
- ",transaction_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",deposit_fee_curr"
- ",timestamp"
- ",refund_deadline"
- ",wire_deadline"
- ",merchant_pub"
- ",h_contract"
- ",h_wire"
- ",coin_sig"
- ",wire"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
- " $11, $12, $13, $14, $15, $16, $17, $18);",
- 18, NULL);
-
- /* Fetch an existing deposit request, used to ensure idempotency
- during /deposit processing. Used in #postgres_have_deposit(). */
- PREPARE ("get_deposit",
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",timestamp"
- ",refund_deadline"
- ",wire_deadline"
- ",h_contract"
- ",h_wire"
- " FROM deposits"
- " WHERE ("
- " (coin_pub=$1) AND"
- " (transaction_id=$2) AND"
- " (merchant_pub=$3)"
- " )",
- 3, NULL);
-
- /* Fetch an existing deposit request.
- Used in #postgres_wire_lookup_deposit_wtid(). */
- PREPARE ("get_deposit_for_wtid",
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",deposit_fee_curr"
- ",wire_deadline"
- " FROM deposits"
- " WHERE ("
- " (coin_pub=$1) AND"
- " (transaction_id=$2) AND"
- " (merchant_pub=$3) AND"
- " (h_contract=$4) AND"
- " (h_wire=$5)"
- " )",
- 5, NULL);
-
- /* Used in #postgres_get_ready_deposit() */
- PREPARE ("deposits_get_ready",
- "SELECT"
- " serial_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",deposit_fee_curr"
- ",wire_deadline"
- ",transaction_id"
- ",h_contract"
- ",wire"
- ",merchant_pub"
- ",coin_pub"
- " FROM deposits"
- " WHERE"
- " tiny=false AND"
- " done=false"
- " ORDER BY wire_deadline ASC"
- " LIMIT 1;",
- 0, NULL);
-
- /* Used in #postgres_iterate_matching_deposits() */
- PREPARE ("deposits_iterate_matching",
- "SELECT"
- " serial_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",deposit_fee_curr"
- ",wire_deadline"
- ",transaction_id"
- ",h_contract"
- ",coin_pub"
- " FROM deposits"
- " WHERE"
- " merchant_pub=$1 AND"
- " h_wire=$2 AND"
- " done=false"
- " ORDER BY wire_deadline ASC"
- " LIMIT $3",
- 3, NULL);
-
- /* Used in #postgres_mark_deposit_tiny() */
- PREPARE ("mark_deposit_tiny",
- "UPDATE deposits"
- " SET tiny=true"
- " WHERE serial_id=$1",
- 1, NULL);
-
- /* Used in #postgres_mark_deposit_done() */
- PREPARE ("mark_deposit_done",
- "UPDATE deposits"
- " SET done=true"
- " WHERE serial_id=$1",
- 1, NULL);
-
- /* Used in #postgres_get_coin_transactions() to obtain information
- about how a coin has been spend with /deposit requests. */
- PREPARE ("get_deposit_with_coin_pub",
- "SELECT"
- " denom_pub"
- ",denom_sig"
- ",transaction_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",amount_with_fee_curr"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",deposit_fee_curr"
- ",timestamp"
- ",refund_deadline"
- ",merchant_pub"
- ",h_contract"
- ",h_wire"
- ",wire"
- ",coin_sig"
- " FROM deposits"
- " WHERE coin_pub=$1",
- 1, NULL);
-
- /* Used in #postgres_insert_refresh_out() to store the
- generated signature(s) for future requests, i.e. /refresh/link */
- PREPARE ("insert_refresh_out",
- "INSERT INTO refresh_out "
- "(session_hash"
- ",newcoin_index"
- ",ev_sig"
- ") VALUES "
- "($1, $2, $3)",
- 3, NULL);
-
- /* Used in #postgres_get_link_data_list(). We use the session_hash
- to obtain the "noreveal_index" for that session, and then select
- the encrypted link vectors (link_vector_enc) and the
- corresponding signatures (ev_sig) and the denomination keys from
- the respective tables (namely refresh_melts and refresh_order)
- using the session_hash as the primary filter (on join) and the
- 'noreveal_index' to constrain the selection on the commitment.
- We also want to get the triplet for each of the newcoins, so we
- have another constraint to ensure we get each triplet with
- matching "newcoin_index" values. NOTE: This may return many
- results, both for different sessions and for the different coins
- being minted in the refresh ops. NOTE: There may be more
- efficient ways to express the same query. */
- PREPARE ("get_link",
- "SELECT link_vector_enc,ev_sig,ro.denom_pub"
- " FROM refresh_melts rm "
- " JOIN refresh_order ro USING (session_hash)"
- " JOIN refresh_commit_coin rcc USING (session_hash)"
- " JOIN refresh_sessions rs USING (session_hash)"
- " JOIN refresh_out rc USING (session_hash)"
- " WHERE ro.session_hash=$1"
- " AND ro.newcoin_index=rcc.newcoin_index"
- " AND ro.newcoin_index=rc.newcoin_index"
- " AND rcc.cnc_index=rs.noreveal_index",
- 1, NULL);
-
- /* Used in #postgres_get_transfer(). Given the public key of a
- melted coin, we obtain the corresponding encrypted link secret
- and the transfer public key. This is done by first finding
- the session_hash(es) of all sessions the coin was melted into,
- and then constraining the result to the selected "noreveal_index"
- and the transfer public key to the corresponding index of the
- old coin.
- NOTE: This may (in theory) return multiple results, one per session
- that the old coin was melted into. */
- PREPARE ("get_transfer",
- "SELECT transfer_pub,link_secret_enc,session_hash"
- " FROM refresh_melts rm"
- " JOIN refresh_commit_link rcl USING (session_hash)"
- " JOIN refresh_sessions rs USING (session_hash)"
- " WHERE rm.coin_pub=$1"
- " AND rm.oldcoin_index = rcl.oldcoin_index"
- " AND rcl.cnc_index=rs.noreveal_index",
- 1, NULL);
-
- /* Used in #postgres_lookup_wire_transfer */
- PREPARE ("lookup_transactions",
- "SELECT"
- " h_contract"
- ",h_wire"
- ",coin_pub"
- ",merchant_pub"
- ",transaction_id"
- ",execution_time"
- ",coin_amount_val"
- ",coin_amount_frac"
- ",coin_amount_curr"
- ",coin_fee_val"
- ",coin_fee_frac"
- ",coin_fee_curr"
- " FROM aggregation_tracking"
- " WHERE wtid_raw=$1",
- 1, NULL);
-
- /* Used in #postgres_wire_lookup_deposit_wtid */
- PREPARE ("lookup_deposit_wtid",
- "SELECT"
- " wtid_raw"
- ",execution_time"
- ",coin_amount_val"
- ",coin_amount_frac"
- ",coin_amount_curr"
- ",coin_fee_val"
- ",coin_fee_frac"
- ",coin_fee_curr"
- " FROM aggregation_tracking"
- " WHERE"
- " coin_pub=$1 AND"
- " h_contract=$2 AND"
- " h_wire=$3 AND"
- " transaction_id=$4 AND"
- " merchant_pub=$5",
- 5, NULL);
-
- /* Used in #postgres_insert_aggregation_tracking */
- PREPARE ("insert_aggregation_tracking",
- "INSERT INTO aggregation_tracking "
- "(h_contract"
- ",h_wire"
- ",coin_pub"
- ",merchant_pub"
- ",transaction_id"
- ",wtid_raw"
- ",execution_time"
- ",coin_amount_val"
- ",coin_amount_frac"
- ",coin_amount_curr"
- ",coin_fee_val"
- ",coin_fee_frac"
- ",coin_fee_curr"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
- 13, NULL);
-
-
- /* Used in #postgres_wire_prepare_data_insert() to store
- wire transfer information before actually committing it with the bank */
- PREPARE ("wire_prepare_data_insert",
- "INSERT INTO prewire "
- "(type"
- ",buf"
- ") VALUES "
- "($1, $2)",
- 2, NULL);
-
- /* Used in #postgres_wire_prepare_data_mark_finished() */
- PREPARE ("wire_prepare_data_mark_done",
- "UPDATE prewire"
- " SET finished=true"
- " WHERE serial_id=$1",
- 1, NULL);
-
- /* Used in #postgres_wire_prepare_data_get() */
- PREPARE ("wire_prepare_data_get",
- "SELECT"
- " serial_id"
- ",buf"
- " FROM prewire"
- " WHERE"
- " type=$1 AND"
- " finished=false"
- " ORDER BY serial_id ASC"
- " LIMIT 1",
- 1, NULL);
-
- return GNUNET_OK;
-#undef PREPARE
-}
-
-
-/**
- * Close thread-local database connection when a thread is destroyed.
- *
- * @param cls closure we get from pthreads (the db handle)
- */
-static void
-db_conn_destroy (void *cls)
-{
- struct TALER_MINTDB_Session *session = cls;
- PGconn *db_conn = session->conn;
-
- if (NULL != db_conn)
- PQfinish (db_conn);
- GNUNET_free (session);
-}
-
-
-/**
- * Get the thread-local database-handle.
- * Connect to the db if the connection does not exist yet.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
- * database default one
- * @return the database connection, or NULL on error
- */
-static struct TALER_MINTDB_Session *
-postgres_get_session (void *cls,
- int temporary)
-{
- struct PostgresClosure *pc = cls;
- PGconn *db_conn;
- struct TALER_MINTDB_Session *session;
-
- if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal)))
- return session;
- db_conn = PQconnectdb (pc->connection_cfg_str);
- if (CONNECTION_OK !=
- PQstatus (db_conn))
- {
- TALER_LOG_ERROR ("Database connection failed: %s\n",
- PQerrorMessage (db_conn));
- GNUNET_break (0);
- return NULL;
- }
- PQsetNoticeReceiver (db_conn,
- &pq_notice_receiver_cb,
- NULL);
- PQsetNoticeProcessor (db_conn,
- &pq_notice_processor_cb,
- NULL);
- if ( (GNUNET_YES == temporary) &&
- (GNUNET_SYSERR == set_temporary_schema(db_conn)) )
- {
- GNUNET_break (0);
- return NULL;
- }
- if (GNUNET_OK !=
- postgres_prepare (db_conn))
- {
- GNUNET_break (0);
- return NULL;
- }
- session = GNUNET_new (struct TALER_MINTDB_Session);
- session->conn = db_conn;
- if (0 != pthread_setspecific (pc->db_conn_threadlocal,
- session))
- {
- GNUNET_break (0);
- PQfinish (db_conn);
- GNUNET_free (session);
- return NULL;
- }
- return session;
-}
-
-
-/**
- * Start a transaction.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session the database connection
- * @return #GNUNET_OK on success
- */
-static int
-postgres_start (void *cls,
- struct TALER_MINTDB_Session *session)
-{
- PGresult *result;
-
- result = PQexec (session->conn,
- "BEGIN");
- if (PGRES_COMMAND_OK !=
- PQresultStatus (result))
- {
- TALER_LOG_ERROR ("Failed to start transaction: %s\n",
- PQresultErrorMessage (result));
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
-
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Roll back the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session the database connection
- * @return #GNUNET_OK on success
- */
-static void
-postgres_rollback (void *cls,
- struct TALER_MINTDB_Session *session)
-{
- PGresult *result;
-
- result = PQexec (session->conn,
- "ROLLBACK");
- GNUNET_break (PGRES_COMMAND_OK ==
- PQresultStatus (result));
- PQclear (result);
-}
-
-
-/**
- * Commit the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session the database connection
- * @return #GNUNET_OK on success
- */
-static int
-postgres_commit (void *cls,
- struct TALER_MINTDB_Session *session)
-{
- PGresult *result;
-
- result = PQexec (session->conn,
- "COMMIT");
- if (PGRES_COMMAND_OK !=
- PQresultStatus (result))
- {
- const char *sqlstate;
-
- sqlstate = PQresultErrorField (result,
- PG_DIAG_SQLSTATE);
- if (NULL == sqlstate)
- {
- /* very unexpected... */
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- /* 40P01: deadlock, 40001: serialization failure */
- if ( (0 == strcmp (sqlstate,
- "40P01")) ||
- (0 == strcmp (sqlstate,
- "40001")) )
- {
- /* These two can be retried and have a fair chance of working
- the next time */
- PQclear (result);
- return GNUNET_NO;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Database commit failure: %s\n",
- sqlstate);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Insert a denomination key's public information into the database for
- * reference by auditors and other consistency checks.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @param denom_pub the public key used for signing coins of this denomination
- * @param issue issuing information with value, fees and other info about the coin
- * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
- */
-static int
-postgres_insert_denomination_info (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_DenominationPublicKey *denom_pub,
- const struct TALER_MINTDB_DenominationKeyInformationP *issue)
-{
- PGresult *result;
- int ret;
-
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key),
- GNUNET_PQ_query_param_auto_from_type (&issue->properties.master),
- GNUNET_PQ_query_param_auto_from_type (&issue->signature),
- GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.start),
- GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_withdraw),
- GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_spend),
- GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_legal),
- TALER_PQ_query_param_amount_nbo (&issue->properties.value),
- TALER_PQ_query_param_amount_nbo (&issue->properties.fee_withdraw),
- TALER_PQ_query_param_amount_nbo (&issue->properties.fee_deposit),
- TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refresh),
- GNUNET_PQ_query_param_end
- };
- /* check fees match coin currency */
- GNUNET_assert (GNUNET_YES ==
- TALER_amount_cmp_currency_nbo (&issue->properties.value,
- &issue->properties.fee_withdraw));
- GNUNET_assert (GNUNET_YES ==
- TALER_amount_cmp_currency_nbo (&issue->properties.value,
- &issue->properties.fee_deposit));
- GNUNET_assert (GNUNET_YES ==
- TALER_amount_cmp_currency_nbo (&issue->properties.value,
- &issue->properties.fee_refresh));
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "denomination_insert",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- ret = GNUNET_SYSERR;
- BREAK_DB_ERR (result);
- }
- else
- {
- ret = GNUNET_OK;
- }
- PQclear (result);
- return ret;
-}
-
-
-/**
- * Fetch information about a denomination key.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to use
- * @param denom_pub the public key used for signing coins of this denomination
- * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL
- * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure
- */
-static int
-postgres_get_denomination_info (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_DenominationPublicKey *denom_pub,
- struct TALER_MINTDB_DenominationKeyInformationP *issue)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "denomination_get",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
- if (1 != PQntuples (result))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (NULL == issue)
- {
- PQclear (result);
- return GNUNET_OK;
- }
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("master_pub",
- &issue->properties.master),
- GNUNET_PQ_result_spec_auto_from_type ("master_sig",
- &issue->signature),
- GNUNET_PQ_result_spec_absolute_time_nbo ("valid_from",
- &issue->properties.start),
- GNUNET_PQ_result_spec_absolute_time_nbo ("expire_withdraw",
- &issue->properties.expire_withdraw),
- GNUNET_PQ_result_spec_absolute_time_nbo ("expire_spend",
- &issue->properties.expire_spend),
- GNUNET_PQ_result_spec_absolute_time_nbo ("expire_legal",
- &issue->properties.expire_legal),
- TALER_PQ_result_spec_amount_nbo ("coin",
- &issue->properties.value),
- TALER_PQ_result_spec_amount_nbo ("fee_withdraw",
- &issue->properties.fee_withdraw),
- TALER_PQ_result_spec_amount_nbo ("fee_deposit",
- &issue->properties.fee_deposit),
- TALER_PQ_result_spec_amount_nbo ("fee_refresh",
- &issue->properties.fee_refresh),
- GNUNET_PQ_result_spec_end
- };
-
- EXITIF (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- 0));
- }
- PQclear (result);
- return GNUNET_OK;
-
- EXITIF_exit:
- PQclear (result);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Get the summary of a reserve.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session the database connection handle
- * @param[in,out] reserve the reserve data. The public key of the reserve should be
- * set in this structure; it is used to query the database. The balance
- * and expiration are then filled accordingly.
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-static int
-postgres_reserve_get (void *cls,
- struct TALER_MINTDB_Session *session,
- struct TALER_MINTDB_Reserve *reserve)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type(&reserve->pub),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "reserve_get",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_amount("current_balance", &reserve->balance),
- GNUNET_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry),
- GNUNET_PQ_result_spec_end
- };
-
- EXITIF (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- 0));
- }
- PQclear (result);
- return GNUNET_OK;
-
- EXITIF_exit:
- PQclear (result);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Updates a reserve with the data from the given reserve structure.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session the database connection
- * @param reserve the reserve structure whose data will be used to update the
- * corresponding record in the database.
- * @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error
- */
-static int
-reserves_update (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_Reserve *reserve)
-{
- PGresult *result;
- int ret;
-
- if (NULL == reserve)
- return GNUNET_SYSERR;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_absolute_time (&reserve->expiry),
- TALER_PQ_query_param_amount (&reserve->balance),
- GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
- GNUNET_PQ_query_param_end
- };
- result = GNUNET_PQ_exec_prepared (session->conn,
- "reserve_update",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus(result))
- {
- QUERY_ERR (result);
- ret = GNUNET_SYSERR;
- }
- else
- {
- ret = GNUNET_OK;
- }
- PQclear (result);
- return ret;
-}
-
-
-/**
- * Insert an incoming transaction into reserves. New reserves are also created
- * through this function. Note that this API call starts (and stops) its
- * own transaction scope (so the application must not do so).
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session the database connection handle
- * @param reserve_pub public key of the reserve
- * @param balance the amount that has to be added to the reserve
- * @param execution_time when was the amount added
- * @param details bank transaction details justifying the increment,
- * must be unique for each incoming transaction
- * @return #GNUNET_OK upon success; #GNUNET_NO if the given
- * @a details are already known for this @a reserve_pub,
- * #GNUNET_SYSERR upon failures (DB error, incompatible currency)
- */
-static int
-postgres_reserves_in_insert (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *balance,
- struct GNUNET_TIME_Absolute execution_time,
- const json_t *details)
-{
- PGresult *result;
- int reserve_exists;
- struct TALER_MINTDB_Reserve reserve;
- struct GNUNET_TIME_Absolute expiry;
-
- if (GNUNET_OK != postgres_start (cls,
- session))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- reserve.pub = *reserve_pub;
- reserve_exists = postgres_reserve_get (cls,
- session,
- &reserve);
- if (GNUNET_SYSERR == reserve_exists)
- {
- GNUNET_break (0);
- goto rollback;
- }
- expiry = GNUNET_TIME_absolute_add (execution_time,
- TALER_IDLE_RESERVE_EXPIRATION_TIME);
- if (GNUNET_NO == reserve_exists)
- {
- /* New reserve, create balance for the first time; we do this
- before adding the actual transaction to "reserves_in", as
- for a new reserve it can't be a duplicate 'add' operation,
- and as the 'add' operation may need the reserve entry
- as a foreign key. */
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- TALER_PQ_query_param_amount (balance),
- GNUNET_PQ_query_param_absolute_time (&expiry),
- GNUNET_PQ_query_param_end
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Reserve does not exist; creating a new one\n");
- result = GNUNET_PQ_exec_prepared (session->conn,
- "reserve_create",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus(result))
- {
- QUERY_ERR (result);
- PQclear (result);
- goto rollback;
- }
- PQclear (result);
- }
- /* Create new incoming transaction, SQL "primary key" logic
- is used to guard against duplicates. If a duplicate is
- detected, we rollback (which really shouldn't undo
- anything) and return #GNUNET_NO to indicate that this failure
- is kind-of harmless (already executed). */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&reserve.pub),
- TALER_PQ_query_param_amount (balance),
- TALER_PQ_query_param_json (details),
- GNUNET_PQ_query_param_absolute_time (&execution_time),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "reserves_in_add_transaction",
- params);
- }
- if (PGRES_COMMAND_OK != PQresultStatus(result))
- {
- const char *efield;
-
- efield = PQresultErrorField (result,
- PG_DIAG_SQLSTATE);
- if ( (PGRES_FATAL_ERROR == PQresultStatus(result)) &&
- (NULL != strstr ("23505", /* unique violation */
- efield)) )
- {
- /* This means we had the same reserve/justification/details
- before */
- PQclear (result);
- postgres_rollback (cls,
- session);
- return GNUNET_NO;
- }
- QUERY_ERR (result);
- PQclear (result);
- goto rollback;
- }
- PQclear (result);
-
- if (GNUNET_YES == reserve_exists)
- {
- /* If the reserve already existed, we need to still update the
- balance; we do this after checking for duplication, as
- otherwise we might have to actually pay the cost to roll this
- back for duplicate transactions; like this, we should virtually
- never actually have to rollback anything. */
- struct TALER_MINTDB_Reserve updated_reserve;
-
- updated_reserve.pub = reserve.pub;
- if (GNUNET_OK !=
- TALER_amount_add (&updated_reserve.balance,
- &reserve.balance,
- balance))
- {
- /* currency overflow or incompatible currency */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Attempt to deposit incompatible amount into reserve\n");
- goto rollback;
- }
- updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry,
- reserve.expiry);
- if (GNUNET_OK != reserves_update (cls,
- session,
- &updated_reserve))
- goto rollback;
- }
- if (GNUNET_OK != postgres_commit (cls,
- session))
- return GNUNET_SYSERR;
- return GNUNET_OK;
-
- rollback:
- postgres_rollback (cls,
- session);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Locate the response for a /reserve/withdraw request under the
- * key of the hash of the blinded message.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection to use
- * @param h_blind hash of the blinded coin to be signed (will match
- * `h_coin_envelope` in the @a collectable to be returned)
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
-static int
-postgres_get_withdraw_info (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *h_blind,
- struct TALER_MINTDB_CollectableBlindcoin *collectable)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_blind),
- GNUNET_PQ_query_param_end
- };
- int ret;
-
- ret = GNUNET_SYSERR;
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_withdraw_info",
- params);
-
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- goto cleanup;
- }
- if (0 == PQntuples (result))
- {
- ret = GNUNET_NO;
- goto cleanup;
- }
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
- &collectable->denom_pub.rsa_public_key),
- GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
- &collectable->sig.rsa_signature),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
- &collectable->reserve_sig),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- &collectable->reserve_pub),
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &collectable->amount_with_fee),
- TALER_PQ_result_spec_amount ("withdraw_fee",
- &collectable->withdraw_fee),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- goto cleanup;
- }
- }
- collectable->h_coin_envelope = *h_blind;
- ret = GNUNET_YES;
-
- cleanup:
- PQclear (result);
- return ret;
-}
-
-
-/**
- * Store collectable bit coin under the corresponding
- * hash of the blinded message.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection to use
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
-static int
-postgres_insert_withdraw_info (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_CollectableBlindcoin *collectable)
-{
- PGresult *result;
- struct TALER_MINTDB_Reserve reserve;
- int ret = GNUNET_SYSERR;
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Absolute expiry;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
- GNUNET_PQ_query_param_rsa_public_key (collectable->denom_pub.rsa_public_key),
- GNUNET_PQ_query_param_rsa_signature (collectable->sig.rsa_signature),
- GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
- GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
- GNUNET_PQ_query_param_absolute_time (&now),
- TALER_PQ_query_param_amount (&collectable->amount_with_fee),
- TALER_PQ_query_param_amount (&collectable->withdraw_fee),
- GNUNET_PQ_query_param_end
- };
-
- now = GNUNET_TIME_absolute_get ();
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_withdraw_info",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- goto cleanup;
- }
- reserve.pub = collectable->reserve_pub;
- if (GNUNET_OK != postgres_reserve_get (cls,
- session,
- &reserve))
- {
- /* Should have been checked before we got here... */
- GNUNET_break (0);
- goto cleanup;
- }
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (&reserve.balance,
- &reserve.balance,
- &collectable->amount_with_fee))
- {
- /* Should have been checked before we got here... */
- GNUNET_break (0);
- goto cleanup;
- }
- expiry = GNUNET_TIME_absolute_add (now,
- TALER_IDLE_RESERVE_EXPIRATION_TIME);
- reserve.expiry = GNUNET_TIME_absolute_max (expiry,
- reserve.expiry);
- if (GNUNET_OK != reserves_update (cls,
- session,
- &reserve))
- {
- GNUNET_break (0);
- goto cleanup;
- }
- ret = GNUNET_OK;
- cleanup:
- PQclear (result);
- return ret;
-}
-
-
-/**
- * Get all of the transaction history associated with the specified
- * reserve.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session connection to use
- * @param reserve_pub public key of the reserve
- * @return known transaction history (NULL if reserve is unknown)
- */
-static struct TALER_MINTDB_ReserveHistory *
-postgres_get_reserve_history (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- PGresult *result;
- struct TALER_MINTDB_ReserveHistory *rh;
- struct TALER_MINTDB_ReserveHistory *rh_tail;
- int rows;
- int ret;
-
- rh = NULL;
- rh_tail = NULL;
- ret = GNUNET_SYSERR;
- {
- struct TALER_MINTDB_BankTransfer *bt;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "reserves_in_get_transactions",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- goto cleanup;
- }
- if (0 == (rows = PQntuples (result)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to fetch history for an unknown reserve.\n");
- goto cleanup;
- }
- while (0 < rows)
- {
- bt = GNUNET_new (struct TALER_MINTDB_BankTransfer);
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_amount ("balance",
- &bt->amount),
- GNUNET_PQ_result_spec_absolute_time ("execution_date",
- &bt->execution_date),
- TALER_PQ_result_spec_json ("details",
- &bt->wire),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_YES !=
- GNUNET_PQ_extract_result (result, rs, --rows))
- {
- GNUNET_break (0);
- GNUNET_free (bt);
- PQclear (result);
- goto cleanup;
- }
- }
- bt->reserve_pub = *reserve_pub;
- if (NULL != rh_tail)
- {
- rh_tail->next = GNUNET_new (struct TALER_MINTDB_ReserveHistory);
- rh_tail = rh_tail->next;
- }
- else
- {
- rh_tail = GNUNET_new (struct TALER_MINTDB_ReserveHistory);
- rh = rh_tail;
- }
- rh_tail->type = TALER_MINTDB_RO_BANK_TO_MINT;
- rh_tail->details.bank = bt;
- }
- PQclear (result);
- }
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_end
- };
-
- GNUNET_assert (NULL != rh);
- GNUNET_assert (NULL != rh_tail);
- GNUNET_assert (NULL == rh_tail->next);
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_reserves_out",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- PQclear (result);
- goto cleanup;
- }
- rows = PQntuples (result);
- while (0 < rows)
- {
- struct TALER_MINTDB_CollectableBlindcoin *cbc;
-
- cbc = GNUNET_new (struct TALER_MINTDB_CollectableBlindcoin);
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
- &cbc->h_coin_envelope),
- GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
- &cbc->denom_pub.rsa_public_key),
- GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
- &cbc->sig.rsa_signature),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
- &cbc->reserve_sig),
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &cbc->amount_with_fee),
- TALER_PQ_result_spec_amount ("withdraw_fee",
- &cbc->withdraw_fee),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_YES !=
- GNUNET_PQ_extract_result (result, rs, --rows))
- {
- GNUNET_break (0);
- GNUNET_free (cbc);
- PQclear (result);
- goto cleanup;
- }
- cbc->reserve_pub = *reserve_pub;
- }
- rh_tail->next = GNUNET_new (struct TALER_MINTDB_ReserveHistory);
- rh_tail = rh_tail->next;
- rh_tail->type = TALER_MINTDB_RO_WITHDRAW_COIN;
- rh_tail->details.withdraw = cbc;
- }
- ret = GNUNET_OK;
- PQclear (result);
- }
- cleanup:
- if (GNUNET_SYSERR == ret)
- {
- common_free_reserve_history (cls,
- rh);
- rh = NULL;
- }
- return rh;
-}
-
-
-/**
- * Check if we have the specified deposit already in the database.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param deposit deposit to search for
- * @return #GNUNET_YES if we know this operation,
- * #GNUNET_NO if this exact deposit is unknown to us
- * #GNUNET_SYSERR on DB error
- */
-static int
-postgres_have_deposit (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_Deposit *deposit)
-{
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
- GNUNET_PQ_query_param_uint64 (&deposit->transaction_id),
- GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_deposit",
- params);
- if (PGRES_TUPLES_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
-
- /* Now we check that the other information in @a deposit
- also matches, and if not report inconsistencies. */
- {
- struct TALER_MINTDB_Deposit deposit2;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &deposit2.amount_with_fee),
- GNUNET_PQ_result_spec_absolute_time ("timestamp",
- &deposit2.timestamp),
- GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
- &deposit2.refund_deadline),
- GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
- &deposit2.wire_deadline),
- GNUNET_PQ_result_spec_auto_from_type ("h_contract",
- &deposit2.h_contract),
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &deposit2.h_wire),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if ( (0 != TALER_amount_cmp (&deposit->amount_with_fee,
- &deposit2.amount_with_fee)) ||
- (deposit->timestamp.abs_value_us !=
- deposit2.timestamp.abs_value_us) ||
- (deposit->refund_deadline.abs_value_us !=
- deposit2.refund_deadline.abs_value_us) ||
- (0 != memcmp (&deposit->h_contract,
- &deposit2.h_contract,
- sizeof (struct GNUNET_HashCode))) ||
- (0 != memcmp (&deposit->h_wire,
- &deposit2.h_wire,
- sizeof (struct GNUNET_HashCode))) )
- {
- /* Inconsistencies detected! Does not match! (We might want to
- expand the API with a 'get_deposit' function to return the
- original transaction details to be used for an error message
- in the future!) #3838 */
- PQclear (result);
- return GNUNET_NO;
- }
- }
- PQclear (result);
- return GNUNET_YES;
-}
-
-
-/**
- * Mark a deposit as tiny, thereby declaring that it cannot be
- * executed by itself and should no longer be returned by
- * @e iterate_ready_deposits()
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit_rowid identifies the deposit row to modify
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-postgres_mark_deposit_tiny (void *cls,
- struct TALER_MINTDB_Session *session,
- unsigned long long rowid)
-{
- uint64_t serial_id = rowid;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&serial_id),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "mark_deposit_tiny",
- params);
- if (PGRES_COMMAND_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Mark a deposit as done, thereby declaring that it cannot be
- * executed at all anymore, and should no longer be returned by
- * @e iterate_ready_deposits() or @e iterate_matching_deposits().
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit_rowid identifies the deposit row to modify
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-postgres_mark_deposit_done (void *cls,
- struct TALER_MINTDB_Session *session,
- unsigned long long rowid)
-{
- uint64_t serial_id = rowid;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&serial_id),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "mark_deposit_done",
- params);
- if (PGRES_COMMAND_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Obtain information about deposits that are ready to be executed.
- * Such deposits must not be marked as "tiny" or "done", and the
- * execution time must be in the past.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param deposit_cb function to call for ONE such deposit
- * @param deposit_cb_cls closure for @a deposit_cb
- * @return number of rows processed, 0 if none exist,
- * #GNUNET_SYSERR on error
- */
-static int
-postgres_get_ready_deposit (void *cls,
- struct TALER_MINTDB_Session *session,
- TALER_MINTDB_DepositIterator deposit_cb,
- void *deposit_cb_cls)
-{
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
- unsigned int n;
- int ret;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "deposits_get_ready",
- params);
- if (PGRES_TUPLES_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == (n = PQntuples (result)))
- {
- PQclear (result);
- return 0;
- }
- GNUNET_break (1 == n);
- {
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct GNUNET_TIME_Absolute wire_deadline;
- struct GNUNET_HashCode h_contract;
- struct TALER_MerchantPublicKeyP merchant_pub;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- uint64_t transaction_id;
- uint64_t serial_id;
- json_t *wire;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("serial_id",
- &serial_id),
- GNUNET_PQ_result_spec_uint64 ("transaction_id",
- &transaction_id),
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_result_spec_amount ("deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
- &wire_deadline),
- GNUNET_PQ_result_spec_auto_from_type ("h_contract",
- &h_contract),
- GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
- &merchant_pub),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- TALER_PQ_result_spec_json ("wire",
- &wire),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- ret = deposit_cb (deposit_cb_cls,
- serial_id,
- &merchant_pub,
- &coin_pub,
- &amount_with_fee,
- &deposit_fee,
- transaction_id,
- &h_contract,
- wire_deadline,
- wire);
- GNUNET_PQ_cleanup_result (rs);
- PQclear (result);
- }
- return (GNUNET_OK == ret) ? 1 : 0;
-}
-
-
-/**
- * Obtain information about other pending deposits for the same
- * destination. Those deposits must not already be "done".
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session connection to the database
- * @param h_wire destination of the wire transfer
- * @param merchant_pub public key of the merchant
- * @param deposit_cb function to call for each deposit
- * @param deposit_cb_cls closure for @a deposit_cb
- * @param limit maximum number of matching deposits to return
- * @return number of rows processed, 0 if none exist,
- * #GNUNET_SYSERR on error
- */
-static int
-postgres_iterate_matching_deposits (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- TALER_MINTDB_DepositIterator deposit_cb,
- void *deposit_cb_cls,
- uint32_t limit)
-{
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_uint32 (&limit),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
- unsigned int i;
- unsigned int n;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "deposits_iterate_matching",
- params);
- if (PGRES_TUPLES_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == (n = PQntuples (result)))
- {
- PQclear (result);
- return 0;
- }
- if (n > limit)
- n = limit;
- for (i=0;i<n;i++)
- {
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct GNUNET_TIME_Absolute wire_deadline;
- struct GNUNET_HashCode h_contract;
- struct TALER_MerchantPublicKeyP merchant_pub;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- uint64_t transaction_id;
- uint64_t serial_id;
- int ret;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("serial_id",
- &serial_id),
- GNUNET_PQ_result_spec_uint64 ("transaction_id",
- &transaction_id),
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_result_spec_amount ("deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
- &wire_deadline),
- GNUNET_PQ_result_spec_auto_from_type ("h_contract",
- &h_contract),
- GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
- &merchant_pub),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, i))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- ret = deposit_cb (deposit_cb_cls,
- serial_id,
- &merchant_pub,
- &coin_pub,
- &amount_with_fee,
- &deposit_fee,
- transaction_id,
- &h_contract,
- wire_deadline,
- NULL);
- GNUNET_PQ_cleanup_result (rs);
- PQclear (result);
- if (GNUNET_OK != ret)
- break;
- }
- return i;
-}
-
-
-/**
- * Insert information about deposited coin into the database.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session connection to the database
- * @param deposit deposit information to store
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-postgres_insert_deposit (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_MINTDB_Deposit *deposit)
-{
- PGresult *result;
- int ret;
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
- GNUNET_PQ_query_param_rsa_public_key (deposit->coin.denom_pub.rsa_public_key),
- GNUNET_PQ_query_param_rsa_signature (deposit->coin.denom_sig.rsa_signature),
- GNUNET_PQ_query_param_uint64 (&deposit->transaction_id),
- TALER_PQ_query_param_amount (&deposit->amount_with_fee),
- TALER_PQ_query_param_amount (&deposit->deposit_fee),
- GNUNET_PQ_query_param_absolute_time (&deposit->timestamp),
- GNUNET_PQ_query_param_absolute_time (&deposit->refund_deadline),
- GNUNET_PQ_query_param_absolute_time (&deposit->wire_deadline),
- GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract),
- GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire),
- GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
- TALER_PQ_query_param_json (deposit->wire),
- GNUNET_PQ_query_param_end
- };
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_deposit",
- params);
- }
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- ret = GNUNET_SYSERR;
- }
- else
- {
- ret = GNUNET_OK;
- }
- PQclear (result);
- return ret;
-}
-
-
-/**
- * Lookup refresh session data under the given @a session_hash.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database handle to use
- * @param session_hash hash over the melt to use to locate the session
- * @param[out] refresh_session where to store the result, can be NULL
- * to just check if the session exists
- * @return #GNUNET_YES on success,
- * #GNUNET_NO if not found,
- * #GNUNET_SYSERR on DB failure
- */
-static int
-postgres_get_refresh_session (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- struct TALER_MINTDB_RefreshSession *refresh_session)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_refresh_session",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
- GNUNET_assert (1 == PQntuples (result));
- if (NULL == refresh_session)
- {
- /* We're done if the caller is only interested in whether the
- * session exists or not */
- PQclear (result);
- return GNUNET_YES;
- }
- memset (refresh_session,
- 0,
- sizeof (struct TALER_MINTDB_RefreshSession));
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint16 ("num_oldcoins",
- &refresh_session->num_oldcoins),
- GNUNET_PQ_result_spec_uint16 ("num_newcoins",
- &refresh_session->num_newcoins),
- GNUNET_PQ_result_spec_uint16 ("noreveal_index",
- &refresh_session->noreveal_index),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- }
- PQclear (result);
- return GNUNET_YES;
-}
-
-
-/**
- * Store new refresh session data under the given @a session_hash.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database handle to use
- * @param session_hash hash over the melt to use to locate the session
- * @param refresh_session session data to store
- * @return #GNUNET_YES on success,
- * #GNUNET_SYSERR on DB failure
- */
-static int
-postgres_create_refresh_session (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- const struct TALER_MINTDB_RefreshSession *refresh_session)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&refresh_session->num_oldcoins),
- GNUNET_PQ_query_param_uint16 (&refresh_session->num_newcoins),
- GNUNET_PQ_query_param_uint16 (&refresh_session->noreveal_index),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_refresh_session",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Insert a coin we know of into the DB. The coin can then be referenced by
- * tables for deposits, lock and refresh functionality.
- *
- * @param cls plugin closure
- * @param session the shared database session
- * @param coin_info the public coin info
- * @return #GNUNET_SYSERR upon error; #GNUNET_OK upon success
- */
-static int
-insert_known_coin (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_CoinPublicInfo *coin_info)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub),
- GNUNET_PQ_query_param_rsa_public_key (coin_info->denom_pub.rsa_public_key),
- GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature),
- GNUNET_PQ_query_param_end
- };
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_known_coin",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Retrieve the record for a known coin.
- *
- * @param cls the plugin closure
- * @param session the database session handle
- * @param coin_pub the public key of the coin to search for
- * @param coin_info place holder for the returned coin information object
- * @return #GNUNET_SYSERR upon error; #GNUNET_NO if no coin is found; #GNUNET_OK
- * if upon succesfullying retrieving the record data info @a
- * coin_info
- */
-static int
-get_known_coin (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- struct TALER_CoinPublicInfo *coin_info)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_end
- };
- int nrows;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_known_coin",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- PQclear (result);
- return GNUNET_NO;
- }
- GNUNET_assert (1 == nrows); /* due to primary key */
- if (NULL == coin_info)
- return GNUNET_YES;
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
- &coin_info->denom_pub.rsa_public_key),
- GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
- &coin_info->denom_sig.rsa_signature),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- PQclear (result);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- }
- PQclear (result);
- coin_info->coin_pub = *coin_pub;
- return GNUNET_OK;
-}
-
-
-/**
- * Store the given /refresh/melt request in the database.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param oldcoin_index index of the coin to store
- * @param melt melt operation details to store; includes
- * the session hash of the melt
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-static int
-postgres_insert_refresh_melt (void *cls,
- struct TALER_MINTDB_Session *session,
- uint16_t oldcoin_index,
- const struct TALER_MINTDB_RefreshMelt *melt)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&melt->coin.coin_pub),
- GNUNET_PQ_query_param_auto_from_type (&melt->session_hash),
- GNUNET_PQ_query_param_uint16 (&oldcoin_index),
- GNUNET_PQ_query_param_auto_from_type (&melt->coin_sig),
- TALER_PQ_query_param_amount (&melt->amount_with_fee),
- TALER_PQ_query_param_amount (&melt->melt_fee),
- GNUNET_PQ_query_param_end
- };
- int ret;
-
- /* check if the coin is already known */
- ret = get_known_coin (cls,
- session,
- &melt->coin.coin_pub,
- NULL);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_NO == ret) /* if not, insert it */
- {
- ret = insert_known_coin (cls,
- session,
- &melt->coin);
- if (ret == GNUNET_SYSERR)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- }
- /* insert the melt */
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_refresh_melt",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Get information about melted coin details from the database.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param session_hash session hash of the melt operation
- * @param oldcoin_index index of the coin to retrieve
- * @param melt melt data to fill in, can be NULL
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-static int
-postgres_get_refresh_melt (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t oldcoin_index,
- struct TALER_MINTDB_RefreshMelt *melt)
-{
- PGresult *result;
- struct TALER_CoinPublicInfo coin;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount melt_fee;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&oldcoin_index),
- GNUNET_PQ_query_param_end
- };
- int nrows;
-
- /* check if the melt record exists and get it */
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_refresh_melt",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "get_refresh_melt() returned 0 matching rows\n");
- PQclear (result);
- return GNUNET_NO;
- }
- GNUNET_assert (1 == nrows); /* due to primary key constraint */
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin.coin_pub),
- GNUNET_PQ_result_spec_auto_from_type ("coin_sig", &coin_sig),
- TALER_PQ_result_spec_amount ("amount_with_fee", &amount_with_fee),
- TALER_PQ_result_spec_amount ("melt_fee", &melt_fee),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- }
- /* fetch the coin info and denomination info */
- if (GNUNET_OK != get_known_coin (cls,
- session,
- &coin.coin_pub,
- &coin))
- return GNUNET_SYSERR;
- if (NULL == melt)
- {
- GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (coin.denom_pub.rsa_public_key);
- return GNUNET_OK;
- }
- melt->coin = coin;
- melt->coin_sig = coin_sig;
- melt->session_hash = *session_hash;
- melt->amount_with_fee = amount_with_fee;
- melt->melt_fee = melt_fee;
- return GNUNET_OK;
-}
-
-
-/**
- * Store in the database which coin(s) we want to create
- * in a given refresh operation.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
- * @param denom_pubs array denominations of the coins to create
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-static int
-postgres_insert_refresh_order (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t num_newcoins,
- const struct TALER_DenominationPublicKey *denom_pubs)
-{
- unsigned int i;
-
- for (i=0;i<(unsigned int) num_newcoins;i++)
- {
- uint16_t newcoin_off = (uint16_t) i;
- PGresult *result;
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint16 (&newcoin_off),
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_rsa_public_key (denom_pubs[i].rsa_public_key),
- GNUNET_PQ_query_param_end
- };
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_refresh_order",
- params);
- }
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 != strcmp ("1", PQcmdTuples (result)))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * We allocated some @a denom_pubs information, but now need
- * to abort. Free allocated memory.
- *
- * @param denom_pubs data to free (but not the array itself)
- * @param denom_pubs_len length of @a denom_pubs array
- */
-static void
-free_dpk_result (struct TALER_DenominationPublicKey *denom_pubs,
- unsigned int denom_pubs_len)
-{
- unsigned int i;
-
- for (i=0;i<denom_pubs_len;i++)
- {
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key);
- denom_pubs[i].rsa_public_key = NULL;
- }
-}
-
-
-/**
- * Lookup in the database the coins that we want to
- * create in the given refresh operation.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param num_newcoins size of the array of the @a denom_pubs array
- * @param denom_pubs where to store the deomination keys
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-static int
-postgres_get_refresh_order (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t num_newcoins,
- struct TALER_DenominationPublicKey *denom_pubs)
-{
- unsigned int i;
-
- for (i=0;i<(unsigned int) num_newcoins;i++)
- {
- uint16_t newcoin_off = (uint16_t) i;
- PGresult *result;
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&newcoin_off),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_refresh_order",
- params);
- }
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- free_dpk_result (denom_pubs, i);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- /* FIXME: may want to distinguish between different error cases! */
- free_dpk_result (denom_pubs, i);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (1 == PQntuples (result));
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
- &denom_pubs[i].rsa_public_key),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- PQclear (result);
- GNUNET_break (0);
- free_dpk_result (denom_pubs, i);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- }
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Store information about the commitment of the
- * given coin for the given refresh session in the database.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose index (1st dimension)
- * @param num_newcoins coin index size of the @a commit_coins array
- * @param commit_coins array of coin commitments to store
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on error
- */
-static int
-postgres_insert_refresh_commit_coins (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_newcoins,
- const struct TALER_MINTDB_RefreshCommitCoin *commit_coins)
-{
- char *rle;
- size_t rle_size;
- PGresult *result;
- unsigned int i;
- uint16_t coin_off;
-
- for (i=0;i<(unsigned int) num_newcoins;i++)
- {
- rle = TALER_refresh_link_encrypted_encode (commit_coins[i].refresh_link,
- &rle_size);
- if (NULL == rle)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- coin_off = (uint16_t) i;
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&cnc_index),
- GNUNET_PQ_query_param_uint16 (&coin_off),
- GNUNET_PQ_query_param_fixed_size (rle,
- rle_size),
- GNUNET_PQ_query_param_fixed_size (commit_coins[i].coin_ev,
- commit_coins[i].coin_ev_size),
- GNUNET_PQ_query_param_end
- };
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_refresh_commit_coin",
- params);
- }
- GNUNET_free (rle);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 != strcmp ("1", PQcmdTuples (result)))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * We allocated some @a commit_coin information, but now need
- * to abort. Free allocated memory.
- *
- * @param commit_coins data to free (but not the array itself)
- * @param commit_coins_len length of @a commit_coins array
- */
-static void
-free_cc_result (struct TALER_MINTDB_RefreshCommitCoin *commit_coins,
- unsigned int commit_coins_len)
-{
- unsigned int i;
-
- for (i=0;i<commit_coins_len;i++)
- {
- GNUNET_free (commit_coins[i].refresh_link);
- commit_coins[i].refresh_link = NULL;
- GNUNET_free (commit_coins[i].coin_ev);
- commit_coins[i].coin_ev = NULL;
- commit_coins[i].coin_ev_size = 0;
- }
-}
-
-
-/**
- * Obtain information about the commitment of the
- * given coin of the given refresh session from the database.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index set index (1st dimension)
- * @param num_newcoins size of the @a commit_coins array
- * @param[out] commit_coins array of coin commitments to return
- * @return #GNUNET_OK on success
- * #GNUNET_NO if not found
- * #GNUNET_SYSERR on error
- */
-static int
-postgres_get_refresh_commit_coins (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_newcoins,
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins)
-{
- unsigned int i;
-
- for (i=0;i<(unsigned int) num_newcoins;i++)
- {
- uint16_t newcoin_off = (uint16_t) i;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&cnc_index),
- GNUNET_PQ_query_param_uint16 (&newcoin_off),
- GNUNET_PQ_query_param_end
- };
- void *c_buf;
- size_t c_buf_size;
- void *rl_buf;
- size_t rl_buf_size;
- struct TALER_RefreshLinkEncrypted *rl;
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_refresh_commit_coin",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- free_cc_result (commit_coins, i);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- free_cc_result (commit_coins, i);
- return GNUNET_NO;
- }
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_variable_size ("link_vector_enc",
- &rl_buf,
- &rl_buf_size),
- GNUNET_PQ_result_spec_variable_size ("coin_ev",
- &c_buf,
- &c_buf_size),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_YES !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- PQclear (result);
- free_cc_result (commit_coins, i);
- return GNUNET_SYSERR;
- }
- }
- PQclear (result);
- if (rl_buf_size < sizeof (struct TALER_CoinSpendPrivateKeyP))
- {
- GNUNET_free (c_buf);
- GNUNET_free (rl_buf);
- free_cc_result (commit_coins, i);
- return GNUNET_SYSERR;
- }
- rl = TALER_refresh_link_encrypted_decode (rl_buf,
- rl_buf_size);
- GNUNET_free (rl_buf);
- commit_coins[i].refresh_link = rl;
- commit_coins[i].coin_ev = c_buf;
- commit_coins[i].coin_ev_size = c_buf_size;
- }
- return GNUNET_YES;
-}
-
-
-/**
- * Store the commitment to the given (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose index (1st dimension)
- * @param num_links size of the @a links array to return
- * @param[out] links array of link information to store return
- * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
- */
-static int
-postgres_insert_refresh_commit_links (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_links,
- const struct TALER_RefreshCommitLinkP *links)
-{
- uint16_t i;
-
- for (i=0;i<num_links;i++)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_auto_from_type (&links[i].transfer_pub),
- GNUNET_PQ_query_param_uint16 (&cnc_index),
- GNUNET_PQ_query_param_uint16 (&i),
- GNUNET_PQ_query_param_auto_from_type (&links[i].shared_secret_enc),
- GNUNET_PQ_query_param_end
- };
-
- PGresult *result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_refresh_commit_link",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
-
- if (0 != strcmp ("1", PQcmdTuples (result)))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Obtain the commited (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @param cnc_index cut and choose index (1st dimension)
- * @param num_links size of the @a commit_link array
- * @param[out] links array of link information to return
- * @return #GNUNET_SYSERR on internal error,
- * #GNUNET_NO if commitment was not found
- * #GNUNET_OK on success
- */
-static int
-postgres_get_refresh_commit_links (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t cnc_index,
- uint16_t num_links,
- struct TALER_RefreshCommitLinkP *links)
-{
- uint16_t i;
-
- for (i=0;i<num_links;i++)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&cnc_index),
- GNUNET_PQ_query_param_uint16 (&i),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_refresh_commit_link",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
- &links[i].transfer_pub),
- GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc",
- &links[i].shared_secret_enc),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_YES !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- PQclear (result);
- return GNUNET_SYSERR;
- }
- }
- PQclear (result);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Get all of the information from the given melt commit operation.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param session database connection to use
- * @param session_hash hash to identify refresh session
- * @return NULL if the @a session_hash does not correspond to any known melt
- * operation
- */
-static struct TALER_MINTDB_MeltCommitment *
-postgres_get_melt_commitment (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash)
-{
- struct TALER_MINTDB_RefreshSession rs;
- struct TALER_MINTDB_MeltCommitment *mc;
- uint16_t cnc_index;
- unsigned int i;
-
- if (GNUNET_OK !=
- postgres_get_refresh_session (cls,
- session,
- session_hash,
- &rs))
- return NULL;
- mc = GNUNET_new (struct TALER_MINTDB_MeltCommitment);
- mc->num_newcoins = rs.num_newcoins;
- mc->num_oldcoins = rs.num_oldcoins;
- mc->melts = GNUNET_malloc (mc->num_oldcoins *
- sizeof (struct TALER_MINTDB_RefreshMelt));
- for (i=0;i<mc->num_oldcoins;i++)
- if (GNUNET_OK !=
- postgres_get_refresh_melt (cls,
- session,
- session_hash,
- (uint16_t) i,
- &mc->melts[i]))
- goto cleanup;
- mc->denom_pubs = GNUNET_malloc (mc->num_newcoins *
- sizeof (struct TALER_DenominationPublicKey));
- if (GNUNET_OK !=
- postgres_get_refresh_order (cls,
- session,
- session_hash,
- mc->num_newcoins,
- mc->denom_pubs))
- goto cleanup;
- for (cnc_index=0;cnc_index<TALER_CNC_KAPPA;cnc_index++)
- {
- mc->commit_coins[cnc_index]
- = GNUNET_malloc (mc->num_newcoins *
- sizeof (struct TALER_MINTDB_RefreshCommitCoin));
- if (GNUNET_OK !=
- postgres_get_refresh_commit_coins (cls,
- session,
- session_hash,
- cnc_index,
- mc->num_newcoins,
- mc->commit_coins[cnc_index]))
- goto cleanup;
- mc->commit_links[cnc_index]
- = GNUNET_malloc (mc->num_oldcoins *
- sizeof (struct TALER_RefreshCommitLinkP));
- if (GNUNET_OK !=
- postgres_get_refresh_commit_links (cls,
- session,
- session_hash,
- cnc_index,
- mc->num_oldcoins,
- mc->commit_links[cnc_index]))
- goto cleanup;
- }
- return mc;
-
- cleanup:
- common_free_melt_commitment (cls, mc);
- return NULL;
-}
-
-
-/**
- * Insert signature of a new coin generated during refresh into
- * the database indexed by the refresh session and the index
- * of the coin. This data is later used should an old coin
- * be used to try to obtain the private keys during "/refresh/link".
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param session_hash hash to identify refresh session
- * @param newcoin_index coin index
- * @param ev_sig coin signature
- * @return #GNUNET_OK on success
- */
-static int
-postgres_insert_refresh_out (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash,
- uint16_t newcoin_index,
- const struct TALER_DenominationSignature *ev_sig)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_uint16 (&newcoin_index),
- GNUNET_PQ_query_param_rsa_signature (ev_sig->rsa_signature),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_refresh_out",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Obtain the link data of a coin, that is the encrypted link
- * information, the denomination keys and the signatures.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param session_hash refresh session to get linkage data for
- * @return all known link data for the session
- */
-static struct TALER_MINTDB_LinkDataList *
-postgres_get_link_data_list (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *session_hash)
-{
- struct TALER_MINTDB_LinkDataList *ldl;
- struct TALER_MINTDB_LinkDataList *pos;
- int i;
- int nrows;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (session_hash),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_link",
- params);
-
- ldl = NULL;
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return NULL;
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- PQclear (result);
- return NULL;
- }
-
- for (i = 0; i < nrows; i++)
- {
- struct TALER_RefreshLinkEncrypted *link_enc;
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
- void *ld_buf;
- size_t ld_buf_size;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_variable_size ("link_vector_enc",
- &ld_buf,
- &ld_buf_size),
- GNUNET_PQ_result_spec_rsa_signature ("ev_sig",
- &sig),
- GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
- &denom_pub),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, i))
- {
- PQclear (result);
- GNUNET_break (0);
- common_free_link_data_list (cls,
- ldl);
- return NULL;
- }
- if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
- {
- PQclear (result);
- GNUNET_free (ld_buf);
- common_free_link_data_list (cls,
- ldl);
- return NULL;
- }
- link_enc = TALER_refresh_link_encrypted_decode (ld_buf,
- ld_buf_size);
- GNUNET_free (ld_buf);
- pos = GNUNET_new (struct TALER_MINTDB_LinkDataList);
- pos->next = ldl;
- pos->link_data_enc = link_enc;
- pos->denom_pub.rsa_public_key = denom_pub;
- pos->ev_sig.rsa_signature = sig;
- ldl = pos;
- }
- return ldl;
-}
-
-
-/**
- * Obtain shared secret and transfer public key from the public key of
- * the coin. This information and the link information returned by
- * #postgres_get_link_data_list() enable the owner of an old coin to
- * determine the private keys of the new coins after the melt.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param coin_pub public key of the coin
- * @param tdc function to call for each session the coin was melted into
- * @param tdc_cls closure for @a tdc
- * @return #GNUNET_OK on success,
- * #GNUNET_NO on failure (not found)
- * #GNUNET_SYSERR on internal failure (database issue)
- */
-static int
-postgres_get_transfer (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- TALER_MINTDB_TransferDataCallback tdc,
- void *tdc_cls)
-{
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
- int nrows;
- int i;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_transfer",
- params);
- if (PGRES_TUPLES_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- /* no matches found */
- PQclear (result);
- return GNUNET_NO;
- }
- for (i=0;i<nrows;i++)
- {
- struct GNUNET_HashCode session_hash;
- struct TALER_TransferPublicKeyP transfer_pub;
- struct TALER_EncryptedLinkSecretP shared_secret_enc;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", &transfer_pub),
- GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc", &shared_secret_enc),
- GNUNET_PQ_result_spec_auto_from_type ("session_hash", &session_hash),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- PQclear (result);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- tdc (tdc_cls,
- &session_hash,
- &transfer_pub,
- &shared_secret_enc);
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Compile a list of all (historic) transactions performed
- * with the given coin (/refresh/melt and /deposit operations).
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session database connection
- * @param coin_pub coin to investigate
- * @return list of transactions, NULL if coin is fresh
- */
-static struct TALER_MINTDB_TransactionList *
-postgres_get_coin_transactions (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_CoinSpendPublicKeyP *coin_pub)
-{
- struct TALER_MINTDB_TransactionList *head;
-
- head = NULL;
- /* check deposits */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub),
- GNUNET_PQ_query_param_end
- };
- int nrows;
- int i;
- PGresult *result;
- struct TALER_MINTDB_TransactionList *tl;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_deposit_with_coin_pub",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- PQclear (result);
- goto cleanup;
- }
- nrows = PQntuples (result);
- for (i = 0; i < nrows; i++)
- {
- struct TALER_MINTDB_Deposit *deposit;
-
- deposit = GNUNET_new (struct TALER_MINTDB_Deposit);
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
- &deposit->coin.denom_pub.rsa_public_key),
- GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
- &deposit->coin.denom_sig.rsa_signature),
- GNUNET_PQ_result_spec_uint64 ("transaction_id",
- &deposit->transaction_id),
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &deposit->amount_with_fee),
- TALER_PQ_result_spec_amount ("deposit_fee",
- &deposit->deposit_fee),
- GNUNET_PQ_result_spec_absolute_time ("timestamp",
- &deposit->timestamp),
- GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
- &deposit->refund_deadline),
- GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
- &deposit->merchant_pub),
- GNUNET_PQ_result_spec_auto_from_type ("h_contract",
- &deposit->h_contract),
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &deposit->h_wire),
- TALER_PQ_result_spec_json ("wire",
- &deposit->wire),
- GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
- &deposit->csig),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, i))
- {
- GNUNET_break (0);
- GNUNET_free (deposit);
- PQclear (result);
- goto cleanup;
- }
- deposit->coin.coin_pub = *coin_pub;
- }
- tl = GNUNET_new (struct TALER_MINTDB_TransactionList);
- tl->next = head;
- tl->type = TALER_MINTDB_TT_DEPOSIT;
- tl->details.deposit = deposit;
- head = tl;
- continue;
- }
- PQclear (result);
- }
- /* Handle refreshing */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub),
- GNUNET_PQ_query_param_end
- };
- int nrows;
- int i;
- PGresult *result;
- struct TALER_MINTDB_TransactionList *tl;
-
- /* check if the melt record exists and get it */
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_refresh_melt_by_coin",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- goto cleanup;
- }
- nrows = PQntuples (result);
- for (i=0;i<nrows;i++)
- {
- struct TALER_MINTDB_RefreshMelt *melt;
-
- melt = GNUNET_new (struct TALER_MINTDB_RefreshMelt);
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("session_hash",
- &melt->session_hash),
- /* oldcoin_index not needed */
- GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
- &melt->coin_sig),
- TALER_PQ_result_spec_amount ("amount_with_fee",
- &melt->amount_with_fee),
- TALER_PQ_result_spec_amount ("melt_fee",
- &melt->melt_fee),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- GNUNET_free (melt);
- PQclear (result);
- goto cleanup;
- }
- melt->coin.coin_pub = *coin_pub;
- }
- tl = GNUNET_new (struct TALER_MINTDB_TransactionList);
- tl->next = head;
- tl->type = TALER_MINTDB_TT_REFRESH_MELT;
- tl->details.melt = melt;
- head = tl;
- continue;
- }
- PQclear (result);
- }
- return head;
- cleanup:
- if (NULL != head)
- common_free_coin_transaction_list (cls,
- head);
- return NULL;
-}
-
-
-/**
- * Lookup the list of Taler transactions that were aggregated
- * into a wire transfer by the respective @a wtid.
- *
- * @param cls closure
- * @param session database connection
- * @param wtid the raw wire transfer identifier we used
- * @param cb function to call on each transaction found
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
- * #GNUNET_NO if we found no results
- */
-static int
-postgres_lookup_wire_transfer (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MINTDB_WireTransferDataCallback cb,
- void *cb_cls)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
- int nrows;
- int i;
-
- /* check if the melt record exists and get it */
- result = GNUNET_PQ_exec_prepared (session->conn,
- "lookup_transactions",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "lookup_wire_transfer() returned 0 matching rows\n");
- PQclear (result);
- return GNUNET_NO;
- }
- for (i=0;i<nrows;i++)
- {
- struct GNUNET_HashCode h_contract;
- struct GNUNET_HashCode h_wire;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_MerchantPublicKeyP merchant_pub;
- uint64_t transaction_id;
- struct GNUNET_TIME_Absolute exec_time;
- struct TALER_Amount coin_amount;
- struct TALER_Amount coin_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_contract", &h_contract),
- GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub),
- GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub),
- GNUNET_PQ_result_spec_uint64 ("transaction_id", &transaction_id),
- GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time),
- TALER_PQ_result_spec_amount ("coin_amount", &coin_amount),
- TALER_PQ_result_spec_amount ("coin_fee", &coin_fee),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, i))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- cb (cb_cls,
- &merchant_pub,
- &h_wire,
- &h_contract,
- transaction_id,
- &coin_pub,
- &coin_amount,
- &coin_fee);
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Try to find the wire transfer details for a deposit operation.
- * If we did not execute the deposit yet, return when it is supposed
- * to be executed.
- *
- * @param cls closure
- * @param session database connection
- * @param h_contract hash of the contract
- * @param h_wire hash of merchant wire details
- * @param coin_pub public key of deposited coin
- * @param merchant_pub merchant public key
- * @param transaction_id transaction identifier
- * @param cb function to call with the result
- * @param cb_cls closure to pass to @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
- * #GNUNET_NO if nothing was found
- */
-static int
-postgres_wire_lookup_deposit_wtid (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct GNUNET_HashCode *h_contract,
- const struct GNUNET_HashCode *h_wire,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- uint64_t transaction_id,
- TALER_MINTDB_DepositWtidCallback cb,
- void *cb_cls)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_auto_from_type (h_contract),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_uint64 (&transaction_id),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_end
- };
- int nrows;
-
- /* check if the melt record exists and get it */
- result = GNUNET_PQ_exec_prepared (session->conn,
- "lookup_deposit_wtid",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "lookup_deposit_wtid returned 0 matching rows\n");
- PQclear (result);
-
- /* Check if transaction exists in deposits, so that we just
- do not have a WTID yet, if so, do call the CB with a NULL wtid
- and return GNUNET_YES! */
- {
- struct GNUNET_PQ_QueryParam params2[] = {
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_uint64 (&transaction_id),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_contract),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "get_deposit_for_wtid",
- params2);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- }
- nrows = PQntuples (result);
- if (0 == nrows)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "get_deposit_for_wtid returned 0 matching rows\n");
- PQclear (result);
- return GNUNET_NO;
- }
-
- /* Ok, we're aware of the transaction, but it has not yet been
- executed */
- {
- struct GNUNET_TIME_Absolute exec_time;
- struct TALER_Amount coin_amount;
- struct TALER_Amount coin_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_amount ("amount_with_fee", &coin_amount),
- TALER_PQ_result_spec_amount ("deposit_fee", &coin_fee),
- GNUNET_PQ_result_spec_absolute_time ("wire_deadline", &exec_time),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- cb (cb_cls,
- NULL,
- &coin_amount,
- &coin_fee,
- exec_time);
- PQclear (result);
- return GNUNET_YES;
- }
- }
- if (1 != nrows)
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- {
- struct TALER_WireTransferIdentifierRawP wtid;
- struct GNUNET_TIME_Absolute exec_time;
- struct TALER_Amount coin_amount;
- struct TALER_Amount coin_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("wtid_raw", &wtid),
- GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time),
- TALER_PQ_result_spec_amount ("coin_amount", &coin_amount),
- TALER_PQ_result_spec_amount ("coin_fee", &coin_fee),
- GNUNET_PQ_result_spec_end
- };
- if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- cb (cb_cls,
- &wtid,
- &coin_amount,
- &coin_fee,
- exec_time);
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called to insert aggregation information into the DB.
- *
- * @param cls closure
- * @param session database connection
- * @param wtid the raw wire transfer identifier we used
- * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
- * @param h_contract which contract was this payment about
- * @param transaction_id merchant's transaction ID for the payment
- * @param coin_pub which public key was this payment about
- * @param coin_value amount contributed by this coin in total
- * @param coin_fee deposit fee charged by mint for this coin
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
- */
-static int
-postgres_insert_aggregation_tracking (void *cls,
- struct TALER_MINTDB_Session *session,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_value,
- const struct TALER_Amount *coin_fee)
-{
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_contract),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_uint64 (&transaction_id),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_absolute_time (&execution_time),
- TALER_PQ_query_param_amount (coin_value),
- TALER_PQ_query_param_amount (coin_fee),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "insert_aggregation_tracking",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 != strcmp ("1", PQcmdTuples (result)))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called to insert wire transfer commit data into the DB.
- *
- * @param cls closure
- * @param session database connection
- * @param type type of the wire transfer (i.e. "sepa")
- * @param buf buffer with wire transfer preparation data
- * @param buf_size number of bytes in @a buf
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
- */
-static int
-postgres_wire_prepare_data_insert (void *cls,
- struct TALER_MINTDB_Session *session,
- const char *type,
- const char *buf,
- size_t buf_size)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1),
- GNUNET_PQ_query_param_fixed_size (buf, buf_size),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "wire_prepare_data_insert",
- params);
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called to mark wire transfer commit data as finished.
- *
- * @param cls closure
- * @param session database connection
- * @param rowid which entry to mark as finished
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
- */
-static int
-postgres_wire_prepare_data_mark_finished (void *cls,
- struct TALER_MINTDB_Session *session,
- unsigned long long rowid)
-{
- uint64_t serial_id = rowid;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&serial_id),
- GNUNET_PQ_query_param_end
- };
- PGresult *result;
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "wire_prepare_data_mark_done",
- params);
- if (PGRES_COMMAND_OK !=
- PQresultStatus (result))
- {
- BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called to get an unfinished wire transfer
- * preparation data. Fetches at most one item.
- *
- * @param cls closure
- * @param session database connection
- * @param type type fo the wire transfer (i.e. "sepa")
- * @param cb function to call for ONE unfinished item
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if there are no entries,
- * #GNUNET_SYSERR on DB errors
- */
-static int
-postgres_wire_prepare_data_get (void *cls,
- struct TALER_MINTDB_Session *session,
- const char *type,
- TALER_MINTDB_WirePreparationCallback cb,
- void *cb_cls)
-{
- PGresult *result;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1),
- GNUNET_PQ_query_param_end
- };
-
- result = GNUNET_PQ_exec_prepared (session->conn,
- "wire_prepare_data_get",
- params);
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- QUERY_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
- if (1 != PQntuples (result))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
-
- {
- uint64_t serial_id;
- void *buf = NULL;
- size_t buf_size;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("serial_id",
- &serial_id),
- GNUNET_PQ_result_spec_variable_size ("buf",
- &buf,
- &buf_size),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- 0))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- cb (cb_cls,
- serial_id,
- buf,
- buf_size);
- GNUNET_PQ_cleanup_result (rs);
- }
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/**
- * Initialize Postgres database subsystem.
- *
- * @param cls a configuration instance
- * @return NULL on error, otherwise a `struct TALER_MINTDB_Plugin`
- */
-void *
-libtaler_plugin_mintdb_postgres_init (void *cls)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct PostgresClosure *pg;
- struct TALER_MINTDB_Plugin *plugin;
-
- pg = GNUNET_new (struct PostgresClosure);
-
- if (0 != pthread_key_create (&pg->db_conn_threadlocal,
- &db_conn_destroy))
- {
- TALER_LOG_ERROR ("Cannnot create pthread key.\n");
- GNUNET_free (pg);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mintdb-postgres",
- "db_conn_str",
- &pg->connection_cfg_str))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mintdb-postgres",
- "db_conn_str");
- GNUNET_free (pg);
- return NULL;
- }
- plugin = GNUNET_new (struct TALER_MINTDB_Plugin);
- plugin->cls = pg;
- plugin->get_session = &postgres_get_session;
- plugin->drop_temporary = &postgres_drop_temporary;
- plugin->create_tables = &postgres_create_tables;
- plugin->start = &postgres_start;
- plugin->commit = &postgres_commit;
- plugin->rollback = &postgres_rollback;
- plugin->insert_denomination_info = &postgres_insert_denomination_info;
- plugin->get_denomination_info = &postgres_get_denomination_info;
- plugin->reserve_get = &postgres_reserve_get;
- plugin->reserves_in_insert = &postgres_reserves_in_insert;
- plugin->get_withdraw_info = &postgres_get_withdraw_info;
- plugin->insert_withdraw_info = &postgres_insert_withdraw_info;
- plugin->get_reserve_history = &postgres_get_reserve_history;
- plugin->free_reserve_history = &common_free_reserve_history;
- plugin->have_deposit = &postgres_have_deposit;
- plugin->mark_deposit_tiny = &postgres_mark_deposit_tiny;
- plugin->mark_deposit_done = &postgres_mark_deposit_done;
- plugin->get_ready_deposit = &postgres_get_ready_deposit;
- plugin->iterate_matching_deposits = &postgres_iterate_matching_deposits;
- plugin->insert_deposit = &postgres_insert_deposit;
- plugin->get_refresh_session = &postgres_get_refresh_session;
- plugin->create_refresh_session = &postgres_create_refresh_session;
- plugin->insert_refresh_melt = &postgres_insert_refresh_melt;
- plugin->get_refresh_melt = &postgres_get_refresh_melt;
- plugin->insert_refresh_order = &postgres_insert_refresh_order;
- plugin->get_refresh_order = &postgres_get_refresh_order;
- plugin->insert_refresh_commit_coins = &postgres_insert_refresh_commit_coins;
- plugin->get_refresh_commit_coins = &postgres_get_refresh_commit_coins;
- plugin->insert_refresh_commit_links = &postgres_insert_refresh_commit_links;
- plugin->get_refresh_commit_links = &postgres_get_refresh_commit_links;
- plugin->get_melt_commitment = &postgres_get_melt_commitment;
- plugin->free_melt_commitment = &common_free_melt_commitment;
- plugin->insert_refresh_out = &postgres_insert_refresh_out;
- plugin->get_link_data_list = &postgres_get_link_data_list;
- plugin->free_link_data_list = &common_free_link_data_list;
- plugin->get_transfer = &postgres_get_transfer;
- plugin->get_coin_transactions = &postgres_get_coin_transactions;
- plugin->free_coin_transaction_list = &common_free_coin_transaction_list;
- plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
- plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid;
- plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
- plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert;
- plugin->wire_prepare_data_mark_finished = &postgres_wire_prepare_data_mark_finished;
- plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get;
- return plugin;
-}
-
-
-/**
- * Shutdown Postgres database subsystem.
- *
- * @param cls a `struct TALER_MINTDB_Plugin`
- * @return NULL (always)
- */
-void *
-libtaler_plugin_mintdb_postgres_done (void *cls)
-{
- struct TALER_MINTDB_Plugin *plugin = cls;
- struct PostgresClosure *pg = plugin->cls;
-
- GNUNET_free (pg->connection_cfg_str);
- GNUNET_free (pg);
- GNUNET_free (plugin);
- return NULL;
-}
-
-/* end of plugin_mintdb_postgres.c */
diff --git a/src/mintdb/test-mint-db-postgres.conf b/src/mintdb/test-mint-db-postgres.conf
deleted file mode 100644
index 2bdb63eb0..000000000
--- a/src/mintdb/test-mint-db-postgres.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-[mint]
-#The DB plugin to use
-DB = postgres
-
-[mintdb-postgres]
-
-#The connection string the plugin has to use for connecting to the database
-DB_CONN_STR = postgres:///talercheck
diff --git a/src/mintdb/test_mintdb.c b/src/mintdb/test_mintdb.c
deleted file mode 100644
index 0938f8fab..000000000
--- a/src/mintdb/test_mintdb.c
+++ /dev/null
@@ -1,907 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mintdb/test_mintdb.c
- * @brief test cases for DB interaction functions
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include "taler_mintdb_lib.h"
-#include "taler_mintdb_plugin.h"
-
-static int result;
-
-#define FAILIF(cond) \
- do { \
- if (!(cond)){ break;} \
- GNUNET_break (0); \
- goto drop; \
- } while (0)
-
-
-#define RND_BLK(ptr) \
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
-
-#define ZR_BLK(ptr) \
- memset (ptr, 0, sizeof (*ptr))
-
-
-#define CURRENCY "EUR"
-
-static struct TALER_MINTDB_Plugin *plugin;
-
-/**
- * Checks if the given reserve has the given amount of balance and expiry
- *
- * @param session the database connection
- * @param pub the public key of the reserve
- * @param value balance value
- * @param fraction balance fraction
- * @param currency currency of the reserve
- * @return #GNUNET_OK if the given reserve has the same balance and expiration
- * as the given parameters; #GNUNET_SYSERR if not
- */
-static int
-check_reserve (struct TALER_MINTDB_Session *session,
- const struct TALER_ReservePublicKeyP *pub,
- uint64_t value,
- uint32_t fraction,
- const char *currency)
-{
- struct TALER_MINTDB_Reserve reserve;
-
- reserve.pub = *pub;
-
- FAILIF (GNUNET_OK !=
- plugin->reserve_get (plugin->cls,
- session,
- &reserve));
- FAILIF (value != reserve.balance.value);
- FAILIF (fraction != reserve.balance.fraction);
- FAILIF (0 != strcmp (currency, reserve.balance.currency));
-
- return GNUNET_OK;
- drop:
- return GNUNET_SYSERR;
-}
-
-
-struct DenomKeyPair
-{
- struct TALER_DenominationPrivateKey priv;
- struct TALER_DenominationPublicKey pub;
-};
-
-
-/**
- * Destroy a denomination key pair. The key is not necessarily removed from the DB.
- *
- * @param dkp the keypair to destroy
- */
-static void
-destroy_denom_key_pair (struct DenomKeyPair *dkp)
-{
- GNUNET_CRYPTO_rsa_public_key_free (dkp->pub.rsa_public_key);
- GNUNET_CRYPTO_rsa_private_key_free (dkp->priv.rsa_private_key);
- GNUNET_free (dkp);
-}
-
-
-/**
- * Create a denominaiton key pair by registering the denomination in the DB.
- *
- * @param size the size of the denomination key
- * @param session the DB session
- * @return the denominaiton key pair; NULL upon error
- */
-static struct DenomKeyPair *
-create_denom_key_pair (unsigned int size,
- struct TALER_MINTDB_Session *session,
- const struct TALER_Amount *value,
- const struct TALER_Amount *fee_withdraw,
- const struct TALER_Amount *fee_deposit,
- const struct TALER_Amount *fee_refresh)
-{
- struct DenomKeyPair *dkp;
- struct TALER_MINTDB_DenominationKeyIssueInformation dki;
-
- dkp = GNUNET_new (struct DenomKeyPair);
- dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size);
- GNUNET_assert (NULL != dkp->priv.rsa_private_key);
- dkp->pub.rsa_public_key
- = GNUNET_CRYPTO_rsa_private_key_get_public (dkp->priv.rsa_private_key);
-
- /* Using memset() as fields like master key and signature
- are not properly initialized for this test. */
- memset (&dki,
- 0,
- sizeof (struct TALER_MINTDB_DenominationKeyIssueInformation));
- dki.denom_pub = dkp->pub;
- dki.issue.properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
- dki.issue.properties.expire_withdraw = GNUNET_TIME_absolute_hton
- (GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
- GNUNET_TIME_UNIT_HOURS));
- dki.issue.properties.expire_spend = GNUNET_TIME_absolute_hton
- (GNUNET_TIME_absolute_add
- (GNUNET_TIME_absolute_get (),
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 2)));
- dki.issue.properties.expire_legal = GNUNET_TIME_absolute_hton
- (GNUNET_TIME_absolute_add
- (GNUNET_TIME_absolute_get (),
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 3)));
- TALER_amount_hton (&dki.issue.properties.value, value);
- TALER_amount_hton (&dki.issue.properties.fee_withdraw, fee_withdraw);
- TALER_amount_hton (&dki.issue.properties.fee_deposit, fee_deposit);
- TALER_amount_hton (&dki.issue.properties.fee_refresh, fee_refresh);
- GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key,
- &dki.issue.properties.denom_hash);
- if (GNUNET_OK !=
- plugin->insert_denomination_info (plugin->cls,
- session,
- &dki.denom_pub,
- &dki.issue))
- {
- GNUNET_break(0);
- destroy_denom_key_pair (dkp);
- return NULL;
- }
- return dkp;
-}
-
-static struct TALER_Amount value;
-static struct TALER_Amount fee_withdraw;
-static struct TALER_Amount fee_deposit;
-static struct TALER_Amount fee_refresh;
-static struct TALER_Amount amount_with_fee;
-
-static void
-free_refresh_commit_coins_array(struct TALER_MINTDB_RefreshCommitCoin
- *commit_coins,
- unsigned int size)
-{
- unsigned int cnt;
- struct TALER_MINTDB_RefreshCommitCoin *ccoin;
- struct TALER_RefreshLinkEncrypted *rlink;
-
- for (cnt = 0; cnt < size; cnt++)
- {
- ccoin = &commit_coins[cnt];
- GNUNET_free_non_null (ccoin->coin_ev);
- rlink = (struct TALER_RefreshLinkEncrypted *) ccoin->refresh_link;
- GNUNET_free_non_null (rlink);
- }
- GNUNET_free (commit_coins);
-}
-
-#define MELT_NEW_COINS 5
-
-static int
-test_refresh_commit_coins (struct TALER_MINTDB_Session *session,
- struct TALER_MINTDB_RefreshSession *refresh_session,
- const struct GNUNET_HashCode *session_hash)
-{
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins;
- struct TALER_MINTDB_RefreshCommitCoin *ret_commit_coins;
- struct TALER_MINTDB_RefreshCommitCoin *a_ccoin;
- struct TALER_RefreshLinkEncrypted *a_rlink;
- struct TALER_MINTDB_RefreshCommitCoin *b_ccoin;
- struct TALER_RefreshLinkEncrypted *b_rlink;
- size_t size;
- unsigned int cnt;
- uint16_t cnc_index;
- int ret;
-
- #define COIN_ENC_MAX_SIZE 512
- ret = GNUNET_SYSERR;
- ret_commit_coins = NULL;
- commit_coins = GNUNET_new_array (MELT_NEW_COINS,
- struct TALER_MINTDB_RefreshCommitCoin);
- cnc_index = (uint16_t) GNUNET_CRYPTO_random_u32
- (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_MIN (MELT_NEW_COINS, UINT16_MAX));
- for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
- {
- struct TALER_MINTDB_RefreshCommitCoin *ccoin;
- struct TALER_RefreshLinkEncrypted *rlink;
- ccoin = &commit_coins[cnt];
- size = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
- COIN_ENC_MAX_SIZE);
- rlink = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + size);
- ccoin->refresh_link = rlink;
- ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64
- (GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE);
- ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- ccoin->coin_ev,
- ccoin->coin_ev_size);
- rlink->blinding_key_enc_size = size;
- RND_BLK (&rlink->coin_priv_enc);
- rlink->blinding_key_enc = (const char *) &rlink[1];
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- (void *)rlink->blinding_key_enc,
- rlink->blinding_key_enc_size);
- }
- FAILIF (GNUNET_OK !=
- plugin->insert_refresh_commit_coins (plugin->cls,
- session,
- session_hash,
- cnc_index,
- MELT_NEW_COINS,
- commit_coins));
- ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS,
- struct TALER_MINTDB_RefreshCommitCoin);
- FAILIF (GNUNET_OK !=
- plugin->get_refresh_commit_coins (plugin->cls,
- session,
- session_hash,
- cnc_index,
- MELT_NEW_COINS,
- ret_commit_coins));
- /* compare the refresh commit coin arrays */
- for (cnt = 0; cnt < MELT_NEW_COINS; cnt++)
- {
- a_ccoin = &commit_coins[cnt];
- b_ccoin = &ret_commit_coins[cnt];
- FAILIF (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size);
- FAILIF (0 != memcmp (a_ccoin->coin_ev,
- a_ccoin->coin_ev,
- a_ccoin->coin_ev_size));
- a_rlink = a_ccoin->refresh_link;
- b_rlink = b_ccoin->refresh_link;
- FAILIF (a_rlink->blinding_key_enc_size != b_rlink->blinding_key_enc_size);
- FAILIF (0 != memcmp (a_rlink->blinding_key_enc,
- b_rlink->blinding_key_enc,
- a_rlink->blinding_key_enc_size));
- FAILIF (0 != memcmp (a_rlink->coin_priv_enc,
- b_rlink->coin_priv_enc,
- sizeof (a_rlink->coin_priv_enc)));
- }
- ret = GNUNET_OK;
-
- drop:
- if (NULL != ret_commit_coins)
- free_refresh_commit_coins_array (ret_commit_coins, MELT_NEW_COINS);
- if (NULL != commit_coins)
- free_refresh_commit_coins_array (commit_coins, MELT_NEW_COINS);
- return ret;
-}
-
-/**
- * Function to test melting of coins as part of a refresh session
- *
- * @param session the database session
- * @param refresh_session the refresh session
- * @return #GNUNET_OK if everything went well; #GNUNET_SYSERR if not
- */
-static int
-test_melting (struct TALER_MINTDB_Session *session)
-{
-#define MELT_OLD_COINS 10
- struct TALER_MINTDB_RefreshSession refresh_session;
- struct TALER_MINTDB_RefreshSession ret_refresh_session;
- struct GNUNET_HashCode session_hash;
- struct DenomKeyPair *dkp;
- struct DenomKeyPair **new_dkp;
- /* struct TALER_CoinPublicInfo *coins; */
- struct TALER_MINTDB_RefreshMelt *melts;
- struct TALER_DenominationPublicKey *new_denom_pubs;
- struct TALER_DenominationPublicKey *ret_denom_pubs;
- unsigned int cnt;
- int ret;
-
- ret = GNUNET_SYSERR;
- RND_BLK (&refresh_session);
- RND_BLK (&session_hash);
- melts = NULL;
- dkp = NULL;
- new_dkp = NULL;
- new_denom_pubs = NULL;
- ret_denom_pubs = NULL;
- /* create and test a refresh session */
- refresh_session.num_oldcoins = MELT_OLD_COINS;
- refresh_session.num_newcoins = 1;
- refresh_session.noreveal_index = 1;
- FAILIF (GNUNET_OK != plugin->create_refresh_session (plugin->cls,
- session,
- &session_hash,
- &refresh_session));
- FAILIF (GNUNET_OK != plugin->get_refresh_session (plugin->cls,
- session,
- &session_hash,
- &ret_refresh_session));
- FAILIF (0 != memcmp (&ret_refresh_session,
- &refresh_session,
- sizeof (refresh_session)));
-
- /* create a denomination (value: 1; fraction: 100) */
- dkp = create_denom_key_pair (512, session,
- &value,
- &fee_withdraw,
- &fee_deposit,
- &fee_refresh);
- /* create MELT_OLD_COINS number of refresh melts */
- melts = GNUNET_new_array (MELT_OLD_COINS, struct TALER_MINTDB_RefreshMelt);
- for (cnt=0; cnt < MELT_OLD_COINS; cnt++)
- {
- RND_BLK (&melts[cnt].coin.coin_pub);
- melts[cnt].coin.denom_sig.rsa_signature =
- GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
- &melts[cnt].coin.coin_pub,
- sizeof (melts[cnt].coin.coin_pub));
- melts[cnt].coin.denom_pub = dkp->pub;
- RND_BLK (&melts[cnt].coin_sig);
- melts[cnt].session_hash = session_hash;
- melts[cnt].amount_with_fee = amount_with_fee;
- melts[cnt].melt_fee = fee_refresh;
- FAILIF (GNUNET_OK != plugin->insert_refresh_melt (plugin->cls,
- session,
- cnt,
- &melts[cnt]));
- }
- for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
- {
- struct TALER_MINTDB_RefreshMelt ret_melt;
- FAILIF (GNUNET_OK != plugin->get_refresh_melt (plugin->cls,
- session,
- &session_hash,
- cnt,
- &ret_melt));
- FAILIF (0 != GNUNET_CRYPTO_rsa_signature_cmp
- (ret_melt.coin.denom_sig.rsa_signature,
- melts[cnt].coin.denom_sig.rsa_signature));
- FAILIF (0 != memcmp (&ret_melt.coin.coin_pub,
- &melts[cnt].coin.coin_pub,
- sizeof (ret_melt.coin.coin_pub)));
- FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp
- (ret_melt.coin.denom_pub.rsa_public_key,
- melts[cnt].coin.denom_pub.rsa_public_key));
- FAILIF (0 != memcmp (&ret_melt.coin_sig,
- &melts[cnt].coin_sig,
- sizeof (ret_melt.coin_sig)));
- FAILIF (0 != memcmp (&ret_melt.session_hash,
- &melts[cnt].session_hash,
- sizeof (ret_melt.session_hash)));
- FAILIF (0 != TALER_amount_cmp (&ret_melt.amount_with_fee,
- &melts[cnt].amount_with_fee));
- FAILIF (0 != TALER_amount_cmp (&ret_melt.melt_fee,
- &melts[cnt].melt_fee));
- GNUNET_CRYPTO_rsa_signature_free (ret_melt.coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (ret_melt.coin.denom_pub.rsa_public_key);
- }
- new_dkp = GNUNET_new_array (MELT_NEW_COINS, struct DenomKeyPair *);
- new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
- struct TALER_DenominationPublicKey);
- for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
- {
- new_dkp[cnt] = create_denom_key_pair (128, session,
- &value,
- &fee_withdraw,
- &fee_deposit,
- &fee_refresh);
- new_denom_pubs[cnt]=new_dkp[cnt]->pub;
- }
- FAILIF (GNUNET_OK != plugin->insert_refresh_order (plugin->cls,
- session,
- &session_hash,
- MELT_NEW_COINS,
- new_denom_pubs));
- ret_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
- struct TALER_DenominationPublicKey);
- FAILIF (GNUNET_OK != plugin->get_refresh_order (plugin->cls,
- session,
- &session_hash,
- MELT_NEW_COINS,
- ret_denom_pubs));
- for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
- {
- FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp
- (ret_denom_pubs[cnt].rsa_public_key,
- new_denom_pubs[cnt].rsa_public_key));
- }
- FAILIF (GNUNET_OK !=
- test_refresh_commit_coins (session,
- &refresh_session,
- &session_hash));
-
- ret = GNUNET_OK;
-
- drop:
- if (NULL != dkp)
- destroy_denom_key_pair (dkp);
- if (NULL != melts)
- {
- for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
- GNUNET_CRYPTO_rsa_signature_free (melts[cnt].coin.denom_sig.rsa_signature);
- GNUNET_free (melts);
- }
- for (cnt = 0;
- (NULL != ret_denom_pubs) && (cnt < MELT_NEW_COINS)
- && (NULL != ret_denom_pubs[cnt].rsa_public_key);
- cnt++)
- GNUNET_CRYPTO_rsa_public_key_free (ret_denom_pubs[cnt].rsa_public_key);
- GNUNET_free_non_null (ret_denom_pubs);
- GNUNET_free_non_null (new_denom_pubs);
- for (cnt = 0;
- (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]);
- cnt++)
- destroy_denom_key_pair (new_dkp[cnt]);
- GNUNET_free_non_null (new_dkp);
- return ret;
-}
-
-
-/**
- * Callback that should never be called.
- */
-static void
-cb_wt_never (void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_value,
- const struct TALER_Amount *coin_fee)
-{
- GNUNET_assert (0); /* this statement should be unreachable */
-}
-
-
-/**
- * Callback that should never be called.
- */
-static void
-cb_wtid_never (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time)
-{
- GNUNET_assert (0);
-}
-
-
-static struct TALER_MerchantPublicKeyP merchant_pub_wt;
-static struct GNUNET_HashCode h_wire_wt;
-static struct GNUNET_HashCode h_contract_wt;
-static uint64_t transaction_id_wt;
-static struct TALER_CoinSpendPublicKeyP coin_pub_wt;
-static struct TALER_Amount coin_value_wt;
-static struct TALER_Amount coin_fee_wt;
-static struct TALER_Amount transfer_value_wt;
-static struct GNUNET_TIME_Absolute execution_time_wt;
-static struct TALER_WireTransferIdentifierRawP wtid_wt;
-
-
-/**
- * Callback that should be called with the WT data.
- */
-static void
-cb_wt_check (void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *coin_value,
- const struct TALER_Amount *coin_fee)
-{
- GNUNET_assert (cls == &cb_wt_never);
- GNUNET_assert (0 == memcmp (merchant_pub,
- &merchant_pub_wt,
- sizeof (struct TALER_MerchantPublicKeyP)));
- GNUNET_assert (0 == memcmp (h_wire,
- &h_wire_wt,
- sizeof (struct GNUNET_HashCode)));
- GNUNET_assert (0 == memcmp (h_contract,
- &h_contract_wt,
- sizeof (struct GNUNET_HashCode)));
- GNUNET_assert (transaction_id == transaction_id_wt);
- GNUNET_assert (0 == memcmp (coin_pub,
- &coin_pub_wt,
- sizeof (struct TALER_CoinSpendPublicKeyP)));
- GNUNET_assert (0 == TALER_amount_cmp (coin_value,
- &coin_value_wt));
- GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
- &coin_fee_wt));
-}
-
-
-/**
- * Callback that should be called with the WT data.
- */
-static void
-cb_wtid_check (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time)
-{
- GNUNET_assert (cls == &cb_wtid_never);
- GNUNET_assert (0 == memcmp (wtid,
- &wtid_wt,
- sizeof (struct TALER_WireTransferIdentifierRawP)));
- GNUNET_assert (execution_time.abs_value_us ==
- execution_time_wt.abs_value_us);
- GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
- &coin_value_wt));
- GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
- &coin_fee_wt));
-}
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param cfg configuration
- */
-static void
-run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct TALER_MINTDB_Session *session;
- struct TALER_ReservePublicKeyP reserve_pub;
- struct DenomKeyPair *dkp;
- struct TALER_MINTDB_CollectableBlindcoin cbc;
- struct TALER_MINTDB_CollectableBlindcoin cbc2;
- struct TALER_MINTDB_ReserveHistory *rh;
- struct TALER_MINTDB_ReserveHistory *rh_head;
- struct TALER_MINTDB_BankTransfer *bt;
- struct TALER_MINTDB_CollectableBlindcoin *withdraw;
- struct TALER_MINTDB_Deposit deposit;
- struct TALER_MINTDB_Deposit deposit2;
- struct TALER_WireTransferIdentifierRawP wtid;
- json_t *wire;
- json_t *just;
- const char * const json_wire_str =
- "{ \"type\":\"SEPA\", \
-\"IBAN\":\"DE67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
-\"bic\":\"GENODEF1SLR\", \
-\"edate\":\"1449930207000\", \
-\"r\":123456789, \
-\"address\": \"foobar\"}";
- unsigned int cnt;
-
- dkp = NULL;
- rh = NULL;
- wire = NULL;
- session = NULL;
- ZR_BLK (&cbc);
- ZR_BLK (&cbc2);
- if (NULL ==
- (plugin = TALER_MINTDB_plugin_load (cfg)))
- {
- result = 1;
- return;
- }
- if (GNUNET_OK !=
- plugin->create_tables (plugin->cls,
- GNUNET_YES))
- {
- result = 2;
- goto drop;
- }
- if (NULL ==
- (session = plugin->get_session (plugin->cls,
- GNUNET_YES)))
- {
- result = 3;
- goto drop;
- }
- RND_BLK (&reserve_pub);
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.000010",
- &value));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fee_withdraw));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fee_deposit));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":0.000010",
- &fee_refresh));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.000010",
- &amount_with_fee));
-
- result = 4;
- just = json_loads ("{ \"justification\":\"1\" }", 0, NULL);
- FAILIF (GNUNET_OK !=
- plugin->reserves_in_insert (plugin->cls,
- session,
- &reserve_pub,
- &value,
- GNUNET_TIME_absolute_get (),
- just));
- json_decref (just);
- FAILIF (GNUNET_OK !=
- check_reserve (session,
- &reserve_pub,
- value.value,
- value.fraction,
- value.currency));
- just = json_loads ("{ \"justification\":\"2\" }", 0, NULL);
- FAILIF (GNUNET_OK !=
- plugin->reserves_in_insert (plugin->cls,
- session,
- &reserve_pub,
- &value,
- GNUNET_TIME_absolute_get (),
- just));
- json_decref (just);
- FAILIF (GNUNET_OK !=
- check_reserve (session,
- &reserve_pub,
- value.value * 2,
- value.fraction * 2,
- value.currency));
- dkp = create_denom_key_pair (1024, session,
- &value,
- &fee_withdraw,
- &fee_deposit,
- &fee_refresh);
- RND_BLK(&cbc.h_coin_envelope);
- RND_BLK(&cbc.reserve_sig);
- cbc.denom_pub = dkp->pub;
- cbc.sig.rsa_signature
- = GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
- &cbc.h_coin_envelope,
- sizeof (cbc.h_coin_envelope));
- cbc.reserve_pub = reserve_pub;
- cbc.amount_with_fee = value;
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee));
- FAILIF (GNUNET_OK !=
- plugin->insert_withdraw_info (plugin->cls,
- session,
- &cbc));
- FAILIF (GNUNET_OK !=
- check_reserve (session,
- &reserve_pub,
- value.value,
- value.fraction,
- value.currency));
- FAILIF (GNUNET_YES !=
- plugin->get_withdraw_info (plugin->cls,
- session,
- &cbc.h_coin_envelope,
- &cbc2));
- FAILIF (NULL == cbc2.denom_pub.rsa_public_key);
- FAILIF (0 != memcmp (&cbc2.reserve_sig,
- &cbc.reserve_sig,
- sizeof (cbc2.reserve_sig)));
- FAILIF (0 != memcmp (&cbc2.reserve_pub,
- &cbc.reserve_pub,
- sizeof (cbc2.reserve_pub)));
- FAILIF (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope,
- cbc2.sig.rsa_signature,
- dkp->pub.rsa_public_key));
- rh = plugin->get_reserve_history (plugin->cls,
- session,
- &reserve_pub);
- FAILIF (NULL == rh);
- rh_head = rh;
- for (cnt=0; NULL != rh_head; rh_head=rh_head->next, cnt++)
- {
- switch (rh_head->type)
- {
- case TALER_MINTDB_RO_BANK_TO_MINT:
- bt = rh_head->details.bank;
- FAILIF (0 != memcmp (&bt->reserve_pub,
- &reserve_pub,
- sizeof (reserve_pub)));
- /* this is the amount we trasferred twice*/
- FAILIF (1 != bt->amount.value);
- FAILIF (10 != bt->amount.fraction);
- FAILIF (0 != strcmp (CURRENCY, bt->amount.currency));
- FAILIF (NULL == bt->wire);
- break;
- case TALER_MINTDB_RO_WITHDRAW_COIN:
- withdraw = rh_head->details.withdraw;
- FAILIF (0 != memcmp (&withdraw->reserve_pub,
- &reserve_pub,
- sizeof (reserve_pub)));
- FAILIF (0 != memcmp (&withdraw->h_coin_envelope,
- &cbc.h_coin_envelope,
- sizeof (cbc.h_coin_envelope)));
- break;
- }
- }
- FAILIF (3 != cnt);
- /* Tests for deposits */
- memset (&deposit, 0, sizeof (deposit));
- RND_BLK (&deposit.coin.coin_pub);
- deposit.coin.denom_pub = dkp->pub;
- deposit.coin.denom_sig = cbc.sig;
- RND_BLK (&deposit.csig);
- RND_BLK (&deposit.merchant_pub);
- RND_BLK (&deposit.h_contract);
- RND_BLK (&deposit.h_wire);
- wire = json_loads (json_wire_str, 0, NULL);
- deposit.wire = wire;
- deposit.transaction_id =
- GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
- deposit.amount_with_fee = value;
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero (CURRENCY, &deposit.deposit_fee));
- FAILIF (GNUNET_OK !=
- plugin->insert_deposit (plugin->cls,
- session, &deposit));
- FAILIF (GNUNET_YES !=
- plugin->have_deposit (plugin->cls,
- session,
- &deposit));
- deposit2 = deposit;
- deposit2.transaction_id++; /* should fail if transaction id is different */
- FAILIF (GNUNET_NO !=
- plugin->have_deposit (plugin->cls,
- session,
- &deposit2));
- deposit2.transaction_id = deposit.transaction_id;
- RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
- FAILIF (GNUNET_NO !=
- plugin->have_deposit (plugin->cls,
- session,
- &deposit2));
- deposit2.merchant_pub = deposit.merchant_pub;
- RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
- FAILIF (GNUNET_NO !=
- plugin->have_deposit (plugin->cls,
- session,
- &deposit2));
- FAILIF (GNUNET_OK != test_melting (session));
-
- /* setup values for wire transfer aggregation data */
- memset (&wtid, 42, sizeof (wtid));
- memset (&merchant_pub_wt, 43, sizeof (merchant_pub_wt));
- memset (&h_wire_wt, 44, sizeof (h_wire_wt));
- memset (&h_contract_wt, 45, sizeof (h_contract_wt));
- memset (&coin_pub_wt, 46, sizeof (coin_pub_wt));
- transaction_id_wt = 47;
- execution_time_wt = GNUNET_TIME_absolute_get ();
- memset (&merchant_pub_wt, 48, sizeof (merchant_pub_wt));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY "KUDOS:1.000010",
- &coin_value_wt));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY "KUDOS:0.000010",
- &coin_fee_wt));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY "KUDOS:1.000000",
- &transfer_value_wt));
-
- FAILIF (GNUNET_NO !=
- plugin->lookup_wire_transfer (plugin->cls,
- session,
- &wtid_wt,
- &cb_wt_never,
- NULL));
- FAILIF (GNUNET_NO !=
- plugin->wire_lookup_deposit_wtid (plugin->cls,
- session,
- &h_contract_wt,
- &h_wire_wt,
- &coin_pub_wt,
- &merchant_pub_wt,
- transaction_id_wt,
- &cb_wtid_never,
- NULL));
- /* insert WT data */
- FAILIF (GNUNET_OK !=
- plugin->insert_aggregation_tracking (plugin->cls,
- session,
- &wtid_wt,
- &merchant_pub_wt,
- &h_wire_wt,
- &h_contract_wt,
- transaction_id_wt,
- execution_time_wt,
- &coin_pub_wt,
- &coin_value_wt,
- &coin_fee_wt));
- FAILIF (GNUNET_OK !=
- plugin->lookup_wire_transfer (plugin->cls,
- session,
- &wtid_wt,
- &cb_wt_check,
- &cb_wt_never));
- FAILIF (GNUNET_OK !=
- plugin->wire_lookup_deposit_wtid (plugin->cls,
- session,
- &h_contract_wt,
- &h_wire_wt,
- &coin_pub_wt,
- &merchant_pub_wt,
- transaction_id_wt,
- &cb_wtid_check,
- &cb_wtid_never));
- result = 0;
-
- drop:
- if (NULL != wire)
- json_decref (wire);
- if (NULL != rh)
- plugin->free_reserve_history (plugin->cls,
- rh);
- rh = NULL;
- if (NULL != session)
- GNUNET_break (GNUNET_OK ==
- plugin->drop_temporary (plugin->cls,
- session));
- if (NULL != dkp)
- destroy_denom_key_pair (dkp);
- if (NULL != cbc.sig.rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (cbc.sig.rsa_signature);
- if (NULL != cbc2.denom_pub.rsa_public_key)
- GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub.rsa_public_key);
- if (NULL != cbc2.sig.rsa_signature)
- GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature);
- dkp = NULL;
- TALER_MINTDB_plugin_unload (plugin);
- plugin = NULL;
-}
-
-
-int
-main (int argc,
- char *const argv[])
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_END
- };
- char *argv2[] = {
- "test-mint-db-<plugin_name>", /* will be replaced later */
- "-c", "test-mint-db-<plugin_name>.conf", /* will be replaced later */
- NULL,
- };
- const char *plugin_name;
- char *config_filename;
- char *testname;
-
- result = -1;
- if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
- {
- GNUNET_break (0);
- return -1;
- }
- plugin_name++;
- (void) GNUNET_asprintf (&testname,
- "test-mint-db-%s", plugin_name);
- (void) GNUNET_asprintf (&config_filename,
- "%s.conf", testname);
- argv2[0] = argv[0];
- argv2[2] = config_filename;
- if (GNUNET_OK !=
- GNUNET_PROGRAM_run ((sizeof (argv2)/sizeof (char *)) - 1, argv2,
- testname,
- "Test cases for mint database helper functions.",
- options, &run, NULL))
- {
- GNUNET_free (config_filename);
- GNUNET_free (testname);
- return 3;
- }
- GNUNET_free (config_filename);
- GNUNET_free (testname);
- return result;
-}
diff --git a/src/mintdb/test_mintdb_deposits.c b/src/mintdb/test_mintdb_deposits.c
deleted file mode 100644
index 3ce0a35a5..000000000
--- a/src/mintdb/test_mintdb_deposits.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint/test_mint_deposits.c
- * @brief testcase for mint deposits
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include <libpq-fe.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_pq_lib.h"
-#include "taler_mintdb_lib.h"
-#include "taler_mintdb_plugin.h"
-
-#define MINT_CURRENCY "EUR"
-
-#define DB_URI "postgres:///taler"
-
-#define break_db_err(result) do { \
- GNUNET_break(0); \
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
- } while (0)
-
-/**
- * Shorthand for exit jumps.
- */
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-
-/**
- * Should we not interact with a temporary table?
- */
-static int persistent;
-
-/**
- * Testcase result
- */
-static int result;
-
-/**
- * The plugin.
- */
-static struct TALER_MINTDB_Plugin *plugin;
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param cfg configuration
- */
-static void
-run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- static const char wire[] = "{"
- "\"type\":\"SEPA\","
- "\"IBAN\":\"DE67830654080004822650\","
- "\"NAME\":\"GNUNET E.V\","
- "\"BIC\":\"GENODEF1SRL\""
- "}";
- struct TALER_MINTDB_Deposit *deposit;
- uint64_t transaction_id;
- struct TALER_MINTDB_Session *session;
-
- deposit = NULL;
- EXITIF (NULL == (plugin = TALER_MINTDB_plugin_load (cfg)));
- EXITIF (GNUNET_OK !=
- plugin->create_tables (plugin->cls,
- ! persistent));
- session = plugin->get_session (plugin->cls,
- ! persistent);
- EXITIF (NULL == session);
- deposit = GNUNET_malloc (sizeof (struct TALER_MINTDB_Deposit) + sizeof (wire));
- /* Makeup a random coin public key */
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- deposit,
- sizeof (struct TALER_MINTDB_Deposit));
- /* Makeup a random 64bit transaction ID */
- transaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
- UINT64_MAX);
- deposit->transaction_id = GNUNET_htonll (transaction_id);
- /* Random amount */
- deposit->amount_with_fee.value =
- htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
- deposit->amount_with_fee.fraction =
- htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
- GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount_with_fee.currency));
- strcpy (deposit->amount_with_fee.currency, MINT_CURRENCY);
- /* Copy wireformat */
- deposit->wire = json_loads (wire, 0, NULL);
- EXITIF (GNUNET_OK !=
- plugin->insert_deposit (plugin->cls,
- session,
- deposit));
- EXITIF (GNUNET_OK !=
- plugin->have_deposit (plugin->cls,
- session,
- deposit));
- result = GNUNET_OK;
-
- EXITIF_exit:
- GNUNET_free_non_null (deposit);
- if (NULL != plugin)
- {
- TALER_MINTDB_plugin_unload (plugin);
- plugin = NULL;
- }
-}
-
-
-int
-main (int argc,
- char *const argv[])
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'T', "persist", NULL,
- gettext_noop ("Use a persistent database table instead of a temporary one"),
- GNUNET_NO, &GNUNET_GETOPT_set_one, &persistent},
- GNUNET_GETOPT_OPTION_END
- };
-
-
- persistent = GNUNET_NO;
- result = GNUNET_SYSERR;
- if (GNUNET_OK !=
- GNUNET_PROGRAM_run (argc, argv,
- "test-mint-deposits",
- "testcase for mint deposits",
- options, &run, NULL))
- return 3;
- return (GNUNET_OK == result) ? 0 : 1;
-}
diff --git a/src/mintdb/test_mintdb_keyio.c b/src/mintdb/test_mintdb_keyio.c
deleted file mode 100644
index aa1ba2f20..000000000
--- a/src/mintdb/test_mintdb_keyio.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e. V. (and other contributing authors)
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint/test_mint_common.c
- * @brief test cases for some functions in mint/mint_common.c
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include "gnunet/gnunet_util_lib.h"
-#include "taler_signatures.h"
-#include "taler_mintdb_lib.h"
-
-#define RSA_KEY_SIZE 1024
-
-
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-
-int
-main (int argc,
- const char *const argv[])
-{
- struct TALER_MINTDB_DenominationKeyIssueInformation dki;
- char *enc;
- size_t enc_size;
- struct TALER_MINTDB_DenominationKeyIssueInformation dki_read;
- char *enc_read;
- size_t enc_read_size;
- char *tmpfile;
- int ret;
-
- ret = 1;
- enc = NULL;
- enc_read = NULL;
- tmpfile = NULL;
- dki.denom_priv.rsa_private_key = NULL;
- dki_read.denom_priv.rsa_private_key = NULL;
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- &dki.issue.signature,
- sizeof (struct TALER_MasterSignatureP));
- dki.denom_priv.rsa_private_key
- = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEY_SIZE);
- enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki.denom_priv.rsa_private_key,
- &enc);
- EXITIF (NULL == (tmpfile = GNUNET_DISK_mktemp ("test_mint_common")));
- EXITIF (GNUNET_OK != TALER_MINTDB_denomination_key_write (tmpfile, &dki));
- EXITIF (GNUNET_OK != TALER_MINTDB_denomination_key_read (tmpfile, &dki_read));
- enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key,
- &enc_read);
- EXITIF (enc_size != enc_read_size);
- EXITIF (0 != memcmp (enc,
- enc_read,
- enc_size));
- ret = 0;
-
- EXITIF_exit:
- GNUNET_free_non_null (enc);
- if (NULL != tmpfile)
- {
- (void) unlink (tmpfile);
- GNUNET_free (tmpfile);
- }
- GNUNET_free_non_null (enc_read);
- if (NULL != dki.denom_priv.rsa_private_key)
- GNUNET_CRYPTO_rsa_private_key_free (dki.denom_priv.rsa_private_key);
- if (NULL != dki_read.denom_priv.rsa_private_key)
- GNUNET_CRYPTO_rsa_private_key_free (dki_read.denom_priv.rsa_private_key);
- return ret;
-}
diff --git a/src/mintdb/test_perf_taler_mintdb.c b/src/mintdb/test_perf_taler_mintdb.c
deleted file mode 100644
index 789a0dd4f..000000000
--- a/src/mintdb/test_perf_taler_mintdb.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file mintdb/test_perf_taler_mintdb.c
- * @brief Mint database performance analysis
- * @author Nicolas Fournier
- */
-#include "platform.h"
-#include "perf_taler_mintdb_interpreter.h"
-#include "perf_taler_mintdb_init.h"
-
-
-#define NB_DENOMINATION_INIT 2
-#define NB_DENOMINATION_SAVE 2
-
-#define NB_RESERVE_INIT 4
-#define NB_RESERVE_SAVE 1
-
-#define NB_DEPOSIT_INIT 1
-#define NB_DEPOSIT_SAVE 1
-
-#define NB_WITHDRAW_INIT 1
-#define NB_WITHDRAW_SAVE 1
-
-/**
- * Allocate, copies and free all the data used in the interpreter
- * Used to check for memory leaks
- */
-static void
-test_allocate ()
-{
- struct TALER_MINTDB_DenominationKeyIssueInformation *dki, *dki_copy;
- struct PERF_TALER_MINTDB_Reserve *reserve, *reserve_copy;
- struct PERF_TALER_MINTDB_Coin *coin, *coin_copy;
- struct TALER_MINTDB_Deposit *deposit, *deposit_copy;
-
- dki = PERF_TALER_MINTDB_denomination_init ();
- reserve = PERF_TALER_MINTDB_reserve_init ();
- coin = PERF_TALER_MINTDB_coin_init (dki,
- reserve);
- deposit = PERF_TALER_MINTDB_deposit_init (coin);
-
- dki_copy = PERF_TALER_MINTDB_denomination_copy (dki);
- reserve_copy = PERF_TALER_MINTDB_reserve_copy (reserve);
- coin_copy = PERF_TALER_MINTDB_coin_copy (coin);
- deposit_copy = PERF_TALER_MINTDB_deposit_copy (deposit);
-
- PERF_TALER_MINTDB_denomination_free (dki);
- PERF_TALER_MINTDB_denomination_free (dki_copy);
- PERF_TALER_MINTDB_reserve_free (reserve);
- PERF_TALER_MINTDB_reserve_free (reserve_copy);
- PERF_TALER_MINTDB_coin_free (coin);
- PERF_TALER_MINTDB_coin_free (coin_copy);
- PERF_TALER_MINTDB_deposit_free (deposit);
- PERF_TALER_MINTDB_deposit_free (deposit_copy);
-}
-
-/**
- * Runs the performances tests for the mint database
- * and logs the results using Gauger
- */
-int
-main (int argc, char ** argv)
-{
- int ret = 0;
- struct PERF_TALER_MINTDB_Cmd init[] =
- {
- PERF_TALER_MINTDB_INIT_CMD_END ("init")
- };
- struct PERF_TALER_MINTDB_Cmd benchmark[] =
- {
- // Denomination used to create coins
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("00 - Start of interpreter"),
-
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("01 - denomination loop",
- NB_DENOMINATION_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("01 - start transaction"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert",
- "01 - denomination"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("01 - commit transaction"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination",
- "01 - denomination loop",
- "01 - denomination",
- NB_DENOMINATION_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("01 - denomination loop end",
- "01 - denomination loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("01 - init denomination complete"),
- // End of initialization
- // Reserve initialization
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("02 - init reserve loop",
- NB_RESERVE_INIT),
-
- PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("02 - insert",
- "02 - reserve"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve",
- "02 - init reserve loop",
- "02 - reserve",
- NB_RESERVE_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("02 - init reserve end loop",
- "02 - init reserve loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("02 - reserve init complete"),
- // End reserve init
- // Withdrawal initialization
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("03 - init withdraw loop",
- NB_WITHDRAW_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("03 - start transaction"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load",
- "03 - init withdraw loop",
- "01 - save denomination"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load",
- "03 - init withdraw loop",
- "02 - save reserve"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw",
- "03 - denomination load",
- "03 - reserve load"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert withdraw",
- "03 - withdraw"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("03 - commit transaction"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("03 - coin array",
- "03 - init withdraw loop",
- "03 - withdraw",
- NB_WITHDRAW_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("03 - withdraw init end loop",
- "03 - init withdraw loop"),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("03 - withdraw init complete"),
- //End of withdrawal initialization
- //Deposit initialization
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("04 - time start"),
- PERF_TALER_MINTDB_INIT_CMD_LOOP ("04 - deposit init loop",
- NB_DEPOSIT_INIT),
- PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"),
- PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("04 - coin load",
- "04 - deposit init loop",
- "03 - coin array"),
- PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit",
- "04 - coin load"),
- PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert deposit",
- "04 - deposit"),
- PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"),
- PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array",
- "04 - deposit init loop",
- "04 - deposit",
- NB_DEPOSIT_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("04 - deposit init loop end",
- "04 - deposit init loop"),
- PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("04 - time stop"),
- PERF_TALER_MINTDB_INIT_CMD_GAUGER ("04 - gauger",
- "04 - time start",
- "04 - time stop",
- "TEST",
- "time to insert a deposit",
- "deposit/sec",
- NB_DEPOSIT_SAVE),
- PERF_TALER_MINTDB_INIT_CMD_DEBUG ("04 - deposit init complete"),
- // End of deposit initialization
- PERF_TALER_MINTDB_INIT_CMD_END ("end"),
- };
-
- test_allocate ();
- ret = PERF_TALER_MINTDB_run_benchmark ("test-perf-taler-mintdb",
- "./test-mint-db-postgres.conf",
- init,
- benchmark);
- if (GNUNET_SYSERR == ret)
- return 1;
- return 0;
-}
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
index 0eab118fe..757dba4b6 100644
--- a/src/util/os_installation.c
+++ b/src/util/os_installation.c
@@ -394,7 +394,7 @@ os_get_taler_path ()
if (NULL != (ret = get_path_from_proc_maps ()))
return ret;
/* try path *first*, before /proc/exe, as /proc/exe can be wrong */
- if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ if (NULL != (ret = get_path_from_PATH ("taler-exchange-httpd")))
return ret;
if (NULL != (ret = get_path_from_proc_exe ()))
return ret;
@@ -409,7 +409,7 @@ os_get_taler_path ()
if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
return ret;
#endif
- if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ if (NULL != (ret = get_path_from_PATH ("taler-exchange-httpd")))
return ret;
/* other attempts here */
LOG (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/util/wireformats.c b/src/util/wireformats.c
index cd5a9c3d4..a69e8a093 100644
--- a/src/util/wireformats.c
+++ b/src/util/wireformats.c
@@ -421,7 +421,7 @@ TALER_json_validate_wireformat (const char **allowed,
if (NULL == allowed[i])
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Wireformat `%s' does not match mint's allowed formats\n",
+ "Wireformat `%s' does not match exchange's allowed formats\n",
stype);
return GNUNET_NO;
}
diff --git a/src/wire/plugin_wire_sepa.c b/src/wire/plugin_wire_sepa.c
index 00d19d4b0..4d902f962 100644
--- a/src/wire/plugin_wire_sepa.c
+++ b/src/wire/plugin_wire_sepa.c
@@ -501,12 +501,12 @@ libtaler_plugin_wire_sepa_init (void *cls)
sc = GNUNET_new (struct SepaClosure);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
+ "exchange",
"CURRENCY",
&sc->currency))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
+ "exchange",
"CURRENCY");
GNUNET_free (sc);
return NULL;
diff --git a/src/wire/plugin_wire_template.c b/src/wire/plugin_wire_template.c
index baf0ee7d5..2e9512e57 100644
--- a/src/wire/plugin_wire_template.c
+++ b/src/wire/plugin_wire_template.c
@@ -197,12 +197,12 @@ libtaler_plugin_wire_template_init (void *cls)
}
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
+ "exchange",
"CURRENCY",
&tc->currency))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
+ "exchange",
"CURRENCY");
GNUNET_free (tc->bank_uri);
GNUNET_free (tc);
diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c
index d6bf411c1..9503e1ca5 100644
--- a/src/wire/plugin_wire_test.c
+++ b/src/wire/plugin_wire_test.c
@@ -46,7 +46,7 @@ struct TestClosure
/**
* Number of the account that the exchange has at the bank.
*/
- uint64_t exchange_account_no;
+ unsigned long long exchange_account_no;
/**
* Handle to the bank task, or NULL.
@@ -494,6 +494,7 @@ test_execute_wire_transfer (void *cls,
eh->aaih = TALER_BANK_admin_add_incoming (tc->bank,
&bf.wtid,
&amount,
+ (uint64_t) tc->exchange_account_no,
(uint64_t) account_no,
&execute_cb,
eh);
@@ -556,6 +557,32 @@ libtaler_plugin_wire_test_init (void *cls)
return NULL;
}
tc = GNUNET_new (struct TestClosure);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "wire-test",
+ "BANK_ACCOUNT_NO",
+ &tc->exchange_account_no))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "wire-test",
+ "BANK_ACCOUNT_NO");
+ GNUNET_free (uri);
+ GNUNET_free (tc);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "CURRENCY",
+ &tc->currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "CURRENCY");
+ GNUNET_free (uri);
+ GNUNET_free (tc);
+ return NULL;
+ }
tc->bank = TALER_BANK_init (uri);
if (NULL == tc->bank)
{
diff --git a/src/wire/test_sepa_wireformat.c b/src/wire/test_sepa_wireformat.c
index edbe5bc45..5081cbe86 100644
--- a/src/wire/test_sepa_wireformat.c
+++ b/src/wire/test_sepa_wireformat.c
@@ -77,7 +77,7 @@ main(int argc,
NULL);
cfg = GNUNET_CONFIGURATION_create ();
GNUNET_CONFIGURATION_set_value_string (cfg,
- "mint",
+ "exchange",
"currency",
"EUR");
plugin = TALER_WIRE_plugin_load (cfg,