aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-04-15 15:00:26 +0200
committerChristian Grothoff <christian@grothoff.org>2016-04-15 15:00:26 +0200
commit74e237164ce7958c19467ad440e45576c4425570 (patch)
treee5156b7197cbb76ad0b0d617d9a04eeb2c08ea48 /src
parentebf049a8c2d982e723fe67dbff64e1eea14d8247 (diff)
parent3098c0a9e0b18a436e484ef693cdebeb16d4c131 (diff)
Merge branch 'master' of ssh://taler.net:/var/git/exchange
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/bank-lib/Makefile.am6
-rw-r--r--src/bank-lib/bank_api_admin.c25
-rw-r--r--src/bank-lib/bank_api_context.c2
-rw-r--r--src/bank-lib/bank_api_context.h1
-rw-r--r--src/bank-lib/bank_api_json.c525
-rw-r--r--src/bank-lib/bank_api_json.h352
-rw-r--r--src/bank-lib/test_bank_api.c83
-rw-r--r--src/exchange-lib/Makefile.am67
-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.c255
-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.c571
-rw-r--r--src/exchange-lib/exchange_api_deposit_wtid.c383
-rw-r--r--src/exchange-lib/exchange_api_handle.c910
-rw-r--r--src/exchange-lib/exchange_api_handle.h59
-rw-r--r--src/exchange-lib/exchange_api_refresh.c2066
-rw-r--r--src/exchange-lib/exchange_api_refresh_link.c484
-rw-r--r--src/exchange-lib/exchange_api_reserve.c936
-rw-r--r--src/exchange-lib/exchange_api_wire.c318
-rw-r--r--src/exchange-lib/exchange_api_wire_deposits.c330
-rw-r--r--src/exchange-lib/test_exchange_api.c2579
-rw-r--r--src/exchange-lib/test_exchange_api.conf95
-rw-r--r--src/exchange-lib/test_exchange_api_home/.config/taler/sepa.json9
-rw-r--r--src/exchange-lib/test_exchange_api_home/.config/taler/test.json8
-rw-r--r--src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv (renamed from src/mint-lib/test-mint-home/master.priv)0
-rw-r--r--src/exchange-tools/Makefile.am96
-rw-r--r--src/exchange-tools/auditor.conf12
-rw-r--r--src/exchange-tools/coins.conf25
-rw-r--r--src/exchange-tools/exchange-signkeys.conf16
-rw-r--r--src/exchange-tools/taler-auditor-sign.c366
-rw-r--r--src/exchange-tools/taler-exchange-dbinit.c91
-rw-r--r--src/exchange-tools/taler-exchange-keycheck.c255
-rw-r--r--src/exchange-tools/taler-exchange-keyup.c1051
-rw-r--r--src/exchange-tools/taler-exchange-reservemod.c214
-rw-r--r--src/exchange-tools/taler-exchange-wire.c214
-rw-r--r--src/exchange/.gitignore6
-rw-r--r--src/exchange/Makefile.am95
-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/exchange.conf29
-rw-r--r--src/exchange/taler-exchange-aggregator.c1010
-rw-r--r--src/exchange/taler-exchange-httpd.c741
-rw-r--r--src/exchange/taler-exchange-httpd.h128
-rw-r--r--src/exchange/taler-exchange-httpd_admin.c165
-rw-r--r--src/exchange/taler-exchange-httpd_admin.h46
-rw-r--r--src/exchange/taler-exchange-httpd_db.c1924
-rw-r--r--src/exchange/taler-exchange-httpd_db.h230
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c284
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.h54
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c1018
-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.c275
-rw-r--r--src/exchange/taler-exchange-httpd_parsing.h139
-rw-r--r--src/exchange/taler-exchange-httpd_refresh.c913
-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.c1223
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h512
-rw-r--r--src/exchange/taler-exchange-httpd_test.c622
-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.c244
-rw-r--r--src/exchange/taler-exchange-httpd_validation.h79
-rw-r--r--src/exchange/taler-exchange-httpd_wire.c57
-rw-r--r--src/exchange/taler-exchange-httpd_wire.h47
-rw-r--r--src/exchange/test-taler-exchange-aggregator-postgres.conf8
-rw-r--r--src/exchange/test_taler_exchange_aggregator.c1557
-rw-r--r--src/exchange/test_taler_exchange_httpd.conf75
-rw-r--r--src/exchange/test_taler_exchange_httpd.data48
-rwxr-xr-xsrc/exchange/test_taler_exchange_httpd.sh39
-rw-r--r--src/exchange/test_taler_exchange_httpd_afl.sh41
-rw-r--r--src/exchange/test_taler_exchange_httpd_home/.config/taler/test.json8
-rw-r--r--src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv (renamed from src/mint/test-mint-home/master.priv)0
-rw-r--r--src/exchangedb/Makefile.am123
-rw-r--r--src/exchangedb/exchangedb-postgres.conf2
-rw-r--r--src/exchangedb/exchangedb.conf7
-rw-r--r--src/exchangedb/exchangedb_keyio.c609
-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.c625
-rw-r--r--src/exchangedb/perf_taler_exchangedb_init.h257
-rw-r--r--src/exchangedb/perf_taler_exchangedb_interpreter.c1997
-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.c980
-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.am7
-rw-r--r--src/include/taler_amount_lib.h13
-rw-r--r--src/include/taler_bank_service.h11
-rw-r--r--src/include/taler_crypto_lib.h30
-rw-r--r--src/include/taler_exchange_service.h1204
-rw-r--r--src/include/taler_exchangedb_lib.h286
-rw-r--r--src/include/taler_exchangedb_plugin.h1445
-rw-r--r--src/include/taler_json_lib.h131
-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_pq_lib.h1
-rw-r--r--src/include/taler_signatures.h301
-rw-r--r--src/include/taler_util.h73
-rw-r--r--src/include/taler_wire_plugin.h39
-rw-r--r--src/json/Makefile.am38
-rw-r--r--src/json/json.c53
-rw-r--r--src/json/json_helper.c178
-rw-r--r--src/json/test_json.c71
-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-home/sepa.json6
-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.c1902
-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/pq/pq_result_helper.c25
-rw-r--r--src/util/Makefile.am44
-rw-r--r--src/util/amount.c24
-rw-r--r--src/util/json.c400
-rw-r--r--src/util/os_installation.c687
-rw-r--r--src/util/paths.conf29
-rw-r--r--src/util/plugin.c88
-rw-r--r--src/util/taler-config.in10
-rw-r--r--src/util/test_amount.c13
-rw-r--r--src/util/test_json.c182
-rw-r--r--src/util/util.c177
-rw-r--r--src/util/wireformats.c441
-rw-r--r--src/wire/Makefile.am31
-rw-r--r--src/wire/plugin_wire_sepa.c292
-rw-r--r--src/wire/plugin_wire_template.c53
-rw-r--r--src/wire/plugin_wire_test.c393
-rw-r--r--src/wire/test_sepa_wireformat.c34
-rw-r--r--src/wire/test_wire_plugin.c196
-rw-r--r--src/wire/test_wire_plugin.conf21
-rw-r--r--src/wire/test_wire_plugin_key.priv1
-rw-r--r--src/wire/test_wire_plugin_sepa.json8
-rw-r--r--src/wire/test_wire_plugin_test.json7
-rw-r--r--src/wire/wire-sepa.conf10
-rw-r--r--src/wire/wire-test.conf16
2314 files changed, 41253 insertions, 42965 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ac839d52a..6e0fb2049 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 json $(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/Makefile.am b/src/bank-lib/Makefile.am
index 2f44adada..58b1c67d5 100644
--- a/src/bank-lib/Makefile.am
+++ b/src/bank-lib/Makefile.am
@@ -15,10 +15,11 @@ libtalerbank_la_LDFLAGS = \
libtalerbank_la_SOURCES = \
bank_api_context.c bank_api_context.h \
- bank_api_json.c bank_api_json.h \
bank_api_admin.c
libtalerbank_la_LIBADD = \
+ $(top_builddir)/src/json/libtalerjson.la \
+ -lgnunetjson \
-lgnunetutil \
-ljansson \
$(XLIB)
@@ -42,4 +43,5 @@ test_bank_api_SOURCES = \
test_bank_api_LDADD = \
libtalerbank.la \
$(top_builddir)/src/util/libtalerutil.la \
- -lgnunetutil
+ -lgnunetutil \
+ -ljansson
diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c
index bfcf16a23..907e15ea7 100644
--- a/src/bank-lib/bank_api_admin.c
+++ b/src/bank-lib/bank_api_admin.c
@@ -24,8 +24,9 @@
#include <jansson.h>
#include <microhttpd.h> /* just for HTTP status codes */
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
#include "taler_bank_service.h"
-#include "bank_api_json.h"
+#include "taler_json_lib.h"
#include "bank_api_context.h"
#include "taler_signatures.h"
@@ -134,7 +135,8 @@ handle_admin_add_incoming_finished (void *cls,
break;
}
aai->cb (aai->cb_cls,
- response_code);
+ response_code,
+ json);
json_decref (json);
TALER_BANK_admin_add_incoming_cancel (aai);
}
@@ -150,7 +152,8 @@ handle_admin_add_incoming_finished (void *cls,
* @param reserve_pub public key of the reserve
* @param amount amount that was deposited
* @param execution_date when did we receive the amount
- * @param account_no account number (53 bits at most)
+ * @param debit_account_no account number to withdraw from (53 bits at most)
+ * @param credit_account_no account number to deposit into (53 bits at most)
* @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
@@ -161,7 +164,8 @@ struct TALER_BANK_AdminAddIncomingHandle *
TALER_BANK_admin_add_incoming (struct TALER_BANK_Context *bank,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *amount,
- uint64_t account_no,
+ uint64_t debit_account_no,
+ uint64_t credit_account_no,
TALER_BANK_AdminAddIncomingResultCallback res_cb,
void *res_cb_cls)
{
@@ -169,12 +173,13 @@ TALER_BANK_admin_add_incoming (struct TALER_BANK_Context *bank,
json_t *admin_obj;
CURL *eh;
- admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */
- " s:I}", /* execution_Date/wire */
- "wtid", TALER_json_from_data (wtid,
- sizeof (*wtid)),
- "amount", TALER_json_from_amount (amount),
- "account", (json_int_t) account_no);
+ admin_obj = json_pack ("{s:o, s:o,"
+ " s:I, s:I}",
+ "wtid", GNUNET_JSON_from_data (wtid,
+ sizeof (*wtid)), /* #4340 */
+ "amount", TALER_JSON_from_amount (amount),
+ "debit_account", (json_int_t) debit_account_no,
+ "credit_account", (json_int_t) credit_account_no);
aai = GNUNET_new (struct TALER_BANK_AdminAddIncomingHandle);
aai->bank = bank;
aai->cb = res_cb;
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_context.h b/src/bank-lib/bank_api_context.h
index 552cbe440..1f21cb8d2 100644
--- a/src/bank-lib/bank_api_context.h
+++ b/src/bank-lib/bank_api_context.h
@@ -21,6 +21,7 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include <jansson.h>
#include <curl/curl.h>
#include <gnunet/gnunet_util_lib.h>
#include "taler_bank_service.h"
diff --git a/src/bank-lib/bank_api_json.c b/src/bank-lib/bank_api_json.c
deleted file mode 100644
index 2a09e5272..000000000
--- a/src/bank-lib/bank_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 bank-lib/bank_api_json.c
- * @brief functions to parse incoming requests (JSON snippets)
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "bank_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 BAJ_Specification *spec)
-{
- int i;
- json_t *pos; /* what's our current position? */
-
- pos = root;
- for (i=0;BAJ_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 BAJ_CMD_END:
- GNUNET_assert (0);
- return i;
- case BAJ_CMD_AMOUNT:
- if (GNUNET_OK !=
- TALER_json_to_amount (pos,
- spec[i].details.amount))
- {
- GNUNET_break_op (0);
- return i;
- }
- break;
- case BAJ_CMD_TIME_ABSOLUTE:
- if (GNUNET_OK !=
- TALER_json_to_abs (pos,
- spec[i].details.abs_time))
- {
- GNUNET_break_op (0);
- return i;
- }
- break;
-
- case BAJ_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 BAJ_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 BAJ_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 BAJ_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 BAJ_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 BAJ_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 BAJ_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 BAJ_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
- * #BAJ_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 BAJ_Specification *spec,
- int end)
-{
- int i;
-
- for (i=0;i<end;i++)
- {
- switch (spec[i].cmd)
- {
- case BAJ_CMD_END:
- GNUNET_assert (0);
- return;
- case BAJ_CMD_AMOUNT:
- break;
- case BAJ_CMD_TIME_ABSOLUTE:
- break;
- case BAJ_CMD_BINARY_FIXED:
- break;
- case BAJ_CMD_STRING:
- break;
- case BAJ_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 BAJ_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 BAJ_CMD_RSA_SIGNATURE:
- GNUNET_CRYPTO_rsa_signature_free (*spec[i].details.rsa_signature);
- *spec[i].details.rsa_signature = NULL;
- break;
- case BAJ_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
-BAJ_parse_json (const json_t *root,
- struct BAJ_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
- * #BAJ_parse_json() operation.
- *
- * @param spec specification of the parse operation
- */
-void
-BAJ_parse_free (struct BAJ_Specification *spec)
-{
- int i;
-
- for (i=0;BAJ_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 BAJ_Specification
-BAJ_spec_string (const char *name,
- const char **strptr)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_absolute_time (const char *name,
- struct GNUNET_TIME_Absolute *at)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_amount (const char *name,
- struct TALER_Amount *amount)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_uint16 (const char *name,
- uint16_t *u16)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_uint64 (const char *name,
- uint64_t *u64)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_json (const char *name,
- json_t **jsonp)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_rsa_public_key (const char *name,
- struct GNUNET_CRYPTO_rsa_PublicKey **pk)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_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 BAJ_Specification
-BAJ_spec_rsa_signature (const char *name,
- struct GNUNET_CRYPTO_rsa_Signature **sig)
-{
- struct BAJ_Specification ret =
- {
- .cmd = BAJ_CMD_RSA_SIGNATURE,
- .field = name,
- .details.rsa_signature = sig
- };
- return ret;
-}
-
-
-/* end of bank_api_json.c */
diff --git a/src/bank-lib/bank_api_json.h b/src/bank-lib/bank_api_json.h
deleted file mode 100644
index 2ecaf8ef1..000000000
--- a/src/bank-lib/bank_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
- * #BAJ_parse_json interpreter.
- */
-enum BAJ_Command
-{
-
- /**
- * End of command list.
- */
- BAJ_CMD_END,
-
- /**
- * Parse amount at current position.
- */
- BAJ_CMD_AMOUNT,
-
- /**
- * Parse absolute time at current position.
- */
- BAJ_CMD_TIME_ABSOLUTE,
-
- /**
- * Parse fixed binary value at current position.
- */
- BAJ_CMD_BINARY_FIXED,
-
- /**
- * Parse variable-size binary value at current position.
- */
- BAJ_CMD_BINARY_VARIABLE,
-
- /**
- * Parse RSA public key at current position.
- */
- BAJ_CMD_RSA_PUBLIC_KEY,
-
- /**
- * Parse RSA signature at current position.
- */
- BAJ_CMD_RSA_SIGNATURE,
-
- /**
- * Parse `const char *` JSON string at current position.
- */
- BAJ_CMD_STRING,
-
- /**
- * Parse `uint16_t` integer at the current position.
- */
- BAJ_CMD_UINT16,
-
- /**
- * Parse `uint64_t` integer at the current position.
- */
- BAJ_CMD_UINT64,
-
- /**
- * Parse JSON object at the current position.
- */
- BAJ_CMD_JSON_OBJECT,
-
- /**
- * Parse ??? at current position.
- */
- BAJ_CMD_C
-
-};
-
-
-/**
- * @brief Entry in parser specification for #BAJ_parse_json.
- */
-struct BAJ_Specification
-{
-
- /**
- * Command to execute.
- */
- enum BAJ_Command cmd;
-
- /**
- * Name of the field to access.
- */
- const char *field;
-
- /**
- * Further details for the command.
- */
- union {
-
- /**
- * Where to store amount for #BAJ_CMD_AMOUNT.
- */
- struct TALER_Amount *amount;
-
- /**
- * Where to store time, for #BAJ_CMD_TIME_ABSOLUTE.
- */
- struct GNUNET_TIME_Absolute *abs_time;
-
- /**
- * Where to write binary data, for #BAJ_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 #BAJ_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 #BAJ_CMD_RSA_PUBLIC_KEY
- */
- struct GNUNET_CRYPTO_rsa_PublicKey **rsa_public_key;
-
- /**
- * Where to store the RSA signature for #BAJ_CMD_RSA_SIGNATURE
- */
- struct GNUNET_CRYPTO_rsa_Signature **rsa_signature;
-
- /**
- * Details for #BAJ_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
-BAJ_parse_json (const json_t *root,
- struct BAJ_Specification *spec);
-
-
-/**
- * Free all elements allocated during a
- * #BAJ_parse_json() operation.
- *
- * @param spec specification of the parse operation
- */
-void
-BAJ_parse_free (struct BAJ_Specification *spec);
-
-
-/**
- * End of a parser specification.
- */
-#define BAJ_spec_end { .cmd = BAJ_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 BAJ_spec_fixed_auto(name,obj) { .cmd = BAJ_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 BAJ_spec_varsize(name,obj,size) { .cmd = BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_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 BAJ_Specification
-BAJ_spec_rsa_signature (const char *name,
- struct GNUNET_CRYPTO_rsa_Signature **sig);
-
-
-
-
-/* end of mint_api_json.h */
diff --git a/src/bank-lib/test_bank_api.c b/src/bank-lib/test_bank_api.c
index b14f523ba..4d6b9700c 100644
--- a/src/bank-lib/test_bank_api.c
+++ b/src/bank-lib/test_bank_api.c
@@ -103,9 +103,14 @@ struct Command
const char *amount;
/**
- * Account number.
+ * Credited account number.
*/
- uint64_t account_no;
+ uint64_t credit_account_no;
+
+ /**
+ * Debited account number.
+ */
+ uint64_t debit_account_no;
/**
* Wire transfer identifier to use. Initialized to
@@ -158,11 +163,9 @@ struct InterpreterState
* 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);
+context_task (void *cls);
/**
@@ -228,11 +231,9 @@ find_command (const struct InterpreterState *is,
* Run the main interpreter loop that performs bank operations.
*
* @param cls contains the `struct InterpreterState`
- * @param tc scheduler context
*/
static void
-interpreter_run (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
+interpreter_run (void *cls);
/**
@@ -241,10 +242,12 @@ interpreter_run (void *cls,
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol)
+ * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
*/
static void
add_incoming_cb (void *cls,
- unsigned int http_status)
+ unsigned int http_status,
+ json_t *json)
{
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
@@ -253,6 +256,14 @@ add_incoming_cb (void *cls,
if (cmd->expected_response_code != http_status)
{
GNUNET_break (0);
+ if (NULL != json)
+ {
+ fprintf (stderr,
+ "Unexpected response code %u:\n",
+ http_status);
+ json_dumpf (json, stderr, 0);
+ fprintf (stderr, "\n");
+ }
fail (is);
return;
}
@@ -266,17 +277,17 @@ add_incoming_cb (void *cls,
* Run the main interpreter loop that performs bank operations.
*
* @param cls contains the `struct InterpreterState`
- * @param tc scheduler context
*/
static void
-interpreter_run (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+interpreter_run (void *cls)
{
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
struct TALER_Amount amount;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
is->task = NULL;
+ tc = GNUNET_SCHEDULER_get_task_context ();
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
{
fprintf (stderr,
@@ -310,7 +321,8 @@ interpreter_run (void *cls,
= TALER_BANK_admin_add_incoming (ctx,
&cmd->details.admin_add_incoming.wtid,
&amount,
- cmd->details.admin_add_incoming.account_no,
+ cmd->details.admin_add_incoming.debit_account_no,
+ cmd->details.admin_add_incoming.credit_account_no,
&add_incoming_cb,
is);
if (NULL == cmd->details.admin_add_incoming.aih)
@@ -338,11 +350,9 @@ interpreter_run (void *cls,
* Cleans up our state.
*
* @param cls the interpreter state.
- * @param tc unused
*/
static void
-do_shutdown (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+do_shutdown (void *cls)
{
struct InterpreterState *is = cls;
struct Command *cmd;
@@ -399,11 +409,9 @@ do_shutdown (void *cls,
* 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)
+context_task (void *cls)
{
long timeout;
int max_fd;
@@ -455,13 +463,9 @@ context_task (void *cls,
* 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)
+run (void *cls)
{
struct InterpreterState *is;
static struct Command commands[] =
@@ -470,8 +474,9 @@ run (void *cls,
{ .oc = OC_ADMIN_ADD_INCOMING,
.label = "deposit-1",
.expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.account_no = 42,
- .details.admin_add_incoming.amount = "EUR:5.01" },
+ .details.admin_add_incoming.credit_account_no = 1,
+ .details.admin_add_incoming.debit_account_no = 2,
+ .details.admin_add_incoming.amount = "PUDOS:5.01" },
{ .oc = OC_END }
};
@@ -503,6 +508,7 @@ main (int argc,
char * const *argv)
{
struct GNUNET_OS_Process *bankd;
+ unsigned int cnt;
GNUNET_log_setup ("test-bank-api",
"WARNING",
@@ -510,32 +516,43 @@ main (int argc,
bankd = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
- "taler-bank-httpd",
- "taler-bank-httpd",
- "-d", "test-bank-home",
+ "taler-bank-manage",
+ "taler-bank-manage",
+ "serve-http", "--port", "8081",
NULL);
if (NULL == bankd)
{
fprintf (stderr,
- "taler-bank-httpd not found, skipping test\n");
+ "taler-bank-manage not found, skipping test\n");
return 77; /* report 'skip' */
}
/* give child time to start and bind against the socket */
fprintf (stderr,
- "Waiting for taler-bank-httpd to be ready");
+ "Waiting for taler-bank-manage to be ready\n");
+ cnt = 0;
do
{
fprintf (stderr, ".");
sleep (1);
+ cnt++;
+ if (cnt > 30)
+ break;
}
- while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
+ while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/ -o /dev/null -O /dev/null"));
fprintf (stderr, "\n");
result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_run (&run, NULL);
+ if (cnt <= 30)
+ GNUNET_SCHEDULER_run (&run, NULL);
GNUNET_OS_process_kill (bankd,
SIGTERM);
GNUNET_OS_process_wait (bankd);
GNUNET_OS_process_destroy (bankd);
+ if (cnt > 30)
+ {
+ fprintf (stderr,
+ "taler-bank-manage failed to start properly.\n");
+ return 77;
+ }
return (GNUNET_OK == result) ? 0 : 1;
}
diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am
new file mode 100644
index 000000000..d953a7a86
--- /dev/null
+++ b/src/exchange-lib/Makefile.am
@@ -0,0 +1,67 @@
+# 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_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 = \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
+ -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
+
+AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
+
+TESTS = \
+ $(check_PROGRAMS)
+
+test_exchange_api_SOURCES = \
+ test_exchange_api.c
+test_exchange_api_LDADD = \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil \
+ -ljansson
+
+EXTRA_DIST = \
+ test_taler_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
+ test_taler_exchange_api_home/.config/taler/test.json \
+ test_taler_exchange_api_home/.config/taler/sepa.json \
+ test_taler_exchange_api.conf
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..871a88a6b
--- /dev/null
+++ b/src/exchange-lib/exchange_api_admin.c
@@ -0,0 +1,255 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_exchange_service.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 ==
+ GNUNET_TIME_round_abs (&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", GNUNET_JSON_from_data (reserve_pub,
+ sizeof (*reserve_pub)),
+ "amount", TALER_JSON_from_amount (amount),
+ "execution_date", GNUNET_JSON_from_time_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..aacbb4a2a
--- /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 "taler_json_lib.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 GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("amount",
+ &amount),
+ GNUNET_JSON_spec_string ("type",
+ &type),
+ GNUNET_JSON_spec_fixed_auto ("signature",
+ &sig),
+ GNUNET_JSON_spec_varsize ("details",
+ &details,
+ &details_size),
+ GNUNET_JSON_spec_end()
+ };
+
+ transaction = json_array_get (history,
+ off);
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ 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);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ dr = (const struct TALER_DepositRequestPS *) details;
+ if (details_size != ntohl (dr->purpose.size))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_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);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+
+ TALER_amount_ntoh (&dr_amount,
+ &dr->amount_with_fee);
+ if (0 != TALER_amount_cmp (&dr_amount,
+ &amount))
+ {
+ GNUNET_break (0);
+ GNUNET_JSON_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);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details;
+ if (details_size != ntohl (rm->purpose.size))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_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);
+ GNUNET_JSON_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);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ /* signature not supported, new version on server? */
+ GNUNET_break_op (0);
+ GNUNET_JSON_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);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_JSON_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..2a521ceb2
--- /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..8d6746a17
--- /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..8ec45a23f
--- /dev/null
+++ b/src/exchange-lib/exchange_api_deposit.c
@@ -0,0 +1,571 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_exchange_service.h"
+#include "exchange_api_common.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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("pub", &exchange_pub),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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) GNUNET_TIME_round_abs (&wire_deadline);
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ /* initialize h_wire */
+ if (GNUNET_OK !=
+ TALER_JSON_hash (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", GNUNET_JSON_from_data (&h_wire,
+ sizeof (h_wire)),
+ "H_contract", GNUNET_JSON_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "coin_pub", GNUNET_JSON_from_data (coin_pub,
+ sizeof (*coin_pub)),
+ "denom_pub", GNUNET_JSON_from_rsa_public_key (denom_pub->rsa_public_key),
+ "ub_sig", GNUNET_JSON_from_rsa_signature (denom_sig->rsa_signature),
+ "timestamp", GNUNET_JSON_from_time_abs (timestamp),
+ "transaction_id", (json_int_t) transaction_id,
+ "merchant_pub", GNUNET_JSON_from_data (merchant_pub,
+ sizeof (*merchant_pub)),
+ "refund_deadline", GNUNET_JSON_from_time_abs (refund_deadline),
+ "edate", GNUNET_JSON_from_time_abs (wire_deadline),
+ "coin_sig", GNUNET_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..1ad1dd019
--- /dev/null
+++ b/src/exchange-lib/exchange_api_deposit_wtid.c
@@ -0,0 +1,383 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_exchange_service.h"
+#include "exchange_api_common.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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
+ GNUNET_JSON_spec_absolute_time ("execution_time", &execution_time),
+ TALER_JSON_spec_amount ("coin_contribution", &coin_contribution_s),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_absolute_time ("execution_time", &execution_time),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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", GNUNET_JSON_from_data (h_wire,
+ sizeof (struct GNUNET_HashCode)),
+ "H_contract", GNUNET_JSON_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "coin_pub", GNUNET_JSON_from_data (coin_pub,
+ sizeof (*coin_pub)),
+ "transaction_id", (json_int_t) transaction_id,
+ "merchant_pub", GNUNET_JSON_from_data (&dtp.merchant,
+ sizeof (struct TALER_MerchantPublicKeyP)),
+ "merchant_sig", GNUNET_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..65597126c
--- /dev/null
+++ b/src/exchange-lib/exchange_api_handle.c
@@ -0,0 +1,910 @@
+/*
+ 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 <microhttpd.h>
+#include "taler_json_lib.h"
+#include "taler_exchange_service.h"
+#include "taler_signatures.h"
+#include "exchange_api_context.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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("master_sig",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("key",
+ &sign_key_issue.signkey_pub),
+ GNUNET_JSON_spec_absolute_time ("stamp_start",
+ &valid_from),
+ GNUNET_JSON_spec_absolute_time ("stamp_expire",
+ &valid_until),
+ GNUNET_JSON_spec_absolute_time ("stamp_end",
+ &valid_legal),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (sign_key_obj,
+ spec,
+ NULL, NULL))
+ {
+ 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_RsaPublicKey *pk;
+ struct GNUNET_CRYPTO_EddsaSignature sig;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("master_sig",
+ &sig),
+ GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit",
+ &deposit_valid_until),
+ GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw",
+ &withdraw_valid_until),
+ GNUNET_JSON_spec_absolute_time ("stamp_start",
+ &valid_from),
+ GNUNET_JSON_spec_absolute_time ("stamp_expire_legal",
+ &expire_legal),
+ TALER_JSON_spec_amount ("value",
+ &value),
+ TALER_JSON_spec_amount ("fee_withdraw",
+ &fee_withdraw),
+ TALER_JSON_spec_amount ("fee_deposit",
+ &fee_deposit),
+ TALER_JSON_spec_amount ("fee_refresh",
+ &fee_refresh),
+ GNUNET_JSON_spec_rsa_public_key ("denom_pub",
+ &pk),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (denom_key_obj,
+ spec, NULL, NULL))
+ {
+ 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:
+ GNUNET_JSON_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;
+ const char *auditor_url;
+ struct TALER_ExchangeKeyValidityPS kv;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("auditor_pub",
+ &auditor->auditor_pub),
+ GNUNET_JSON_spec_string ("auditor_url",
+ &auditor_url),
+ GNUNET_JSON_spec_json ("denomination_keys",
+ &keys),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (auditor_obj,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ auditor->auditor_url = GNUNET_strdup (auditor_url);
+ kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS);
+ kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS));
+ GNUNET_CRYPTO_hash (auditor_url,
+ strlen (auditor_url) + 1,
+ &kv.auditor_url_hash);
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
+ &denom_h),
+ GNUNET_JSON_spec_fixed_auto ("auditor_sig",
+ &auditor_sig),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (key,
+ spec,
+ NULL, NULL))
+ {
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("master_public_key",
+ &key_data->master_pub),
+ GNUNET_JSON_spec_fixed_auto ("eddsa_sig",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
+ &pub),
+ GNUNET_JSON_spec_absolute_time ("list_issue_date",
+ &list_issue_date),
+ GNUNET_JSON_spec_end()
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ spec,
+ NULL, NULL));
+ }
+
+ /* 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_refresh.c b/src/exchange-lib/exchange_api_refresh.c
new file mode 100644
index 000000000..5cdf059b7
--- /dev/null
+++ b/src/exchange-lib/exchange_api_refresh.c
@@ -0,0 +1,2066 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_exchange_service.h"
+#include "exchange_api_common.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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
+ GNUNET_JSON_spec_uint16 ("noreveal_index", noreveal_index),
+ GNUNET_JSON_spec_end()
+ };
+ struct TALER_RefreshMeltConfirmationPS confirm;
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("history", &history),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
+ TALER_JSON_spec_amount ("original_value", &original_value),
+ TALER_JSON_spec_amount ("requested_value", &melt_value_with_fee),
+ GNUNET_JSON_spec_end()
+ };
+ const struct MeltedCoin *mc;
+
+ /* parse JSON reply */
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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",
+ GNUNET_JSON_from_data (&melt.coin_pub,
+ sizeof (melt.coin_pub)),
+ "denom_pub",
+ GNUNET_JSON_from_rsa_public_key (mc->pub_key.rsa_public_key),
+ "denom_sig",
+ GNUNET_JSON_from_rsa_signature (mc->sig.rsa_signature),
+ "confirm_sig",
+ GNUNET_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,
+ GNUNET_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,
+ GNUNET_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,
+ GNUNET_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,
+ GNUNET_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,
+ GNUNET_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("ev_sigs", &jsona),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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_RsaSignature *blind_sig;
+ struct GNUNET_CRYPTO_RsaSignature *sig;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode coin_hash;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_rsa_signature ("ev_sig", &blind_sig),
+ GNUNET_JSON_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 !=
+ GNUNET_JSON_parse (jsonai,
+ spec,
+ NULL, NULL))
+ {
+ 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,
+ GNUNET_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",
+ GNUNET_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..8bb40d7f4
--- /dev/null
+++ b/src/exchange-lib/exchange_api_refresh_link.c
@@ -0,0 +1,484 @@
+/*
+ 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 <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_json_lib.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_RsaSignature *bsig;
+ struct GNUNET_CRYPTO_RsaPublicKey *rpub;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_varsize ("link_enc", &link_enc, &link_enc_size),
+ GNUNET_JSON_spec_rsa_public_key ("denom_pub", &rpub),
+ GNUNET_JSON_spec_rsa_signature ("ev_sig", &bsig),
+ GNUNET_JSON_spec_end()
+ };
+ struct TALER_RefreshLinkEncrypted *rle;
+ struct TALER_RefreshLinkDecrypted *rld;
+ struct TALER_LinkSecretP secret;
+
+ /* parse reply */
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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);
+ GNUNET_JSON_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);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ rld = TALER_refresh_decrypt (rle,
+ &secret);
+ if (NULL == rld)
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_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);
+ GNUNET_JSON_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("new_coins", &jsona),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json_array_get (json,
+ session),
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! json_is_array (jsona))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+
+ /* count all coins over all sessions */
+ num_coins += json_array_size (jsona);
+ GNUNET_JSON_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("new_coins", &jsona),
+ GNUNET_JSON_spec_fixed_auto ("transfer_pub", &trans_pub),
+ GNUNET_JSON_spec_fixed_auto ("secret_enc", &secret_enc),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json_array_get (json,
+ session),
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! json_is_array (jsona))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_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;
+ GNUNET_JSON_parse_free (spec);
+ break;
+ }
+ GNUNET_JSON_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..8c3663244
--- /dev/null
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -0,0 +1,936 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_json_lib.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 GNUNET_JSON_Specification hist_spec[] = {
+ GNUNET_JSON_spec_string ("type", &type),
+ TALER_JSON_spec_amount ("amount",
+ &amount),
+ /* 'wire' and 'signature' are optional depending on 'type'! */
+ GNUNET_JSON_spec_end()
+ };
+
+ transaction = json_array_get (history,
+ off);
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ hist_spec,
+ NULL, NULL))
+ {
+ 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 GNUNET_JSON_Specification withdraw_spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("signature",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("details",
+ &withdraw_purpose),
+ GNUNET_JSON_spec_end()
+ };
+ unsigned int i;
+
+ rhistory[off].type = TALER_EXCHANGE_RTT_WITHDRAWAL;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ withdraw_spec,
+ NULL, NULL))
+ {
+ 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);
+ GNUNET_JSON_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);
+ GNUNET_JSON_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);
+ GNUNET_JSON_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);
+ GNUNET_JSON_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 GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("balance", &balance),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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_RsaSignature *blind_sig;
+ struct GNUNET_CRYPTO_RsaSignature *sig;
+ struct TALER_DenominationSignature dsig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_rsa_signature ("ev_sig", &blind_sig),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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 GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("balance", &balance),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ 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", GNUNET_JSON_from_rsa_public_key (pk->key.rsa_public_key),
+ "coin_ev", GNUNET_JSON_from_data (coin_ev,
+ coin_ev_size),
+ "reserve_pub", GNUNET_JSON_from_data (&wsh->reserve_pub,
+ sizeof (struct TALER_ReservePublicKeyP)),
+ "reserve_sig", GNUNET_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..0e93a9d20
--- /dev/null
+++ b/src/exchange-lib/exchange_api_wire.c
@@ -0,0 +1,318 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 Inria and 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 "taler_json_lib.h"
+#include "taler_wire_plugin.h"
+#include "exchange_api_common.h"
+#include "exchange_api_context.h"
+#include "exchange_api_handle.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/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)
+{
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct TALER_WIRE_Plugin *plugin;
+ char *lib_name;
+ int ret;
+
+ key_state = TALER_EXCHANGE_get_keys (wh->exchange);
+ (void) GNUNET_asprintf (&lib_name,
+ "libtaler_plugin_wire_%s",
+ method);
+ plugin = GNUNET_PLUGIN_load (lib_name,
+ NULL);
+ if (NULL == plugin)
+ {
+ GNUNET_free (lib_name);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Wire transfer method `%s' not supported\n",
+ method);
+ return GNUNET_NO;
+ }
+ plugin->library_name = lib_name;
+ ret = plugin->wire_validate (plugin->cls,
+ json,
+ &key_state->master_pub);
+ GNUNET_PLUGIN_unload (lib_name,
+ plugin);
+ GNUNET_free (lib_name);
+ return (GNUNET_YES == ret) ? GNUNET_OK : GNUNET_SYSERR;
+}
+
+
+/**
+ * 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:
+ {
+ const char *key;
+ json_t *method;
+ json_t *keep;
+ int ret;
+
+ /* We 'keep' methods that we support and that are well-formed;
+ we fail (by setting response_code=0) if any method that we do
+ support fails to verify. */
+ keep = json_object ();
+ json_object_foreach (json, key, method) {
+ ret = verify_wire_method_signature_ok (wh,
+ key,
+ method);
+ if (GNUNET_SYSERR == ret)
+ {
+ /* bogus reply */
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ /* GNUNET_NO: not understood by us, simply skip! */
+ if (GNUNET_OK == ret)
+ {
+ /* supported and valid, keep! */
+ json_object_set (keep,
+ key,
+ method);
+ }
+ }
+ if (0 != response_code)
+ {
+ /* all supported methods were valid, use 'keep' for 'json' */
+ json_decref (json);
+ json = keep;
+ break;
+ }
+ else
+ {
+ /* some supported methods were invalid, release 'keep', preserve
+ full 'json' for application-level error handling. */
+ json_decref (keep);
+ }
+ }
+ 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;
+ }
+ wh->cb (wh->cb_cls,
+ response_code,
+ json);
+ 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..49a50f640
--- /dev/null
+++ b/src/exchange-lib/exchange_api_wire_deposits.c
@@ -0,0 +1,330 @@
+/*
+ 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 "taler_json_lib.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 TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
+ TALER_JSON_spec_amount ("total_amount", &total_amount),
+ GNUNET_JSON_spec_json ("details", &details_j),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ num_details = json_array_size (details_j);
+ {
+ struct TALER_WireDepositDetails details[num_details];
+ unsigned int i;
+ struct GNUNET_HashContext *hash_context;
+ struct TALER_WireDepositDetailP dd;
+ struct TALER_WireDepositDataPS wdp;
+
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
+ 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 GNUNET_JSON_Specification spec_detail[] = {
+ GNUNET_JSON_spec_fixed_auto ("H_contract", &detail->h_contract),
+ TALER_JSON_spec_amount ("deposit_value", &detail->coin_value),
+ TALER_JSON_spec_amount ("deposit_fee", &detail->coin_fee),
+ GNUNET_JSON_spec_uint64 ("transaction_id", &detail->transaction_id),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &detail->coin_pub),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (detail_j,
+ spec_detail,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ /* build up big hash for signature checking later */
+ dd.h_contract = detail->h_contract;
+ dd.transaction_id = GNUNET_htonll (detail->transaction_id);
+ dd.coin_pub = detail->coin_pub;
+ TALER_amount_hton (&dd.deposit_value,
+ &detail->coin_value);
+ TALER_amount_hton (&dd.deposit_fee,
+ &detail->coin_fee);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &dd,
+ sizeof (struct TALER_WireDepositDetailP));
+ }
+ /* Check signature */
+ wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT);
+ wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
+ TALER_amount_hton (&wdp.total,
+ &total_amount);
+ wdp.merchant_pub = merchant_pub;
+ wdp.h_wire = h_wire;
+ GNUNET_CRYPTO_hash_context_finish (hash_context,
+ &wdp.h_details);
+ if ( (0 == response_code /* avoid crypto if things are already wrong */) &&
+ (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (TALER_EXCHANGE_get_keys (wdh->exchange),
+ &exchange_pub)) )
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ if ( (0 == response_code /* avoid crypto if things are already wrong */) &&
+ (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (TALER_EXCHANGE_get_keys (wdh->exchange),
+ &exchange_pub)) )
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ 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_api.c b/src/exchange-lib/test_exchange_api.c
new file mode 100644
index 000000000..3659e119e
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api.c
@@ -0,0 +1,2579 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V. and Inria
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, 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 "taler_json_lib.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
+ */
+static void
+context_task (void *cls);
+
+
+/**
+ * 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`
+ */
+static void
+interpreter_run (void *cls);
+
+
+/**
+ * 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);
+ GNUNET_assert (NULL != 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);
+ GNUNET_assert (NULL != 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.
+ *
+ * @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 obj the received JSON reply, if successful this should be the wire
+ * format details as provided by /wire.
+ */
+static void
+wire_cb (void *cls,
+ unsigned int http_status,
+ json_t *obj)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.wire.wh = 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;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ {
+ json_t *method;
+
+ method = json_object_get (obj,
+ cmd->details.wire.format);
+ if (NULL == method)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected method `%s' not included in response to command %s\n",
+ cmd->details.wire.format,
+ cmd->label);
+ json_dumpf (obj, stderr, 0);
+ fail (is);
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * 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;
+ 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:
+ ref = find_command (is,
+ cmd->details.wire_deposits.wtid_ref);
+ GNUNET_assert (NULL != ref);
+ 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_assert (NULL != dep);
+ 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`
+ */
+static void
+interpreter_run (void *cls)
+{
+ 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;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+ is->task = NULL;
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ 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 ();
+ GNUNET_TIME_round_abs (&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_JSON_hash (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 ();
+ GNUNET_TIME_round_abs (&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_JSON_hash (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);
+ GNUNET_assert (NULL != 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);
+ GNUNET_assert (NULL != ref);
+ /* find melt command */
+ ref = find_command (is,
+ ref->details.refresh_reveal.melt_ref);
+ GNUNET_assert (NULL != 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 (NULL != 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_JSON_hash (wire,
+ &h_wire);
+ json_decref (wire);
+ contract = json_loads (ref->details.deposit.contract,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_assert (NULL != contract);
+ TALER_JSON_hash (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.
+ */
+static void
+do_shutdown (void *cls)
+{
+ 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
+ */
+static void
+context_task (void *cls)
+{
+ 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
+ */
+static void
+run (void *cls)
+{
+ 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",
+ /* expecting 'test' method in response */
+ .expected_response_code = MHD_HTTP_OK,
+ .details.wire.format = "test" },
+#endif
+#if WIRE_SEPA
+ { .oc = OC_WIRE,
+ .label = "wire-sepa",
+ /* expecting 'sepa' method in response */
+ .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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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_uri\":\"http://localhost:8082/\", \"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);
+ /* These might get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-c", "test_exchange_api.conf",
+ 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",
+ "-c", "test_exchange_api.conf",
+ 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-lib/test_exchange_api.conf b/src/exchange-lib/test_exchange_api.conf
new file mode 100644
index 000000000..281ac7361
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api.conf
@@ -0,0 +1,95 @@
+# This file is in the public domain.
+#
+[PATHS]
+# Persistant data storage for the testcase
+TALER_TEST_HOME = test_exchange_api_home/
+
+[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-incoming-test]
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
+
+[wire-outgoing-test]
+# What is the main website of the bank?
+BANK_URI = "http://localhost:8082/"
+# Into which account at the 'bank' should (incoming) wire transfers be made?
+BANK_ACCOUNT_NUMBER = 2
+
+[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
diff --git a/src/exchange-lib/test_exchange_api_home/.config/taler/sepa.json b/src/exchange-lib/test_exchange_api_home/.config/taler/sepa.json
new file mode 100644
index 000000000..b435ce86b
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api_home/.config/taler/sepa.json
@@ -0,0 +1,9 @@
+{
+ "name": "Max Musterman",
+ "bic": "COBADEFF370",
+ "type": "sepa",
+ "sig": "4EVRC2MCJPXQC8MC00831DNWEXMZAP4JQDDE1A7R6KR3MANG24RC1VQ55AX5A2E35S58VW1VSTENFTPHG5MWG9BSN8B8WXSV21KKW20",
+ "address": "Musterstadt",
+ "salt": "3KTM1ZRMWGEQPQ254S4R5R4Q8XM0ZYWTCTE01TZ76MVBSQ6RX7A5DR08WXVH1DCHR1R7ACRB7X0EVC2XDW1CBZM9WFSD9TRMZ90BR98",
+ "iban": "DE89370400440532013000"
+} \ No newline at end of file
diff --git a/src/exchange-lib/test_exchange_api_home/.config/taler/test.json b/src/exchange-lib/test_exchange_api_home/.config/taler/test.json
new file mode 100644
index 000000000..be5e92c11
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api_home/.config/taler/test.json
@@ -0,0 +1,8 @@
+{
+ "salt": "AZPRFVJ58NM6M7J5CZQPJAH3EW5DYM52AEZ9Y1C1ER3W94QV8D8TQKF6CK8MYQRA9QMSKDQTGZ306ZS9GQ0M6R01CJ20KPP49WFDZK8",
+ "name": "The exchange",
+ "account_number": 3,
+ "bank_uri": "http://localhost:8082/",
+ "type": "test",
+ "sig": "RPQXP9S4P8PQP7HEZQNRSZCT0ATNEP8GW0P5TPM34V5RX86FCD670V44R9NETSYDDKB8SZV7TKY9PAJYTY51D3VDWY9XXQ5BPFRXR28"
+} \ No newline at end of file
diff --git a/src/mint-lib/test-mint-home/master.priv b/src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv
index 394926938..394926938 100644
--- a/src/mint-lib/test-mint-home/master.priv
+++ b/src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv
diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am
new file mode 100644
index 000000000..631f3af20
--- /dev/null
+++ b/src/exchange-tools/Makefile.am
@@ -0,0 +1,96 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+pkgcfgdir = $(prefix)/share/taler/config.d/
+
+pkgcfg_DATA = \
+ auditor.conf \
+ exchange-signkeys.conf \
+ coins.conf
+
+
+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-wire \
+ 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_wire_SOURCES = \
+ taler-exchange-wire.c
+taler_exchange_wire_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/wire/libtalerwire.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson $(XLIB)
+taler_exchange_wire_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)
+
+
+EXTRA_DIST = \
+ auditor.conf
diff --git a/src/exchange-tools/auditor.conf b/src/exchange-tools/auditor.conf
new file mode 100644
index 000000000..7eb5f8ae9
--- /dev/null
+++ b/src/exchange-tools/auditor.conf
@@ -0,0 +1,12 @@
+# This configuration file is in the public domain
+#
+# It cointains options for the auditor.
+
+[auditor]
+
+# Where do we store the auditor's private key?
+AUDITOR_PRIV_FILE = ${TALER_DATA_HOME}/auditor/offline-keys/auditor.priv
+
+# What is the Web site of the auditor (i.e. to file complaints about
+# a misbehaving exchange)?
+# AUDITOR_URL = https://auditor.taler.net/
diff --git a/src/exchange-tools/coins.conf b/src/exchange-tools/coins.conf
new file mode 100644
index 000000000..90bf7064c
--- /dev/null
+++ b/src/exchange-tools/coins.conf
@@ -0,0 +1,25 @@
+# This configuration file is in the public domain
+#
+# This is a template file for coin definitions. There are no
+# reasonable defaults, as legal and business concerns influence each
+# value given.
+#
+# Note that while we only give one section here, you can define
+# any number of coins by providing many "coin_" sections.
+#
+# 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]
+
+# All options are mandatory!
+# value = EUR:0.01
+# duration_overlap = 60 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
diff --git a/src/exchange-tools/exchange-signkeys.conf b/src/exchange-tools/exchange-signkeys.conf
new file mode 100644
index 000000000..3146f09b2
--- /dev/null
+++ b/src/exchange-tools/exchange-signkeys.conf
@@ -0,0 +1,16 @@
+# General data for signing keys.
+[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
diff --git a/src/exchange-tools/taler-auditor-sign.c b/src/exchange-tools/taler-auditor-sign.c
new file mode 100644
index 000000000..d5a3a9403
--- /dev/null
+++ b/src/exchange-tools/taler-auditor-sign.c
@@ -0,0 +1,366 @@
+/*
+ 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;
+
+/**
+ * URL of the auditor (informative for the user).
+ */
+static char *auditor_url;
+
+/**
+ * Master public key of the exchange.
+ */
+static struct TALER_MasterPublicKeyP master_public_key;
+
+/**
+ * Our configuration.
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/**
+ * 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)
+{
+ char *cfgfile = NULL;
+ const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'a', "auditor-key", "FILENAME",
+ "file containing the private key of the auditor", 1,
+ &GNUNET_GETOPT_set_filename, &auditor_key_file},
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ GNUNET_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},
+ {'u', "auditor-url", "URL",
+ "URL of the auditor (informative link for the user)", 1,
+ &GNUNET_GETOPT_set_string, &auditor_url},
+ {'r', "exchange-request", "FILENAME",
+ "set of keys the exchange requested the auditor to sign", 1,
+ &GNUNET_GETOPT_set_string, &exchange_request_file},
+ {'o', "output", "FILENAME",
+ "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-auditor-sign",
+ "WARNING",
+ NULL));
+ if (GNUNET_GETOPT_run ("taler-auditor-sign",
+ options,
+ argc, argv) < 0)
+ return 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+ cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ if ( (NULL == auditor_key_file) &&
+ (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "auditor",
+ "AUDITOR_PRIV_FILE",
+ &auditor_key_file)) )
+ {
+ fprintf (stderr,
+ "Auditor key file not given in neither configuration nor command-line\n");
+ return 1;
+ }
+ if ( (NULL == auditor_url) &&
+ (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "auditor",
+ "AUDITOR_URL",
+ &auditor_url)) )
+ {
+ fprintf (stderr,
+ "Auditor URL 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));
+ GNUNET_CRYPTO_hash (auditor_url,
+ strlen (auditor_url) + 1,
+ &kv.auditor_url_hash);
+ 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,
+ auditor_url,
+ 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..9f301854f
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-dbinit.c
@@ -0,0 +1,91 @@
+/*
+ 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 "taler_exchangedb_plugin.h"
+
+
+/**
+ * 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)
+{
+ char *cfgfile = NULL;
+ const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ GNUNET_GETOPT_OPTION_HELP ("Initialize Taler Exchange database"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct TALER_EXCHANGEDB_Plugin *plugin;
+
+ 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));
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+ cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ if (NULL ==
+ (plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
+ {
+ fprintf (stderr,
+ "Failed to initialize database plugin.\n");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return 1;
+ }
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ GNUNET_NO))
+ {
+ fprintf (stderr,
+ "Failed to initialize database.\n");
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return 1;
+ }
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ 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..064f2249e
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-keycheck.c
@@ -0,0 +1,255 @@
+/*
+ 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-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)
+{
+ char *cfgfile;
+ const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ GNUNET_GETOPT_OPTION_HELP ("gnunet-exchange-keycheck OPTIONS"),
+ 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;
+ kcfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (kcfg,
+ cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (kcfg,
+ "exchange",
+ "KEYDIR",
+ &exchange_directory))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KEYDIR");
+ 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..ab2123a15
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -0,0 +1,1051 @@
+/*
+ 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-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;
+ }
+ GNUNET_TIME_round_rel (&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;
+ }
+ GNUNET_TIME_round_rel (&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;
+ }
+ GNUNET_TIME_round_rel (&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;
+ }
+ GNUNET_TIME_round_rel (&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;
+ }
+ GNUNET_TIME_round_rel (&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)
+{
+ char *cfgfile = NULL;
+ const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ GNUNET_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;
+ kcfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (kcfg,
+ cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ 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 ();
+ }
+ GNUNET_TIME_round_abs (&now);
+ if ( (NULL == masterkeyfile) &&
+ (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (kcfg,
+ "exchange",
+ "MASTER_PRIV_FILE",
+ &masterkeyfile)) )
+ {
+ fprintf (stderr,
+ "Master key file not given in neither configuration nor command-line\n");
+ return 1;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (kcfg,
+ "exchange",
+ "KEYDIR",
+ &exchange_directory))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KEYDIR");
+ 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;
+ }
+ GNUNET_TIME_round_rel (&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..3494e88a0
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-reservemod.c
@@ -0,0 +1,214 @@
+/*
+ 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 *cfgfile = NULL;
+ 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},
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ {'d', "details", "JSON",
+ "details about the bank transaction which justify why we add this amount", 1,
+ &GNUNET_GETOPT_set_string, &details},
+ GNUNET_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;
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+ cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ GNUNET_free_non_null (add_str);
+ GNUNET_free_non_null (details);
+ GNUNET_free_non_null (reserve_pub_str);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange",
+ "KEYDIR",
+ &exchange_directory))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KEYDIR");
+ 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;
+ }
+
+ 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-wire.c b/src/exchange-tools/taler-exchange-wire.c
new file mode 100644
index 000000000..c57e45f09
--- /dev/null
+++ b/src/exchange-tools/taler-exchange-wire.c
@@ -0,0 +1,214 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015, 2016 Inria
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-wire.c
+ * @brief Create signed response for /wire requests.
+ * @author Christian Grothoff
+ */
+#include <platform.h>
+#include <jansson.h>
+#include <gnunet/gnunet_json_lib.h>
+#include "taler_crypto_lib.h"
+#include "taler_wire_lib.h"
+#include "taler_signatures.h"
+
+
+/**
+ * Filename of the master private key.
+ */
+static char *masterkeyfile;
+
+/**
+ * Account holder information in JSON format.
+ */
+static char *json_in;
+
+/**
+ * Which wire method is this for?
+ */
+static char *method;
+
+/**
+ * Where to write the result.
+ */
+static char *output_filename;
+
+/**
+ * Our configuration.
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/**
+ * 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)
+{
+ char *cfgfile = NULL;
+ const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ {'j', "json", "JSON",
+ "account information in JSON format", 1,
+ &GNUNET_GETOPT_set_string, &json_in},
+ {'m', "master-key", "FILE",
+ "master key file (private key)", 1,
+ &GNUNET_GETOPT_set_filename, &masterkeyfile},
+ {'t', "type", "METHOD",
+ "which wire transfer method (i.e. 'test' or 'sepa') is this for?", 1,
+ &GNUNET_GETOPT_set_string, &method},
+ {'o', "output", "FILE",
+ "where to write the result", 1,
+ &GNUNET_GETOPT_set_filename, &output_filename},
+ GNUNET_GETOPT_OPTION_HELP ("Setup /wire response"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
+ struct TALER_MasterPrivateKeyP key;
+ struct TALER_MasterSignatureP sig;
+ json_t *j;
+ json_error_t err;
+ char *json_out;
+ struct GNUNET_HashCode salt;
+ struct TALER_WIRE_Plugin *plugin;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-exchange-wire",
+ "WARNING",
+ NULL));
+
+ if (GNUNET_GETOPT_run ("taler-exchange-wire",
+ options,
+ argc, argv) < 0)
+ return 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+ cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ if ( (NULL == masterkeyfile) &&
+ (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange-master",
+ "MASTER_PRIV_FILE",
+ &masterkeyfile)) )
+ {
+ fprintf (stderr,
+ "Master key file not given in neither configuration nor command-line\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;
+ }
+ if (NULL == json_in)
+ {
+ fprintf (stderr,
+ "Required -j argument missing\n");
+ return 1;
+ }
+ if (NULL == method)
+ {
+ fprintf (stderr,
+ "Required -t argument missing\n");
+ return 1;
+ }
+ j = json_loads (json_in,
+ JSON_REJECT_DUPLICATES,
+ &err);
+ if (NULL == j)
+ {
+ fprintf (stderr,
+ "Failed to parse JSON: %s (at offset %u)\n",
+ err.text,
+ (unsigned int) err.position);
+ return 1;
+ }
+ key.eddsa_priv = *eddsa_priv;
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &salt,
+ sizeof (salt));
+ plugin = TALER_WIRE_plugin_load (cfg,
+ method);
+ if (NULL == plugin)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Wire transfer method `%s' not supported\n",
+ method);
+ return 1;
+ }
+ if (GNUNET_OK !=
+ plugin->sign_wire_details (plugin->cls,
+ j,
+ &key,
+ &salt,
+ &sig))
+ {
+ /* sign function should have logged applicable errors */
+ json_decref (j);
+ TALER_WIRE_plugin_unload (plugin);
+ return 1;
+ }
+ TALER_WIRE_plugin_unload (plugin);
+ GNUNET_free (eddsa_priv);
+
+ /* add signature and salt to JSON message */
+ json_object_set_new (j,
+ "salt",
+ GNUNET_JSON_from_data (&salt,
+ sizeof (salt)));
+ json_object_set_new (j,
+ "sig",
+ GNUNET_JSON_from_data (&sig,
+ sizeof (sig)));
+
+ /* dump result to stdout */
+ json_out = json_dumps (j, JSON_INDENT(2));
+ json_decref (j);
+ GNUNET_assert (NULL != json_out);
+
+ if (NULL != output_filename)
+ {
+ fclose (stdout);
+ stdout = fopen (output_filename,
+ "w+");
+ }
+ fprintf (stdout,
+ "%s",
+ json_out);
+ fflush (stdout);
+ free (json_out);
+ return 0;
+}
+
+/* end of taler-exchange-wire.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..a283e78b8
--- /dev/null
+++ b/src/exchange/Makefile.am
@@ -0,0 +1,95 @@
+# 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
+
+pkgcfgdir = $(prefix)/share/taler/config.d/
+
+pkgcfg_DATA = \
+ exchange.conf
+
+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/json/libtalerjson.la \
+ $(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/wire/libtalerwire.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lmicrohttpd \
+ -lgnunetutil \
+ -lgnunetjson \
+ -ljansson \
+ -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
+
+test_taler_exchange_aggregator_postgres_SOURCES = \
+ test_taler_exchange_aggregator.c
+test_taler_exchange_aggregator_postgres_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lmicrohttpd \
+ -lgnunetutil \
+ -lgnunetjson \
+ -ljansson \
+ -lpthread
+
+check_PROGRAMS = \
+ test_taler_exchange_aggregator-postgres
+
+AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
+
+TESTS = \
+ $(check_SCRIPTS) \
+ $(check_PROGRAMS)
+
+
+EXTRA_DIST = \
+ test-taler-exchange-aggregator-postgres.conf \
+ test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv \
+ test_taler_exchange_httpd.conf \
+ exchange.conf
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/exchange.conf b/src/exchange/exchange.conf
new file mode 100644
index 000000000..eab476ccd
--- /dev/null
+++ b/src/exchange/exchange.conf
@@ -0,0 +1,29 @@
+# This file is in the public domain.
+#
+[exchange]
+# Currency supported by the exchange (can only be one)
+# CURRENCY = EUR
+
+# Where do we store the private keys the exchange needs at
+# runtime? (Denomination and signing keys are then stored
+# in respective subdirectories.)
+KEYDIR = ${TALER_DATA_HOME}/exchange/live-keys/
+
+# Wire format supported by the exchange. We use 'test' for testing of
+# the actual coin operations.
+# WIREFORMAT = test
+
+# 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
+
+# Where do we store the offline master private key of the exchange?
+MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
new file mode 100644
index 000000000..e4ba975a2
--- /dev/null
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -0,0 +1,1010 @@
+/*
+ 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
+ */
+#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_json_lib.h"
+#include "taler_wire_lib.h"
+
+
+/**
+ * Data we keep to #run_transfers(). There is at most
+ * one of these around at any given point in time.
+ */
+struct WirePrepareData
+{
+
+ /**
+ * Database session for all of our transactions.
+ */
+ struct TALER_EXCHANGEDB_Session *session;
+
+ /**
+ * Wire execution handle.
+ */
+ struct TALER_WIRE_ExecuteHandle *eh;
+
+ /**
+ * Row ID of the transfer.
+ */
+ unsigned long long row_id;
+
+};
+
+
+/**
+ * Information about one aggregation process to be executed. There is
+ * at most one of these around at any given point in time.
+ */
+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;
+
+ /**
+ * 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;
+
+};
+
+
+/**
+ * Which currency is used by this exchange?
+ */
+static char *exchange_currency_string;
+
+/**
+ * Which wireformat should be supported by this aggregator?
+ */
+static char *exchange_wireformat;
+
+/**
+ * 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;
+
+/**
+ * Next task to run, if any.
+ */
+static struct GNUNET_SCHEDULER_Task *task;
+
+/**
+ * If we are currently executing a transfer, information about
+ * the active transfer is here. Otherwise, this variable is NULL.
+ */
+static struct WirePrepareData *wpd;
+
+/**
+ * If we are currently aggregating transactions, information about the
+ * active aggregation is here. Otherwise, this variable is NULL.
+ */
+static struct AggregationUnit *au;
+
+/**
+ * Value to return from main(). #GNUNET_OK on success, #GNUNET_SYSERR
+ * on serious errors.
+ */
+static int global_ret;
+
+/**
+ * #GNUNET_YES if we are in test mode and are using temporary tables.
+ */
+static int test_mode;
+
+/**
+ * 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!
+ *
+ * Note: do not change here, Postgres requires us to hard-code the
+ * LIMIT in the prepared statement.
+ */
+static unsigned int aggregation_limit = TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT;
+
+
+/**
+ * We're being aborted with CTRL-C (or SIGTERM). Shut down.
+ *
+ * @param cls closure
+ */
+static void
+shutdown_task (void *cls)
+{
+ if (NULL != task)
+ {
+ GNUNET_SCHEDULER_cancel (task);
+ task = NULL;
+ }
+ if (NULL != wpd)
+ {
+ if (NULL != wpd->eh)
+ {
+ wire_plugin->execute_wire_transfer_cancel (wire_plugin->cls,
+ wpd->eh);
+ wpd->eh = NULL;
+ }
+ db_plugin->rollback (db_plugin->cls,
+ wpd->session);
+ GNUNET_free (wpd);
+ wpd = NULL;
+ }
+ if (NULL != au)
+ {
+ if (NULL != au->ph)
+ {
+ wire_plugin->prepare_wire_transfer_cancel (wire_plugin->cls,
+ au->ph);
+ au->ph = NULL;
+ }
+ db_plugin->rollback (db_plugin->cls,
+ au->session);
+ GNUNET_free_non_null (au->additional_rows);
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ au = NULL;
+ GNUNET_free (au);
+ }
+ TALER_EXCHANGEDB_plugin_unload (db_plugin);
+ TALER_WIRE_plugin_unload (wire_plugin);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ cfg = NULL;
+}
+
+
+/**
+ * Parse configuration parameters for the exchange server into the
+ * corresponding global variables.
+ *
+ * @return #GNUNET_OK on success
+ */
+static int
+exchange_serve_process_config ()
+{
+ 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",
+ &exchange_wireformat))
+ {
+ 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");
+ return GNUNET_SYSERR;
+ }
+
+ if (NULL ==
+ (wire_plugin = TALER_WIRE_plugin_load (cfg,
+ exchange_wireformat)))
+ {
+ fprintf (stderr,
+ "Failed to load wire plugin for `%s'\n",
+ exchange_wireformat);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with details about deposits that have been made,
+ * with the goal of executing the corresponding wire transaction.
+ *
+ * @param cls NULL
+ * @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)
+{
+ 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 row %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_JSON_hash (au->wire,
+ &au->h_wire);
+ json_incref (au->wire);
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &au->wtid,
+ sizeof (au->wtid));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Starting aggregation under WTID %s\n",
+ TALER_B2S (&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 NULL
+ * @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 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 NULL
+ */
+static void
+run_aggregation (void *cls)
+{
+ struct TALER_EXCHANGEDB_Session *session;
+ unsigned int i;
+ int ret;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+ task = NULL;
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking for ready deposits to aggregate\n");
+ if (NULL == (session = db_plugin->get_session (db_plugin->cls,
+ test_mode)))
+ {
+ 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)
+ {
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ GNUNET_free (au);
+ au = NULL;
+ 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;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No more ready deposits, going to sleep\n");
+ if (GNUNET_YES == test_mode)
+ {
+ /* in test mode, shutdown if we end up being idle */
+ GNUNET_SCHEDULER_shutdown ();
+ }
+ else
+ {
+ /* nothing to do, sleep for a minute and try again */
+ task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &run_aggregation,
+ NULL);
+ }
+ return;
+ }
+ /* Now try to find other deposits to aggregate */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Found ready deposit for %s, aggregating\n",
+ TALER_B2S (&au->merchant_pub));
+ 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);
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ GNUNET_free (au);
+ au = NULL;
+ 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) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Aggregate value too low for transfer\n");
+ /* 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);
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ GNUNET_free (au);
+ au = NULL;
+ 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);
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ GNUNET_free (au);
+ au = NULL;
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ NULL);
+ return;
+ }
+ {
+ char *amount_s;
+
+ amount_s = TALER_amount_to_string (&au->total_amount);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Preparing wire transfer of %s to %s\n",
+ amount_s,
+ TALER_B2S (&au->merchant_pub));
+ }
+ au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls,
+ au->wire,
+ &au->total_amount,
+ &au->wtid,
+ &prepare_cb,
+ au);
+ 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);
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ au = NULL;
+ GNUNET_free (au);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ NULL);
+ 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()
+ */
+static void
+run_transfers (void *cls);
+
+
+/**
+ * Function to be called with the prepared transfer data.
+ *
+ * @param cls NULL
+ * @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 TALER_EXCHANGEDB_Session *session = au->session;
+
+ GNUNET_free_non_null (au->additional_rows);
+ if (NULL != au->wire)
+ json_decref (au->wire);
+ GNUNET_free (au);
+ au = NULL;
+ 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,
+ NULL);
+ 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,
+ NULL);
+ 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,
+ NULL);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Preparation complete, switching to transfer mode\n");
+ /* run alternative task: actually do wire transfer! */
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ NULL);
+}
+
+
+/**
+ * Function called with the result from the execute step.
+ *
+ * @param cls NULL
+ * @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 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);
+ wpd = NULL;
+ 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);
+ wpd = NULL;
+ return;
+ }
+ GNUNET_free (wpd);
+ wpd = NULL;
+ 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,
+ NULL);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Wire transfer complete\n");
+ /* continue with #run_transfers(), just to guard
+ against the unlikely case that there are more. */
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ NULL);
+
+}
+
+
+/**
+ * Callback with data about a prepared transaction.
+ *
+ * @param cls NULL
+ * @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)
+{
+ wpd->row_id = rowid;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Starting wire transfer %llu\n",
+ rowid);
+ wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls,
+ buf,
+ buf_size,
+ &wire_confirm_cb,
+ NULL);
+ 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);
+ wpd = NULL;
+ return;
+ }
+}
+
+
+/**
+ * Execute the wire transfers that we have committed to
+ * do.
+ *
+ * @param cls NULL
+ * @param tc scheduler context
+ */
+static void
+run_transfers (void *cls)
+{
+ int ret;
+ struct TALER_EXCHANGEDB_Session *session;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+ task = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking for pending wire transfers\n");
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ if (NULL == (session = db_plugin->get_session (db_plugin->cls,
+ test_mode)))
+ {
+ 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;
+ ret = db_plugin->wire_prepare_data_get (db_plugin->cls,
+ session,
+ exchange_wireformat,
+ &wire_prepare_cb,
+ NULL);
+ 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);
+ wpd = NULL;
+ return;
+ }
+ if (GNUNET_NO == ret)
+ {
+ /* no more prepared wire transfers, go back to aggregation! */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No more pending wire transfers, starting aggregation\n");
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ NULL);
+ GNUNET_free (wpd);
+ wpd = NULL;
+ return;
+ }
+ /* otherwise, continues in #wire_prepare_cb() */
+}
+
+
+/**
+ * First task.
+ *
+ * @param cls closure, NULL
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ cfg = GNUNET_CONFIGURATION_dup (c);
+ if (GNUNET_OK != exchange_serve_process_config ())
+ {
+ GNUNET_CONFIGURATION_destroy (cfg);
+ cfg = NULL;
+ global_ret = 1;
+ return;
+ }
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task,
+ cls);
+}
+
+
+/**
+ * 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[] = {
+ {'f', "format", "WIREFORMAT",
+ "wireformat to use, overrides WIREFORMAT option in [exchange] section", 1,
+ &GNUNET_GETOPT_set_filename, &exchange_wireformat},
+ {'t', "test", NULL,
+ "run in test mode with temporary tables", 0,
+ &GNUNET_GETOPT_set_one, &test_mode},
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
+ &argc, &argv))
+ return 2;
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run (argc, argv,
+ "taler-exchange-aggregator",
+ gettext_noop ("background process that aggregates and executes wire transfers to merchants"),
+ options,
+ &run, NULL))
+ return 1;
+ return global_ret;
+}
+
+/* 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..a8e9b3b08
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd.c
@@ -0,0 +1,741 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 Inria and 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 TALER_MasterPublicKeyP 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 incoming HTTP request.
+ *
+ * @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 },
+
+ /* 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 ()
+{
+ unsigned long long port;
+ char *TMH_master_public_key_str;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange",
+ "KEYDIR",
+ &TMH_exchange_directory))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KEYDIR");
+ 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.eddsa_pub))
+ {
+ 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)
+{
+ char *cfgfile = NULL;
+ 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},
+ GNUNET_GETOPT_OPTION_CFG_FILE (&cfgfile),
+ {'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
+ GNUNET_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;
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfgfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ cfgfile);
+ GNUNET_free_non_null (cfgfile);
+ return 1;
+ }
+ GNUNET_free_non_null (cfgfile);
+ if (GNUNET_OK !=
+ exchange_serve_process_config ())
+ 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..236df9e19
--- /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 TALER_MasterPublicKeyP 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..29da2d441
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_admin.c
@@ -0,0 +1,165 @@
+/*
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("reserve_pub", &reserve_pub),
+ TALER_JSON_spec_amount ("amount", &amount),
+ GNUNET_JSON_spec_absolute_time ("execution_date", &at),
+ GNUNET_JSON_spec_json ("wire", &wire),
+ GNUNET_JSON_spec_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_NO))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "wire");
+ }
+ res = TMH_DB_execute_admin_add_incoming (connection,
+ &reserve_pub,
+ &amount,
+ at,
+ wire);
+ GNUNET_JSON_parse_free (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..1e392c584
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -0,0 +1,1924 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.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->rollback (TMH_plugin->cls,
+ session);
+ 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_blinded (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_blinded (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;
+
+ /**
+ * Head of DLL with details for /wire/deposit response.
+ */
+ struct TMH_WireDepositDetail *wdd_head;
+
+ /**
+ * Head of DLL with details for /wire/deposit response.
+ */
+ struct TMH_WireDepositDetail *wdd_tail;
+
+ /**
+ * 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;
+ struct TMH_WireDepositDetail *wdd;
+
+ 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;
+ }
+ }
+ wdd = GNUNET_new (struct TMH_WireDepositDetail);
+ wdd->deposit_value = *deposit_value;
+ wdd->deposit_fee = *deposit_fee;
+ wdd->h_contract = *h_contract;
+ wdd->transaction_id = transaction_id;
+ wdd->coin_pub = *coin_pub;
+ GNUNET_CONTAINER_DLL_insert (ctx->wdd_head,
+ ctx->wdd_tail,
+ wdd);
+}
+
+
+/**
+ * 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;
+ struct TMH_WireDepositDetail *wdd;
+
+ 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.wdd_head = NULL;
+ ctx.wdd_tail = NULL;
+ ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls,
+ session,
+ wtid,
+ &handle_transaction_data,
+ &ctx);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ ret = TMH_RESPONSE_reply_internal_db_error (connection);
+ goto cleanup;
+ }
+ if (GNUNET_SYSERR == ctx.is_valid)
+ {
+ GNUNET_break (0);
+ ret = TMH_RESPONSE_reply_internal_db_error (connection);
+ goto cleanup;
+ }
+ if (GNUNET_NO == ctx.is_valid)
+ {
+ ret = TMH_RESPONSE_reply_arg_unknown (connection,
+ "wtid");
+ goto cleanup;
+ }
+ ret = TMH_RESPONSE_reply_wire_deposit_details (connection,
+ &ctx.total,
+ &ctx.merchant_pub,
+ &ctx.h_wire,
+ ctx.wdd_head);
+ cleanup:
+ while (NULL != (wdd = ctx.wdd_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (ctx.wdd_head,
+ ctx.wdd_tail,
+ wdd);
+ GNUNET_free (wdd);
+ }
+ return ret;
+}
+
+
+/**
+ * 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..efef3d04e
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -0,0 +1,284 @@
+/*
+ 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 <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.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 GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_denomination_public_key ("denom_pub", &deposit.coin.denom_pub),
+ TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub", &deposit.merchant_pub),
+ GNUNET_JSON_spec_fixed_auto ("H_contract", &deposit.h_contract),
+ GNUNET_JSON_spec_fixed_auto ("H_wire", &deposit.h_wire),
+ GNUNET_JSON_spec_fixed_auto ("coin_sig", &deposit.csig),
+ GNUNET_JSON_spec_uint64 ("transaction_id", &deposit.transaction_id),
+ GNUNET_JSON_spec_absolute_time ("timestamp", &deposit.timestamp),
+ GNUNET_JSON_spec_absolute_time ("refund_deadline", &deposit.refund_deadline),
+ GNUNET_JSON_spec_absolute_time ("edate", &deposit.wire_deadline),
+ GNUNET_JSON_spec_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,
+ GNUNET_NO))
+ {
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_arg_unknown (connection,
+ "wire");
+ }
+ if (GNUNET_OK !=
+ TALER_JSON_hash (wire,
+ &my_h_wire))
+ {
+ TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
+ GNUNET_JSON_parse_free (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 */
+ GNUNET_JSON_parse_free (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);
+ GNUNET_JSON_parse_free (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 */
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "f");
+ }
+ res = verify_and_execute_deposit (connection,
+ &deposit);
+ GNUNET_JSON_parse_free (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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("wire", &wire),
+ TALER_JSON_spec_amount ("f", &amount),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (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..c9db50895
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -0,0 +1,1018 @@
+/*
+ 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_json_lib.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",
+ GNUNET_JSON_from_data (&dki->signature,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature)),
+ "stamp_start",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)),
+ "stamp_expire_withdraw",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)),
+ "stamp_expire_deposit",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_spend)),
+ "stamp_expire_legal",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)),
+ "denom_pub",
+ GNUNET_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",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (ski->start)),
+ "stamp_expire",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (ski->expire)),
+ "stamp_end",
+ GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (ski->end)),
+ "master_pub",
+ GNUNET_JSON_from_data (&ski->master_public_key,
+ sizeof (struct TALER_MasterPublicKeyP)),
+ "master_sig",
+ GNUNET_JSON_from_data (&ski->signature,
+ sizeof (struct TALER_MasterSignatureP)),
+ "key",
+ GNUNET_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 auditor_url URL of the auditor
+ * @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,
+ const char *auditor_url,
+ 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",
+ GNUNET_JSON_from_data (&dki[i]->denom_hash,
+ sizeof (struct GNUNET_HashCode)),
+ "auditor_sig",
+ GNUNET_JSON_from_data (asigs[i],
+ sizeof (struct TALER_AuditorSignatureP))));
+ return
+ json_pack ("{s:o, s:s, s:o}",
+ "denomination_keys", ja,
+ "auditor_url", auditor_url,
+ "auditor_pub",
+ GNUNET_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 auditor_url URL of the auditor
+ * @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 char *auditor_url,
+ 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,
+ auditor_url,
+ 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 ();
+ GNUNET_TIME_round_abs (&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 (cfg,
+ &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",
+ GNUNET_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", GNUNET_JSON_from_time_abs (key_state->reload_time),
+ "eddsa_pub", GNUNET_JSON_from_data (&key_state->current_sign_key_issue.issue.signkey_pub,
+ sizeof (struct TALER_ExchangePublicKeyP)),
+ "eddsa_sig", GNUNET_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..beac81a1c
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_parsing.c
@@ -0,0 +1,275 @@
+/*
+ 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_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 <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Maximum POST request size.
+ */
+#define REQUEST_BUFFER_MAX (1024*1024)
+
+
+
+/**
+ * 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)
+{
+ enum GNUNET_JSON_PostResult pr;
+
+ pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+ con_cls,
+ upload_data,
+ upload_data_size,
+ json);
+ switch (pr)
+ {
+ case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_internal_error (connection,
+ "out of memory"))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ case GNUNET_JSON_PR_CONTINUE:
+ return GNUNET_YES;
+ case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_request_too_large (connection))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ case GNUNET_JSON_PR_JSON_INVALID:
+ return (MHD_YES ==
+ TMH_RESPONSE_reply_invalid_json (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ case GNUNET_JSON_PR_SUCCESS:
+ GNUNET_break (NULL != *json);
+ return GNUNET_YES;
+ }
+ /* this should never happen */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * 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)
+{
+ GNUNET_JSON_post_parser_cleanup (con_cls);
+}
+
+
+/**
+ * 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;
+}
+
+
+/**
+ * Parse JSON object into components based on the given field
+ * specification. Generates error response on parse errors.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param[in,out] spec field specification for the parser
+ * @return
+ * #GNUNET_YES if navigation was successful (caller is responsible
+ * for freeing allocated variable-size data using
+ * #GNUNET_JSON_parse_free() 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 GNUNET_JSON_Specification *spec)
+{
+ int ret;
+ const char *error_json_name;
+ unsigned int error_line;
+
+ ret = GNUNET_JSON_parse (root,
+ spec,
+ &error_json_name,
+ &error_line);
+ if (GNUNET_SYSERR == ret)
+ {
+ if (NULL == error_json_name)
+ error_json_name = "<no field>";
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s, s:I}",
+ "error", "parse error",
+ "field", error_json_name,
+ "line", (json_int_t) error_line))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ return ret;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Parse JSON array into components based on the given field
+ * specification. Generates error response on parse errors.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param[in,out] spec field specification for the parser
+ * @param ... -1-terminated list of array offsets of type 'int'
+ * @return
+ * #GNUNET_YES if navigation was successful (caller is responsible
+ * for freeing allocated variable-size data using
+ * #GNUNET_JSON_parse_free() when done)
+ * #GNUNET_NO if json is malformed, error response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+int
+TMH_PARSE_json_array (struct MHD_Connection *connection,
+ const json_t *root,
+ struct GNUNET_JSON_Specification *spec,
+ ...)
+{
+ int ret;
+ const char *error_json_name;
+ unsigned int error_line;
+ va_list ap;
+ json_int_t dim;
+
+ va_start (ap, spec);
+ dim = 0;
+ while ( (-1 != (ret = va_arg (ap, int))) &&
+ (NULL != root) )
+ {
+ dim++;
+ root = json_array_get (root, ret);
+ }
+ if (NULL == root)
+ {
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:I}",
+ "error", "parse error",
+ "dimension", dim))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ return ret;
+ }
+ ret = GNUNET_JSON_parse (root,
+ spec,
+ &error_json_name,
+ &error_line);
+ if (GNUNET_SYSERR == ret)
+ {
+ if (NULL == error_json_name)
+ error_json_name = "<no field>";
+ ret = (MHD_YES ==
+ TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s, s:I}",
+ "error", "parse error",
+ "field", error_json_name,
+ "line", (json_int_t) error_line))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ return ret;
+ }
+ return GNUNET_YES;
+}
+
+
+/* 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..d09f58767
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_parsing.h
@@ -0,0 +1,139 @@
+/*
+ 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_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"
+#include "taler_json_lib.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);
+
+
+/**
+ * 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
+ * #GNUNET_JSON_parse_free() 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 GNUNET_JSON_Specification *spec);
+
+
+/**
+ * Parse JSON array into components based on the given field
+ * specification. Generates error response on parse errors.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param[in,out] spec field specification for the parser
+ * @param ... -1-terminated list of array offsets of type 'int'
+ * @return
+ * #GNUNET_YES if navigation was successful (caller is responsible
+ * for freeing allocated variable-size data using
+ * #GNUNET_JSON_parse_free() when done)
+ * #GNUNET_NO if json is malformed, error response was generated
+ * #GNUNET_SYSERR on internal error
+ */
+int
+TMH_PARSE_json_array (struct MHD_Connection *connection,
+ const json_t *root,
+ struct GNUNET_JSON_Specification *spec,
+ ...);
+
+
+/**
+ * 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);
+
+
+#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..2349d90ac
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_refresh.c
@@ -0,0 +1,913 @@
+/*
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &r_melt_detail->coin_info.coin_pub),
+ TALER_JSON_spec_denomination_signature ("denom_sig", &sig),
+ TALER_JSON_spec_denomination_public_key ("denom_pub", &pk),
+ GNUNET_JSON_spec_fixed_auto ("confirm_sig", &melt_sig),
+ TALER_JSON_spec_amount ("value_with_fee", &amount),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (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;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_denomination_public_key (NULL,
+ &denom_pubs[i]),
+ GNUNET_JSON_spec_end ()
+ };
+
+ res = TMH_PARSE_json_array (connection,
+ new_denoms,
+ spec,
+ i, -1);
+ 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;
+
+ // FIXME: check json_array_get() return value for NULL!
+ 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];
+ struct GNUNET_JSON_Specification coin_spec[] = {
+ GNUNET_JSON_spec_varsize (NULL,
+ (void **) &rcc->coin_ev,
+ &rcc->coin_ev_size),
+ GNUNET_JSON_spec_end ()
+ };
+ struct GNUNET_JSON_Specification link_spec[] = {
+ GNUNET_JSON_spec_varsize (NULL,
+ (void **) &link_enc,
+ &link_enc_size),
+ GNUNET_JSON_spec_end ()
+ };
+
+ res = TMH_PARSE_json_array (connection,
+ coin_evs,
+ coin_spec,
+ i, j, -1);
+ 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_json_array (connection,
+ link_encs,
+ link_spec,
+ i, j, -1);
+ 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_JSON_parse_free (link_spec);
+ }
+ }
+
+ 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];
+ struct GNUNET_JSON_Specification trans_spec[] = {
+ GNUNET_JSON_spec_fixed_auto (NULL, &rcl->transfer_pub),
+ GNUNET_JSON_spec_end ()
+ };
+ struct GNUNET_JSON_Specification sec_spec[] = {
+ GNUNET_JSON_spec_fixed_auto (NULL, &rcl->shared_secret_enc),
+ GNUNET_JSON_spec_end ()
+ };
+
+ res = TMH_PARSE_json_array (connection,
+ transfer_pubs,
+ trans_spec,
+ i, j, -1);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ goto cleanup;
+ }
+ res = TMH_PARSE_json_array (connection,
+ secret_encs,
+ sec_spec,
+ i, j, -1);
+ 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;
+ json_t *trans_detail;
+ int res;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("new_denoms", &new_denoms),
+ GNUNET_JSON_spec_json ("melt_coins", &melt_coins),
+ GNUNET_JSON_spec_json ("coin_evs", &coin_evs),
+ GNUNET_JSON_spec_json ("link_encs", &link_encs),
+ GNUNET_JSON_spec_json ("transfer_pubs", &transfer_pubs),
+ GNUNET_JSON_spec_json ("secret_encs", &secret_encs),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "coin_evs");
+ }
+ if (TALER_CNC_KAPPA != json_array_size (transfer_pubs))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "transfer_pubs");
+ }
+ coin_detail = json_array_get (coin_evs, 0);
+ if (NULL == coin_detail)
+ {
+ // FIXME: generate proper HTTP response!
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ num_newcoins = json_array_size (coin_detail);
+
+ trans_detail = json_array_get (transfer_pubs, 0);
+ if (NULL == trans_detail)
+ {
+ // FIXME: generate proper HTTP response!
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ num_oldcoins = json_array_size (trans_detail);
+ res = handle_refresh_melt_json (connection,
+ new_denoms,
+ melt_coins,
+ num_oldcoins,
+ transfer_pubs,
+ secret_encs,
+ num_newcoins,
+ coin_evs,
+ link_encs);
+ GNUNET_JSON_parse_free (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++)
+ {
+ struct GNUNET_JSON_Specification tp_spec[] = {
+ GNUNET_JSON_spec_fixed_auto (NULL, &transfer_privs[i][j]),
+ GNUNET_JSON_spec_end ()
+ };
+ if (GNUNET_OK != res)
+ break;
+ res = TMH_PARSE_json_array (connection,
+ tp_json,
+ tp_spec,
+ i, j, -1);
+ 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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("session_hash", &session_hash),
+ GNUNET_JSON_spec_json ("transfer_privs", &transfer_privs),
+ GNUNET_JSON_spec_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)
+ {
+ GNUNET_JSON_parse_free (spec);
+ GNUNET_break_op (0);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ "transfer_privs");
+ }
+ reveal_detail = json_array_get (transfer_privs, 0);
+ if (NULL == reveal_detail)
+ {
+ // FIXME: generate proper HTTP response!
+ GNUNET_JSON_parse_free (spec);
+ GNUNET_break_op (0);
+ return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ }
+ num_oldcoins = json_array_size (reveal_detail);
+ res = handle_refresh_reveal_json (connection,
+ &session_hash,
+ num_oldcoins,
+ transfer_privs);
+ GNUNET_JSON_parse_free (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..1763280ed
--- /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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_varsize ("coin_ev",
+ (void **) &blinded_msg,
+ &blinded_msg_len),
+ GNUNET_JSON_spec_fixed_auto ("reserve_pub",
+ &wsrd.reserve_pub),
+ GNUNET_JSON_spec_fixed_auto ("reserve_sig",
+ &signature),
+ TALER_JSON_spec_denomination_public_key ("denom_pub",
+ &denomination_pub),
+ GNUNET_JSON_spec_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)
+ {
+ GNUNET_JSON_parse_free (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");
+ GNUNET_JSON_parse_free (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);
+ GNUNET_JSON_parse_free (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..f8ff67228
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -0,0 +1,1223 @@
+/*
+ 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 "taler_json_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", GNUNET_JSON_from_data (&sig,
+ sizeof (sig)),
+ "pub", GNUNET_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 = GNUNET_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 = GNUNET_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", GNUNET_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", GNUNET_JSON_from_data (&pos->details.withdraw->reserve_sig,
+ sizeof (struct TALER_ReserveSignatureP)),
+ "details", GNUNET_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 = GNUNET_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",
+ GNUNET_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 = GNUNET_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", GNUNET_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",
+ GNUNET_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",
+ GNUNET_JSON_from_data (&rm->coin_sig,
+ sizeof (struct TALER_CoinSpendSignatureP)));
+ json_object_set_new (rm_json,
+ "coin_pub",
+ GNUNET_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,
+ GNUNET_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",
+ GNUNET_JSON_from_data (cc->coin_ev,
+ cc->coin_ev_size));
+ json_object_set_new (cc_json,
+ "coin_priv_enc",
+ GNUNET_JSON_from_data (cc->refresh_link->coin_priv_enc,
+ sizeof (struct TALER_CoinSpendPrivateKeyP)));
+ json_object_set_new (cc_json,
+ "blinding_key_enc",
+ GNUNET_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",
+ GNUNET_JSON_from_data (&cl->transfer_pub,
+ sizeof (struct TALER_TransferPublicKeyP)));
+ json_object_set_new (cl_json,
+ "shared_secret_enc",
+ GNUNET_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",
+ GNUNET_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",
+ GNUNET_JSON_from_rsa_public_key (pos->denom_pub.rsa_public_key));
+ json_object_set_new (obj,
+ "ev_sig",
+ GNUNET_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",
+ GNUNET_JSON_from_data (&sessions[i].transfer_pub,
+ sizeof (struct TALER_TransferPublicKeyP)));
+ json_object_set_new (root,
+ "secret_enc",
+ GNUNET_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", GNUNET_JSON_from_time_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", GNUNET_JSON_from_data (wtid,
+ sizeof (*wtid)),
+ "execution_time", GNUNET_JSON_from_time_abs (exec_time),
+ "coin_contribution", TALER_JSON_from_amount (coin_contribution),
+ "exchange_sig", GNUNET_JSON_from_data (&sig,
+ sizeof (sig)),
+ "exchange_pub", GNUNET_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 wdd_head linked list with 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,
+ const struct TMH_WireDepositDetail *wdd_head)
+{
+ const struct TMH_WireDepositDetail *wdd_pos;
+ json_t *deposits;
+ struct TALER_WireDepositDetailP dd;
+ struct GNUNET_HashContext *hash_context;
+ struct TALER_WireDepositDataPS wdp;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+
+ deposits = json_array ();
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
+ for (wdd_pos = wdd_head; NULL != wdd_pos; wdd_pos = wdd_pos->next)
+ {
+ dd.h_contract = wdd_pos->h_contract;
+ dd.transaction_id = GNUNET_htonll (wdd_pos->transaction_id);
+ dd.coin_pub = wdd_pos->coin_pub;
+ TALER_amount_hton (&dd.deposit_value,
+ &wdd_pos->deposit_value);
+ TALER_amount_hton (&dd.deposit_fee,
+ &wdd_pos->deposit_fee);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &dd,
+ sizeof (struct TALER_WireDepositDetailP));
+ json_array_append (deposits,
+ json_pack ("{s:o, s:o, s:o, s:I, s:o}",
+ "deposit_value", TALER_JSON_from_amount (&wdd_pos->deposit_value),
+ "deposit_fee", TALER_JSON_from_amount (&wdd_pos->deposit_fee),
+ "H_contract", GNUNET_JSON_from_data (&wdd_pos->h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "transaction_id", (json_int_t) wdd_pos->transaction_id,
+ "coin_pub", GNUNET_JSON_from_data (&wdd_pos->coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP))));
+ }
+ wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT);
+ wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
+ TALER_amount_hton (&wdp.total,
+ total);
+ wdp.merchant_pub = *merchant_pub;
+ wdp.h_wire = *h_wire;
+ GNUNET_CRYPTO_hash_context_finish (hash_context,
+ &wdp.h_details);
+ TMH_KS_sign (&wdp.purpose,
+ &pub,
+ &sig);
+ 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", GNUNET_JSON_from_data (merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP)),
+ "h_wire", GNUNET_JSON_from_data (h_wire,
+ sizeof (struct GNUNET_HashCode)),
+ "deposits", deposits,
+ "exchange_sig", GNUNET_JSON_from_data (&sig,
+ sizeof (sig)),
+ "exchange_pub", GNUNET_JSON_from_data (&pub,
+ sizeof (pub)));
+}
+
+
+/* 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..c7139bf20
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -0,0 +1,512 @@
+/*
+ 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);
+
+
+/**
+ * Detail for /wire/deposit response.
+ */
+struct TMH_WireDepositDetail
+{
+
+ /**
+ * We keep deposit details in a DLL.
+ */
+ struct TMH_WireDepositDetail *next;
+
+ /**
+ * We keep deposit details in a DLL.
+ */
+ struct TMH_WireDepositDetail *prev;
+
+ /**
+ * Hash of the contract
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Merchant's transaction ID.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * Coin's public key.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Total value of the coin.
+ */
+ struct TALER_Amount deposit_value;
+
+ /**
+ * Fees charged by the exchange for the deposit.
+ */
+ struct TALER_Amount deposit_fee;
+};
+
+
+/**
+ * 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 wdd_head linked list with 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,
+ const struct TMH_WireDepositDetail *wdd_head);
+
+
+/**
+ * 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..7c9e0820d
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_test.c
@@ -0,0 +1,622 @@
+/*
+ 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 <gnunet/gnunet_json_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_RsaPrivateKey *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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_varsize ("input", &in_ptr, &in_ptr_size),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (spec);
+ json_decref (json);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "output",
+ GNUNET_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_varsize ("input", &in_ptr, &in_ptr_size),
+ GNUNET_JSON_spec_fixed_auto ("key_hash", &key),
+ GNUNET_JSON_spec_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 = GNUNET_JSON_from_data (out,
+ in_ptr_size);
+ GNUNET_free (out);
+ GNUNET_JSON_parse_free (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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_varsize ("input", &in_ptr, &in_ptr_size),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (spec);
+ json = GNUNET_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("ecdhe_pub", &pub),
+ GNUNET_JSON_spec_fixed_auto ("ecdhe_priv", &priv),
+ GNUNET_JSON_spec_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))
+ {
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to perform ECDH");
+ }
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "ecdh_hash",
+ GNUNET_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("eddsa_pub", &pub),
+ GNUNET_JSON_spec_fixed_auto ("eddsa_sig", &sig),
+ GNUNET_JSON_spec_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))
+ {
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_signature_invalid (connection,
+ "eddsa_sig");
+ }
+ GNUNET_JSON_parse_free (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",
+ GNUNET_JSON_from_data (&pub,
+ sizeof (pub)),
+ "eddsa_sig",
+ GNUNET_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_RsaPublicKey *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",
+ GNUNET_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_RsaSignature *sig;
+ void *in_ptr;
+ size_t in_ptr_size;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_varsize ("blind_ev", &in_ptr, &in_ptr_size),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to create RSA key");
+ }
+ sig = GNUNET_CRYPTO_rsa_sign_blinded (rsa_pk,
+ in_ptr,
+ in_ptr_size);
+ if (NULL == sig)
+ {
+ GNUNET_break (0);
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "Failed to RSA-sign");
+ }
+ GNUNET_JSON_parse_free (spec);
+ res = TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o}",
+ "rsa_blind_sig",
+ GNUNET_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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("secret_enc", &secret_enc),
+ GNUNET_JSON_spec_fixed_auto ("trans_priv", &trans_priv),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
+ GNUNET_JSON_spec_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))
+ {
+ GNUNET_JSON_parse_free (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",
+ GNUNET_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..36782332d
--- /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 GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("H_wire", &tps.h_wire),
+ GNUNET_JSON_spec_fixed_auto ("H_contract", &tps.h_contract),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &tps.coin_pub),
+ GNUNET_JSON_spec_uint64 ("transaction_id", &transaction_id),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub", &tps.merchant),
+ GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig),
+ GNUNET_JSON_spec_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);
+ GNUNET_JSON_parse_free (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..830120a31
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_validation.c
@@ -0,0 +1,244 @@
+/*
+ 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.h"
+#include "taler-exchange-httpd_validation.h"
+#include "taler_wire_lib.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;
+ 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,
+ " "))
+ {
+ p = GNUNET_new (struct Plugin);
+ p->type = GNUNET_strdup (token);
+ p->plugin = TALER_WIRE_plugin_load (cfg,
+ token);
+ if (NULL == p->plugin)
+ {
+ GNUNET_free (p);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to load plugin %s\n",
+ token);
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ 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;
+
+ while (NULL != (p = wire_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (wire_head,
+ wire_tail,
+ p);
+ TALER_WIRE_plugin_unload (p->plugin);
+ 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
+ * @param ours #GNUNET_YES if the signature should match our master key
+ * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
+ */
+int
+TMH_json_validate_wireformat (const json_t *wire,
+ int ours)
+{
+ 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 (p->plugin->cls,
+ wire,
+ (GNUNET_YES == ours)
+ ? &TMH_master_public_key
+ : NULL);
+ 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 JSON of the supported wire methods for a given
+ * account name prefix.
+ *
+ * @param prefix prefix for the account, the suffix will
+ * be determined by the name of the plugin
+ * @return JSON array with the supported validation methods
+ */
+json_t *
+TMH_VALIDATION_get_wire_methods (const char *prefix)
+{
+ json_t *methods;
+ json_t *method;
+ struct Plugin *p;
+ struct TALER_WIRE_Plugin *plugin;
+ char *account_name;
+
+ methods = json_object ();
+ for (p=wire_head;NULL != p;p = p->next)
+ {
+ plugin = p->plugin;
+ GNUNET_asprintf (&account_name,
+ "%s-%s",
+ prefix,
+ p->type);
+ method = plugin->get_wire_details (plugin->cls,
+ cfg,
+ account_name);
+ if (GNUNET_YES !=
+ TMH_json_validate_wireformat (method,
+ GNUNET_YES))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Account details for method `%s' ill-formed. Disabling method\n",
+ p->type);
+ json_decref (method);
+ method = NULL;
+ }
+ if (NULL != method)
+ json_object_set_new (methods,
+ p->type,
+ method);
+ GNUNET_free (account_name);
+ }
+ 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..bd04994ef
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_validation.h
@@ -0,0 +1,79 @@
+/*
+ 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
+ * @param ours #GNUNET_YES if the signature should match our master key
+ * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
+ */
+int
+TMH_json_validate_wireformat (const json_t *wire,
+ int ours);
+
+/**
+ * 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 JSON of the supported wire methods for a given
+ * account name prefix.
+ *
+ * @param prefix prefix for the account, the suffix will
+ * be determined by the name of the plugin
+ * @return JSON array with the supported validation methods
+ */
+json_t *
+TMH_VALIDATION_get_wire_methods (const char *prefix);
+
+
+#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..975788b35
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_wire.c
@@ -0,0 +1,57 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015, 2016 GNUnet e.V. and INRIA
+
+ 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 <gnunet/gnunet_json_lib.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)
+{
+ static json_t *wire_methods;
+
+ if (NULL == wire_methods)
+ wire_methods = TMH_VALIDATION_get_wire_methods ("wire-incoming");
+
+ return TMH_RESPONSE_reply_json (connection,
+ wire_methods,
+ MHD_HTTP_OK);
+}
+
+
+/* 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..cf04f16ff
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_wire.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 Inria and 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);
+
+
+#endif
diff --git a/src/exchange/test-taler-exchange-aggregator-postgres.conf b/src/exchange/test-taler-exchange-aggregator-postgres.conf
new file mode 100644
index 000000000..0822bab44
--- /dev/null
+++ b/src/exchange/test-taler-exchange-aggregator-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/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c
new file mode 100644
index 000000000..a799316f3
--- /dev/null
+++ b/src/exchange/test_taler_exchange_aggregator.c
@@ -0,0 +1,1557 @@
+/*
+ This file is part of TALER
+ (C) 2016 Inria and 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_taler_exchange_aggregator.c
+ * @brief Tests for taler-exchange-aggregator logic
+ * @author Christian Grothoff <christian@grothoff.org>
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+#include <microhttpd.h>
+
+
+/**
+ * Maximum POST request size (for /admin/add/incoming)
+ */
+#define REQUEST_BUFFER_MAX (4*1024)
+
+/**
+ * Details about a transcation we (as the simulated bank) received.
+ */
+struct Transaction
+{
+
+ /**
+ * We store transactions in a DLL.
+ */
+ struct Transaction *next;
+
+ /**
+ * We store transactions in a DLL.
+ */
+ struct Transaction *prev;
+
+ /**
+ * Amount to be transferred.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Account to debit.
+ */
+ uint64_t debit_account;
+
+ /**
+ * Account to credit.
+ */
+ uint64_t credit_account;
+
+ /**
+ * Subject of the transfer.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+};
+
+
+/**
+ * Commands for the interpreter.
+ */
+enum OpCode {
+
+ /**
+ * Terminate testcase with 'skipped' result.
+ */
+ OPCODE_TERMINATE_SKIP,
+
+ /**
+ * Run taler-exchange-aggregator.
+ */
+ OPCODE_RUN_AGGREGATOR,
+
+ /**
+ * Expect that we have exhaustively gone over all transactions.
+ */
+ OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+
+ /**
+ * Execute deposit operation against database.
+ */
+ OPCODE_DATABASE_DEPOSIT,
+
+ /**
+ * Wait a certain amount of time.
+ */
+ OPCODE_WAIT,
+
+ /**
+ * Expect that we have received the specified transaction.
+ */
+ OPCODE_EXPECT_TRANSACTION,
+
+ /**
+ * Finish testcase with success.
+ */
+ OPCODE_TERMINATE_SUCCESS
+};
+
+/**
+ * Command state for the interpreter.
+ */
+struct Command
+{
+
+ /**
+ * What instruction should we run?
+ */
+ enum OpCode opcode;
+
+ /**
+ * Human-readable label for the command.
+ */
+ const char *label;
+
+ union {
+
+ /**
+ * If @e opcode is #OPCODE_EXPECT_TRANSACTION, this
+ * specifies which transaction we expected. Note that
+ * the WTID will be set, not checked!
+ */
+ struct {
+
+ /**
+ * Amount to be transferred.
+ */
+ const char *amount;
+
+ /**
+ * Account to debit.
+ */
+ uint64_t debit_account;
+
+ /**
+ * Account to credit.
+ */
+ uint64_t credit_account;
+
+ /**
+ * Subject of the transfer, set by the command.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ } expect_transaction;
+
+ /**
+ * If @e opcode is #OPCODE_DATABASE_DEPOST, this
+ * specifies which deposit operation we should fake.
+ */
+ struct {
+
+ /**
+ * Each merchant name is automatically mapped to a unique
+ * merchant public key.
+ */
+ const char *merchant_name;
+
+ /**
+ * Merchant account number, is mapped to wire details.
+ */
+ uint64_t merchant_account;
+
+ /**
+ * Merchant's transaction ID.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * By when does the merchant request the funds to be wired.
+ */
+ struct GNUNET_TIME_Relative wire_deadline;
+
+ /**
+ * What is the total amount (including exchange fees).
+ */
+ const char *amount_with_fee;
+
+ /**
+ * How high are the exchange fees? Must be smaller than @e amount_with_fee.
+ */
+ const char *deposit_fee;
+
+ } deposit;
+
+ /**
+ * How long should we wait if the opcode is #OPCODE_WAIT.
+ */
+ struct GNUNET_TIME_Relative wait_delay;
+
+ } details;
+
+};
+
+
+/**
+ * State of the interpreter.
+ */
+struct State
+{
+ /**
+ * Array of commands to run.
+ */
+ struct Command* commands;
+
+ /**
+ * Offset of the next command to be run.
+ */
+ unsigned int ioff;
+};
+
+
+/**
+ * Pipe used to communicate child death via signal.
+ */
+static struct GNUNET_DISK_PipeHandle *sigpipe;
+
+/**
+ * ID of task called whenever we get a SIGCHILD.
+ */
+static struct GNUNET_SCHEDULER_Task *child_death_task;
+
+/**
+ * ID of task called whenever are shutting down.
+ */
+static struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+/**
+ * Return value from main().
+ */
+static int result;
+
+/**
+ * Name of the configuration file to use.
+ */
+static char *config_filename;
+
+/**
+ * Database plugin.
+ */
+static struct TALER_EXCHANGEDB_Plugin *plugin;
+
+/**
+ * Our session with the database.
+ */
+static struct TALER_EXCHANGEDB_Session *session;
+
+/**
+ * The handle for the aggregator process that we are testing.
+ */
+static struct GNUNET_OS_Process *aggregator_proc;
+
+/**
+ * State of our interpreter while we are running the aggregator
+ * process.
+ */
+static struct State *aggregator_state;
+
+/**
+ * HTTP server we run to pretend to be the "test" bank.
+ */
+static struct MHD_Daemon *mhd_bank;
+
+/**
+ * Task running HTTP server for the "test" bank.
+ */
+static struct GNUNET_SCHEDULER_Task *mhd_task;
+
+/**
+ * Task running the interpreter().
+ */
+static struct GNUNET_SCHEDULER_Task *int_task;
+
+/**
+ * We store transactions in a DLL.
+ */
+static struct Transaction *transactions_head;
+
+/**
+ * We store transactions in a DLL.
+ */
+static struct Transaction *transactions_tail;
+
+/**
+ * Private key we use for fake coins.
+ */
+static struct GNUNET_CRYPTO_RsaPrivateKey *coin_pk;
+
+/**
+ * Public key we use for fake coins.
+ */
+static struct GNUNET_CRYPTO_RsaPublicKey *coin_pub;
+
+
+/**
+ * Interprets the commands from the test program.
+ *
+ * @param cls the `struct State` of the interpreter
+ */
+static void
+interpreter (void *cls);
+
+
+/**
+ * Task triggered whenever we are to shutdown.
+ *
+ * @param cls closure, NULL if we need to self-restart
+ */
+static void
+shutdown_action (void *cls)
+{
+ shutdown_task = NULL;
+ if (NULL != mhd_task)
+ {
+ GNUNET_SCHEDULER_cancel (mhd_task);
+ mhd_task = NULL;
+ }
+ if (NULL != int_task)
+ {
+ GNUNET_SCHEDULER_cancel (int_task);
+ int_task = NULL;
+ }
+ if (NULL != mhd_bank)
+ {
+ MHD_stop_daemon (mhd_bank);
+ mhd_bank = NULL;
+ }
+ if (NULL == aggregator_proc)
+ {
+ GNUNET_SCHEDULER_cancel (child_death_task);
+ child_death_task = NULL;
+ }
+ else
+ {
+ GNUNET_break (0 == GNUNET_OS_process_kill (aggregator_proc,
+ SIGKILL));
+ }
+ plugin->drop_temporary (plugin->cls,
+ session);
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ plugin = NULL;
+}
+
+
+/**
+ * Task triggered whenever we receive a SIGCHLD (child
+ * process died).
+ *
+ * @param cls closure, NULL if we need to self-restart
+ */
+static void
+maint_child_death (void *cls)
+{
+ const struct GNUNET_DISK_FileHandle *pr;
+ char c[16];
+ struct State *state;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+ child_death_task = NULL;
+ pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
+ {
+ /* shutdown scheduled us, ignore! */
+ child_death_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ pr,
+ &maint_child_death,
+ NULL);
+ return;
+ }
+ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
+ GNUNET_OS_process_wait (aggregator_proc);
+ GNUNET_OS_process_destroy (aggregator_proc);
+ aggregator_proc = NULL;
+ aggregator_state->ioff++;
+ state = aggregator_state;
+ aggregator_state = NULL;
+ interpreter (state);
+ if (NULL == shutdown_task)
+ return;
+ child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ pr,
+ &maint_child_death, NULL);
+
+}
+
+/**
+ * Setup (fake) information about a coin used in deposit.
+ *
+ * @param[out] issue information to initialize with "valid" data
+ */
+static void
+fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
+{
+ memset (issue, 0, sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:1",
+ &issue->properties.value));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_withdraw));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_deposit));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_refresh));
+}
+
+
+/**
+ * Setup (fake) information about a coin used in deposit.
+ *
+ * @param[out] coin information to initialize with "valid" data
+ */
+static void
+fake_coin (struct TALER_CoinPublicInfo *coin)
+{
+ struct GNUNET_HashCode hc;
+
+ coin->denom_pub.rsa_public_key = coin_pub;
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &hc);
+ coin->denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (coin_pk,
+ &hc);
+}
+
+
+/**
+ * Helper function to fake a deposit operation.
+ *
+ * @return #GNUNET_OK on success
+ */
+static int
+do_deposit (struct Command *cmd)
+{
+ struct TALER_EXCHANGEDB_Deposit deposit;
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+ int ret;
+
+ memset (&deposit, 0, sizeof (deposit));
+ /* we derive the merchant's private key from the
+ name, to ensure that the same name always
+ results in the same key pair. */
+ GNUNET_CRYPTO_kdf (&merchant_priv,
+ sizeof (struct TALER_MerchantPrivateKeyP),
+ "merchant-priv",
+ strlen ("merchant-priv"),
+ cmd->details.deposit.merchant_name,
+ strlen (cmd->details.deposit.merchant_name),
+ NULL, 0);
+ GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
+ &deposit.merchant_pub.eddsa_pub);
+ /* contract is just picked at random;
+ note: we may want to write this back to 'cmd' in the future. */
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &deposit.h_contract);
+ if ( (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.deposit.amount_with_fee,
+ &deposit.amount_with_fee)) ||
+ (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.deposit.deposit_fee,
+ &deposit.deposit_fee)) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ fake_coin (&deposit.coin);
+ /* Build JSON for wire details */
+ deposit.wire = json_pack ("{s:s, s:s, s:I}",
+ "type", "test",
+ "bank_uri", "http://localhost:8082/",
+ "account_number", (json_int_t) cmd->details.deposit.merchant_account);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_hash (deposit.wire,
+ &deposit.h_wire));
+ deposit.transaction_id = cmd->details.deposit.transaction_id;
+ deposit.timestamp = GNUNET_TIME_absolute_get ();
+ deposit.wire_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.wire_deadline);
+
+ /* finally, actually perform the DB operation */
+ if ( (GNUNET_OK !=
+ plugin->start (plugin->cls,
+ session)) ||
+ (GNUNET_OK !=
+ plugin->insert_deposit (plugin->cls,
+ session,
+ &deposit)) ||
+ (GNUNET_OK !=
+ plugin->commit (plugin->cls,
+ session)) )
+ ret = GNUNET_SYSERR;
+ else
+ ret = GNUNET_OK;
+ GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature);
+ json_decref (deposit.wire);
+ return ret;
+}
+
+
+/**
+ * Fail the testcase at the current command.
+ */
+static void
+fail (struct Command *cmd)
+{
+ fprintf (stderr,
+ "Testcase failed at command `%s'\n",
+ cmd->label);
+ result = 2;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Interprets the commands from the test program.
+ *
+ * @param cls the `struct State` of the interpreter
+ */
+static void
+interpreter (void *cls)
+{
+ struct State *state = cls;
+
+ int_task = NULL;
+ while (1)
+ {
+ struct Command *cmd = &state->commands[state->ioff];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Running command %u (%s)\n",
+ state->ioff,
+ cmd->label);
+ switch (cmd->opcode)
+ {
+ case OPCODE_TERMINATE_SKIP:
+ /* return skip: test not finished, but did not fail either */
+ result = 77;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ case OPCODE_WAIT:
+ state->ioff++;
+ int_task = GNUNET_SCHEDULER_add_delayed (cmd->details.wait_delay,
+ &interpreter,
+ state);
+ return;
+ case OPCODE_RUN_AGGREGATOR:
+ GNUNET_assert (NULL == aggregator_state);
+ aggregator_state = state;
+ aggregator_proc
+ = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-aggregator",
+ "taler-exchange-aggregator",
+ "-c", "test_taler_exchange_httpd.conf",
+ "-t", /* enable temporary tables */
+ NULL);
+ return;
+ case OPCODE_EXPECT_TRANSACTIONS_EMPTY:
+ if (NULL != transactions_head)
+ {
+ struct Transaction *t;
+
+ fprintf (stderr,
+ "Expected empty transaction set, but I have:\n");
+ for (t = transactions_head; NULL != t; t = t->next)
+ {
+ char *s;
+
+ s = TALER_amount_to_string (&t->amount);
+ fprintf (stderr,
+ "%llu -> %llu (%s)\n",
+ (unsigned long long) t->debit_account,
+ (unsigned long long) t->credit_account,
+ s);
+ GNUNET_free (s);
+ }
+ fail (cmd);
+ return;
+ }
+ state->ioff++;
+ break;
+ case OPCODE_DATABASE_DEPOSIT:
+ if (GNUNET_OK !=
+ do_deposit (cmd))
+ {
+ fail (cmd);
+ return;
+ }
+ state->ioff++;
+ break;
+ case OPCODE_EXPECT_TRANSACTION:
+ {
+ struct TALER_Amount want_amount;
+ struct Transaction *t;
+ int found;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.expect_transaction.amount,
+ &want_amount))
+ {
+ GNUNET_break (0);
+ fail (cmd);
+ return;
+ }
+ found = GNUNET_NO;
+ for (t = transactions_head; NULL != t; t = t->next)
+ {
+ if ( (cmd->details.expect_transaction.debit_account == t->debit_account) &&
+ (cmd->details.expect_transaction.credit_account == t->credit_account) &&
+ (0 == TALER_amount_cmp (&want_amount,
+ &t->amount)) )
+ {
+ GNUNET_CONTAINER_DLL_remove (transactions_head,
+ transactions_tail,
+ t);
+ cmd->details.expect_transaction.wtid = t->wtid;
+ GNUNET_free (t);
+ found = GNUNET_YES;
+ break;
+ }
+ }
+ if (GNUNET_NO == found)
+ {
+ fprintf (stderr,
+ "Did not find matching transaction!\nI have:\n");
+ for (t = transactions_head; NULL != t; t = t->next)
+ {
+ char *s;
+
+ s = TALER_amount_to_string (&t->amount);
+ fprintf (stderr,
+ "%llu -> %llu (%s)\n",
+ (unsigned long long) t->debit_account,
+ (unsigned long long) t->credit_account,
+ s);
+ GNUNET_free (s);
+ }
+ fail (cmd);
+ return;
+ }
+ state->ioff++;
+ break;
+ }
+ case OPCODE_TERMINATE_SUCCESS:
+ result = 0;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+}
+
+
+/**
+ * Contains the test program. Here each step of the testcase
+ * is defined.
+ */
+static void
+run_test ()
+{
+ static struct Command commands[] = {
+ /* test running with empty DB */
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-on-empty-db"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-on-start"
+ },
+
+ /* test simple deposit */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-1",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:1",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-1"
+ },
+
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-1",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:1"
+ },
+
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-on-start"
+ },
+
+ /* test idempotency: run again on transactions already done */
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-1"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-1"
+ },
+
+ /* test combining deposits */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-2a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:1",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-2b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:1",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-2"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-2",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:2"
+ },
+
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-2"
+ },
+
+ /* test NOT combining deposits of different accounts or keys */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-3a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:1",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-3b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 5,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:1",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-3c",
+ .details.deposit.merchant_name = "alice",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:1",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-3"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-3a",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:1"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-3b",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:1"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-3c",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 5,
+ .details.expect_transaction.amount = "EUR:1"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-3"
+ },
+
+ /* test NOT running deposits instantly, but after delay */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-4a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.01",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-4b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.01",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-4-early"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-4-fast"
+ },
+ {
+ .opcode = OPCODE_WAIT,
+ .label = "wait (5s)",
+ .details.wait_delay = { 1000LL * 1000 * 6 } /* 6s */
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-4-delayed"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-4",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.02"
+ },
+
+ /* test picking all deposits at earliest deadline */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-5a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 10 }, /* 10s */
+ .details.deposit.amount_with_fee = "EUR:0.01",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-5b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.01",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-5-early"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-5-early"
+ },
+ {
+ .opcode = OPCODE_WAIT,
+ .label = "wait (5s)",
+ .details.wait_delay = { 1000LL * 1000 * 6 } /* 6s */
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-5-delayed"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-5",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.02"
+ },
+
+ /* Test NEVER running 'tiny' unless they make up minimum unit */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-6a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.002",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-6a-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-6a-tiny"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-6b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.002",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-6c",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.002",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-6c-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-6c-tiny"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-6d",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.002",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-6d-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-6d-tiny"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-6e",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.002",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-6e"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-6",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.01"
+ },
+
+ /* Test profiteering if wire deadline is short */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-7a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.009",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-7a-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-7a-tiny"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-7b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.009",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-7-profit"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-7",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.01"
+ },
+ /* Now check profit was actually taken */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-7c",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.022",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-7c-loss"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-7",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.02"
+ },
+
+ /* Test that aggregation would happen fully if wire deadline is long */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-8a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.009",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-8a-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-8a-tiny"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-8b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.009",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-8b-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-8b-tiny"
+ },
+ /* now trigger aggregate with large transaction and short deadline */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-8c",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.022",
+ .details.deposit.deposit_fee = "EUR:0"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-8"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-8",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.04"
+ },
+
+
+ /* Test aggregation with fees and rounding profits */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-9a",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.009",
+ .details.deposit.deposit_fee = "EUR:0.001"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-9a-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-9a-tiny"
+ },
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-9b",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 5 }, /* 5s */
+ .details.deposit.amount_with_fee = "EUR:0.009",
+ .details.deposit.deposit_fee = "EUR:0.002"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-9b-tiny"
+ },
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
+ .label = "expect-empty-transactions-after-9b-tiny"
+ },
+ /* now trigger aggregate with large transaction and short deadline */
+ {
+ .opcode = OPCODE_DATABASE_DEPOSIT,
+ .label = "do-deposit-9c",
+ .details.deposit.merchant_name = "bob",
+ .details.deposit.merchant_account = 4,
+ .details.deposit.transaction_id = 1,
+ .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
+ .details.deposit.amount_with_fee = "EUR:0.022",
+ .details.deposit.deposit_fee = "EUR:0.008"
+ },
+ {
+ .opcode = OPCODE_RUN_AGGREGATOR,
+ .label = "run-aggregator-deposit-9"
+ },
+ /* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */
+ {
+ .opcode = OPCODE_EXPECT_TRANSACTION,
+ .label = "expect-deposit-9",
+ .details.expect_transaction.debit_account = 3,
+ .details.expect_transaction.credit_account = 4,
+ .details.expect_transaction.amount = "EUR:0.02"
+ },
+
+ /* Everything tested, terminate with success */
+ {
+ .opcode = OPCODE_TERMINATE_SUCCESS,
+ .label = "testcase-complete-terminating-with-success"
+ },
+ /* note: rest not reached, this is just sample code */
+ {
+ .opcode = OPCODE_TERMINATE_SKIP,
+ .label = "testcase-incomplete-terminating-with-skip"
+ }
+ };
+ static struct State state = {
+ .commands = commands
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Launching interpreter\n");
+ int_task = GNUNET_SCHEDULER_add_now (&interpreter,
+ &state);
+}
+
+
+/**
+ * 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)
+{
+ GNUNET_JSON_post_parser_cleanup (*con_cls);
+ *con_cls = NULL;
+}
+
+
+/**
+ * Handle incoming HTTP request.
+ *
+ * @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)
+{
+ enum GNUNET_JSON_PostResult pr;
+ json_t *json;
+ struct Transaction *t;
+ struct MHD_Response *resp;
+ int ret;
+
+ if (0 != strcasecmp (url,
+ "/admin/add/incoming"))
+ {
+ /* Unexpected URI path, just close the connection. */
+ /* we're rather impolite here, but it's a testcase. */
+ GNUNET_break_op (0);
+ return MHD_NO;
+ }
+ pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+ con_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ switch (pr)
+ {
+ case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ GNUNET_break (0);
+ return MHD_NO;
+ case GNUNET_JSON_PR_CONTINUE:
+ return MHD_YES;
+ case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ GNUNET_break (0);
+ return MHD_NO;
+ case GNUNET_JSON_PR_JSON_INVALID:
+ GNUNET_break (0);
+ return MHD_NO;
+ case GNUNET_JSON_PR_SUCCESS:
+ break;
+ }
+ t = GNUNET_new (struct Transaction);
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("wtid", &t->wtid),
+ GNUNET_JSON_spec_uint64 ("debit_account", &t->debit_account),
+ GNUNET_JSON_spec_uint64 ("credit_account", &t->credit_account),
+ TALER_JSON_spec_amount ("amount", &t->amount),
+ GNUNET_JSON_spec_end ()
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ json_decref (json);
+ return MHD_NO;
+ }
+ GNUNET_CONTAINER_DLL_insert (transactions_head,
+ transactions_tail,
+ t);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Receiving incoming wire transfer: %llu->%llu\n",
+ (unsigned long long) t->debit_account,
+ (unsigned long long) t->credit_account);
+ json_decref (json);
+ resp = MHD_create_response_from_buffer (0, "", MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_OK,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+}
+
+
+/**
+ * Task run whenever HTTP server operations are pending.
+ *
+ * @param cls NULL
+ */
+static void
+run_mhd (void *cls);
+
+
+/**
+ * Schedule MHD. This function should be called initially when an
+ * MHD is first getting its client socket, and will then automatically
+ * always be called later whenever there is work to be done.
+ */
+static void
+schedule_httpd ()
+{
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ struct GNUNET_NETWORK_FDSet *wrs;
+ struct GNUNET_NETWORK_FDSet *wws;
+ int max;
+ int haveto;
+ MHD_UNSIGNED_LONG_LONG timeout;
+ struct GNUNET_TIME_Relative tv;
+
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ max = -1;
+ if (MHD_YES != MHD_get_fdset (mhd_bank, &rs, &ws, &es, &max))
+ {
+ GNUNET_assert (0);
+ return;
+ }
+ haveto = MHD_get_timeout (mhd_bank, &timeout);
+ if (MHD_YES == haveto)
+ tv.rel_value_us = (uint64_t) timeout * 1000LL;
+ else
+ tv = GNUNET_TIME_UNIT_FOREVER_REL;
+ if (-1 != max)
+ {
+ wrs = GNUNET_NETWORK_fdset_create ();
+ wws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
+ }
+ else
+ {
+ wrs = NULL;
+ wws = NULL;
+ }
+ if (NULL != mhd_task)
+ GNUNET_SCHEDULER_cancel (mhd_task);
+ mhd_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ tv,
+ wrs,
+ wws,
+ &run_mhd, NULL);
+ if (NULL != wrs)
+ GNUNET_NETWORK_fdset_destroy (wrs);
+ if (NULL != wws)
+ GNUNET_NETWORK_fdset_destroy (wws);
+}
+
+
+/**
+ * Task run whenever HTTP server operations are pending.
+ *
+ * @param cls NULL
+ */
+static void
+run_mhd (void *cls)
+{
+ mhd_task = NULL;
+ MHD_run (mhd_bank);
+ schedule_httpd ();
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure with configuration
+ */
+static void
+run (void *cls)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
+ struct TALER_DenominationPublicKey dpk;
+
+ plugin = TALER_EXCHANGEDB_plugin_load (cfg);
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ GNUNET_YES))
+ {
+ GNUNET_break (0);
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ plugin = NULL;
+ result = 77;
+ return;
+ }
+ session = plugin->get_session (plugin->cls,
+ GNUNET_YES);
+ GNUNET_assert (NULL != session);
+ fake_issue (&issue);
+ dpk.rsa_public_key = coin_pub;
+ if ( (GNUNET_OK !=
+ plugin->start (plugin->cls,
+ session)) ||
+ (GNUNET_OK !=
+ plugin->insert_denomination_info (plugin->cls,
+ session,
+ &dpk,
+ &issue)) ||
+ (GNUNET_OK !=
+ plugin->commit (plugin->cls,
+ session)) )
+ {
+ GNUNET_break (0);
+ TALER_EXCHANGEDB_plugin_unload (plugin);
+ plugin = NULL;
+ result = 77;
+ return;
+ }
+ child_death_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_DISK_pipe_handle (sigpipe,
+ GNUNET_DISK_PIPE_END_READ),
+ &maint_child_death, NULL);
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_action,
+ NULL);
+ result = 1; /* test failed for undefined reason */
+ mhd_bank = MHD_start_daemon (MHD_USE_DEBUG,
+ 8082,
+ NULL, NULL,
+ &handle_mhd_request, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL,
+ MHD_OPTION_END);
+ if (NULL == mhd_bank)
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ schedule_httpd ();
+ run_test ();
+}
+
+
+/**
+ * Signal handler called for SIGCHLD. Triggers the
+ * respective handler by writing to the trigger pipe.
+ */
+static void
+sighandler_child_death ()
+{
+ static char c;
+ int old_errno = errno; /* back-up errno */
+
+ GNUNET_break (1 ==
+ GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
+ (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
+ &c, sizeof (c)));
+ errno = old_errno; /* restore errno */
+}
+
+
+int
+main (int argc,
+ char *const argv[])
+{
+ const char *plugin_name;
+ char *testname;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_SIGNAL_Context *shc_chld;
+
+ result = -1;
+ if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ plugin_name++;
+ (void) GNUNET_asprintf (&testname,
+ "test-taler-exchange-aggregator-%s", plugin_name);
+ (void) GNUNET_asprintf (&config_filename,
+ "%s.conf", testname);
+ /* these might get in the way */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test_taler_exchange_aggregator",
+ "WARNING",
+ NULL);
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_parse (cfg,
+ config_filename))
+ {
+ GNUNET_break (0);
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return 2;
+ }
+ sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
+ GNUNET_assert (NULL != sigpipe);
+ shc_chld =
+ GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
+ coin_pk = GNUNET_CRYPTO_rsa_private_key_create (1024);
+ coin_pub = GNUNET_CRYPTO_rsa_private_key_get_public (coin_pk);
+ GNUNET_SCHEDULER_run (&run, cfg);
+ GNUNET_CRYPTO_rsa_private_key_free (coin_pk);
+ GNUNET_CRYPTO_rsa_public_key_free (coin_pub);
+ GNUNET_SIGNAL_handler_uninstall (shc_chld);
+ shc_chld = NULL;
+ GNUNET_DISK_pipe_close (sigpipe);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return result;
+}
+
+/* end of test_taler_exchange_aggregator.c */
diff --git a/src/exchange/test_taler_exchange_httpd.conf b/src/exchange/test_taler_exchange_httpd.conf
new file mode 100644
index 000000000..5b49c0824
--- /dev/null
+++ b/src/exchange/test_taler_exchange_httpd.conf
@@ -0,0 +1,75 @@
+[PATHS]
+# Persistant data storage for the testcase
+TALER_TEST_HOME = test_taler_exchange_httpd_home/
+
+
+[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.
+WIREFORMAT = test
+
+# 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-outgoing-test]
+# What is the main website of the bank?
+BANK_URI = "http://localhost:8082/"
+
+# From which account at the 'bank' should outgoing
+# wire transfers be made?
+EXCHANGE_ACCOUNT_NUMBER = 3
+
+
+# Coins for the tests.
+[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
diff --git a/src/exchange/test_taler_exchange_httpd.data b/src/exchange/test_taler_exchange_httpd.data
new file mode 100644
index 000000000..8a1d6baa9
--- /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..2b55ef5f4
--- /dev/null
+++ b/src/exchange/test_taler_exchange_httpd.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# This file is part of TALER
+# Copyright (C) 2015, 2016 Inria and 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).
+#
+#
+# Clear environment from variables that override config.
+export XDG_DATA_HOME=
+export XDG_CONFIG_HOME=
+#
+# Setup keys.
+taler-exchange-keyup -c test_taler_exchange_httpd.conf
+# Run Exchange HTTPD (in background)
+taler-exchange-httpd -c test_taler_exchange_httpd.conf &
+# Give HTTP time to start
+sleep 5
+# Finally run test...
+# We read the JSON snippets to POST from test_taler_exchange_httpd.data
+cat test_taler_exchange_httpd.data | grep -v ^\# | awk '{ print "curl -d \47" $2 "\47 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/exchange/test_taler_exchange_httpd_home/.config/taler/test.json b/src/exchange/test_taler_exchange_httpd_home/.config/taler/test.json
new file mode 100644
index 000000000..be5e92c11
--- /dev/null
+++ b/src/exchange/test_taler_exchange_httpd_home/.config/taler/test.json
@@ -0,0 +1,8 @@
+{
+ "salt": "AZPRFVJ58NM6M7J5CZQPJAH3EW5DYM52AEZ9Y1C1ER3W94QV8D8TQKF6CK8MYQRA9QMSKDQTGZ306ZS9GQ0M6R01CJ20KPP49WFDZK8",
+ "name": "The exchange",
+ "account_number": 3,
+ "bank_uri": "http://localhost:8082/",
+ "type": "test",
+ "sig": "RPQXP9S4P8PQP7HEZQNRSZCT0ATNEP8GW0P5TPM34V5RX86FCD670V44R9NETSYDDKB8SZV7TKY9PAJYTY51D3VDWY9XXQ5BPFRXR28"
+} \ No newline at end of file
diff --git a/src/mint/test-mint-home/master.priv b/src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv
index 394926938..394926938 100644
--- a/src/mint/test-mint-home/master.priv
+++ b/src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
new file mode 100644
index 000000000..0c6a73138
--- /dev/null
+++ b/src/exchangedb/Makefile.am
@@ -0,0 +1,123 @@
+# 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
+
+pkgcfgdir = $(prefix)/share/taler/config.d/
+
+pkgcfg_DATA = \
+ exchangedb.conf \
+ exchangedb-postgres.conf
+
+EXTRA_DIST = \
+ exchangedb.conf \
+ exchangedb-postgres.conf
+
+
+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
+
+AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
+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_builddir)/src/json/libtalerjson.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_init.h \
+ perf_taler_exchangedb_interpreter.c perf_taler_exchangedb_interpreter.h
+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_init.h \
+ perf_taler_exchangedb_interpreter.c perf_taler_exchangedb_interpreter.h
+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-postgres.conf b/src/exchangedb/exchangedb-postgres.conf
new file mode 100644
index 000000000..3de7474ff
--- /dev/null
+++ b/src/exchangedb/exchangedb-postgres.conf
@@ -0,0 +1,2 @@
+[exchangedb-postgres]
+DB_CONN_STR = "postgres:///taler"
diff --git a/src/exchangedb/exchangedb.conf b/src/exchangedb/exchangedb.conf
new file mode 100644
index 000000000..19277ed23
--- /dev/null
+++ b/src/exchangedb/exchangedb.conf
@@ -0,0 +1,7 @@
+# This file is in the public domain.
+#
+# Database-backend independent specification for the exchangedb module.
+#
+[exchangedb]
+# Where do we expect to find information about auditors?
+AUDITOR_BASE_DIR = ${TALER_DATA_HOME}/auditors/
diff --git a/src/exchangedb/exchangedb_keyio.c b/src/exchangedb/exchangedb_keyio.c
new file mode 100644
index 000000000..9f170f645
--- /dev/null
+++ b/src/exchangedb/exchangedb_keyio.c
@@ -0,0 +1,609 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 Inria & 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_RsaPrivateKey *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;
+
+ /**
+ * Number of signatures and DKI entries in this file.
+ */
+ uint32_t dki_len;
+
+};
+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;
+ const char *auditor_url;
+ unsigned int dki_len;
+ size_t url_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))
+ {
+ 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;
+ }
+ dki_len = ntohl (af->dki_len);
+ if (0 == dki_len)
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No signed keys in %s\n",
+ filename);
+ GNUNET_free (af);
+ return GNUNET_SYSERR;
+ }
+ if ( (size - sizeof (struct AuditorFileHeaderP)) / dki_len <
+ (sizeof (struct TALER_DenominationKeyValidityPS) +
+ sizeof (struct TALER_AuditorSignatureP)) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Malformed key file %s\n",
+ filename);
+ GNUNET_free (af);
+ return GNUNET_SYSERR;
+ }
+ url_len = size
+ - sizeof (struct AuditorFileHeaderP)
+ - dki_len * (sizeof (struct TALER_DenominationKeyValidityPS) +
+ sizeof (struct TALER_AuditorSignatureP));
+ sigs = (const struct TALER_AuditorSignatureP *) &af[1];
+ dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[dki_len];
+ auditor_url = (const char *) &dki[dki_len];
+ if ( (0 == url_len) ||
+ ('\0' != auditor_url[url_len - 1]) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Malformed key file %s\n",
+ filename);
+ GNUNET_free (af);
+ return GNUNET_SYSERR;
+ }
+ ret = aic->it (aic->it_cls,
+ &af->apub,
+ auditor_url,
+ &af->mpub,
+ dki_len,
+ sigs,
+ dki);
+ GNUNET_free (af);
+ return ret;
+}
+
+
+/**
+ * Call @a it with information for each auditor found in the @a exchange_base_dir.
+ *
+ * @param cfg configuration to use
+ * @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 struct GNUNET_CONFIGURATION_Handle *cfg,
+ TALER_EXCHANGEDB_AuditorIterator it,
+ void *it_cls)
+{
+ struct AuditorIterateContext aic;
+ int ret;
+ char *auditor_base_dir;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchangedb",
+ "AUDITOR_BASE_DIR",
+ &auditor_base_dir))
+ return -1;
+ aic.it = it;
+ aic.it_cls = it_cls;
+ ret = GNUNET_DISK_directory_scan (auditor_base_dir,
+ &auditor_iter,
+ &aic);
+ GNUNET_free (auditor_base_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 auditor_url the URL of the auditor
+ * @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 char *auditor_url,
+ 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;
+ af.dki_len = htonl ((uint32_t) dki_len);
+ 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;
+ wsize = strlen (auditor_url) + 1;
+ if (wsize ==
+ GNUNET_DISK_file_write (fh,
+ auditor_url,
+ 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..516f3ea58
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_init.c
@@ -0,0 +1,625 @@
+/*
+ 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;
+ struct GNUNET_HashCode hc;
+
+ 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);
+ GNUNET_CRYPTO_hash (&coin->public_info.coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP),
+ &hc);
+ coin->public_info.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_sign_fdh (dki->denom_priv.rsa_private_key,
+ &hc);
+ 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..78b58a5ae
--- /dev/null
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -0,0 +1,1997 @@
+/*
+ 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_parse (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..092aebc48
--- /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 AND"
+ " wire_deadline<$1"
+ " ORDER BY wire_deadline ASC"
+ " LIMIT 1",
+ 1, 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 " TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT_STR,
+ 2, 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_OK !=
+ 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_OK !=
+ 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_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_absolute_time (&now),
+ 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_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_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 ("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);
+ if (GNUNET_OK != ret)
+ break;
+ }
+ PQclear (result);
+ 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_RsaPublicKey *denom_pub;
+ struct GNUNET_CRYPTO_RsaSignature *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_string (type),
+ 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_string (type),
+ 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..f2c473fd9
--- /dev/null
+++ b/src/exchangedb/test_exchangedb.c
@@ -0,0 +1,980 @@
+/*
+ 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_json_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++)
+ {
+ struct GNUNET_HashCode hc;
+
+ RND_BLK (&melts[cnt].coin.coin_pub);
+ GNUNET_CRYPTO_hash (&melts[cnt].coin.coin_pub,
+ sizeof (melts[cnt].coin.coin_pub),
+ &hc);
+ melts[cnt].coin.denom_sig.rsa_signature =
+ GNUNET_CRYPTO_rsa_sign_fdh (dkp->priv.rsa_private_key,
+ &hc);
+ 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));
+}
+
+
+/**
+ * Function called with details about deposits that
+ * have been made. Called in the test on the
+ * deposit given in @a cls.
+ *
+ * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *`
+ * @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 if deposit does
+ * not match our expectations
+ */
+static int
+deposit_cb (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)
+{
+ struct TALER_EXCHANGEDB_Deposit *deposit = cls;
+ struct GNUNET_HashCode h_wire;
+
+ if (NULL != wire)
+ TALER_JSON_hash (wire, &h_wire);
+ if ( (0 != memcmp (merchant_pub,
+ &deposit->merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP))) ||
+ (0 != TALER_amount_cmp (amount_with_fee,
+ &deposit->amount_with_fee)) ||
+ (0 != TALER_amount_cmp (deposit_fee,
+ &deposit->deposit_fee)) ||
+ (0 != memcmp (h_contract,
+ &deposit->h_contract,
+ sizeof (struct GNUNET_HashCode))) ||
+ (0 != memcmp (coin_pub,
+ &deposit->coin.coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP))) ||
+ (transaction_id != deposit->transaction_id) ||
+ ( (NULL != wire) &&
+ (0 != memcmp (&h_wire,
+ &deposit->h_wire,
+ sizeof (struct GNUNET_HashCode))) ) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure with config
+ */
+static void
+run (void *cls)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct TALER_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));
+ result = 5;
+ 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_fdh (dkp->priv.rsa_private_key,
+ &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)));
+ result = 6;
+ FAILIF (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope,
+ cbc2.sig.rsa_signature,
+ dkp->pub.rsa_public_key));
+ result = 7;
+ 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);
+ wire = json_loads (json_wire_str, 0, NULL);
+ TALER_JSON_hash (wire,
+ &deposit.h_wire);
+ 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));
+ result = 8;
+ FAILIF (GNUNET_OK !=
+ plugin->insert_deposit (plugin->cls,
+ session, &deposit));
+ FAILIF (GNUNET_YES !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit));
+ result = 9;
+ FAILIF (1 !=
+ plugin->iterate_matching_deposits (plugin->cls,
+ session,
+ &deposit.h_wire,
+ &deposit.merchant_pub,
+ &deposit_cb, &deposit,
+ 2));
+ result = 10;
+ 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[])
+{
+ const char *plugin_name;
+ char *config_filename;
+ char *testname;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ result = -1;
+ if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ GNUNET_log_setup (argv[0],
+ "WARNING",
+ NULL);
+ plugin_name++;
+ (void) GNUNET_asprintf (&testname,
+ "test-exchange-db-%s", plugin_name);
+ (void) GNUNET_asprintf (&config_filename,
+ "%s.conf", testname);
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_parse (cfg,
+ config_filename))
+ {
+ GNUNET_break (0);
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return 2;
+ }
+ GNUNET_SCHEDULER_run (&run, cfg);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ return result;
+}
diff --git a/src/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..310263f0b 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -13,12 +13,13 @@ else
talerinclude_HEADERS = \
platform.h \
taler_amount_lib.h \
+ taler_bank_service.h \
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_amount_lib.h b/src/include/taler_amount_lib.h
index 094b96f7f..2fd547196 100644
--- a/src/include/taler_amount_lib.h
+++ b/src/include/taler_amount_lib.h
@@ -128,6 +128,19 @@ TALER_string_to_amount (const char *str,
/**
+ * Parse denomination description, in the format "T:V.F".
+ *
+ * @param str denomination description
+ * @param denom denomination to write the result to, in NBO
+ * @return #GNUNET_OK if the string is a valid denomination specification,
+ * #GNUNET_SYSERR if it is invalid.
+ */
+int
+TALER_string_to_amount_nbo (const char *str,
+ struct TALER_AmountNBO *denom);
+
+
+/**
* Get the value of "zero" in a particular currency.
*
* @param cur currency description
diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h
index a4f33fc97..920ae47fd 100644
--- a/src/include/taler_bank_service.h
+++ b/src/include/taler_bank_service.h
@@ -22,6 +22,7 @@
#ifndef _TALER_BANK_SERVICE_H
#define _TALER_BANK_SERVICE_H
+#include <jansson.h>
#include "taler_util.h"
/* ********************* event loop *********************** */
@@ -117,10 +118,12 @@ struct TALER_BANK_AdminAddIncomingHandle;
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol)
+ * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
*/
typedef void
(*TALER_BANK_AdminAddIncomingResultCallback) (void *cls,
- unsigned int http_status);
+ unsigned int http_status,
+ json_t *json);
/**
@@ -133,7 +136,8 @@ typedef void
* @param reserve_pub public key of the reserve
* @param amount amount that was deposited
* @param execution_date when did we receive the amount
- * @param account_no account number (53 bits at most)
+ * @param debit_account_no account number to withdraw from (53 bits at most)
+ * @param credit_account_no account number to deposit into (53 bits at most)
* @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
@@ -144,7 +148,8 @@ struct TALER_BANK_AdminAddIncomingHandle *
TALER_BANK_admin_add_incoming (struct TALER_BANK_Context *bank,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *amount,
- uint64_t account_no,
+ uint64_t debit_account_no,
+ uint64_t credit_account_no,
TALER_BANK_AdminAddIncomingResultCallback res_cb,
void *res_cb_cls);
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 6056270fa..a3275b74d 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
{
@@ -299,7 +299,7 @@ struct TALER_DenominationSignature
/**
* Taler uses RSA for blinding.
*/
- struct GNUNET_CRYPTO_rsa_Signature *rsa_signature;
+ struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
};
@@ -311,7 +311,7 @@ struct TALER_DenominationPublicKey
/**
* Taler uses RSA for signing coins.
*/
- struct GNUNET_CRYPTO_rsa_PublicKey *rsa_public_key;
+ struct GNUNET_CRYPTO_RsaPublicKey *rsa_public_key;
};
@@ -323,7 +323,7 @@ struct TALER_DenominationPrivateKey
/**
* Taler uses RSA for signing coins.
*/
- struct GNUNET_CRYPTO_rsa_PrivateKey *rsa_private_key;
+ struct GNUNET_CRYPTO_RsaPrivateKey *rsa_private_key;
};
@@ -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..4a1592cf2
--- /dev/null
+++ b/src/include/taler_exchange_service.h
@@ -0,0 +1,1204 @@
+/*
+ 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 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 <jansson.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. Wallets and merchants
+ * are expected to be configured with a set of public keys of
+ * auditors that they deem acceptable. These public keys are
+ * the roots of the Taler PKI.
+ */
+ struct TALER_AuditorPublicKeyP auditor_pub;
+
+ /**
+ * URL of the auditing institution. Signed by the auditor's public
+ * key, this URL is a place where applications can direct users for
+ * additional information about the auditor. In the future, there
+ * should also be an auditor API for automated submission about
+ * claims of misbehaving exchange providers.
+ */
+ const char *auditor_url;
+
+ /**
+ * Number of denomination keys audited by this auditor.
+ */
+ unsigned int num_denom_keys;
+
+ /**
+ * Array of length @a num_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.
+ *
+ * If the request fails to generate a valid response from the
+ * exchange, @a http_status will also be zero.
+ *
+ * @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 obj the received JSON reply, if successful this should be the wire
+ * format details as provided by /wire, or NULL if the
+ * reply was not in JSON format.
+ */
+typedef void
+(*TALER_EXCHANGE_WireResultCallback) (void *cls,
+ unsigned int http_status,
+ 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
+ * reserve status 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
+ * withdraw 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 refresh 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 refresh 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..1f6445212
--- /dev/null
+++ b/src/include/taler_exchangedb_lib.h
@@ -0,0 +1,286 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 Inria & 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"
+
+
+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 auditor_url URL of the auditor
+ * @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 char *auditor_url,
+ 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 cfg configuration to use
+ * @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 struct GNUNET_CONFIGURATION_Handle *cfg,
+ 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 auditor_url the URL of the auditor
+ * @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 char *auditor_url,
+ 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..3646981cd
--- /dev/null
+++ b/src/include/taler_exchangedb_plugin.h
@@ -0,0 +1,1445 @@
+/*
+ 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 <jansson.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);
+
+
+/**
+ * Maximum number of results we return from iterate_matching_deposits().
+ *
+ * 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!
+ */
+#define TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT 10000
+#define TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT_STR "10000"
+
+ /**
+ * 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; should
+ * be #TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT, larger values
+ * are not supported, smaller values would be inefficient.
+ * @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_json_lib.h b/src/include/taler_json_lib.h
index d9fa05188..79589dba7 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -17,14 +17,18 @@
* @file include/taler_json_lib.h
* @brief helper functions for JSON processing using libjansson
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
*/
-#ifndef TALER_json_LIB_H_
-#define TALER_json_LIB_H_
+#ifndef TALER_JSON_LIB_H_
+#define TALER_JSON_LIB_H_
#include <jansson.h>
+#include <gnunet/gnunet_json_lib.h>
+#include "taler_util.h"
/**
* Print JSON parsing related error information
+ * @deprecated
*/
#define TALER_json_warn(error) \
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
@@ -39,106 +43,42 @@
* @return a json object describing the amount
*/
json_t *
-TALER_json_from_amount (const struct TALER_Amount *amount);
+TALER_JSON_from_amount (const struct TALER_Amount *amount);
/**
- * Convert absolute timestamp to a json string.
+ * Provide specification to parse given JSON object to an amount.
*
- * @param stamp the time stamp
- * @return a json string with the timestamp in @a stamp
- */
-json_t *
-TALER_json_from_abs (struct GNUNET_TIME_Absolute stamp);
-
-
-/**
- * Convert RSA public key to JSON.
- *
- * @param pk public key to convert
- * @return corresponding JSON encoding
- */
-json_t *
-TALER_json_from_rsa_public_key (struct GNUNET_CRYPTO_rsa_PublicKey *pk);
-
-
-/**
- * Convert RSA signature to JSON.
- *
- * @param sig signature to convert
- * @return corresponding JSON encoding
- */
-json_t *
-TALER_json_from_rsa_signature (struct GNUNET_CRYPTO_rsa_Signature *sig);
-
-
-/**
- * Convert binary data to a JSON string
- * with the base32crockford encoding.
- *
- * @param data binary data
- * @param size size of @a data in bytes
- * @return json string that encodes @a data
- */
-json_t *
-TALER_json_from_data (const void *data,
- size_t size);
-
-
-/**
- * Parse given JSON object to Amount
- *
- * @param json the json object representing Amount
+ * @param name name of the amount field in the JSON
* @param[out] r_amount where the amount has to be written
- * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
-int
-TALER_json_to_amount (json_t *json,
- struct TALER_Amount *r_amount);
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount (const char *name,
+ struct TALER_Amount *r_amount);
-/**
- * Parse given JSON object to absolute time.
- *
- * @param json the json object representing absolute time in seconds
- * @param[out] abs where the time has to be written
- * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
- */
-int
-TALER_json_to_abs (json_t *json,
- struct GNUNET_TIME_Absolute *abs);
/**
- * Parse given JSON object to data
+ * Generate line in parser specification for denomination public key.
*
- * @param json the json object representing data
- * @param out the pointer to hold the parsed data.
- * @param out_size the size of @a out
- * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ * @param field name of the field
+ * @param[out] pk key to initialize
+ * @return corresponding field spec
*/
-int
-TALER_json_to_data (json_t *json,
- void *out,
- size_t out_size);
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_public_key (const char *field,
+ struct TALER_DenominationPublicKey *pk);
/**
- * Convert JSON to RSA public key.
+ * Generate line in parser specification for denomination signature.
*
- * @param json JSON encoding to convert
- * @return corresponding public key
+ * @param field name of the field
+ * @param sig the signature to initialize
+ * @return corresponding field spec
*/
-struct GNUNET_CRYPTO_rsa_PublicKey *
-TALER_json_to_rsa_public_key (json_t *json);
-
-
-/**
- * Convert JSON to RSA signature.
- *
- * @param json JSON encoding to convert
- * @return corresponding signature
- */
-struct GNUNET_CRYPTO_rsa_Signature *
-TALER_json_to_rsa_signature (json_t *json);
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_signature (const char *field,
+ struct TALER_DenominationSignature *sig);
/**
@@ -149,22 +89,9 @@ TALER_json_to_rsa_signature (json_t *json);
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
int
-TALER_hash_json (json_t *json,
+TALER_JSON_hash (const json_t *json,
struct GNUNET_HashCode *hc);
-
-/**
- * Check if the given wire format JSON object is correctly formatted
- *
- * @param allowed NULL-terminated array of allowed wire format types
- * @param wire the JSON wire format object
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-int
-TALER_json_validate_wireformat (const char **allowed,
- const json_t *wire);
-
-
-#endif /* TALER_json_LIB_H_ */
+#endif /* TALER_JSON_LIB_H_ */
/* End of taler_json_lib.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_pq_lib.h b/src/include/taler_pq_lib.h
index 49e067846..dfcea30e1 100644
--- a/src/include/taler_pq_lib.h
+++ b/src/include/taler_pq_lib.h
@@ -24,6 +24,7 @@
#define TALER_PQ_LIB_H_
#include <libpq-fe.h>
+#include <jansson.h>
#include <gnunet/gnunet_pq_lib.h>
#include "taler_util.h"
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 2526597ee..bd892e793 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -54,62 +54,68 @@
#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
- * the /wire/sepa response.
+ * Signature where the Exchange confirms its SEPA details in
+ * the /wire response.
*/
#define TALER_SIGNATURE_MASTER_SEPA_DETAILS 1026
+/**
+ * Signature where the Exchange confirms its TEST details in
+ * the /wire response.
+ */
+#define TALER_SIGNATURE_MASTER_TEST_DETAILS 1027
+
/*********************************************/
-/* 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 /deposit/wtid response.
*/
-#define TALER_SIGNATURE_MINT_WIRE_TYPES 1036
+#define TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE 1036
/**
- * Signature where the Mint confirms the /deposit/wtid response.
+ * Signature where the Exchange confirms the /wire/deposit response.
*/
-#define TALER_SIGNATURE_MINT_CONFIRM_WIRE 1036
+#define TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT 1037
/*********************/
@@ -118,9 +124,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 +182,7 @@
/**
* EdDSA test signature.
*/
-#define TALER_SIGNATURE_MINT_TEST_EDDSA 1303
+#define TALER_SIGNATURE_EXCHANGE_TEST_EDDSA 1303
@@ -202,7 +208,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 +217,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 +235,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 +266,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 +299,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 +323,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 +333,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 +368,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 +381,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 +423,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 +435,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 +443,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 +475,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 +495,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 +507,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 +518,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 +571,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 +582,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 +598,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 +610,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 +622,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,19 +651,24 @@ 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
- * auditor.
+ * Hash of the auditor's URL.
+ */
+ struct GNUNET_HashCode auditor_url_hash;
+
+ /**
+ * The long-term offline master key of the exchange, affirmed by the
+ * auditor. Hashed string, including 0-terminator.
*/
struct TALER_MasterPublicKeyP master;
@@ -667,14 +678,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 +694,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 +706,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 +718,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 +748,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,14 +770,15 @@ 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
+struct TALER_MasterWireDetailsPS
{
/**
- * Purpose is #TALER_SIGNATURE_MASTER_SEPA_DETAILS.
+ * Purpose is #TALER_SIGNATURE_MASTER_SEPA_DETAILS or
+ * #TALER_SIGNATURE_MASTER_TEST_DETAILS.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
@@ -780,27 +792,6 @@ struct TALER_MasterWireSepaDetailsPS
/**
- * @brief Information signed by a mint's online signing key affirming
- * the wire formats supported by the mint.
- */
-struct TALER_MintWireSupportMethodsPS
-{
-
- /**
- * Purpose is #TALER_SIGNATURE_MINT_WIRE_TYPES.
- */
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
-
- /**
- * Hash over the various wire formats supported by this mint
- * (all as 0-terminated strings).
- */
- struct GNUNET_HashCode h_wire_types GNUNET_PACKED;
-
-};
-
-
-/**
* @brief Format used to generate the signature on a request to obtain
* the wire transfer identifier associated with a deposit.
*/
@@ -841,14 +832,84 @@ 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;
+
+};
+
+
+/**
+ * @brief Format internally used for packing the detailed information
+ * to generate the signature for /wire/deposit signatures.
+ */
+struct TALER_WireDepositDetailP
+{
+
+ /**
+ * Hash of the contract
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Merchant's transaction ID in NBO.
+ */
+ uint64_t transaction_id GNUNET_PACKED;
+
+ /**
+ * Coin's public key.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
+ /**
+ * Total value of the coin.
+ */
+ struct TALER_AmountNBO deposit_value;
+
+ /**
+ * Fees charged by the exchange for the deposit.
+ */
+ struct TALER_AmountNBO deposit_fee;
+
};
/**
+ * @brief Format used to generate the signature for /wire/deposit
+ * replies.
+ */
+struct TALER_WireDepositDataPS
+{
+ /**
+ * Purpose header for the signature over the contract with
+ * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Total amount that was transferred.
+ */
+ struct TALER_AmountNBO total;
+
+ /**
+ * Public key of the merchant (for all aggregated transactions).
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * Hash of wire details of the merchant.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Hash of the individual deposits that were aggregated,
+ * each in the format of a `struct TALER_WireDepositDetailP`.
+ */
+ struct GNUNET_HashCode h_details;
+
+};
+
+/**
* The contract sent by the merchant to the wallet.
*/
struct TALER_ContractPS
@@ -896,14 +957,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 +985,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 +1002,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/include/taler_util.h b/src/include/taler_util.h
index 380901812..0b1d40c85 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -24,8 +24,6 @@
#include <gnunet/gnunet_util_lib.h>
#include "taler_amount_lib.h"
#include "taler_crypto_lib.h"
-#include "taler_json_lib.h"
-
/* Define logging functions */
@@ -98,41 +96,6 @@ TALER_b2s (const void *buf,
/**
- * Round a time value so that it is suitable for transmission
- * via JSON encodings.
- *
- * @param at time to round
- * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
- * it was just now rounded
- */
-int
-TALER_round_abs_time (struct GNUNET_TIME_Absolute *at);
-
-
-/**
- * Round a time value so that it is suitable for transmission
- * via JSON encodings.
- *
- * @param rt time to round
- * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
- * it was just now rounded
- */
-int
-TALER_round_rel_time (struct GNUNET_TIME_Relative *rt);
-
-
-/**
- * Load configuration by parsing all configuration
- * files in the given directory.
- *
- * @param base_dir directory with the configuration files
- * @return NULL on error, otherwise configuration
- */
-struct GNUNET_CONFIGURATION_Handle *
-TALER_config_load (const char *base_dir);
-
-
-/**
* Obtain denomination amount from configuration file.
*
* @param section section of the configuration to access
@@ -147,40 +110,4 @@ TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg,
struct TALER_Amount *denom);
-/**
- * Get the path to a specific Taler installation directory or, with
- * #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation
- * directory.
- *
- * @param dirkind what kind of directory is desired?
- * @return a pointer to the dir path (to be freed by the caller)
- */
-char *
-TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind);
-
-
-/**
- * Print out details on command line options (implements --help).
- *
- * @param ctx command line processing context
- * @param scls additional closure (points to about text)
- * @param option name of the option
- * @param value not used (NULL)
- * @return #GNUNET_NO (do not continue, not an error)
- */
-int
-TALER_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
- void *scls,
- const char *option,
- const char *value);
-
-/**
- * Macro defining the option to print the command line
- * help text (-h option).
- *
- * @param about string with brief description of the application
- */
-#define TALER_GETOPT_OPTION_HELP(about) \
- { 'h', "help", (const char *) NULL, gettext_noop("print this help"), 0, &TALER_GETOPT_format_help_, (void *) about }
-
#endif
diff --git a/src/include/taler_wire_plugin.h b/src/include/taler_wire_plugin.h
index 8fb194c57..9b2bc8fde 100644
--- a/src/include/taler_wire_plugin.h
+++ b/src/include/taler_wire_plugin.h
@@ -99,13 +99,50 @@ struct TALER_WIRE_Plugin
/**
+ * Obtain wire transfer details in the plugin-specific format
+ * from the configuration.
+ *
+ * @param cls closure
+ * @param cfg configuration with details about wire accounts
+ * @param account_name which section in the configuration should we parse
+ * @return NULL if @a cfg fails to have valid wire details for @a account_name
+ */
+ json_t *
+ (*get_wire_details)(void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *account_name);
+
+
+ /**
+ * Sign wire transfer details in the plugin-specific format.
+ *
+ * @param cls closure
+ * @param in wire transfer details in JSON format
+ * @param key private signing key to use
+ * @param salt salt to add
+ * @param[out] sig where to write the signature
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*sign_wire_details)(void *cls,
+ const json_t *in,
+ const struct TALER_MasterPrivateKeyP *key,
+ const struct GNUNET_HashCode *salt,
+ struct TALER_MasterSignatureP *sig);
+
+
+ /**
* Check if the given wire format JSON object is correctly formatted
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
int
- (*wire_validate) (const json_t *wire);
+ (*wire_validate) (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub);
/**
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
new file mode 100644
index 000000000..6f71b8718
--- /dev/null
+++ b/src/json/Makefile.am
@@ -0,0 +1,38 @@
+# 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 = \
+ libtalerjson.la
+
+libtalerjson_la_SOURCES = \
+ json.c \
+ json_helper.c
+libtalerjson_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -export-dynamic -no-undefined
+libtalerjson_la_LIBADD = \
+ -lgnunetjson \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+TESTS = \
+ test_json
+
+check_PROGRAMS= \
+ test_json
+
+test_json_SOURCES = \
+ test_json.c
+test_json_LDADD = \
+ -ltalerjson \
+ -lgnunetjson \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil \
+ -ljansson
diff --git a/src/json/json.c b/src/json/json.c
new file mode 100644
index 000000000..da9e8b9f8
--- /dev/null
+++ b/src/json/json.c
@@ -0,0 +1,53 @@
+/*
+ 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 json/json.c
+ * @brief helper functions for JSON processing using libjansson
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_util.h"
+#include "taler_json_lib.h"
+
+
+/**
+ * Hash a JSON for binary signing.
+ *
+ * @param[in] json some JSON value
+ * @param[out] hc resulting hash code
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_JSON_hash (const json_t *json,
+ struct GNUNET_HashCode *hc)
+{
+ char *wire_enc;
+ size_t len;
+
+ if (NULL == (wire_enc = json_dumps (json,
+ JSON_COMPACT | JSON_SORT_KEYS)))
+ return GNUNET_SYSERR;
+ len = strlen (wire_enc) + 1;
+ GNUNET_CRYPTO_hash (wire_enc,
+ len,
+ hc);
+ free (wire_enc);
+ return GNUNET_OK;
+}
+
+
+/* End of json/json.c */
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
new file mode 100644
index 000000000..7eaaa441a
--- /dev/null
+++ b/src/json/json_helper.c
@@ -0,0 +1,178 @@
+/*
+ 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 json/json_helper.c
+ * @brief helper functions to generate specifications to parse
+ * Taler-specific JSON objects with libgnunetjson
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_util.h"
+#include "taler_json_lib.h"
+
+
+/**
+ * Convert a TALER amount to a JSON object.
+ *
+ * @param amount the amount
+ * @return a json object describing the amount
+ */
+json_t *
+TALER_JSON_from_amount (const struct TALER_Amount *amount)
+{
+ json_t *j;
+
+ if ( (amount->value != (uint64_t) ((json_int_t) amount->value)) ||
+ (0 > ((json_int_t) amount->value)) )
+ {
+ /* Theoretically, json_int_t can be a 32-bit "long", or we might
+ have a 64-bit value which converted to a 63-bit signed long
+ long causes problems here. So we check. Note that depending
+ on the platform, the compiler may be able to statically tell
+ that at least the first check is always false. */
+ GNUNET_break (0);
+ return NULL;
+ }
+ j = json_pack ("{s:s, s:I, s:I}",
+ "currency", amount->currency,
+ "value", (json_int_t) amount->value,
+ "fraction", (json_int_t) amount->fraction);
+ GNUNET_assert (NULL != j);
+ return j;
+}
+
+
+/**
+ * Parse given JSON object to Amount
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_amount (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_Amount *r_amount = spec->ptr;
+ json_int_t value;
+ json_int_t fraction;
+ const char *currency;
+
+ memset (r_amount,
+ 0,
+ sizeof (struct TALER_Amount));
+ if (0 != json_unpack (root,
+ "{s:I, s:I, s:s}",
+ "value", &value,
+ "fraction", &fraction,
+ "currency", &currency))
+ {
+ char *json_enc;
+
+ if (NULL == (json_enc = json_dumps (root,
+ JSON_COMPACT | JSON_ENCODE_ANY)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Malformed JSON amount: %s\n",
+ json_enc);
+ free (json_enc);
+ return GNUNET_SYSERR;
+ }
+ if ( (value < 0) ||
+ (fraction < 0) ||
+ (value > UINT64_MAX) ||
+ (fraction > UINT32_MAX) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (strlen (currency) >= TALER_CURRENCY_LEN)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ r_amount->value = (uint64_t) value;
+ r_amount->fraction = (uint32_t) fraction;
+ strcpy (r_amount->currency, currency);
+ (void) TALER_amount_normalize (r_amount);
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Provide specification to parse given JSON object to an amount.
+ *
+ * @param name name of the amount field in the JSON
+ * @param[out] r_amount where the amount has to be written
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount (const char *name,
+ struct TALER_Amount *r_amount)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_amount,
+ .cleaner = NULL,
+ .cls = NULL,
+ .field = name,
+ .ptr = r_amount,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+ return ret;
+}
+
+
+/**
+ * Generate line in parser specification for denomination public key.
+ *
+ * @param field name of the field
+ * @param[out] pk key to initialize
+ * @return corresponding field spec
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_public_key (const char *field,
+ struct TALER_DenominationPublicKey *pk)
+{
+ return GNUNET_JSON_spec_rsa_public_key (field,
+ &pk->rsa_public_key);
+}
+
+
+/**
+ * Generate line in parser specification for denomination signature.
+ *
+ * @param field name of the field
+ * @param sig the signature to initialize
+ * @return corresponding field spec
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_signature (const char *field,
+ struct TALER_DenominationSignature *sig)
+{
+ return GNUNET_JSON_spec_rsa_signature (field,
+ &sig->rsa_signature);
+}
+
+
+/* end of json/json_helper.c */
diff --git a/src/json/test_json.c b/src/json/test_json.c
new file mode 100644
index 000000000..9f42dbd34
--- /dev/null
+++ b/src/json/test_json.c
@@ -0,0 +1,71 @@
+/*
+ This file is part of TALER
+ (C) 2015, 2016 GNUnet e.V. and Inria
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file json/test_json.c
+ * @brief Tests for Taler-specific crypto logic
+ * @author Christian Grothoff <christian@grothoff.org>
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_json_lib.h"
+
+
+/**
+ * Test amount conversion from/to JSON.
+ *
+ * @return 0 on success
+ */
+static int
+test_amount ()
+{
+ json_t *j;
+ struct TALER_Amount a1;
+ struct TALER_Amount a2;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount (NULL, &a2),
+ GNUNET_JSON_spec_end()
+ };
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:4.3",
+ &a1));
+ j = TALER_JSON_from_amount (&a1);
+ GNUNET_assert (NULL != j);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_JSON_parse (j, spec,
+ NULL, NULL));
+ GNUNET_assert (0 ==
+ TALER_amount_cmp (&a1,
+ &a2));
+ json_decref (j);
+ return 0;
+}
+
+
+int
+main(int argc,
+ const char *const argv[])
+{
+ GNUNET_log_setup ("test-json",
+ "WARNING",
+ NULL);
+ if (0 != test_amount ())
+ return 1;
+ return 0;
+}
+
+/* end of test_json.c */
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-home/sepa.json b/src/mint-lib/test-mint-home/sepa.json
deleted file mode 100644
index 36d12f661..000000000
--- a/src/mint-lib/test-mint-home/sepa.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "receiver_name": "Max Mustermann",
- "iban": "DE89370400440532013000",
- "bic": "COBADEFF370",
- "sig": "8M5YJXM68PRAXKH76HYEBCJW657B23JA0RFGNDMZK2379YZMT626H1BN89KC0M1KJBWGYEN5Z763Q0Y7MCTZQ6BPPT7D9KFCTW60C10"
-} \ No newline at end of file
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 cff24bdc8..000000000
--- a/src/mint/taler-mint-httpd_db.c
+++ /dev/null
@@ -1,1902 +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->rollback (TMH_plugin->cls,
- session);
- 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 461e88759..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",
- lib_name);
- 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/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index 748ce0c29..49d0668a0 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -72,7 +72,7 @@ extract_amount_nbo_helper (PGresult *result,
frac_name);
curr_num = PQfnumber (result,
curr_name);
- if (val_num < 0)
+ if (val_num < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Field `%s' does not exist in result\n",
@@ -140,7 +140,7 @@ extract_amount_nbo_helper (PGresult *result,
* #GNUNET_YES if all results could be extracted
* #GNUNET_NO if at least one result was NULL
* #GNUNET_SYSERR if a result was invalid (non-existing field)
- */
+ */
static int
extract_amount_nbo (void *cls,
PGresult *result,
@@ -153,7 +153,7 @@ extract_amount_nbo (void *cls,
char *frac_name;
char *curr_name;
int ret;
-
+
GNUNET_asprintf (&val_name,
"%s_val",
fname);
@@ -189,7 +189,7 @@ TALER_PQ_result_spec_amount_nbo (const char *name,
{
struct GNUNET_PQ_ResultSpec res =
{ &extract_amount_nbo, NULL, NULL,
- (void *) amount, sizeof (*amount),
+ (void *) amount, sizeof (*amount),
name, NULL };
return res;
}
@@ -208,7 +208,7 @@ TALER_PQ_result_spec_amount_nbo (const char *name,
* #GNUNET_YES if all results could be extracted
* #GNUNET_NO if at least one result was NULL
* #GNUNET_SYSERR if a result was invalid (non-existing field)
- */
+ */
static int
extract_amount (void *cls,
PGresult *result,
@@ -223,7 +223,7 @@ extract_amount (void *cls,
char *curr_name;
struct TALER_AmountNBO amount_nbo;
int ret;
-
+
GNUNET_asprintf (&val_name,
"%s_val",
fname);
@@ -280,7 +280,7 @@ TALER_PQ_result_spec_amount (const char *name,
* #GNUNET_YES if all results could be extracted
* #GNUNET_NO if at least one result was NULL
* #GNUNET_SYSERR if a result was invalid (non-existing field)
- */
+ */
static int
extract_json (void *cls,
PGresult *result,
@@ -294,7 +294,7 @@ extract_json (void *cls,
int fnum;
json_error_t json_error;
size_t slen;
-
+
fnum = PQfnumber (result,
fname);
if (fnum < 0)
@@ -320,10 +320,11 @@ extract_json (void *cls,
&json_error);
if (NULL == *j_dst)
{
- TALER_json_warn (json_error);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse JSON result for field `%s'\n",
- fname);
+ "Failed to parse JSON result for field `%s': %s (%s)\n",
+ fname,
+ json_error.text,
+ json_error.source);
return GNUNET_SYSERR;
}
return GNUNET_OK;
@@ -364,7 +365,7 @@ TALER_PQ_result_spec_json (const char *name,
{
struct GNUNET_PQ_ResultSpec res =
{ &extract_json, &clean_json, NULL,
- (void *) jp, 0,
+ (void *) jp, 0,
name, NULL };
return res;
}
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 8efc3987a..22bc788b8 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -1,11 +1,32 @@
# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include $(LIBGCRYPT_CFLAGS) $(POSTGRESQL_CPPFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir)/src/include $(LIBGCRYPT_CFLAGS)
if USE_COVERAGE
AM_CFLAGS = --coverage -O0
XLIB = -lgcov
endif
+
+pkgcfgdir = $(prefix)/share/taler/config.d/
+
+pkgcfg_DATA = \
+ paths.conf
+
+EXTRA_DIST = \
+ paths.conf
+
+dist_bin_SCRIPTS = taler-config
+
+# See https://www.gnu.org/software/autoconf/manual/autoconf-2.63/html_node/Installation-Directory-Variables.html
+# for and explanation and why this ugliness is necessary.
+edit = sed -e 's|@libdir[@]|$(libdir)|g'
+taler-config: Makefile $(srcdir)/taler-config.in
+ rm -f $@ $@.tmp
+ $(edit) '$(srcdir)/$@.in' >$@.tmp
+ chmod +x $@.tmp
+ chmod a-w $@.tmp
+ mv $@.tmp $@
+
if WALLET_ONLY
lib_LTLIBRARIES = \
libtalerutil_wallet.la
@@ -31,15 +52,11 @@ libtalerutil_la_SOURCES = \
amount.c \
crypto.c \
util.c \
- json.c \
- os_installation.c \
- plugin.c \
- wireformats.c
+ os_installation.c
libtalerutil_la_LIBADD = \
-lgnunetutil \
$(LIBGCRYPT_LIBS) \
- -ljansson \
-lmicrohttpd $(XLIB)
libtalerutil_la_LDFLAGS = \
@@ -48,13 +65,11 @@ libtalerutil_la_LDFLAGS = \
TESTS = \
test_amount \
- test_crypto \
- test_json
+ test_crypto
-check_PROGRAMS= \
+check_PROGRAMS = \
test_amount \
- test_crypto \
- test_json
+ test_crypto
test_amount_SOURCES = \
@@ -68,10 +83,3 @@ test_crypto_SOURCES = \
test_crypto_LDADD = \
-lgnunetutil \
libtalerutil.la
-
-test_json_SOURCES = \
- test_json.c
-test_json_LDADD = \
- -lgnunetutil \
- -ljansson \
- libtalerutil.la
diff --git a/src/util/amount.c b/src/util/amount.c
index dc2d2e400..4ac7d30ab 100644
--- a/src/util/amount.c
+++ b/src/util/amount.c
@@ -151,6 +151,30 @@ TALER_string_to_amount (const char *str,
/**
+ * Parse denomination description, in the format "T:V.F".
+ *
+ * @param str denomination description
+ * @param denom denomination to write the result to, in NBO
+ * @return #GNUNET_OK if the string is a valid denomination specification,
+ * #GNUNET_SYSERR if it is invalid.
+ */
+int
+TALER_string_to_amount_nbo (const char *str,
+ struct TALER_AmountNBO *denom)
+{
+ struct TALER_Amount amount;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (str,
+ &amount))
+ return GNUNET_SYSERR;
+ TALER_amount_hton (denom,
+ &amount);
+ return GNUNET_OK;
+}
+
+
+/**
* Convert amount from host to network representation.
*
* @param res where to store amount in network representation
diff --git a/src/util/json.c b/src/util/json.c
deleted file mode 100644
index 6aca7548c..000000000
--- a/src/util/json.c
+++ /dev/null
@@ -1,400 +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 util/json.c
- * @brief helper functions for JSON processing using libjansson
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#if HAVE_GNUNET_GNUNET_UTIL_TALER_WALLET_LIB_H
-#include <gnunet/gnunet_util_taler_wallet_lib.h>
-#endif
-#if HAVE_GNUNET_GNUNET_UTIL_LIB_H
-#include <gnunet/gnunet_util_lib.h>
-#endif
-#include "taler_util.h"
-
-/**
- * Shorthand for exit jumps.
- */
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-/**
- * Shorthand for JSON parsing related exit jumps.
- */
-#define UNPACK_EXITIF(cond) \
- do { \
- if (cond) { TALER_json_warn (error); goto EXITIF_exit; } \
- } while (0)
-
-
-/**
- * Convert a TALER amount to a JSON
- * object.
- *
- * @param amount the amount
- * @return a json object describing the amount
- */
-json_t *
-TALER_json_from_amount (const struct TALER_Amount *amount)
-{
- json_t *j;
-
- if ( (amount->value != (uint64_t) ((json_int_t) amount->value)) ||
- (0 > ((json_int_t) amount->value)) )
- {
- /* Theoretically, json_int_t can be a 32-bit "long", or we might
- have a 64-bit value which converted to a 63-bit signed long
- long causes problems here. So we check. Note that depending
- on the platform, the compiler may be able to statically tell
- that at least the first check is always false. */
- GNUNET_break (0);
- return NULL;
- }
- j = json_pack ("{s:s, s:I, s:I}",
- "currency", amount->currency,
- "value", (json_int_t) amount->value,
- "fraction", (json_int_t) amount->fraction);
- GNUNET_assert (NULL != j);
- return j;
-}
-
-
-/**
- * Convert absolute timestamp to a json string.
- *
- * @param stamp the time stamp
- * @return a json string with the timestamp in @a stamp
- */
-json_t *
-TALER_json_from_abs (struct GNUNET_TIME_Absolute stamp)
-{
- json_t *j;
- char *mystr;
- int ret;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_round_abs_time (&stamp));
- if (stamp.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
- return json_string ("/never/");
- ret = GNUNET_asprintf (&mystr,
- "/Date(%llu)/",
- (unsigned long long) (stamp.abs_value_us / (1000LL * 1000LL)));
- GNUNET_assert (ret > 0);
- j = json_string (mystr);
- GNUNET_free (mystr);
- return j;
-}
-
-
-/**
- * Convert RSA public key to JSON.
- *
- * @param pk public key to convert
- * @return corresponding JSON encoding
- */
-json_t *
-TALER_json_from_rsa_public_key (struct GNUNET_CRYPTO_rsa_PublicKey *pk)
-{
- char *buf;
- size_t buf_len;
- json_t *ret;
-
- buf_len = GNUNET_CRYPTO_rsa_public_key_encode (pk,
- &buf);
- ret = TALER_json_from_data (buf,
- buf_len);
- GNUNET_free (buf);
- return ret;
-}
-
-
-/**
- * Convert JSON to RSA public key.
- *
- * @param json JSON encoding to convert
- * @return corresponding public key
- */
-struct GNUNET_CRYPTO_rsa_PublicKey *
-TALER_json_to_rsa_public_key (json_t *json)
-{
- const char *enc;
- char *buf;
- size_t len;
- size_t buf_len;
- struct GNUNET_CRYPTO_rsa_PublicKey *pk;
-
- buf = NULL;
- EXITIF (NULL == (enc = json_string_value (json)));
- len = strlen (enc);
- buf_len = (len * 5) / 8;
- buf = GNUNET_malloc (buf_len);
- EXITIF (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (enc,
- len,
- buf,
- buf_len));
- EXITIF (NULL == (pk = GNUNET_CRYPTO_rsa_public_key_decode (buf,
- buf_len)));
- GNUNET_free (buf);
- return pk;
- EXITIF_exit:
- GNUNET_free_non_null (buf);
- return NULL;
-}
-
-
-/**
- * Convert JSON to RSA signature.
- *
- * @param json JSON encoding to convert
- * @return corresponding signature
- */
-struct GNUNET_CRYPTO_rsa_Signature *
-TALER_json_to_rsa_signature (json_t *json)
-{
- const char *enc;
- char *buf;
- size_t len;
- size_t buf_len;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
-
- buf = NULL;
- EXITIF (NULL == (enc = json_string_value (json)));
- len = strlen (enc);
- buf_len = (len * 5) / 8;
- buf = GNUNET_malloc (buf_len);
- EXITIF (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (enc,
- len,
- buf,
- buf_len));
- EXITIF (NULL == (sig = GNUNET_CRYPTO_rsa_signature_decode (buf,
- buf_len)));
- GNUNET_free (buf);
- return sig;
- EXITIF_exit:
- GNUNET_free_non_null (buf);
- return NULL;
-}
-
-
-/**
- * Convert RSA signature to JSON.
- *
- * @param sig signature to convert
- * @return corresponding JSON encoding
- */
-json_t *
-TALER_json_from_rsa_signature (struct GNUNET_CRYPTO_rsa_Signature *sig)
-{
- char *buf;
- size_t buf_len;
- json_t *ret;
-
- buf_len = GNUNET_CRYPTO_rsa_signature_encode (sig,
- &buf);
- ret = TALER_json_from_data (buf,
- buf_len);
- GNUNET_free (buf);
- return ret;
-}
-
-
-/**
- * Convert binary data to a JSON string
- * with the base32crockford encoding.
- *
- * @param data binary data
- * @param size size of @a data in bytes
- * @return json string that encodes @a data
- */
-json_t *
-TALER_json_from_data (const void *data,
- size_t size)
-{
- char *buf;
- json_t *json;
-
- buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
- json = json_string (buf);
- GNUNET_free (buf);
- return json;
-}
-
-
-/**
- * Parse given JSON object to Amount
- *
- * @param json the json object representing Amount
- * @param[out] r_amount where the amount has to be written
- * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
- */
-int
-TALER_json_to_amount (json_t *json,
- struct TALER_Amount *r_amount)
-{
- json_int_t value;
- json_int_t fraction;
- const char *currency;
-
- memset (r_amount,
- 0,
- sizeof (struct TALER_Amount));
- if (0 != json_unpack (json,
- "{s:I, s:I, s:s}",
- "value", &value,
- "fraction", &fraction,
- "currency", &currency))
- {
- char *json_enc;
-
- if (NULL == (json_enc = json_dumps (json,
- JSON_COMPACT | JSON_ENCODE_ANY)))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Malformed JSON amount: %s\n",
- json_enc);
- free (json_enc);
- return GNUNET_SYSERR;
- }
- if ( (value < 0) ||
- (fraction < 0) ||
- (value > UINT64_MAX) ||
- (fraction > UINT32_MAX) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (strlen (currency) >= TALER_CURRENCY_LEN)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- r_amount->value = (uint64_t) value;
- r_amount->fraction = (uint32_t) fraction;
- strcpy (r_amount->currency, currency);
- (void) TALER_amount_normalize (r_amount);
- return GNUNET_OK;
-}
-
-
-/**
- * Parse given JSON object to absolute time.
- *
- * @param json the json object representing Amount
- * @param[out] abs where the amount has to be written
- * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
- */
-int
-TALER_json_to_abs (json_t *json,
- struct GNUNET_TIME_Absolute *abs)
-{
- const char *val;
- unsigned long long int tval;
-
- val = json_string_value (json);
- if (NULL == val)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if ( (0 == strcasecmp (val,
- "/forever/")) ||
- (0 == strcasecmp (val,
- "/never/")) )
- {
- *abs = GNUNET_TIME_UNIT_FOREVER_ABS;
- return GNUNET_OK;
- }
- if (1 != sscanf (val,
- "/Date(%llu)/",
- &tval))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* Time is in seconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
- abs->abs_value_us = tval * 1000LL * 1000LL;
- if ( (abs->abs_value_us) / 1000LL / 1000LL != tval)
- {
- /* Integer overflow */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Parse given JSON object to data
- *
- * @param json the json object representing data
- * @param out the pointer to hold the parsed data.
- * @param out_size the size of @a out
- * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
- */
-int
-TALER_json_to_data (json_t *json,
- void *out,
- size_t out_size)
-{
- const char *enc;
- unsigned int len;
-
- EXITIF (NULL == (enc = json_string_value (json)));
- len = strlen (enc);
- EXITIF (((len * 5) / 8) != out_size);
- EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, len, out, out_size));
- return GNUNET_OK;
- EXITIF_exit:
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Hash a JSON for binary signing.
- *
- * @param[in] json some JSON value
- * @param[out] hc resulting hash code
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-TALER_hash_json (json_t *json,
- struct GNUNET_HashCode *hc)
-{
- char *wire_enc;
- size_t len;
-
- if (NULL == (wire_enc = json_dumps (json,
- JSON_COMPACT | JSON_SORT_KEYS)))
- return GNUNET_SYSERR;
- len = strlen (wire_enc) + 1;
- GNUNET_CRYPTO_hash (wire_enc,
- len,
- hc);
- free (wire_enc);
- return GNUNET_OK;
-}
-
-
-/* End of util/json.c */
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
index 0eab118fe..5aa34f1b9 100644
--- a/src/util/os_installation.c
+++ b/src/util/os_installation.c
@@ -1,701 +1,64 @@
/*
- This file is part of GNUnet.
- Copyright (C) 2006-2014 GNUnet e.V.
+ This file is part of GNU Taler.
+ Copyright (C) 2016 Inria
- GNUnet is free software; you can redistribute it and/or modify
+ 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.
- GNUnet is distributed in the hope that it will be useful, but
+ 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 GNUnet; see the file COPYING. If not, write to the
+ along with Taler; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/**
* @file os_installation.c
- * @brief get paths used by the program; based heavily on the
- * corresponding GNUnet file, just adapted for Taler.
- * @author Milan
+ * @brief initialize libgnunet OS subsystem for Taler.
+ * @author Christian Grothoff
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
-#if DARWIN
-#include <mach-o/ldsyms.h>
-#include <mach-o/dyld.h>
-#elif WINDOWS
-#include <windows.h>
-#endif
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
-
-
-#if LINUX
/**
- * Try to determine path by reading /proc/PID/exe
- *
- * @return NULL on error
+ * Default project data used for installation path detection
+ * for GNU Taler.
*/
-static char *
-get_path_from_proc_maps ()
-{
- char fn[64];
- char line[1024];
- char dir[1024];
- FILE *f;
- char *lgu;
-
- GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
- if (NULL == (f = FOPEN (fn, "r")))
- return NULL;
- while (NULL != fgets (line, sizeof (line), f))
- {
- if ((1 ==
- SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
- (NULL != (lgu = strstr (dir, "libtalerutil"))))
- {
- lgu[0] = '\0';
- FCLOSE (f);
- return GNUNET_strdup (dir);
- }
- }
- FCLOSE (f);
- return NULL;
-}
+static const struct GNUNET_OS_ProjectData taler_pd = {
+ .libname = "libtalerutil",
+ .project_dirname = "taler",
+ .binary_name = "taler-exchange-httpd",
+ .env_varname = "TALER_PREFIX",
+ .bug_email = "taler@gnu.org",
+ .homepage = "http://www.gnu.org/s/taler/",
+};
/**
- * Try to determine path by reading /proc/PID/exe
- *
- * @return NULL on error
+ * Return default project data used by Taler.
*/
-static char *
-get_path_from_proc_exe ()
+const struct GNUNET_OS_ProjectData *
+TALER_project_data_default (void)
{
- char fn[64];
- char lnk[1024];
- ssize_t size;
-
- GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ());
- size = readlink (fn, lnk, sizeof (lnk) - 1);
- if (size <= 0)
- {
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
- return NULL;
- }
- GNUNET_assert (size < sizeof (lnk));
- lnk[size] = '\0';
- while ((lnk[size] != '/') && (size > 0))
- size--;
- /* test for being in lib/taler/libexec/ or lib/MULTIARCH/taler/libexec */
- if ( (size > strlen ("/taler/libexec/")) &&
- (0 == strcmp ("/taler/libexec/",
- &lnk[size - strlen ("/taler/libexec/")])) )
- size -= strlen ("taler/libexec/");
- if ((size < 4) || (lnk[size - 4] != '/'))
- {
- /* not installed in "/bin/" -- binary path probably useless */
- return NULL;
- }
- lnk[size] = '\0';
- return GNUNET_strdup (lnk);
+ return &taler_pd;
}
-#endif
-
-
-#if WINDOWS
-static HINSTANCE dll_instance;
/**
- * GNUNET_util_cl_init() in common_logging.c is preferred.
- * This function is only for thread-local storage (not used in GNUnet)
- * and hInstance saving.
+ * Initialize libtalerutil.
*/
-BOOL WINAPI
-DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+void __attribute__ ((constructor))
+TALER_OS_init ()
{
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- dll_instance = hinstDLL;
- break;
- case DLL_THREAD_ATTACH:
- break;
- case DLL_THREAD_DETACH:
- break;
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
+ GNUNET_OS_init (&taler_pd);
}
-/**
- * Try to determine path with win32-specific function
- *
- * @return NULL on error
- */
-static char *
-get_path_from_module_filename ()
-{
- size_t pathlen = 512;
- DWORD real_pathlen;
- wchar_t *idx;
- wchar_t *modulepath = NULL;
- char *upath;
- uint8_t *u8_string;
- size_t u8_string_length;
-
- /* This braindead function won't tell us how much space it needs, so
- * we start at 1024 and double the space up if it doesn't fit, until
- * it fits, or we exceed the threshold.
- */
- do
- {
- pathlen = pathlen * 2;
- modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
- SetLastError (0);
- real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
- } while (real_pathlen >= pathlen && pathlen < 16*1024);
- if (real_pathlen >= pathlen)
- GNUNET_assert (0);
- /* To be safe */
- modulepath[real_pathlen] = '\0';
-
- idx = modulepath + real_pathlen;
- while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
- idx--;
- *idx = L'\0';
-
- /* Now modulepath holds full path to the directory where libtalerutil is.
- * This directory should look like <TALER_PREFIX>/bin or <TALER_PREFIX>.
- */
- if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
- {
- /* At least one directory component (i.e. we're not in a root directory) */
- wchar_t *dirname = idx;
- while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
- dirname--;
- *dirname = L'\0';
- if (dirname > modulepath)
- {
- dirname++;
- /* Now modulepath holds full path to the parent directory of the directory
- * where libtalerutil is.
- * dirname holds the name of the directory where libtalerutil is.
- */
- if (wcsicmp (dirname, L"bin") == 0)
- {
- /* pass */
- }
- else
- {
- /* Roll back our changes to modulepath */
- dirname--;
- *dirname = L'/';
- }
- }
- }
-
- /* modulepath is TALER_PREFIX */
- u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
- if (NULL == u8_string)
- GNUNET_assert (0);
-
- upath = GNUNET_malloc (u8_string_length + 1);
- memcpy (upath, u8_string, u8_string_length);
- upath[u8_string_length] = '\0';
-
- free (u8_string);
- GNUNET_free (modulepath);
-
- return upath;
-}
-#endif
-
-
-#if DARWIN
-/**
- * Signature of the '_NSGetExecutablePath" function.
- *
- * @param buf where to write the path
- * @param number of bytes available in 'buf'
- * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
- */
-typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
-
-
-/**
- * Try to obtain the path of our executable using '_NSGetExecutablePath'.
- *
- * @return NULL on error
- */
-static char *
-get_path_from_NSGetExecutablePath ()
-{
- static char zero = '\0';
- char *path;
- size_t len;
- MyNSGetExecutablePathProto func;
-
- path = NULL;
- if (NULL == (func =
- (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
- return NULL;
- path = &zero;
- len = 0;
- /* get the path len, including the trailing \0 */
- (void) func (path, &len);
- if (0 == len)
- return NULL;
- path = GNUNET_malloc (len);
- if (0 != func (path, &len))
- {
- GNUNET_free (path);
- return NULL;
- }
- len = strlen (path);
- while ((path[len] != '/') && (len > 0))
- len--;
- path[len] = '\0';
- return path;
-}
-
-
-/**
- * Try to obtain the path of our executable using '_dyld_image' API.
- *
- * @return NULL on error
- */
-static char *
-get_path_from_dyld_image ()
-{
- const char *path;
- char *p;
- char *s;
- unsigned int i;
- int c;
-
- c = _dyld_image_count ();
- for (i = 0; i < c; i++)
- {
- if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
- continue;
- path = _dyld_get_image_name (i);
- if ( (NULL == path) || (0 == strlen (path)) )
- continue;
- p = GNUNET_strdup (path);
- s = p + strlen (p);
- while ((s > p) && ('/' != *s))
- s--;
- s++;
- *s = '\0';
- return p;
- }
- return NULL;
-}
-#endif
-
-
-/**
- * Return the actual path to a file found in the current
- * PATH environment variable.
- *
- * @param binary the name of the file to find
- * @return path to binary, NULL if not found
- */
-static char *
-get_path_from_PATH (const char *binary)
-{
- char *path;
- char *pos;
- char *end;
- char *buf;
- const char *p;
-
- if (NULL == (p = getenv ("PATH")))
- return NULL;
-#if WINDOWS
- /* On W32 look in CWD first. */
- GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
-#else
- path = GNUNET_strdup (p); /* because we write on it */
-#endif
- buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
- pos = path;
- while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
- {
- *end = '\0';
- sprintf (buf, "%s/%s", pos, binary);
- if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
- {
- pos = GNUNET_strdup (pos);
- GNUNET_free (buf);
- GNUNET_free (path);
- return pos;
- }
- pos = end + 1;
- }
- sprintf (buf, "%s/%s", pos, binary);
- if (GNUNET_YES == GNUNET_DISK_file_test (buf))
- {
- pos = GNUNET_strdup (pos);
- GNUNET_free (buf);
- GNUNET_free (path);
- return pos;
- }
- GNUNET_free (buf);
- GNUNET_free (path);
- return NULL;
-}
-
-
-/**
- * Try to obtain the installation path using the "TALER_PREFIX" environment
- * variable.
- *
- * @return NULL on error (environment variable not set)
- */
-static char *
-get_path_from_TALER_PREFIX ()
-{
- const char *p;
-
- if (NULL != (p = getenv ("TALER_PREFIX")))
- return GNUNET_strdup (p);
- return NULL;
-}
-
-
-/**
- * @brief get the path to Taler bin/ or lib/, prefering the lib/ path
- * @author Milan
- *
- * @return a pointer to the executable path, or NULL on error
- */
-static char *
-os_get_taler_path ()
-{
- char *ret;
-
- if (NULL != (ret = get_path_from_TALER_PREFIX ()))
- return ret;
-#if LINUX
- 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")))
- return ret;
- if (NULL != (ret = get_path_from_proc_exe ()))
- return ret;
-#endif
-#if WINDOWS
- if (NULL != (ret = get_path_from_module_filename ()))
- return ret;
-#endif
-#if DARWIN
- if (NULL != (ret = get_path_from_dyld_image ()))
- return ret;
- if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
- return ret;
-#endif
- if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
- return ret;
- /* other attempts here */
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Could not determine installation path for %s. Set `%s' environment variable.\n"),
- "Taler", "TALER_PREFIX");
- return NULL;
-}
-
-
-/**
- * @brief get the path to current app's bin/
- * @author Milan
- *
- * @return a pointer to the executable path, or NULL on error
- */
-static char *
-os_get_exec_path ()
-{
- char *ret = NULL;
-
-#if LINUX
- if (NULL != (ret = get_path_from_proc_exe ()))
- return ret;
-#endif
-#if WINDOWS
- if (NULL != (ret = get_path_from_module_filename ()))
- return ret;
-#endif
-#if DARWIN
- if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
- return ret;
-#endif
- /* other attempts here */
- return ret;
-}
-
-
-/**
- * @brief get the path to a specific Taler installation directory or,
- * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
- * @author Milan
- * @return a pointer to the dir path (to be freed by the caller)
- */
-char *
-TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
-{
- size_t n;
- const char *dirname;
- char *execpath = NULL;
- char *tmp;
- char *multiarch;
- char *libdir;
- int isbasedir;
-
- /* if wanted, try to get the current app's bin/ */
- if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
- execpath = os_get_exec_path ();
-
- /* try to get Taler's bin/ or lib/, or if previous was unsuccessful some
- * guess for the current app */
- if (NULL == execpath)
- execpath = os_get_taler_path ();
-
- if (NULL == execpath)
- return NULL;
-
- n = strlen (execpath);
- if (0 == n)
- {
- /* should never happen, but better safe than sorry */
- GNUNET_free (execpath);
- return NULL;
- }
- /* remove filename itself */
- while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
- execpath[--n] = '\0';
-
- isbasedir = 1;
- if ((n > 6) &&
- ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
- (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
- {
- if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
- (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
- {
- /* strip '/lib32' or '/lib64' */
- execpath[n - 6] = '\0';
- n -= 6;
- }
- else
- isbasedir = 0;
- }
- else if ((n > 4) &&
- ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
- (0 == strcasecmp (&execpath[n - 4], "/lib"))))
- {
- /* strip '/bin' or '/lib' */
- execpath[n - 4] = '\0';
- n -= 4;
- }
- multiarch = NULL;
- if (NULL != (libdir = strstr (execpath, "/lib/")))
- {
- /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
- here we need to re-add 'multiarch' to lib and libexec paths later! */
- multiarch = &libdir[5];
- if (NULL == strchr (multiarch, '/'))
- libdir[0] = '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
- else
- multiarch = NULL; /* maybe not, multiarch still has a '/', which is not OK */
- }
- /* in case this was a directory named foo-bin, remove "foo-" */
- while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
- execpath[--n] = '\0';
- switch (dirkind)
- {
- case GNUNET_OS_IPK_PREFIX:
- case GNUNET_OS_IPK_SELF_PREFIX:
- dirname = DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_BINDIR:
- dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_LIBDIR:
- if (isbasedir)
- {
- GNUNET_asprintf (&tmp,
- "%s%s%s%s%s",
- execpath,
- DIR_SEPARATOR_STR "lib",
- (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
- (NULL != multiarch) ? multiarch : "",
- DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR);
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (tmp, GNUNET_YES))
- {
- GNUNET_free (execpath);
- return tmp;
- }
- GNUNET_free (tmp);
- tmp = NULL;
- if (4 == sizeof (void *))
- {
- dirname =
- DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
- GNUNET_asprintf (&tmp,
- "%s%s",
- execpath,
- dirname);
- }
- if (8 == sizeof (void *))
- {
- dirname =
- DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
- GNUNET_asprintf (&tmp,
- "%s%s",
- execpath,
- dirname);
- }
-
- if ( (NULL != tmp) &&
- (GNUNET_YES ==
- GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
- {
- GNUNET_free (execpath);
- return tmp;
- }
- GNUNET_free (tmp);
- }
- dirname = DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_DATADIR:
- dirname =
- DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_LOCALEDIR:
- dirname =
- DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_ICONDIR:
- dirname =
- DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_DOCDIR:
- dirname =
- DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
- "gnunet" DIR_SEPARATOR_STR;
- break;
- case GNUNET_OS_IPK_LIBEXECDIR:
- if (isbasedir)
- {
- dirname =
- DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR "libexec" DIR_SEPARATOR_STR;
- GNUNET_asprintf (&tmp,
- "%s%s%s%s",
- execpath,
- DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
- (NULL != multiarch) ? multiarch : "",
- dirname);
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (tmp, GNUNET_YES))
- {
- GNUNET_free (execpath);
- return tmp;
- }
- GNUNET_free (tmp);
- tmp = NULL;
- if (4 == sizeof (void *))
- {
- dirname =
- DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
- "libexec" DIR_SEPARATOR_STR;
- GNUNET_asprintf (&tmp,
- "%s%s",
- execpath,
- dirname);
- }
- if (8 == sizeof (void *))
- {
- dirname =
- DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
- "libexec" DIR_SEPARATOR_STR;
- GNUNET_asprintf (&tmp,
- "%s%s",
- execpath,
- dirname);
- }
- if ( (NULL != tmp) &&
- (GNUNET_YES ==
- GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
- {
- GNUNET_free (execpath);
- return tmp;
- }
-
- GNUNET_free (tmp);
- }
- dirname =
- DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
- "libexec" DIR_SEPARATOR_STR;
- break;
- default:
- GNUNET_free (execpath);
- return NULL;
- }
- GNUNET_asprintf (&tmp,
- "%s%s",
- execpath,
- dirname);
- GNUNET_free (execpath);
- return tmp;
-}
-
-
-/**
- * Given the name of a taler-helper, taler-service or taler-daemon
- * binary, try to prefix it with the libexec/-directory to get the
- * full path.
- *
- * @param progname name of the binary
- * @return full path to the binary, if possible, otherwise copy of 'progname'
- */
-char *
-TALER_OS_get_libexec_binary_path (const char *progname)
-{
- static char *cache;
- char *libexecdir;
- char *binary;
-
- if ( (DIR_SEPARATOR == progname[0]) ||
- (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
- return GNUNET_strdup (progname);
- if (NULL != cache)
- libexecdir = cache;
- else
- libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
- if (NULL == libexecdir)
- return GNUNET_strdup (progname);
- GNUNET_asprintf (&binary,
- "%s%s",
- libexecdir,
- progname);
- cache = libexecdir;
- return binary;
-}
-
-
-
/* end of os_installation.c */
diff --git a/src/util/paths.conf b/src/util/paths.conf
new file mode 100644
index 000000000..03febb0e4
--- /dev/null
+++ b/src/util/paths.conf
@@ -0,0 +1,29 @@
+# This file is in the public domain.
+#
+[PATHS]
+# The PATHS section is special, as filenames including $-expression are
+# expanded using the values from PATHS or the system environment (PATHS
+# is checked first). Taler also supports expanding $-expressions using
+# defaults with the syntax "${VAR:-default}". Here, "default" can again
+# be a $-expression.
+#
+# We usually want $HOME for $TALER_HOME, but we allow testcases to
+# easily override this by setting $TALER_TEST_HOME.
+#
+TALER_HOME = ${TALER_TEST_HOME:-${HOME:-${USERPROFILE}}}
+
+# see XDG Base Directory Specification at
+# http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+# for how these should be used.
+
+# Persistant data storage
+TALER_DATA_HOME = ${XDG_DATA_HOME:-$TALER_HOME/.local/share}/taler/
+
+# Configuration files
+TALER_CONFIG_HOME = ${XDG_CONFIG_HOME:-$TALER_HOME/.config}/taler/
+
+# Cached data, no big deal if lost
+TALER_CACHE_HOME = ${XDG_CACHE_HOME:-$TALER_HOME/.cache}/taler/
+
+# Runtime data (always lost on system boot)
+TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/taler-system-runtime/
diff --git a/src/util/plugin.c b/src/util/plugin.c
deleted file mode 100644
index 6f8e03df6..000000000
--- a/src/util/plugin.c
+++ /dev/null
@@ -1,88 +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 util/plugin.c
- * @brief Setup paths so that we can load Taler plugins
- * @author Christian Grothoff
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include "taler_util.h"
-#include <ltdl.h>
-
-/**
- * Libtool search path before we started.
- */
-static char *old_dlsearchpath;
-
-
-/**
- * Setup libtool paths.
- */
-void __attribute__ ((constructor))
-plugin_init ()
-{
- int err;
- const char *opath;
- char *path;
- char *cpath;
-
- err = lt_dlinit ();
- if (err > 0)
- {
- FPRINTF (stderr,
- _("Initialization of plugin mechanism failed: %s!\n"),
- lt_dlerror ());
- return;
- }
- opath = lt_dlgetsearchpath ();
- if (NULL != opath)
- old_dlsearchpath = GNUNET_strdup (opath);
- path = TALER_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
- if (NULL != path)
- {
- if (NULL != opath)
- {
- GNUNET_asprintf (&cpath, "%s:%s", opath, path);
- lt_dlsetsearchpath (cpath);
- GNUNET_free (path);
- GNUNET_free (cpath);
- }
- else
- {
- lt_dlsetsearchpath (path);
- GNUNET_free (path);
- }
- }
-}
-
-
-/**
- * Shutdown libtool.
- */
-void __attribute__ ((destructor))
-plugin_fini ()
-{
- lt_dlsetsearchpath (old_dlsearchpath);
- if (NULL != old_dlsearchpath)
- {
- GNUNET_free (old_dlsearchpath);
- old_dlsearchpath = NULL;
- }
- lt_dlexit ();
-}
-
-/* end of plugin.c */
diff --git a/src/util/taler-config.in b/src/util/taler-config.in
new file mode 100644
index 000000000..eb4114c82
--- /dev/null
+++ b/src/util/taler-config.in
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+if ! type gnunet-config >/dev/null; then
+ echo "$0 needs gnunet-config to be installed"
+ exit 1
+fi
+
+# FIXME: not very portable ...
+export LD_PRELOAD=@libdir@/libtalerutil.so
+exec gnunet-config "$@"
diff --git a/src/util/test_amount.c b/src/util/test_amount.c
index 3f33334bc..640477156 100644
--- a/src/util/test_amount.c
+++ b/src/util/test_amount.c
@@ -73,6 +73,19 @@ main(int argc,
GNUNET_assert (4 == a1.value);
GNUNET_assert (0 == a1.fraction);
+ /* test conversion with leading zero in fraction */
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("eur:0.02",
+ &a2));
+ GNUNET_assert (0 == strcasecmp ("eur",
+ a2.currency));
+ GNUNET_assert (0 == a2.value);
+ GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 2 == a2.fraction);
+ c = TALER_amount_to_string (&a2);
+ GNUNET_assert (0 == strcmp ("eur:0.02",
+ c));
+ GNUNET_free (c);
+
/* test conversion with leading space and with fraction */
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (" eur:4.12",
diff --git a/src/util/test_json.c b/src/util/test_json.c
deleted file mode 100644
index 5e2f50fe8..000000000
--- a/src/util/test_json.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- This file is part of TALER
- (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 util/test_json.c
- * @brief Tests for Taler-specific crypto logic
- * @author Christian Grothoff <christian@grothoff.org>
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_json_lib.h"
-
-
-/**
- * Test amount conversion from/to JSON.
- *
- * @return 0 on success
- */
-static int
-test_amount ()
-{
- json_t *j;
- struct TALER_Amount a1;
- struct TALER_Amount a2;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount ("EUR:4.3",
- &a1));
- j = TALER_json_from_amount (&a1);
- GNUNET_assert (NULL != j);
- GNUNET_assert (GNUNET_OK ==
- TALER_json_to_amount (j,
- &a2));
- GNUNET_assert (0 ==
- TALER_amount_cmp (&a1,
- &a2));
- json_decref (j);
- return 0;
-}
-
-
-/**
- * Test time conversion from/to JSON.
- *
- * @return 0 on success
- */
-static int
-test_time ()
-{
- json_t *j;
- struct GNUNET_TIME_Absolute a1;
- struct GNUNET_TIME_Absolute a2;
-
- a1 = GNUNET_TIME_absolute_get ();
- TALER_round_abs_time (&a1);
- j = TALER_json_from_abs (a1);
- GNUNET_assert (NULL != j);
- GNUNET_assert (GNUNET_OK ==
- TALER_json_to_abs (j,
- &a2));
- GNUNET_assert (a1.abs_value_us ==
- a2.abs_value_us);
- json_decref (j);
-
- a1 = GNUNET_TIME_UNIT_FOREVER_ABS;
- j = TALER_json_from_abs (a1);
- GNUNET_assert (NULL != j);
- GNUNET_assert (GNUNET_OK ==
- TALER_json_to_abs (j,
- &a2));
- GNUNET_assert (a1.abs_value_us ==
- a2.abs_value_us);
- json_decref (j);
- return 0;
-}
-
-
-/**
- * Test raw (binary) conversion from/to JSON.
- *
- * @return 0 on success
- */
-static int
-test_raw ()
-{
- char blob[256];
- char blob2[256];
- unsigned int i;
- json_t *j;
-
- for (i=0;i<=256;i++)
- {
- memset (blob, i, i);
- j = TALER_json_from_data (blob, i);
- GNUNET_assert (NULL != j);
- GNUNET_assert (GNUNET_OK ==
- TALER_json_to_data (j,
- blob2,
- i));
- GNUNET_assert (0 ==
- memcmp (blob,
- blob2,
- i));
- }
- return 0;
-}
-
-
-/**
- * Test rsa conversions from/to JSON.
- *
- * @return 0 on success
- */
-static int
-test_rsa ()
-{
- struct GNUNET_CRYPTO_rsa_PublicKey *pub;
- struct GNUNET_CRYPTO_rsa_PublicKey *pub2;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
- struct GNUNET_CRYPTO_rsa_Signature *sig2;
- struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
- char msg[] = "Hello";
- json_t *jp;
- json_t *js;
-
- priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
- pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
- sig = GNUNET_CRYPTO_rsa_sign (priv,
- msg,
- sizeof (msg));
- GNUNET_assert (NULL != (jp = TALER_json_from_rsa_public_key (pub)));
- GNUNET_assert (NULL != (js = TALER_json_from_rsa_signature (sig)));
- GNUNET_assert (NULL != (pub2 = TALER_json_to_rsa_public_key (jp)));
- GNUNET_assert (NULL != (sig2 = TALER_json_to_rsa_signature (js)));
- GNUNET_break (0 ==
- GNUNET_CRYPTO_rsa_signature_cmp (sig,
- sig2));
- GNUNET_break (0 ==
- GNUNET_CRYPTO_rsa_public_key_cmp (pub,
- pub2));
- GNUNET_CRYPTO_rsa_signature_free (sig);
- GNUNET_CRYPTO_rsa_signature_free (sig2);
- GNUNET_CRYPTO_rsa_private_key_free (priv);
- GNUNET_CRYPTO_rsa_public_key_free (pub);
- GNUNET_CRYPTO_rsa_public_key_free (pub2);
- return 0;
-}
-
-
-int
-main(int argc,
- const char *const argv[])
-{
- GNUNET_log_setup ("test-json",
- "WARNING",
- NULL);
- if (0 != test_amount ())
- return 1;
- if (0 != test_time ())
- return 1;
- if (0 != test_raw ())
- return 1;
- if (0 != test_rsa ())
- return 1;
- /* FIXME: test EdDSA signature conversion... */
- return 0;
-}
-
-/* end of test_json.c */
diff --git a/src/util/util.c b/src/util/util.c
index addafacf7..d5fa8c05c 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -56,7 +56,7 @@ TALER_b2s (const void *buf,
GNUNET_free (tmp);
ret[8] = '\0';
return ret;
-}
+}
/**
@@ -89,179 +89,4 @@ TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg,
}
-/**
- * Round a time value so that it is suitable for transmission
- * via JSON encodings.
- *
- * @param at time to round
- * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
- * it was just now rounded
- */
-int
-TALER_round_abs_time (struct GNUNET_TIME_Absolute *at)
-{
- if (at->abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
- return GNUNET_OK;
- if (0 == at->abs_value_us % 1000000)
- return GNUNET_OK;
- at->abs_value_us -= at->abs_value_us % 1000000;
- return GNUNET_NO;
-}
-
-
-/**
- * Round a time value so that it is suitable for transmission
- * via JSON encodings.
- *
- * @param rt time to round
- * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
- * it was just now rounded
- */
-int
-TALER_round_rel_time (struct GNUNET_TIME_Relative *rt)
-{
- if (rt->rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
- return GNUNET_OK;
- if (0 == rt->rel_value_us % 1000000)
- return GNUNET_OK;
- rt->rel_value_us -= rt->rel_value_us % 1000000;
- return GNUNET_NO;
-}
-
-
-/**
- * Load configuration by parsing all configuration
- * files in the given directory.
- *
- * @param base_dir directory with the configuration files
- * @return NULL on error, otherwise configuration
- */
-struct GNUNET_CONFIGURATION_Handle *
-TALER_config_load (const char *base_dir)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- char *cfg_dir;
- int res;
-
- res = GNUNET_asprintf (&cfg_dir,
- "%s" DIR_SEPARATOR_STR "config",
- base_dir);
- GNUNET_assert (res > 0);
- cfg = GNUNET_CONFIGURATION_create ();
- res = GNUNET_CONFIGURATION_load_from (cfg, cfg_dir);
- GNUNET_free (cfg_dir);
- if (GNUNET_OK != res)
- return NULL;
- return cfg;
-}
-
-
-
-/**
- * At what offset does the help text start?
- */
-#define BORDER 29
-
-/**
- * Print out details on command line options (implements --help).
- *
- * @param ctx command line processing context
- * @param scls additional closure (points to about text)
- * @param option name of the option
- * @param value not used (NULL)
- * @return #GNUNET_NO (do not continue, not an error)
- */
-int
-TALER_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
- void *scls,
- const char *option,
- const char *value)
-{
- const char *about = scls;
- size_t slen;
- unsigned int i;
- int j;
- size_t ml;
- size_t p;
- char *scp;
- const char *trans;
- const struct GNUNET_GETOPT_CommandLineOption *opt;
-
- if (NULL != about)
- {
- printf ("%s\n%s\n",
- ctx->binaryOptions,
- gettext (about));
- printf (_("Arguments mandatory for long options are also mandatory for short options.\n"));
- }
- opt = ctx->allOptions;
- for (i=0;NULL != opt[i].description;i++)
- {
- if (opt[i].shortName == '\0')
- printf (" ");
- else
- printf (" -%c, ", opt[i].shortName);
- printf ("--%s", opt[i].name);
- slen = 8 + strlen (opt[i].name);
- if (opt[i].argumentHelp != NULL)
- {
- printf ("=%s", opt[i].argumentHelp);
- slen += 1 + strlen (opt[i].argumentHelp);
- }
- if (slen > BORDER)
- {
- printf ("\n%*s", BORDER, "");
- slen = BORDER;
- }
- if (slen < BORDER)
- {
- printf ("%*s", (int) (BORDER - slen), "");
- slen = BORDER;
- }
- if (0 < strlen (opt[i].description))
- trans = gettext (opt[i].description);
- else
- trans = "";
- ml = strlen (trans);
- p = 0;
-OUTER:
- while (ml - p > 78 - slen)
- {
- for (j = p + 78 - slen; j > p; j--)
- {
- if (isspace ((unsigned char) trans[j]))
- {
- scp = GNUNET_malloc (j - p + 1);
- memcpy (scp, &trans[p], j - p);
- scp[j - p] = '\0';
- printf ("%s\n%*s", scp, BORDER + 2, "");
- GNUNET_free (scp);
- p = j + 1;
- slen = BORDER + 2;
- goto OUTER;
- }
- }
- /* could not find space to break line */
- scp = GNUNET_malloc (78 - slen + 1);
- memcpy (scp, &trans[p], 78 - slen);
- scp[78 - slen] = '\0';
- printf ("%s\n%*s", scp, BORDER + 2, "");
- GNUNET_free (scp);
- slen = BORDER + 2;
- p = p + 78 - slen;
- }
- /* print rest */
- if (p < ml)
- printf ("%s\n", &trans[p]);
- if (strlen (trans) == 0)
- printf ("\n");
- }
- printf ("Report bugs to taler@gnu.org.\n"
- "Taler home page: http://www.gnu.org/software/taler/\n"
- "General help using GNU software: http://www.gnu.org/gethelp/\n");
- return GNUNET_NO;
-}
-
-
-
/* end of util.c */
diff --git a/src/util/wireformats.c b/src/util/wireformats.c
deleted file mode 100644
index cd5a9c3d4..000000000
--- a/src/util/wireformats.c
+++ /dev/null
@@ -1,441 +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 util/wireformats.c
- * @brief helper functions for JSON processing using libjansson
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_util.h"
-
-/**
- * Shorthand for exit jumps.
- */
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-/**
- * Shorthand for JSON parsing related exit jumps.
- */
-#define UNPACK_EXITIF(cond) \
- do { \
- if (cond) { TALER_json_warn (error); goto EXITIF_exit; } \
- } while (0)
-
-
-/* Taken from GNU gettext */
-
-/**
- * Entry in the country table.
- */
-struct table_entry
-{
- /**
- * 2-Character international country code.
- */
- const char *code;
-
- /**
- * Long English name of the country.
- */
- const char *english;
-};
-
-/* Keep the following table in sync with gettext.
- WARNING: the entries should stay sorted according to the code */
-/**
- * List of country codes.
- */
-static const struct table_entry country_table[] =
- {
- { "AE", "U.A.E." },
- { "AF", "Afghanistan" },
- { "AL", "Albania" },
- { "AM", "Armenia" },
- { "AN", "Netherlands Antilles" },
- { "AR", "Argentina" },
- { "AT", "Austria" },
- { "AU", "Australia" },
- { "AZ", "Azerbaijan" },
- { "BA", "Bosnia and Herzegovina" },
- { "BD", "Bangladesh" },
- { "BE", "Belgium" },
- { "BG", "Bulgaria" },
- { "BH", "Bahrain" },
- { "BN", "Brunei Darussalam" },
- { "BO", "Bolivia" },
- { "BR", "Brazil" },
- { "BT", "Bhutan" },
- { "BY", "Belarus" },
- { "BZ", "Belize" },
- { "CA", "Canada" },
- { "CG", "Congo" },
- { "CH", "Switzerland" },
- { "CI", "Cote d'Ivoire" },
- { "CL", "Chile" },
- { "CM", "Cameroon" },
- { "CN", "People's Republic of China" },
- { "CO", "Colombia" },
- { "CR", "Costa Rica" },
- { "CS", "Serbia and Montenegro" },
- { "CZ", "Czech Republic" },
- { "DE", "Germany" },
- { "DK", "Denmark" },
- { "DO", "Dominican Republic" },
- { "DZ", "Algeria" },
- { "EC", "Ecuador" },
- { "EE", "Estonia" },
- { "EG", "Egypt" },
- { "ER", "Eritrea" },
- { "ES", "Spain" },
- { "ET", "Ethiopia" },
- { "FI", "Finland" },
- { "FO", "Faroe Islands" },
- { "FR", "France" },
- { "GB", "United Kingdom" },
- { "GD", "Caribbean" },
- { "GE", "Georgia" },
- { "GL", "Greenland" },
- { "GR", "Greece" },
- { "GT", "Guatemala" },
- { "HK", "Hong Kong" },
- { "HK", "Hong Kong S.A.R." },
- { "HN", "Honduras" },
- { "HR", "Croatia" },
- { "HT", "Haiti" },
- { "HU", "Hungary" },
- { "ID", "Indonesia" },
- { "IE", "Ireland" },
- { "IL", "Israel" },
- { "IN", "India" },
- { "IQ", "Iraq" },
- { "IR", "Iran" },
- { "IS", "Iceland" },
- { "IT", "Italy" },
- { "JM", "Jamaica" },
- { "JO", "Jordan" },
- { "JP", "Japan" },
- { "KE", "Kenya" },
- { "KG", "Kyrgyzstan" },
- { "KH", "Cambodia" },
- { "KR", "South Korea" },
- { "KW", "Kuwait" },
- { "KZ", "Kazakhstan" },
- { "LA", "Laos" },
- { "LB", "Lebanon" },
- { "LI", "Liechtenstein" },
- { "LK", "Sri Lanka" },
- { "LT", "Lithuania" },
- { "LU", "Luxembourg" },
- { "LV", "Latvia" },
- { "LY", "Libya" },
- { "MA", "Morocco" },
- { "MC", "Principality of Monaco" },
- { "MD", "Moldava" },
- { "MD", "Moldova" },
- { "ME", "Montenegro" },
- { "MK", "Former Yugoslav Republic of Macedonia" },
- { "ML", "Mali" },
- { "MM", "Myanmar" },
- { "MN", "Mongolia" },
- { "MO", "Macau S.A.R." },
- { "MT", "Malta" },
- { "MV", "Maldives" },
- { "MX", "Mexico" },
- { "MY", "Malaysia" },
- { "NG", "Nigeria" },
- { "NI", "Nicaragua" },
- { "NL", "Netherlands" },
- { "NO", "Norway" },
- { "NP", "Nepal" },
- { "NZ", "New Zealand" },
- { "OM", "Oman" },
- { "PA", "Panama" },
- { "PE", "Peru" },
- { "PH", "Philippines" },
- { "PK", "Islamic Republic of Pakistan" },
- { "PL", "Poland" },
- { "PR", "Puerto Rico" },
- { "PT", "Portugal" },
- { "PY", "Paraguay" },
- { "QA", "Qatar" },
- { "RE", "Reunion" },
- { "RO", "Romania" },
- { "RS", "Serbia" },
- { "RU", "Russia" },
- { "RW", "Rwanda" },
- { "SA", "Saudi Arabia" },
- { "SE", "Sweden" },
- { "SG", "Singapore" },
- { "SI", "Slovenia" },
- { "SK", "Slovak" },
- { "SN", "Senegal" },
- { "SO", "Somalia" },
- { "SR", "Suriname" },
- { "SV", "El Salvador" },
- { "SY", "Syria" },
- { "TH", "Thailand" },
- { "TJ", "Tajikistan" },
- { "TM", "Turkmenistan" },
- { "TN", "Tunisia" },
- { "TR", "Turkey" },
- { "TT", "Trinidad and Tobago" },
- { "TW", "Taiwan" },
- { "TZ", "Tanzania" },
- { "UA", "Ukraine" },
- { "US", "United States" },
- { "UY", "Uruguay" },
- { "VA", "Vatican" },
- { "VE", "Venezuela" },
- { "VN", "Viet Nam" },
- { "YE", "Yemen" },
- { "ZA", "South Africa" },
- { "ZW", "Zimbabwe" }
- };
-
-
-/**
- * Country code comparator function, for binary search with bsearch().
- *
- * @param ptr1 pointer to a `struct table_entry`
- * @param ptr2 pointer to a `struct table_entry`
- * @return result of strncmp()'ing the 2-digit country codes of the entries
- */
-static int
-cmp_country_code (const void *ptr1,
- const void *ptr2)
-{
- const struct table_entry *cc1 = ptr1;
- const struct table_entry *cc2 = ptr2;
-
- return strncmp (cc1->code, cc2->code, 2);
-}
-
-
-/**
- * Validates given IBAN according to the European Banking Standards. See:
- * http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
- *
- * @param iban the IBAN number to validate
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-static int
-validate_iban (const char *iban)
-{
- char cc[2];
- char ibancpy[35];
- struct table_entry cc_entry;
- unsigned int len;
- char *nbuf;
- unsigned int i;
- unsigned int j;
- unsigned long long dividend;
- unsigned long long remainder;
- int nread;
- int ret;
-
- len = strlen (iban);
- if (len > 34)
- return GNUNET_NO;
- strncpy (cc, iban, 2);
- strncpy (ibancpy, iban + 4, len - 4);
- strncpy (ibancpy + len - 4, iban, 4);
- ibancpy[len] = '\0';
- cc_entry.code = cc;
- cc_entry.english = NULL;
- if (NULL ==
- bsearch (&cc_entry,
- country_table,
- sizeof (country_table) / sizeof (struct table_entry),
- sizeof (struct table_entry),
- &cmp_country_code))
- return GNUNET_NO;
- nbuf = GNUNET_malloc ((len * 2) + 1);
- for (i=0, j=0; i < len; i++)
- {
- if (isalpha ((int) ibancpy[i]))
- {
- EXITIF(2 != snprintf(&nbuf[j],
- 3,
- "%2u",
- (ibancpy[i] - 'A' + 10)));
- j += 2;
- continue;
- }
- nbuf[j] = ibancpy[i];
- j++;
- }
- for (j=0;'\0' != nbuf[j];j++)
- GNUNET_assert (isdigit(nbuf[j]));
- GNUNET_assert (sizeof(dividend) >= 8);
- remainder = 0;
- for (i=0; i<j; i+=16)
- {
- EXITIF (1 !=
- (ret = sscanf (&nbuf[i],
- "%16llu %n",
- &dividend,
- &nread)));
- if (0 != remainder)
- dividend += remainder * (pow (10, nread));
- remainder = dividend % 97;
- }
- if (1 == remainder)
- {
- GNUNET_free (nbuf);
- return GNUNET_YES;
- }
- EXITIF_exit:
- GNUNET_free (nbuf);
- return GNUNET_NO;
-}
-
-
-/**
- * Validate SEPA account details.
- *
- * @param wire JSON with the SEPA details
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-static int
-validate_sepa (const json_t *wire)
-{
- json_error_t error;
- const char *type;
- const char *iban;
- const char *name;
- const char *bic;
- uint64_t r;
- const char *address;
-
- UNPACK_EXITIF (0 != json_unpack_ex
- ((json_t *) wire,
- &error, JSON_STRICT,
- "{"
- "s:s," /* TYPE: sepa */
- "s:s," /* IBAN: iban */
- "s:s," /* name: beneficiary name */
- "s:s," /* BIC: beneficiary bank's BIC */
- "s:i," /* r: random 64-bit integer nounce */
- "s:s" /* address: address of the beneficiary */
- "}",
- "type", &type,
- "IBAN", &iban,
- "name", &name,
- "bic", &bic,
- "r", &r,
- "address", &address));
- if (1 != validate_iban (iban))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "IBAN `%s' invalid\n",
- iban);
- return GNUNET_NO;
- }
- return GNUNET_YES;
- EXITIF_exit:
- return GNUNET_NO;
-}
-
-
-/**
- * Validate TEST account details. The "test" format is used
- * for testing, so this validator does nothing.
- *
- * @param wire JSON with the TEST details
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-static int
-validate_test (const json_t *wire)
-{
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for a wire format.
- */
-struct FormatHandler
-{
- /**
- * Type handled by this format handler.
- */
- const char *type;
-
- /**
- * Function to call to evaluate the format.
- *
- * @param wire the JSON to evaluate
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
- int (*handler)(const json_t *wire);
-};
-
-
-/**
- * Check if the given wire format JSON object is correctly formatted
- *
- * @param allowed NULL-terminated array of allowed wire format types
- * @param wire the JSON wire format object
- * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
- */
-int
-TALER_json_validate_wireformat (const char **allowed,
- const json_t *wire)
-{
- static const struct FormatHandler format_handlers[] = {
- { "SEPA", &validate_sepa },
- { "TEST", &validate_test },
- { NULL, NULL}
- };
- unsigned int i;
- const char *stype;
- json_error_t error;
-
- UNPACK_EXITIF (0 != json_unpack_ex
- ((json_t *) wire,
- &error, 0,
- "{s:s}",
- "type", &stype));
- for (i=0;NULL != allowed[i];i++)
- if (0 == strcasecmp (allowed[i],
- stype))
- break;
- if (NULL == allowed[i])
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Wireformat `%s' does not match mint's allowed formats\n",
- stype);
- return GNUNET_NO;
- }
-
- for (i=0;NULL != format_handlers[i].type;i++)
- if (0 == strcasecmp (format_handlers[i].type,
- stype))
- return format_handlers[i].handler (wire);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Wireformat `%s' not supported\n",
- stype);
- return GNUNET_NO;
- EXITIF_exit:
- return GNUNET_NO;
-}
-
-/* end of wireformats.c */
diff --git a/src/wire/Makefile.am b/src/wire/Makefile.am
index eb2e893fa..debb27828 100644
--- a/src/wire/Makefile.am
+++ b/src/wire/Makefile.am
@@ -6,6 +6,18 @@ if USE_COVERAGE
XLIB = -lgcov
endif
+pkgcfgdir = $(prefix)/share/taler/config.d/
+
+pkgcfg_DATA = \
+ wire-sepa.conf \
+ wire-test.conf
+
+
+EXTRA_DIST = \
+ wire-sepa.conf \
+ wire-test.conf \
+ test_wire_plugin.conf
+
plugindir = $(libdir)/taler
plugin_LTLIBRARIES = \
@@ -36,7 +48,9 @@ libtaler_plugin_wire_sepa_la_LIBADD = \
$(LTLIBINTL)
libtaler_plugin_wire_sepa_la_LDFLAGS = \
$(TALER_PLUGIN_LDFLAGS) \
+ $(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
-lgnunetutil $(XLIB)
@@ -60,11 +74,15 @@ libtalerwire_la_LDFLAGS = \
-export-dynamic -no-undefined
+AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
+
TESTS = \
- test_sepa_wireformat
+ test_sepa_wireformat \
+ test_wire_plugin
check_PROGRAMS= \
- test_sepa_wireformat
+ test_sepa_wireformat \
+ test_wire_plugin
@@ -76,3 +94,12 @@ test_sepa_wireformat_LDADD = \
libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la
+
+test_wire_plugin_SOURCES = \
+ test_wire_plugin.c
+test_wire_plugin_LDADD = \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ libtalerwire.la \
+ $(top_builddir)/src/util/libtalerutil.la
diff --git a/src/wire/plugin_wire_sepa.c b/src/wire/plugin_wire_sepa.c
index 00d19d4b0..6f01167d9 100644
--- a/src/wire/plugin_wire_sepa.c
+++ b/src/wire/plugin_wire_sepa.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
+ Copyright (C) 2016 GNUnet e.V. & Inria
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -23,6 +23,8 @@
*/
#include "platform.h"
#include "taler_wire_plugin.h"
+#include "taler_signatures.h"
+#include <gnunet/gnunet_json_lib.h>
/**
@@ -58,6 +60,8 @@ sepa_amount_round (void *cls,
struct SepaClosure *sc = cls;
uint32_t delta;
+ if (NULL == sc->currency)
+ return GNUNET_SYSERR;
if (0 != strcasecmp (amount->currency,
sc->currency))
{
@@ -348,41 +352,138 @@ validate_iban (const char *iban)
/**
+ * Compute purpose for signing.
+ *
+ * @param sepa_name name of the account holder
+ * @param iban bank account number in IBAN format
+ * @param bic bank identifier
+ * @param[out] mp purpose to be signed
+ */
+static void
+compute_purpose (const char *sepa_name,
+ const char *iban,
+ const char *bic,
+ struct TALER_MasterWireDetailsPS *wsd)
+{
+ struct GNUNET_HashContext *hc;
+
+ wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
+ wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ "sepa",
+ strlen ("sepa") + 1);
+ 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);
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &wsd->h_sepa_details);
+}
+
+
+/**
+ * Verify that the signature in the @a json for /wire/sepa is valid.
+ *
+ * @param json json reply with the signature
+ * @param master_pub public key of the exchange to verify against
+ * @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 json_t *json,
+ const struct TALER_MasterPublicKeyP *master_pub)
+{
+ struct TALER_MasterSignatureP exchange_sig;
+ struct TALER_MasterWireDetailsPS mp;
+ const char *name;
+ const char *iban;
+ const char *bic;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig),
+ GNUNET_JSON_spec_string ("name", &name),
+ GNUNET_JSON_spec_string ("iban", &iban),
+ GNUNET_JSON_spec_string ("bic", &bic),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (NULL == master_pub)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Skipping signature check as master public key not given\n");
+ return GNUNET_OK;
+ }
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json, spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ compute_purpose (name,
+ iban,
+ bic,
+ &mp);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
+ &mp.purpose,
+ &exchange_sig.eddsa_signature,
+ &master_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_OK;
+}
+
+
+/**
* Check if the given wire format JSON object is correctly formatted
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
-sepa_wire_validate (const json_t *wire)
+sepa_wire_validate (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub)
{
json_error_t error;
const char *type;
const char *iban;
const char *name;
const char *bic;
- uint64_t r;
- const char *address;
if (0 != json_unpack_ex
((json_t *) wire,
- &error, JSON_STRICT,
+ &error, 0,
"{"
- "s:s," /* TYPE: sepa */
- "s:s," /* IBAN: iban */
+ "s:s," /* type: sepa */
+ "s:s," /* iban: IBAN */
"s:s," /* name: beneficiary name */
- "s:s," /* BIC: beneficiary bank's BIC */
- "s:i," /* r: random 64-bit integer nounce */
- "s:s" /* address: address of the beneficiary */
+ "s:s" /* bic: beneficiary bank's BIC */
"}",
"type", &type,
- "IBAN", &iban,
+ "iban", &iban,
"name", &name,
- "bic", &bic,
- "r", &r,
- "address", &address))
+ "bic", &bic))
{
- TALER_json_warn (error);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "JSON parsing failed at %s:%u: %s (%s)\n",
+ __FILE__, __LINE__,
+ error.text, error.source);
+ json_dumpf (wire, stderr, 0);
+ fprintf (stderr, "\n");
return GNUNET_SYSERR;
}
if (0 != strcasecmp (type,
@@ -400,11 +501,144 @@ sepa_wire_validate (const json_t *wire)
iban);
return GNUNET_NO;
}
+ /* FIXME: don't parse again, integrate properly... */
+ if (GNUNET_OK !=
+ verify_wire_sepa_signature_ok (wire,
+ master_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Signature invalid\n");
+ return GNUNET_NO;
+ }
return GNUNET_YES;
}
/**
+ * Obtain wire transfer details in the plugin-specific format
+ * from the configuration.
+ *
+ * @param cls closure
+ * @param cfg configuration with details about wire accounts
+ * @param account_name which section in the configuration should we parse
+ * @return NULL if @a cfg fails to have valid wire details for @a account_name
+ */
+static json_t *
+sepa_get_wire_details (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *account_name)
+{
+ char *sepa_wire_file;
+ json_error_t err;
+ json_t *ret;
+
+ /* Fetch reply */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ account_name,
+ "SEPA_RESPONSE_FILE",
+ &sepa_wire_file))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ account_name,
+ "SEPA_RESPONSE_FILE");
+ return NULL;
+ }
+ ret = json_load_file (sepa_wire_file,
+ JSON_REJECT_DUPLICATES,
+ &err);
+ if (NULL == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse JSON in %s: %s (%s:%u)\n",
+ sepa_wire_file,
+ err.text,
+ err.source,
+ err.line);
+ GNUNET_free (sepa_wire_file);
+ return NULL;
+ }
+ if (GNUNET_YES != sepa_wire_validate (cls,
+ ret,
+ NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to validate SEPA data in %s\n",
+ sepa_wire_file);
+ GNUNET_free (sepa_wire_file);
+ json_decref (ret);
+ return NULL;
+ }
+ GNUNET_free (sepa_wire_file);
+ return ret;
+}
+
+
+/**
+ * Sign wire transfer details in the plugin-specific format.
+ *
+ * @param cls closure
+ * @param in wire transfer details in JSON format
+ * @param key private signing key to use
+ * @param salt salt to add
+ * @param[out] sig where to write the signature
+ * @return #GNUNET_OK on success
+ */
+static int
+sepa_sign_wire_details (void *cls,
+ const json_t *in,
+ const struct TALER_MasterPrivateKeyP *key,
+ const struct GNUNET_HashCode *salt,
+ struct TALER_MasterSignatureP *sig)
+{
+ struct TALER_MasterWireDetailsPS wsd;
+ const char *sepa_name;
+ const char *iban;
+ const char *bic;
+ const char *type;
+ json_error_t err;
+
+ if (0 !=
+ json_unpack_ex ((json_t *) in,
+ &err,
+ 0 /* flags */,
+ "{s:s, s:s, s:s, s:s}",
+ "type", &type,
+ "name", &sepa_name,
+ "iban", &iban,
+ "bic", &bic))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to unpack JSON: %s (at %u)\n",
+ err.text,
+ err.position);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp (type,
+ "sepa"))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "`type' must be `sepa' for SEPA wire details\n");
+ return GNUNET_SYSERR;
+ }
+ if (1 != validate_iban (iban))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "IBAN invalid in SEPA wire details\n");
+ return GNUNET_SYSERR;
+ }
+ compute_purpose (sepa_name,
+ iban,
+ bic,
+ &wsd);
+ GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
+ &wsd.purpose,
+ &sig->eddsa_signature);
+ return GNUNET_OK;
+}
+
+
+/**
* Prepare for exeuction of a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -499,22 +733,26 @@ libtaler_plugin_wire_sepa_init (void *cls)
struct TALER_WIRE_Plugin *plugin;
sc = GNUNET_new (struct SepaClosure);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "CURRENCY",
- &sc->currency))
+ if (NULL != cfg)
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "CURRENCY");
- GNUNET_free (sc);
- return NULL;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "CURRENCY",
+ &sc->currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "CURRENCY");
+ GNUNET_free (sc);
+ return NULL;
+ }
}
-
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = sc;
plugin->amount_round = &sepa_amount_round;
+ plugin->get_wire_details = &sepa_get_wire_details;
+ plugin->sign_wire_details = &sepa_sign_wire_details;
plugin->wire_validate = &sepa_wire_validate;
plugin->prepare_wire_transfer = &sepa_prepare_wire_transfer;
plugin->prepare_wire_transfer_cancel = &sepa_prepare_wire_transfer_cancel;
@@ -536,7 +774,7 @@ libtaler_plugin_wire_sepa_done (void *cls)
struct TALER_WIRE_Plugin *plugin = cls;
struct SepaClosure *sc = plugin->cls;
- GNUNET_free (sc->currency);
+ GNUNET_free_non_null (sc->currency);
GNUNET_free (sc);
GNUNET_free (plugin);
return NULL;
diff --git a/src/wire/plugin_wire_template.c b/src/wire/plugin_wire_template.c
index baf0ee7d5..46908c297 100644
--- a/src/wire/plugin_wire_template.c
+++ b/src/wire/plugin_wire_template.c
@@ -74,13 +74,36 @@ template_amount_round (void *cls,
/**
+ * Obtain wire transfer details in the plugin-specific format
+ * from the configuration.
+ *
+ * @param cls closure
+ * @param cfg configuration with details about wire accounts
+ * @param account_name which section in the configuration should we parse
+ * @return NULL if @a cfg fails to have valid wire details for @a account_name
+ */
+static json_t *
+template_get_wire_details (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *account_name)
+{
+ GNUNET_break (0);
+ return NULL;
+}
+
+
+/**
* Check if the given wire format JSON object is correctly formatted
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
-template_wire_validate (const json_t *wire)
+template_wire_validate (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub)
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -149,6 +172,28 @@ template_execute_wire_transfer (void *cls,
/**
+ * Sign wire transfer details in the plugin-specific format.
+ *
+ * @param cls closure
+ * @param in wire transfer details in JSON format
+ * @param key private signing key to use
+ * @param salt salt to add
+ * @param[out] sig where to write the signature
+ * @return #GNUNET_OK on success
+ */
+static int
+template_sign_wire_details (void *cls,
+ const json_t *in,
+ const struct TALER_MasterPrivateKeyP *key,
+ const struct GNUNET_HashCode *salt,
+ struct TALER_MasterSignatureP *sig)
+{
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+}
+
+
+/**
* Abort execution of a wire transfer. For example, because we are
* shutting down. Note that if an execution is aborted, it may or
* may not still succeed. The caller MUST run @e
@@ -197,12 +242,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);
@@ -212,6 +257,8 @@ libtaler_plugin_wire_template_init (void *cls)
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = tc;
plugin->amount_round = &template_amount_round;
+ plugin->get_wire_details = &template_get_wire_details;
+ plugin->sign_wire_details = &template_sign_wire_details;
plugin->wire_validate = &template_wire_validate;
plugin->prepare_wire_transfer = &template_prepare_wire_transfer;
plugin->prepare_wire_transfer_cancel = &template_prepare_wire_transfer_cancel;
diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c
index 8a6f98ea2..d467b7bdd 100644
--- a/src/wire/plugin_wire_test.c
+++ b/src/wire/plugin_wire_test.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
+ Copyright (C) 2016 GNUnet e.V. & Inria
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -22,6 +22,7 @@
#include "platform.h"
#include "taler_wire_plugin.h"
#include "taler_bank_service.h"
+#include "taler_signatures.h"
/* only for HTTP status codes */
#include <microhttpd.h>
@@ -34,20 +35,31 @@ struct TestClosure
{
/**
- * Handle to the bank for sending funds to the bank.
+ * Which currency do we support?
*/
- struct TALER_BANK_Context *bank;
+ char *currency;
/**
- * Which currency do we support?
+ * URI of our bank.
*/
- char *currency;
+ char *bank_uri;
+
+ /**
+ * Handle to the bank for sending funds to the bank.
+ */
+ struct TALER_BANK_Context *bank;
/**
* Handle to the bank task, or NULL.
*/
struct GNUNET_SCHEDULER_Task *bt;
+ /**
+ * Number of the account that the exchange has at the bank for
+ * outgoing transfers.
+ */
+ unsigned long long exchange_account_outgoing_no;
+
};
@@ -124,11 +136,9 @@ struct TALER_WIRE_ExecuteHandle
* scheduler.
*
* @param cls our `struct TestClosure`
- * @param tc scheduler context (unused)
*/
static void
-context_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *sct)
+context_task (void *cls)
{
struct TestClosure *tc = cls;
long timeout;
@@ -171,7 +181,7 @@ context_task (void *cls,
rs,
ws,
&context_task,
- cls);
+ tc);
GNUNET_NETWORK_fdset_destroy (rs);
GNUNET_NETWORK_fdset_destroy (ws);
}
@@ -210,6 +220,13 @@ test_amount_round (void *cls,
struct TestClosure *tc = cls;
uint32_t delta;
+ if (NULL == tc->currency)
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "CURRENCY");
+ return GNUNET_SYSERR; /* not configured with currency */
+ }
if (0 != strcasecmp (amount->currency,
tc->currency))
{
@@ -226,27 +243,69 @@ test_amount_round (void *cls,
/**
+ * Compute purpose for signing.
+ *
+ * @param account number of the account
+ * @param bank_uri URI of the bank
+ * @param[out] mp purpose to be signed
+ */
+static void
+compute_purpose (uint64_t account,
+ const char *bank_uri,
+ struct TALER_MasterWireDetailsPS *wsd)
+{
+ struct GNUNET_HashContext *hc;
+ uint64_t n = GNUNET_htonll (account);
+
+ wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
+ wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_TEST_DETAILS);
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ "test",
+ strlen ("test") + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ &n,
+ sizeof (n));
+ GNUNET_CRYPTO_hash_context_read (hc,
+ bank_uri,
+ strlen (bank_uri) + 1);
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &wsd->h_sepa_details);
+}
+
+
+/**
* Check if the given wire format JSON object is correctly formatted.
* Right now, the only thing we require is a field
* "account_number" which must contain a positive 53-bit integer.
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
-test_wire_validate (const json_t *wire)
+test_wire_validate (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub)
{
+ struct TestClosure *tc = cls;
json_error_t error;
json_int_t account_no;
+ const char *bank_uri;
+ const char *sig_s;
+ struct TALER_MasterWireDetailsPS wsd;
+ struct TALER_MasterSignatureP sig;
if (0 !=
json_unpack_ex ((json_t *) wire,
&error,
0,
- "{s:I}",
- "account_number", &account_no))
+ "{s:I, s:s}",
+ "account_number", &account_no,
+ "bank_uri", &bank_uri))
{
- GNUNET_break (0);
+ GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if ( (account_no < 0) ||
@@ -255,10 +314,119 @@ test_wire_validate (const json_t *wire)
GNUNET_break (0);
return GNUNET_SYSERR;
}
+ if ( (NULL != tc->bank_uri) &&
+ (0 != strcmp (bank_uri,
+ tc->bank_uri)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire specifies bank URI %s, but this exchange only supports %s\n",
+ bank_uri,
+ tc->bank_uri);
+ return GNUNET_NO;
+ }
+ if (NULL == master_pub)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Skipping signature check as master public key not given\n");
+ return GNUNET_OK;
+ }
+ if (0 !=
+ json_unpack_ex ((json_t *) wire,
+ &error,
+ 0,
+ "{s:s}",
+ "sig", &sig_s))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Signature check required, but signature is missing\n");
+ return GNUNET_NO;
+ }
+ compute_purpose (account_no,
+ bank_uri,
+ &wsd);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (sig_s,
+ strlen (sig_s),
+ &sig,
+ sizeof (sig)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_TEST_DETAILS,
+ &wsd.purpose,
+ &sig.eddsa_signature,
+ &master_pub->eddsa_pub))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
return GNUNET_YES;
}
+/**
+ * Obtain wire transfer details in the plugin-specific format
+ * from the configuration.
+ *
+ * @param cls closure
+ * @param cfg configuration with details about wire accounts
+ * @param account_name which section in the configuration should we parse
+ * @return NULL if @a cfg fails to have valid wire details for @a account_name
+ */
+static json_t *
+test_get_wire_details (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *account_name)
+{
+ struct TestClosure *tc = cls;
+ char *test_wire_file;
+ json_error_t err;
+ json_t *ret;
+
+ /* Fetch reply */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ account_name,
+ "TEST_RESPONSE_FILE",
+ &test_wire_file))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ account_name,
+ "TEST_RESPONSE_FILE");
+ return NULL;
+ }
+ ret = json_load_file (test_wire_file,
+ JSON_REJECT_DUPLICATES,
+ &err);
+ if (NULL == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse JSON in %s: %s (%s:%u)\n",
+ test_wire_file,
+ err.text,
+ err.source,
+ err.line);
+ GNUNET_free (test_wire_file);
+ return NULL;
+ }
+ if (GNUNET_YES != test_wire_validate (tc,
+ ret,
+ NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to validate TEST wire data in %s\n",
+ test_wire_file);
+ GNUNET_free (test_wire_file);
+ json_decref (ret);
+ return NULL;
+ }
+ GNUNET_free (test_wire_file);
+ return ret;
+}
+
+
GNUNET_NETWORK_STRUCT_BEGIN
/**
* Format we used for serialized transaction data.
@@ -287,11 +455,9 @@ GNUNET_NETWORK_STRUCT_END
* callback with the serialized state.
*
* @param cls the `struct TALER_WIRE_PrepareHandle`
- * @param sct unused
*/
static void
-do_prepare (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *sct)
+do_prepare (void *cls)
{
struct TALER_WIRE_PrepareHandle *pth = cls;
char *wire_enc;
@@ -363,9 +529,11 @@ test_prepare_wire_transfer (void *cls,
struct TALER_WIRE_PrepareHandle *pth;
if (GNUNET_YES !=
- test_wire_validate (wire))
+ test_wire_validate (tc,
+ wire,
+ NULL))
{
- GNUNET_break (0);
+ GNUNET_break_op (0);
return NULL;
}
pth = GNUNET_new (struct TALER_WIRE_PrepareHandle);
@@ -406,27 +574,100 @@ test_prepare_wire_transfer_cancel (void *cls,
* @param cls closure with the `struct TALER_WIRE_ExecuteHandle`
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol)
+ * @param json detailed response from the HTTPD, or NULL if reply was not JSON
*/
static void
execute_cb (void *cls,
- unsigned int http_status)
+ unsigned int http_status,
+ json_t *json)
{
struct TALER_WIRE_ExecuteHandle *eh = cls;
- char s[14];
+ json_t *reason;
+ const char *emsg;
+ char *s;
eh->aaih = NULL;
- GNUNET_snprintf (s,
- sizeof (s),
- "%u",
- http_status);
+ emsg = NULL;
+ if (NULL != json)
+ {
+ reason = json_object_get (json,
+ "reason");
+ if (NULL != reason)
+ emsg = json_string_value (reason);
+ }
+ if (NULL != emsg)
+ GNUNET_asprintf (&s,
+ "%u (%s)",
+ http_status,
+ emsg);
+ else
+ GNUNET_asprintf (&s,
+ "%u",
+ http_status);
eh->cc (eh->cc_cls,
(MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR,
(MHD_HTTP_OK == http_status) ? NULL : s);
+ GNUNET_free (s);
GNUNET_free (eh);
}
/**
+ * Sign wire transfer details in the plugin-specific format.
+ *
+ * @param cls closure
+ * @param in wire transfer details in JSON format
+ * @param key private signing key to use
+ * @param salt salt to add
+ * @param[out] sig where to write the signature
+ * @return #GNUNET_OK on success
+ */
+static int
+test_sign_wire_details (void *cls,
+ const json_t *in,
+ const struct TALER_MasterPrivateKeyP *key,
+ const struct GNUNET_HashCode *salt,
+ struct TALER_MasterSignatureP *sig)
+{
+ struct TALER_MasterWireDetailsPS wsd;
+ const char *bank_uri;
+ const char *type;
+ json_int_t account;
+ json_error_t err;
+
+ if (0 !=
+ json_unpack_ex ((json_t *) in,
+ &err,
+ 0 /* flags */,
+ "{s:s, s:s, s:I}",
+ "type", &type,
+ "bank_uri", &bank_uri,
+ "account_number", &account))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to unpack JSON: %s (at %u)\n",
+ err.text,
+ err.position);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp (type,
+ "test"))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "`type' must be `test' for test wire details\n");
+ return GNUNET_SYSERR;
+ }
+ compute_purpose (account,
+ bank_uri,
+ &wsd);
+ GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
+ &wsd.purpose,
+ &sig->eddsa_signature);
+ return GNUNET_OK;
+}
+
+
+/**
* Execute a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -451,6 +692,12 @@ test_execute_wire_transfer (void *cls,
json_int_t account_no;
struct BufFormatP bf;
+ if (NULL == tc->bank)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Bank not initialized, cannot do transfers!\n");
+ return NULL; /* not initialized with configuration, cannot do transfers */
+ }
if ( (buf_size <= sizeof (struct BufFormatP)) ||
('\0' != buf[buf_size -1]) )
{
@@ -471,7 +718,9 @@ test_execute_wire_transfer (void *cls,
return NULL;
}
GNUNET_assert (GNUNET_YES ==
- test_wire_validate (wire));
+ test_wire_validate (tc,
+ wire,
+ NULL));
if (0 !=
json_unpack_ex (wire,
&error,
@@ -482,13 +731,14 @@ test_execute_wire_transfer (void *cls,
GNUNET_break (0);
return NULL;
}
-
+
eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle);
eh->cc = cc;
eh->cc_cls = cc_cls;
eh->aaih = TALER_BANK_admin_add_incoming (tc->bank,
&bf.wtid,
&amount,
+ (uint64_t) tc->exchange_account_outgoing_no,
(uint64_t) account_no,
&execute_cb,
eh);
@@ -537,45 +787,63 @@ libtaler_plugin_wire_test_init (void *cls)
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
struct TestClosure *tc;
struct TALER_WIRE_Plugin *plugin;
- char *uri;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "wire-test",
- "bank_uri",
- &uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "wire-test",
- "bank_uri");
- return NULL;
- }
tc = GNUNET_new (struct TestClosure);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "CURRENCY",
- &tc->currency))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "CURRENCY");
- GNUNET_free (uri);
- GNUNET_free (tc);
- return NULL;
- }
- tc->bank = TALER_BANK_init (uri);
- if (NULL == tc->bank)
+ if (NULL != cfg)
{
- GNUNET_break (0);
- GNUNET_free (tc->currency);
- GNUNET_free (tc);
- return NULL;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "wire-outgoing-test",
+ "BANK_URI",
+ &tc->bank_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "wire-outgoing-test",
+ "BANK_URI");
+ GNUNET_free (tc);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "wire-outgoing-test",
+ "EXCHANGE_ACCOUNT_NUMBER",
+ &tc->exchange_account_outgoing_no))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "wire-outgoing-test",
+ "EXCHANGE_ACCOUNT_NUMBER");
+ GNUNET_free (tc->bank_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 (tc->bank_uri);
+ GNUNET_free (tc);
+ return NULL;
+ }
+ tc->bank = TALER_BANK_init (tc->bank_uri);
+ if (NULL == tc->bank)
+ {
+ GNUNET_break (0);
+ GNUNET_free (tc->currency);
+ GNUNET_free (tc->bank_uri);
+ GNUNET_free (tc);
+ return NULL;
+ }
}
-
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = tc;
plugin->amount_round = &test_amount_round;
+ plugin->get_wire_details = &test_get_wire_details;
+ plugin->sign_wire_details = &test_sign_wire_details;
plugin->wire_validate = &test_wire_validate;
plugin->prepare_wire_transfer = &test_prepare_wire_transfer;
plugin->prepare_wire_transfer_cancel = &test_prepare_wire_transfer_cancel;
@@ -602,8 +870,13 @@ libtaler_plugin_wire_test_done (void *cls)
GNUNET_SCHEDULER_cancel (tc->bt);
tc->bt = NULL;
}
- TALER_BANK_fini (tc->bank);
- GNUNET_free (tc->currency);
+ if (NULL != tc->bank)
+ {
+ TALER_BANK_fini (tc->bank);
+ tc->bank = NULL;
+ }
+ GNUNET_free_non_null (tc->currency);
+ GNUNET_free_non_null (tc->bank_uri);
GNUNET_free (tc);
GNUNET_free (plugin);
return NULL;
diff --git a/src/wire/test_sepa_wireformat.c b/src/wire/test_sepa_wireformat.c
index edbe5bc45..cd31a971c 100644
--- a/src/wire/test_sepa_wireformat.c
+++ b/src/wire/test_sepa_wireformat.c
@@ -28,37 +28,37 @@
/* Valid SEPA data */
static const char * const valid_wire_str =
"{ \"type\":\"SEPA\", \
-\"IBAN\":\"DE67830654080004822650\", \
+\"iban\":\"DE67830654080004822650\", \
\"name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
/* IBAN has wrong country code */
static const char * const invalid_wire_str =
"{ \"type\":\"SEPA\", \
-\"IBAN\":\"XX67830654080004822650\", \
+\"iban\":\"XX67830654080004822650\", \
\"name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
/* IBAN has wrong checksum */
static const char * const invalid_wire_str2 =
"{ \"type\":\"SEPA\", \
-\"IBAN\":\"DE67830654080004822651\", \
+\"iban\":\"DE67830654080004822651\", \
\"name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
/* Unsupported wireformat type */
static const char * const unsupported_wire_str =
"{ \"type\":\"unsupported\", \
-\"IBAN\":\"DE67830654080004822650\", \
+\"iban\":\"DE67830654080004822650\", \
\"name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
@@ -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,
@@ -85,16 +85,24 @@ main(int argc,
GNUNET_assert (NULL != plugin);
(void) memset(&error, 0, sizeof(error));
GNUNET_assert (NULL != (wire = json_loads (unsupported_wire_str, 0, NULL)));
- GNUNET_assert (GNUNET_YES != plugin->wire_validate (wire));
+ GNUNET_assert (GNUNET_YES != plugin->wire_validate (NULL,
+ wire,
+ NULL));
json_decref (wire);
GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str, 0, NULL)));
- GNUNET_assert (GNUNET_NO == plugin->wire_validate (wire));
+ GNUNET_assert (GNUNET_NO == plugin->wire_validate (NULL,
+ wire,
+ NULL));
json_decref (wire);
GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str2, 0, NULL)));
- GNUNET_assert (GNUNET_NO == plugin->wire_validate (wire));
+ GNUNET_assert (GNUNET_NO == plugin->wire_validate (NULL,
+ wire,
+ NULL));
json_decref (wire);
GNUNET_assert (NULL != (wire = json_loads (valid_wire_str, 0, &error)));
- ret = plugin->wire_validate (wire);
+ ret = plugin->wire_validate (NULL,
+ wire,
+ NULL);
json_decref (wire);
TALER_WIRE_plugin_unload (plugin);
GNUNET_CONFIGURATION_destroy (cfg);
diff --git a/src/wire/test_wire_plugin.c b/src/wire/test_wire_plugin.c
new file mode 100644
index 000000000..27b4366c1
--- /dev/null
+++ b/src/wire/test_wire_plugin.c
@@ -0,0 +1,196 @@
+/*
+ This file is part of TALER
+ (C) 2015, 2016 GNUnet e.V. and Inria
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file wire/test_wire_plugin.c
+ * @brief Tests for wire plugins
+ * @author Christian Grothoff
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_wire_lib.h"
+#include "taler_wire_plugin.h"
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+
+
+/**
+ * Definitions for a test with a plugin.
+ */
+struct TestBlock {
+
+ /**
+ * Name of the plugin to test.
+ */
+ const char *plugin_name;
+
+ /**
+ * JSON template expected by the plugin for an account definition.
+ */
+ const char *json_proto;
+
+};
+
+
+/**
+ * List of plugins and (unsigned) JSON account definitions
+ * to use for the tests.
+ */
+static struct TestBlock tests[] = {
+ { "sepa", "{ \"type\":\"sepa\", \"iban\":\"DE67830654080004822650\", \"name\":\"GNUnet e.V.\", \"bic\":\"GENODEF1SLR\" }" },
+ { "test", "{ \"type\":\"test\", \"bank_uri\":\"http://localhost/\", \"account_number\":42 }" },
+ { NULL, NULL }
+};
+
+
+/**
+ * Private key used to sign wire details.
+ */
+static struct TALER_MasterPrivateKeyP priv_key;
+
+/**
+ * Public key matching #priv_key.
+ */
+static struct TALER_MasterPublicKeyP pub_key;
+
+/**
+ * Our configuration.
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/**
+ * Run the test.
+ *
+ * @param name of the test
+ * @param plugin plugin to test
+ * @param wire wire details for testing
+ * @return #GNUNET_OK on success
+ */
+static int
+run_test (const char *name,
+ struct TALER_WIRE_Plugin *plugin,
+ json_t *wire)
+{
+ struct GNUNET_HashCode salt;
+ struct TALER_MasterSignatureP sig;
+ json_t *lwire;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &salt,
+ sizeof (salt));
+ if (GNUNET_OK !=
+ plugin->sign_wire_details (plugin->cls,
+ wire,
+ &priv_key,
+ &salt,
+ &sig))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ json_object_set_new (wire,
+ "salt",
+ GNUNET_JSON_from_data (&salt,
+ sizeof (salt)));
+ json_object_set_new (wire,
+ "sig",
+ GNUNET_JSON_from_data (&sig,
+ sizeof (sig)));
+ if (GNUNET_OK !=
+ plugin->wire_validate (plugin->cls,
+ wire,
+ &pub_key))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* load wire details from file */
+ lwire = plugin->get_wire_details (plugin->cls,
+ cfg,
+ name);
+ if (NULL == lwire)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ plugin->wire_validate (plugin->cls,
+ lwire,
+ &pub_key))
+ {
+ GNUNET_break (0);
+ json_decref (lwire);
+ return GNUNET_SYSERR;
+ }
+ json_decref (lwire);
+ return GNUNET_OK;
+}
+
+
+int
+main (int argc,
+ const char *const argv[])
+{
+ json_t *wire;
+ int ret;
+ struct TALER_WIRE_Plugin *plugin;
+ const struct TestBlock *test;
+ unsigned int i;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
+
+ GNUNET_log_setup ("test-wire-plugin",
+ "WARNING",
+ NULL);
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_load (cfg,
+ "test_wire_plugin.conf"));
+ pk = GNUNET_CRYPTO_eddsa_key_create_from_file ("test_wire_plugin_key.priv");
+ priv_key.eddsa_priv = *pk;
+ GNUNET_free (pk);
+ GNUNET_CRYPTO_eddsa_key_get_public (&priv_key.eddsa_priv,
+ &pub_key.eddsa_pub);
+ ret = GNUNET_OK;
+ for (i=0;NULL != (test = &tests[i])->plugin_name;i++)
+ {
+ plugin = TALER_WIRE_plugin_load (cfg,
+ test->plugin_name);
+ GNUNET_assert (NULL != plugin);
+ wire = json_loads (test->json_proto, 0, NULL);
+ GNUNET_assert (NULL != wire);
+ ret = run_test (test->plugin_name, plugin, wire);
+ json_decref (wire);
+ TALER_WIRE_plugin_unload (plugin);
+ if (GNUNET_OK != ret)
+ {
+ fprintf (stdout,
+ "%s FAILED\n",
+ test->plugin_name);
+ break;
+ }
+ else
+ {
+ fprintf (stdout,
+ "%s PASS\n",
+ test->plugin_name);
+ }
+ }
+ GNUNET_CONFIGURATION_destroy (cfg);
+ if (GNUNET_NO == ret)
+ return 1;
+ return 0;
+}
diff --git a/src/wire/test_wire_plugin.conf b/src/wire/test_wire_plugin.conf
new file mode 100644
index 000000000..ece816954
--- /dev/null
+++ b/src/wire/test_wire_plugin.conf
@@ -0,0 +1,21 @@
+# This file is in the public domain.
+#
+[test]
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+TEST_RESPONSE_FILE = test_wire_plugin_test.json
+
+[sepa]
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+SEPA_RESPONSE_FILE = test_wire_plugin_sepa.json
+
+
+[wire-outgoing-test]
+# For transfers made by the exchange, we need to know
+# the URI of the bank (where the /admin/add/incoming API
+# is avaialble).
+BANK_URI = http://localhost/
+
+[exchange]
+CURRENCY = "EUR"
diff --git a/src/wire/test_wire_plugin_key.priv b/src/wire/test_wire_plugin_key.priv
new file mode 100644
index 000000000..26b4f26f6
--- /dev/null
+++ b/src/wire/test_wire_plugin_key.priv
@@ -0,0 +1 @@
+?Sgb@Js; %aKȉs_Hў \ No newline at end of file
diff --git a/src/wire/test_wire_plugin_sepa.json b/src/wire/test_wire_plugin_sepa.json
new file mode 100644
index 000000000..175345f0c
--- /dev/null
+++ b/src/wire/test_wire_plugin_sepa.json
@@ -0,0 +1,8 @@
+{
+ "salt": "32V01R7K4T02S74PZZMVXRQ1K7FR948RBNB9BJ5Z101HEQFH7CW7J82006GY3BPTGQ4FM775PSSRD3K9MY97HSNVVCGEVBPVSAQ2710",
+ "type": "sepa",
+ "iban": "DE67830654080004822650",
+ "sig": "K48GPPM715ZXX0DC597WESD5ECT3R0B3TAFQMB68SBF4K5CZ5KCE9NESN1JX412SPZ82PSV7JAPVJFXDDTZ63YV4295S5RC28E4221G",
+ "name": "GNUnet e.V.",
+ "bic": "GENODEF1SLR"
+} \ No newline at end of file
diff --git a/src/wire/test_wire_plugin_test.json b/src/wire/test_wire_plugin_test.json
new file mode 100644
index 000000000..6fe6b2359
--- /dev/null
+++ b/src/wire/test_wire_plugin_test.json
@@ -0,0 +1,7 @@
+{
+ "type": "test",
+ "bank_uri": "http://localhost/",
+ "sig": "KX1CMHNFH1WE10244AEF07AXHJCF9PZDZVNZBC9P4EJEQ1MH1Y3C2TWF08VTQMK4N5TCV0V1VTGWSV0WB8TB9YQRZW87F5A6KCEZ81R",
+ "account_number": 42,
+ "salt": "EZV905MQPVAZEMGC6SEZQF2Z75P6ZKTN8TX00JHN11S7J81DQ78G8Z551K6TGR9WHPP0JW1X9J9X9CVRY48JTHBCP6Q4XKJ6R2G18G0"
+} \ No newline at end of file
diff --git a/src/wire/wire-sepa.conf b/src/wire/wire-sepa.conf
new file mode 100644
index 000000000..7321a2be6
--- /dev/null
+++ b/src/wire/wire-sepa.conf
@@ -0,0 +1,10 @@
+# Configuration for SEPA wire plugin.
+
+[wire-incoming-sepa]
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+SEPA_RESPONSE_FILE = ${TALER_CONFIG_HOME}/sepa.json
+
+[wire-outgoing-sepa]
+# This section should contain the options required for making outgoing
+# SEPA transfers. Not yet supported (need libebics).
diff --git a/src/wire/wire-test.conf b/src/wire/wire-test.conf
new file mode 100644
index 000000000..98e486acb
--- /dev/null
+++ b/src/wire/wire-test.conf
@@ -0,0 +1,16 @@
+# This file is in the public domain.
+#
+[wire-incoming-test]
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
+
+[wire-outgoing-test]
+# For outgoing transfers, we need to know the exchange's
+# account number at the bank.
+EXCHANGE_ACCOUNT_NUMBER = 2
+
+# For transfers made by the exchange, we need to know
+# the URI of the bank (where the /admin/add/incoming API
+# is avaialble).
+# BANK_URI = https://bank.demo.taler.net/